superstruct icon indicating copy to clipboard operation
superstruct copied to clipboard

Add moving getters to `RefMut`

Open michaelsproul opened this issue 2 years ago • 0 comments

Presently the mutable getters on RefMut require that the self parameter has the same lifetime as the inner reference. So for a type like this Message, we generate getters as shown below:

#[superstruct(variants(A, B))]
struct Message {
    pub x: String,
    #[superstruct(only(B))]
    pub y: String,
}
impl MessageRefMut<'a> {
    fn x_mut(&'a mut self) -> &'a mut String;
    fn y_mut(&'a mut self) -> Result<&'a mut String, ()>;
}

Note how the getters require &'a mut self, when self also contains a &'a mut Message{A,B}.

This lifetime restriction prevents converting a MessageRefMut into a reference that outlives the RefMut itself, e.g.

// Does not compile
fn get_x(message: &mut Message) -> &mut String {
    message.to_mut().x_mut()
}

This pattern may be useful sometimes, and is possible with an ordinary mutable reference, i.e. if we had just &'a mut Message{A,B} we could get a &'a mut to one of its fields.

To fix the issue I propose we generate additional moving getters on RefMut that take self by value:

impl MessageRefMut<'a> {
    fn into_x_mut(self) -> &'a mut String;
    fn into_y_mut(self) -> Result<&'a mut String, ()>;
}

This is a similar pattern to hash_map::OccupiedEntry::into_mut.

NB: this issue doesn't affect Ref because it uses immutable references: message.to_ref().x() is fine.

michaelsproul avatar Dec 29 '21 22:12 michaelsproul