Trying to get a mutable String (or maybe &mut str) from an enum

I have this enum

pub enum ArgVal<'argval> {
...
    RustString(&'argval String),
    None,
...
}

I have a Vec of them in a struct

pub struct FuncDef<'argval> {
...
    pub(crate) arg_vals: Vec<ArgVal<'argval>>,
...
}

I need to perform an update on the string if I have an ArgVal::RustString. I cannot find the correct incantation. Here is my current effort

                       // I know val_idx is valid
                        let arg_str = self.arg_vals.get_mut(val_idx).unwrap();
                        if let ArgVal::RustString(str) = arg_str {
                            unsafe {
                                str.as_mut_vec().set_len(len);
                            }
                        }

I get

error[E0596]: cannot borrow `**str` as mutable, as it is behind a `&` reference
   --> src\caller.rs:121:33
    |
121 | ...                   str.as_mut_vec().set_len(len);
    |                       ^^^ cannot borrow as mutable

Hovering over str shows that it is an &mut &String, which isnt right. I need a &mut String.
I have tried changing RustString to be &'argval str but it makes no difference.

Note that I want to update my callers String (like read_line does) , hence the reference in the enum, not a String instance.

You can't modify the String because it's behind a shared reference. If you want to be able to modify it, it needs to be:

pub enum ArgVal<'argval> {
    RustString(&'argval mut String),
    None,
}

my problem with that is that it makes ArgVal uncloneable

Indeed, &mut _ cannot be cloned, as they are exclusive references.

Perhaps you need an Arc<Mutex<String>> or similar. Sounds like you need some sort of shared mutability at any rate.

1 Like

OK, I removed the need for the clone (I will come back to the functionality I had to remove later)

Thanks for being a second brain