`&mut self` version of Option methods

It will be convenient to have f(&mut self, optb: Option<T>) version of Option<T>'s f(self, optb: Option<T>) -> Option<T> methods, especially when an option is a field of a struct.

Do you have specific examples? Most of the time, it works to call option.as_mut() first.

trait OrSelf<T> {
    fn or_self(&mut self, optb: Option<T>);
}

impl<T> OrSelf<T> for Option<T> {
    fn or_self(&mut self, optb: Option<T>) {
        match self {
            Some(_) => {},
            None => {
                let _ = core::mem::replace(self, optb);
            }
        }
    }
}

// for more complex types we can use or_else_self, concept is the same
type SomeProp = bool;

struct List {
    prop: Option<SomeProp>,
    items: Vec<Item>,
}

struct Item {
    prop: Option<SomeProp>,
}

impl List {
    fn apply_list_prop(&mut self) {
        for item in &mut self.items {
            item.prop.or_self(self.prop);
        }
    }
}

playground

Side note: Instead of

let _ = core::mem::replace(self, optb);

you can just write

*self = optb;

so the implementation could become

impl<T> OrSelf<T> for Option<T> {
    fn or_self(&mut self, optb: Option<T>) {
        if self.is_none() {
            *self = optb; 
        }
    }
}

In general, it’s also possible to call the existing Option methods relatively easily using the .take() method, e.g. – demonstrated as an alternative implementation of OrSelf:

impl<T> OrSelf<T> for Option<T> {
    fn or_self(&mut self, optb: Option<T>) {
        *self = self.take().or(optb)
    }
}

Of course, it’d be interesting to check whether this optimizes properly or if there’s any overhead left.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.