Files
Mike Hommey 1c26b8dd06 Bug 2011354 - Bump required cargo version to 1.90 for vendoring. r=firefox-build-system-reviewers,webrtc-reviewers,dom-worker-reviewers,ng,ahochheiden
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
2026-01-23 04:16:34 +00:00
..
…
…

replace_with

Crates.io MIT / Apache 2.0 licensed Build Status

📖 Docs | 💬 Chat

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

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.