You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardexpand all lines: src/lib.rs
+8-89
Original file line number
Diff line number
Diff line change
@@ -1,19 +1,21 @@
1
-
//! This crate provides (at this time) a single function, `take()`.
1
+
//! This crate provides several functions for handling `&mut T` including `take()`.
2
2
//!
3
3
//! `take()` allows for taking `T` out of a `&mut T`, doing anything with it including consuming it, and producing another `T` to put back in the `&mut T`.
4
4
//!
5
-
//! During `take()`, if a panic occurs, the entire process will be exited, as there's no valid `T` to put back into the `&mut T`.
5
+
//! During `take()`, if a panic occurs, the entire process will be aborted, as there's no valid `T` to put back into the `&mut T`.
6
6
//! Use `take_or_recover()` to replace the `&mut T` with a recovery value before continuing the panic.
7
7
//!
8
8
//! Contrast with `std::mem::replace()`, which allows for putting a different `T` into a `&mut T`, but requiring the new `T` to be available before being able to consume the old `T`.
9
9
10
10
use std::panic;
11
11
12
+
pubmod scoped;
13
+
12
14
/// Allows use of a value pointed to by `&mut T` as though it was owned, as long as a `T` is made available afterwards.
13
15
///
14
16
/// The closure must return a valid T.
15
17
/// # Important
16
-
/// Will exit the program (with status code 101) if the closure panics.
//! This module provides a scoped API, allowing for taking an arbitrary number of `&mut T` into `T` within one closure.
2
+
//! The references are all required to outlive the closure.
3
+
//!
4
+
//! # Example
5
+
//! ```
6
+
//! use take_mut::scoped;
7
+
//! struct Foo;
8
+
//! let mut foo = Foo; // Must outlive scope
9
+
//! scoped::scope(|scope| {
10
+
//! let (t, hole) = scope.take(&mut foo);
11
+
//! drop(t);
12
+
//! hole.fill(Foo); // If not called before the closure ends, causes an abort.
13
+
//! });
14
+
//! ```
15
+
//!
16
+
//! # Invalid Example (does not compile)
17
+
//! ```ignore
18
+
//! use take_mut::scoped;
19
+
//! struct Foo;
20
+
//! scoped::scope(|scope| {
21
+
//! let mut foo = Foo; // Invalid because foo must come from outside the scope.
22
+
//! let (t, hole) = scope.take(&mut foo);
23
+
//! drop(t);
24
+
//! hole.fill(Foo);
25
+
//! });
26
+
//! ```
27
+
//!
28
+
//! `Scope` also offers `take_or_recover`, which takes a function to call in the event the hole isn't filled.
29
+
30
+
#![warn(missing_docs)]
31
+
32
+
33
+
use std;
34
+
use std::panic;
35
+
use std::cell::Cell;
36
+
use std::marker::PhantomData;
37
+
38
+
/// Represents a scope within which, it is possible to take a `T` from a `&mut T` as long as the `&mut T` outlives the scope.
39
+
pubstructScope<'s>{
40
+
active_holes:Cell<usize>,
41
+
marker:PhantomData<Cell<&'smut()>>
42
+
}
43
+
44
+
impl<'s>Scope<'s>{
45
+
46
+
/// Takes a `(T, Hole<'c, 'm, T, F>)` from an `&'m mut T`.
47
+
///
48
+
/// If the `Hole` is dropped without being filled, either due to panic or forgetting to fill, will run the `recovery` function to obtain a `T` to fill itself with.
/// If the given closure ends without all Holes filled, will abort the program.
84
+
pubfnscope<'s,F,R>(f:F) -> R
85
+
whereF:FnOnce(&Scope<'s>) -> R{
86
+
let this = Scope{active_holes:Cell::new(0),marker:PhantomData};
87
+
let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
88
+
f(&this)
89
+
}));
90
+
if this.active_holes.get() != 0{
91
+
std::process::abort();
92
+
}
93
+
match result {
94
+
Ok(r) => r,
95
+
Err(p) => panic::resume_unwind(p),
96
+
}
97
+
98
+
}
99
+
100
+
/// A `Hole<'c, 'm, T, F>` represents an unfilled `&'m mut T` which must be filled before the end of the `Scope` with lifetime `'c` and recovery closure `F`.
101
+
///
102
+
/// An unfilled `Hole<'c, 'm, T, F> that is destructed will try to use `F` to fill the hole.
103
+
///
104
+
/// If the scope ends without the `Hole` being filled, the program will `std::process::abort()`.
0 commit comments