We're going to update the MSRV to 1.90 soon, and we might as well remove the hacks we have in place from bug 1982939 and bug 1995920 for vendoring backwards compatibility early. Differential Revision: https://phabricator.services.mozilla.com/D279628
replace_with
Temporarily take ownership of a value at a mutable location, and replace it with a new value based on the old one.
This crate provides the function replace_with(), which is like std::mem::replace() except it allows the replacement value to be mapped from the original value.
See RFC 1736 for a lot of discussion as to its merits. It was never merged, and the desired ability to temporarily move out of &mut T doesn't exist yet, so this crate is my interim solution.
It's very akin to take_mut, though uses Drop instead of std::panic::catch_unwind() to react to unwinding, which avoids the optimisation barrier of calling the extern "C" __rust_maybe_catch_panic(). As such it's up to ∞x faster. The API also attempts to make slightly more explicit the behavior on panic – replace_with() accepts two closures such that aborting in the "standard case" where the mapping closure (FnOnce(T) -> T) panics (as take_mut::take() does) is avoided. If the second closure (FnOnce() -> T) panics, however, then it does indeed abort. The "abort on first panic" behaviour is available with replace_with_or_abort().
Example
Consider this motivating example:
enum States {
A(String),
B(String),
}
impl States {
fn poll(&mut self) {
// error[E0507]: cannot move out of borrowed content
*self = match *self {
// ^^^^^ cannot move out of borrowed content
States::A(a) => States::B(a),
States::B(a) => States::A(a),
};
}
}
Depending on context this can be quite tricky to work around. With this crate, however:
enum States {
A(String),
B(String),
}
impl States {
fn poll(&mut self) {
replace_with_or_abort(self, |self_| match self_ {
States::A(a) => States::B(a),
States::B(a) => States::A(a),
});
}
}
Huzzah!
no_std
To use replace_with with no_std you have to disable the std feature, which is active by default, by specifying your dependency to it like this:
# Cargo.toml
replace_with = { version = "0.1", default-features = false }
The nightly feature can be enabled to use core::intrinsics::abort() instead of triggering an abort via std::process::abort() or extern "C" fn abort() { panic!() } abort().
License
Licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE.txt or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT.txt or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.