Skip to content

Transferring ownership of fields #54

Closed
@icorderi

Description

@icorderi

Say type T has a field u of type U and field v of type V.
T and U are both ::protobuf::Message.

I have the following function:

fn foo(t: T) -> Result<U> {
    // look into t.v and return Err based on same value
    // return Ok(t.u) 
}

Even though it seems like I have ownership over t, I can't deconstruct a Message and pass on ownership of the field u.

I recommend adding something similar to the following two extra functions per field

    // same as existing
    pub fn mut_field(&'a mut self) -> &'a mut T {
        if self.status.is_none() {
            self.field.set_default();
        };
        self.field.as_mut().unwrap()
    }

    // same as existing
    pub fn get_field(&'a self) -> &'a T {
        self.field.as_ref().unwrap_or_else(|| T::default_instance())
    }

    // new, the idea is to take the field away from the enclosing message
    // ownership is transferred to the caller
    pub fn take_field(&mut self) -> T {
        // perhaps we should leave a tombstone behind 
        // the current impl of take refill the value with default
        self.field.take().unwrap() 
    }

    // the original message's life ends here, 
    // ownership of the field is passed on
    pub fn unwrap_field(self) -> T {
        self.field.unwrap()
    }

With the new semantics I can now implement my method by:

fn foo(t: T) -> Result<U> {
    let v = t.take_v();
    if v.w { Err("Error...") }
    else { Ok ( t.unwrap_u() ) }
}

I don't know if this is the correct way of solving the use case, but it makes it possible to implement.

Another option is...

A possible breaking change given that this needs to be implemented for each field is to have a single get_field that returns Field<T> and have that wrapper trait surface take(), unwrap(), as_ref(), and as_mut() (perhaps clone() if T : Clone). I know this is a subset of SingularField and SingularPtrField backing the internal Message.

Honestly, I've seen all those functions being used throughout the std and other crates, I'm not sure if it's worth bringing it up with the Rust devs but having 4 unique traits that represent each of those operations might clean up a lot of code and allow for certain generic macro sugaring. If I'm not mistaken, Deref and DerefMut cover the signatures for as_ref and as_mut as operator overloads which is what is currently available with get_field and get_mut_field. I'm not sure if the borrow module is more applicable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions