takeable/lib.rs
1// Copyright 2017 Mathias Svensson. See the COPYRIGHT file at the top-level
2// directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or https://opensource.org/licenses/MIT> or the Unlicense
7// <LICENSE-UNLICENSE or https://unlicense.org/UNLICENSE>, at your option.
8// All files in the project carrying such notice may not be copied,
9// modified, or distributed except according to those terms.
10
11//! Crate for temporarily or permanently moving out of a mutable pointer.
12//!
13//! This crate implements a single wrapper-type [`Takeable<T>`]. The main purpose of this wrapper
14//! is that it provides two convenient helper functions [`Takeable::borrow`] and [`Takeable::borrow_result`]
15//! that allows for temporarily moving out of the wrapper without violating safety. The value can also be permanently
16//! moved out, invalidating the container and causing a panic on any future attempts to access
17//! the value.
18//!
19//! The [`Takeable::borrow`] and [`Takeable::borrow_result`] methods work similarly to
20//! [`take`] from the [`take_mut`] crate. The main difference is that, while the [`take_mut`]
21//! is implemented using careful handling of unwind safety, this crate uses an [`Option<T>`] inside to make
22//! unwinding work as expected.
23//!
24//! The [`Takeable::take`] method works similarly to [`Option::take`], but has the advantage that the object becomes
25//! permanently invalidated. Additionally, using a [`Takeable<T>`] instead of an [`Option<T>`] makes
26//! it clear in code that a value is always expected and avoids the need to handle possible
27//! [`Option::None`] variants when accessing the `T`.
28//!
29//! [`take`]: https://docs.rs/take_mut/latest/take_mut/fn.take.html
30//! [`take_mut`]: https://crates.io/crates/take_mut
31#![no_std]
32#![deny(
33 missing_docs,
34 unsafe_code,
35 missing_debug_implementations,
36 missing_copy_implementations,
37 unstable_features,
38 unused_import_braces,
39 unused_qualifications
40)]
41
42use core::{
43 fmt::Display,
44 ops::{Deref, DerefMut},
45};
46
47/// A wrapper-type that always holds a single `T` value.
48///
49/// This type is implemented using an [`Option<T>`], however, the wrapper requires the [`Option<T>`] to
50/// always contain a value.
51///
52/// # Panics
53///
54/// If the closure given to [`borrow`][Self::borrow] or [`borrow_result`][Self::borrow_result] panics, then the `Takeable` is left in an
55/// invalid state without holding a `T`. Calling any method on the object besides [`is_usable`][Self::is_usable] when
56/// in this state will result in a panic. This includes trying to dereference the object. The object
57/// will also be permanently invalidated if the value is moved out manually using [`take`][Self::take].
58///
59/// It is always safe to drop the `Takeable` even when invalidated.
60#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
61pub struct Takeable<T> {
62 // During normal usage, the invariant is that that this value should *always* be a Some(value),
63 // unless we are inside the `borrow_result` function. However if the closure given the
64 // `borrow_result` panics, or the value is taken with `take`, then this will no longer be the
65 // case.
66 value: Option<T>,
67}
68
69/// Message to print when panicking because the `Takeable<T>` has been invalidated.
70const PANIC_MESSAGE: &str = "the value has already been removed from the Takeable";
71
72impl<T> Takeable<T> {
73 /// Constructs a new [`Takeable<T>`] value.
74 #[inline(always)]
75 pub fn new(value: T) -> Takeable<T> {
76 Takeable { value: Some(value) }
77 }
78
79 /// Takes ownership of the inner value.
80 #[inline(always)]
81 #[track_caller]
82 pub fn into_inner(self) -> T {
83 self.value.expect(PANIC_MESSAGE)
84 }
85
86 /// Updates the inner value using the provided closure.
87 #[inline(always)]
88 #[track_caller]
89 pub fn borrow<F>(&mut self, f: F)
90 where
91 F: FnOnce(T) -> T,
92 {
93 self.borrow_result(|v| (f(v), ()))
94 }
95
96 /// Updates the inner value using the provided closure, which also returns a result.
97 #[inline(always)]
98 #[track_caller]
99 pub fn borrow_result<F, R>(&mut self, f: F) -> R
100 where
101 F: FnOnce(T) -> (T, R),
102 {
103 let old = self.value.take().expect(PANIC_MESSAGE);
104 let (new, result) = f(old);
105 self.value = Some(new);
106 result
107 }
108
109 /// Moves out the inner value and invalidates the object.
110 ///
111 /// Subsequent calls to any methods except [`is_usable`][Self::is_usable] will panic, including attempts to
112 /// deference the object.
113 #[inline(always)]
114 #[track_caller]
115 pub fn take(&mut self) -> T {
116 self.value.take().expect(PANIC_MESSAGE)
117 }
118
119 /// Check if the object is still usable.
120 ///
121 /// The object will always start out as usable, and can only enter an unusable state if the
122 /// methods [`borrow`][Self::borrow] or [`borrow_result`][Self::borrow_result] are called with closures that panic, or if the value
123 /// is explicitly moved out permanently with [`take`][Self::take].
124 #[inline(always)]
125 pub fn is_usable(&self) -> bool {
126 self.value.is_some()
127 }
128}
129
130impl<T: Display> Display for Takeable<T> {
131 #[inline(always)]
132 #[track_caller]
133 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
134 write!(f, "{}", self.as_ref())
135 }
136}
137
138impl<T> Deref for Takeable<T> {
139 type Target = T;
140 #[inline(always)]
141 #[track_caller]
142 fn deref(&self) -> &T {
143 self.as_ref()
144 }
145}
146
147impl<T> DerefMut for Takeable<T> {
148 #[inline(always)]
149 #[track_caller]
150 fn deref_mut(&mut self) -> &mut T {
151 self.as_mut()
152 }
153}
154
155impl<T> From<T> for Takeable<T> {
156 #[inline(always)]
157 #[track_caller]
158 /// Converts a `T` value into a [`Takeable<T>`].
159 fn from(value: T) -> Self {
160 Self::new(value)
161 }
162}
163
164impl<T> AsRef<T> for Takeable<T> {
165 #[inline(always)]
166 #[track_caller]
167 /// Gets a reference to the underlying value.
168 fn as_ref(&self) -> &T {
169 self.value.as_ref().expect(PANIC_MESSAGE)
170 }
171}
172
173impl<T> AsMut<T> for Takeable<T> {
174 #[inline(always)]
175 #[track_caller]
176 /// Gets a mutable reference to the underlying value.
177 fn as_mut(&mut self) -> &mut T {
178 self.value.as_mut().expect(PANIC_MESSAGE)
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::Takeable;
185 #[test]
186 fn test_takeable() {
187 let mut takeable = Takeable::new(42u32);
188 *takeable += 1;
189 assert_eq!(*takeable, 43);
190 *takeable.as_mut() += 1;
191 assert_eq!(takeable.as_ref(), &44);
192 takeable.borrow(|n: u32| n + 1);
193 assert_eq!(*takeable, 45);
194 let out = takeable.borrow_result(|n: u32| (n + 1, n));
195 assert_eq!(out, 45);
196 assert_eq!(takeable.into_inner(), 46);
197 let mut takeable = Takeable::new(34u32);
198 assert_eq!(takeable.take(), 34);
199 }
200
201 #[test]
202 #[should_panic]
203 fn test_usable() {
204 struct MyDrop {
205 value: Takeable<()>,
206 should_be_usable: bool,
207 }
208 impl Drop for MyDrop {
209 fn drop(&mut self) {
210 assert_eq!(self.value.is_usable(), self.should_be_usable);
211 }
212 }
213
214 let _drop1 = MyDrop {
215 value: Takeable::new(()),
216 should_be_usable: true,
217 };
218 let mut drop2 = MyDrop {
219 value: Takeable::new(()),
220 should_be_usable: false,
221 };
222 let mut drop3 = MyDrop {
223 value: Takeable::new(()),
224 should_be_usable: false,
225 };
226 let _ = drop3.value.take();
227 drop2.value.borrow(|_| panic!());
228 }
229}