Skip to content

Commit

Permalink
Merge pull request #13 from alecmocatta/ondrop
Browse files Browse the repository at this point in the history
Add on_return_or_unwind
  • Loading branch information
mergify[bot] authored Jul 18, 2020
2 parents 840b826 + f110470 commit c3730ae
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 92 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "replace_with"
version = "0.1.5"
version = "0.1.6"
license = "MIT OR Apache-2.0"
authors = ["Alec Mocatta <[email protected]>"]
categories = ["rust-patterns"]
Expand All @@ -10,12 +10,12 @@ Temporarily take ownership of a value at a mutable location, and replace it with
"""
repository = "https://github.com/alecmocatta/replace_with"
homepage = "https://github.com/alecmocatta/replace_with"
documentation = "https://docs.rs/replace_with/0.1.5"
documentation = "https://docs.rs/replace_with"
readme = "README.md"
edition = "2018"

[badges]
azure-devops = { project = "alecmocatta/replace_with", pipeline = "tests" }
azure-devops = { project = "alecmocatta/replace_with", pipeline = "tests", build = "11" }
maintenance = { status = "actively-developed" }

[features]
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

[![Crates.io](https://img.shields.io/crates/v/replace_with.svg?maxAge=86400)](https://crates.io/crates/replace_with)
[![MIT / Apache 2.0 licensed](https://img.shields.io/crates/l/replace_with.svg?maxAge=2592000)](#License)
[![Build Status](https://dev.azure.com/alecmocatta/replace_with/_apis/build/status/tests?branchName=master)](https://dev.azure.com/alecmocatta/replace_with/_build/latest?branchName=master)
[![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)

[Docs](https://docs.rs/replace_with/0.1.5)
[📖 Docs](https://docs.rs/replace_with) | [💬 Chat](https://constellation.zulipchat.com/#narrow/stream/213236-subprojects)

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()`](https://docs.rs/replace_with/0.1.5/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.
This 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.

See [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 `&mut T` doesn't exist yet, so this crate is my interim solution.

It'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.5/replace_with/fn.replace_with.html) accepts two closures such that aborting in the "standard case" where the mapping closure (`FnOnce(T) -> 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() -> 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.5/replace_with/fn.replace_with_or_abort.html).
It'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) -> 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() -> 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).

## Example

Expand Down Expand Up @@ -70,9 +70,9 @@ features = []
...
```

The [`replace_with()`](https://docs.rs/replace_with/0.1.5/replace_with/fn.replace_with.html) & [`replace_with_or_default()`](https://docs.rs/replace_with/0.1.5/replace_with/fn.replace_with_or_default.html) functions are available on stable Rust both, with and without `std`.
The [`replace_with()`](https://docs.rs/replace_with/0.1/replace_with/fn.replace_with.html) & [`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`.

The [`replace_with_or_abort()`](https://docs.rs/replace_with/0.1.5/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`.
The [`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`.

As 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.

Expand Down Expand Up @@ -102,7 +102,7 @@ features = ["panic_abort"]
...
```

… the `"panic_abort"` feature enables the [`replace_with_or_abort_unchecked()`](https://docs.rs/replace_with/0.1.5/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)));`.
… 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)));`.

**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!

Expand Down
10 changes: 5 additions & 5 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ jobs:
endpoint: alecmocatta
default:
rust_toolchain: 1.21.0 stable beta nightly
rust_lint_toolchain: nightly-2019-07-19
rust_lint_toolchain: nightly-2020-07-12
rust_flags: ''
rust_features: ';default;all'
rust_target_check: ''
rust_target_build: ''
rust_target_run: ''
matrix:
windows:
imageName: 'vs2017-win2016'
imageName: 'windows-latest'
rust_target_run: 'x86_64-pc-windows-msvc'
mac:
imageName: 'macos-10.13'
imageName: 'macos-latest'
rust_target_run: 'x86_64-apple-darwin'
linux:
imageName: 'ubuntu-16.04'
rust_target_run: 'x86_64-unknown-linux-gnu x86_64-unknown-linux-musl'
imageName: 'ubuntu-latest'
rust_target_run: 'x86_64-unknown-linux-gnu'
Loading

0 comments on commit c3730ae

Please sign in to comment.