{"id":16687800,"url":"https://github.com/alecmocatta/replace_with","last_synced_at":"2025-04-05T15:05:31.395Z","repository":{"id":52417294,"uuid":"156761503","full_name":"alecmocatta/replace_with","owner":"alecmocatta","description":"Temporarily take ownership of a value at a mutable location, and replace it with a new value based on the old one.","archived":false,"fork":false,"pushed_at":"2022-06-13T15:15:37.000Z","size":56,"stargazers_count":109,"open_issues_count":7,"forks_count":8,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-29T14:06:51.010Z","etag":null,"topics":["mutability","rust","rust-patterns"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alecmocatta.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-11-08T19:57:55.000Z","updated_at":"2025-01-31T06:38:26.000Z","dependencies_parsed_at":"2022-09-06T23:20:46.638Z","dependency_job_id":null,"html_url":"https://github.com/alecmocatta/replace_with","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecmocatta%2Freplace_with","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecmocatta%2Freplace_with/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecmocatta%2Freplace_with/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecmocatta%2Freplace_with/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alecmocatta","download_url":"https://codeload.github.com/alecmocatta/replace_with/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247353731,"owners_count":20925329,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mutability","rust","rust-patterns"],"created_at":"2024-10-12T15:25:08.528Z","updated_at":"2025-04-05T15:05:31.368Z","avatar_url":"https://github.com/alecmocatta.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# replace_with\n\n[![Crates.io](https://img.shields.io/crates/v/replace_with.svg?maxAge=86400)](https://crates.io/crates/replace_with)\n[![MIT / Apache 2.0 licensed](https://img.shields.io/crates/l/replace_with.svg?maxAge=2592000)](#License)\n[![Build Status](https://dev.azure.com/alecmocatta/replace_with/_apis/build/status/tests?branchName=master)](https://dev.azure.com/alecmocatta/replace_with/_build?definitionId=11)\n\n[📖 Docs](https://docs.rs/replace_with) | [💬 Chat](https://constellation.zulipchat.com/#narrow/stream/213236-subprojects)\n\nTemporarily take ownership of a value at a mutable location, and replace it with a new value based on the old one.\n\nThis crate provides the function [`replace_with()`](https://docs.rs/replace_with/0.1/replace_with/fn.replace_with.html), which is like [`std::mem::replace()`](https://doc.rust-lang.org/std/mem/fn.replace.html) except it allows the replacement value to be mapped from the original value.\n\nSee [RFC 1736](https://github.com/rust-lang/rfcs/pull/1736) for a lot of discussion as to its merits. It was never merged, and the desired ability to temporarily move out of `\u0026mut T` doesn't exist yet, so this crate is my interim solution.\n\nIt's very akin to [`take_mut`](https://github.com/Sgeo/take_mut), though uses `Drop` instead of [`std::panic::catch_unwind()`](https://doc.rust-lang.org/std/panic/fn.catch_unwind.html) 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()`](https://docs.rs/replace_with/0.1/replace_with/fn.replace_with.html) accepts two closures such that aborting in the \"standard case\" where the mapping closure (`FnOnce(T) -\u003e T`) panics (as [`take_mut::take()`](https://docs.rs/take_mut/0.2.2/take_mut/fn.take.html) does) is avoided. If the second closure (`FnOnce() -\u003e T`) panics, however, then it does indeed abort. The \"abort on first panic\" behaviour is available with [`replace_with_or_abort()`](https://docs.rs/replace_with/0.1/replace_with/fn.replace_with_or_abort.html).\n\n## Example\n\nConsider this motivating example:\n\n```rust\nenum States {\n    A(String),\n    B(String),\n}\n\nimpl States {\n    fn poll(\u0026mut self) {\n        // error[E0507]: cannot move out of borrowed content\n        *self = match *self {\n            //        ^^^^^ cannot move out of borrowed content\n            States::A(a) =\u003e States::B(a),\n            States::B(a) =\u003e States::A(a),\n        };\n    }\n}\n```\n\nDepending on context this can be quite tricky to work around. With this crate, however:\n\n```rust\nenum States {\n    A(String),\n    B(String),\n}\n\nimpl States {\n    fn poll(\u0026mut self) {\n        replace_with_or_abort(self, |self_| match self_ {\n            States::A(a) =\u003e States::B(a),\n            States::B(a) =\u003e States::A(a),\n        });\n    }\n}\n```\n\nHuzzah!\n\n## `no_std`\n\nTo 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:\n\n```toml\n# Cargo.toml\n\n[dependencies.replace_with]\nversion = ...\ndefault-features = false\nfeatures = []\n...\n```\n\nThe [`replace_with()`](https://docs.rs/replace_with/0.1/replace_with/fn.replace_with.html) \u0026 [`replace_with_or_default()`](https://docs.rs/replace_with/0.1/replace_with/fn.replace_with_or_default.html) functions are available on stable Rust both, with and without `std`.\n\nThe [`replace_with_or_abort()`](https://docs.rs/replace_with/0.1/replace_with/fn.replace_with_or_abort.html) function however by default makes use of [`std::process::abort()`](https://doc.rust-lang.org/std/process/fn.abort.html) which is not available with `no_std`.\n\nAs such `replace_with` will by default call [`core::intrinsics::abort()`](https://doc.rust-lang.org/core/intrinsics/fn.abort.html) instead, which in turn requires nightly Rust.\n\nNot everything is lost for stable `no_std` though, `replace_with` has one more trick up its sleeve:\n\n### panic = \"abort\"\n\nIf you define [`panic = abort`](https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/aborting-on-panic.html) in the `[profile]` section of your crate's `Cargo.toml` …\n\n```toml\n# Cargo.toml\n\n[profile.debug]\npanic = \"abort\"\n\n[profile.release]\npanic = \"abort\"\n```\n\n… and add the `\"panic_abort\"` feature to `replace_with` in the `dependencies` section of your crate's `Cargo.toml` …\n\n```toml\n# Cargo.toml\n\n[dependencies.replace_with]\nfeatures = [\"panic_abort\"]\n...\n```\n\n… the `\"panic_abort\"` feature enables the [`replace_with_or_abort_unchecked()`](https://docs.rs/replace_with/0.1/replace_with/fn.replace_with_or_abort_unchecked.html) function becomes on stable Rust as an `unsafe` function, a simple wrapper around `ptr::write(dest, f(ptr::read(dest)));`.\n\n**Word of caution:** It is crucial to only ever use this function having defined `panic = \"abort\"`, or else bad things may happen. It's *up to you* to uphold this invariant!\n\n## License\nLicensed under either of\n\n * Apache License, Version 2.0, ([LICENSE-APACHE.txt](LICENSE-APACHE.txt) or http://www.apache.org/licenses/LICENSE-2.0)\n * MIT license ([LICENSE-MIT.txt](LICENSE-MIT.txt) or http://opensource.org/licenses/MIT)\n\nat your option.\n\nUnless 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.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falecmocatta%2Freplace_with","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falecmocatta%2Freplace_with","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falecmocatta%2Freplace_with/lists"}