I'm exercising with Arc and trying to make zero-copy structures. And here's a problem I don't know what to do about. Here's the playground with the code.
20 | impl<'a> TryFrom<ParsedAttrs<'a>> for OsmElementAttrs<'a> {
| -- lifetime `'a` defined here
21 | type Error = ParseError;
22 | fn try_from(attrs: ParsedAttrs) -> Result<Self, Self::Error> {
| ----- has type `HashMap<&'1 str, &'1 str>`
...
32 | Some(v) => Some(Arc::new(v)),
| ^^^^^^^^^^^^^^^^^ this usage requires that `'1` must outlive `'a`
How can I make sure the output outlives 'a if I can't annotate lifetimes inline?
What I was trying to do was to implement structs like in osmio crate (arc_types.rc module). There's an example here, but couldn't figure out what I'm missing. I've also tried to add 'b lifetime to output type, but it was just pure guessing and didn't work in any way.
Why are you putting a reference &'a str inside an Arc? That will almost always be less efficient and useful than either storing the reference directly or storing an Arc<str> (depending on what your goal is).
Oh. Now I see, I did read an article about Arc and it says this is double referencing and double work when reading.
The problem is if I try to remove &'a str the compiler says it can't know str size at compile time:
Compiling playground v0.0.1 (/playground)
error[E0277]: the size for values of type `str` cannot be known at compilation time
--> src/lib.rs:32:30
|
32 | Some(v) => Some(Arc::new(**v)),
| -------- ^^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `str`
note: required by a bound in `Arc::<T>::new`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to previous error
You can't clone dynamically-sized values by-value. If you only have a &str and you want an Arc<str>, then use the library-provided From impl for cloning the contents of the string.
In order to convert a &str to an Arc<str> you must convert it with .into() or Arc::from() — you can't dereference and use Arc::new(), specifically because that can only work with statically-sized (Sized) types.
However, this will copy the characters of the string. In order to get the most benefit from Arc<str> you should create it as early as possible in your program — for example, if you're parsing an input file, do it while parsing, right when you know which substrings you're splitting the input into. This will minimize the number of string copies rather than refcount increments. It's cheap to get an &str from Arc<str> for temporary use, but not vice versa.
On the other hand, if you want a truly zero-copy (as you mentioned in your original post) program, then you cannot use Arc and you must use only &strs that borrow from the original input string. This is often impossible — don't take it as the “correct” way to do things, but as one extreme.
I got back to where I insert-ed into HashMap, and now I see Arc::new(str) caused compiler error, and that's why I worked around with HashMap<&'a str, &'a str>. But Arc::from like in osmio arc_types.rc, does not have this problem.