Skip to content
/ takeable Public

A simple wrapper library to allow efficient updates.

License

Unknown and 2 other licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Unlicense
LICENSE-UNLICENSE
Notifications You must be signed in to change notification settings

kyp44/takeable

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Takeable

A simple wrapper type that holds values that need to be moved out from only a mutable reference.

Sometimes it's useful to be able to move out of a mutable reference temporarily or permanently. This often occurs for instance when dealing with state machines implemented using an enum. For instance let's say you have the following state machine:

enum State {
    Starting,
    Running(Resource1, Resource2),
    Finished(Option<Resource2>)
}

Let's say that you want to implement a function that changes state from Running to Finished. The naive approach would be:

pub fn to_finished(state: &mut State) {
    let newstate = match *state {
        State::Starting => State::Finished(None),
        State::Running(_, r) => State::Finished(Some(r)),
        State::Finished(r) => State::Finished(r),
    };
    *state = newstate;
}

However, this would fail with a "cannot move out of borrowed content" error.

There are a few solutions to this problem:

  • Use an Option<State>. Temporarily set it to None to move out the state.

  • Introduce a new, invalid state for the same purpose.

  • Use take from the take_mut crate.

  • Restructure your code to avoid the problem.

Depending on your scenario, any of these options might be preferable. This crate provides a wrapper around an Option<T> with an API that forces correct usage of the Option. This approach also has the advantage that it allows the performance-optimization of not actually checking the enum-tag outside of destructor-logic.

Using this library, the code could have been written like this:

struct StateMachine(Takeable<State>);

enum State {
    Starting,
    Running(Resource1, Resource2),
    Finished(Option<Resource2>)
}

pub fn to_finished(state: &mut StateMachine) {
    state.0.borrow(|state| {
        match state {
            State::Starting => State::Finished(None),
            State::Running(_, r) => State::Finished(Some(r)),
            State::Finished(r) => State::Finished(r),
        }
    });
}

It can also sometimes be useful to permanently move a value out while only having a mutable reference. One such use case is when implementing drop and needing to call a method of a field that consumes the field. This can be done using this crate as follows:

struct Resource;
impl Resource {
    pub fn close(self) {}
}

struct ResourceUser {
    resource: Takeable<Resource>;
}
impl Drop for ResourceUser {
    fn drop(&mut self) {
        self.resource.take().close();
    }
}

The above code would also work by using an Option directly instead of a Takeable. However, the latter has the advantage that it is clear by its type that it must always have a value, and also that None variants do not have to be handled when accessing the Resource elsewhere. Rather, the Takeable will panic if this is attempted after the value has been moved out.

About

A simple wrapper library to allow efficient updates.

Resources

License

Unknown and 2 other licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Unlicense
LICENSE-UNLICENSE

Stars

Watchers

Forks

Packages

No packages published

Languages