tock_cells/take_cell.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Tock specific `TakeCell` type for sharing references.
6
7use core::cell::Cell;
8
9/// A shared reference to a mutable reference.
10///
11/// A `TakeCell` wraps potential reference to mutable memory that may be
12/// available at a given point. Rather than enforcing borrow rules at
13/// compile-time, `TakeCell` enables multiple clients to hold references to it,
14/// but ensures that only one referrer has access to the underlying mutable
15/// reference at a time. Clients either move the memory out of the `TakeCell` or
16/// operate on a borrow within a closure. Attempts to take the value from inside
17/// a `TakeCell` may fail by returning `None`.
18pub struct TakeCell<'a, T: 'a + ?Sized> {
19 val: Cell<Option<&'a mut T>>,
20}
21
22impl<'a, T: ?Sized> TakeCell<'a, T> {
23 const EMPTY: Self = Self {
24 val: Cell::new(None),
25 };
26
27 pub const fn empty() -> TakeCell<'a, T> {
28 Self::EMPTY
29 }
30
31 /// Creates a new `TakeCell` containing `value`
32 pub fn new(value: &'a mut T) -> TakeCell<'a, T> {
33 TakeCell {
34 val: Cell::new(Some(value)),
35 }
36 }
37
38 pub fn is_none(&self) -> bool {
39 let inner = self.take();
40 let return_val = inner.is_none();
41 self.val.set(inner);
42 return_val
43 }
44
45 pub fn is_some(&self) -> bool {
46 !self.is_none()
47 }
48
49 /// Takes the mutable reference out of the `TakeCell` leaving a `None` in
50 /// it's place. If the value has already been taken elsewhere (and not
51 /// `replace`ed), the returned `Option` will be empty.
52 ///
53 /// # Examples
54 ///
55 /// ```
56 /// extern crate tock_cells;
57 /// use tock_cells::take_cell::TakeCell;
58 ///
59 /// let mut value = 1234;
60 /// let cell = TakeCell::new(&mut value);
61 /// let x = &cell;
62 /// let y = &cell;
63 ///
64 /// x.take();
65 /// assert_eq!(y.take(), None);
66 /// ```
67 pub fn take(&self) -> Option<&'a mut T> {
68 self.val.replace(None)
69 }
70
71 /// Stores `val` in the `TakeCell`
72 pub fn put(&self, val: Option<&'a mut T>) {
73 self.val.replace(val);
74 }
75
76 /// Replaces the contents of the `TakeCell` with `val`. If the cell was not
77 /// empty, the previous value is returned, otherwise `None` is returned.
78 pub fn replace(&self, val: &'a mut T) -> Option<&'a mut T> {
79 self.val.replace(Some(val))
80 }
81
82 /// Retrieves a mutable reference to the inner value that only lives as long
83 /// as the reference to this does.
84 ///
85 /// This escapes the "take" aspect of TakeCell in a way which is guaranteed
86 /// safe due to the returned reference sharing the lifetime of `&mut self`.
87 pub fn get_mut(&mut self) -> Option<&mut T> {
88 self.val.get_mut().as_mut().map(|v| &mut **v)
89 }
90
91 /// Allows `closure` to borrow the contents of the `TakeCell` if-and-only-if
92 /// it is not `take`n already. The state of the `TakeCell` is unchanged
93 /// after the closure completes.
94 ///
95 /// # Examples
96 ///
97 /// ```
98 /// extern crate tock_cells;
99 /// use tock_cells::take_cell::TakeCell;
100 ///
101 /// let mut value = 1234;
102 /// let cell = TakeCell::new(&mut value);
103 /// let x = &cell;
104 /// let y = &cell;
105 ///
106 /// x.map(|value| {
107 /// // We have mutable access to the value while in the closure
108 /// *value += 1;
109 /// });
110 ///
111 /// // After the closure completes, the mutable memory is still in the cell,
112 /// // but potentially changed.
113 /// assert_eq!(y.take(), Some(&mut 1235));
114 /// ```
115 pub fn map<F, R>(&self, closure: F) -> Option<R>
116 where
117 F: FnOnce(&mut T) -> R,
118 {
119 let maybe_val = self.take();
120 maybe_val.map(|val| {
121 let res = closure(val);
122 self.replace(val);
123 res
124 })
125 }
126
127 /// Performs a `map` or returns a default value if the `TakeCell` is empty
128 pub fn map_or<F, R>(&self, default: R, closure: F) -> R
129 where
130 F: FnOnce(&mut T) -> R,
131 {
132 let maybe_val = self.take();
133 maybe_val.map_or(default, |val| {
134 let res = closure(val);
135 self.replace(val);
136 res
137 })
138 }
139
140 /// Performs a `map` or generates a value with the default
141 /// closure if the `TakeCell` is empty
142 pub fn map_or_else<U, D, F>(&self, default: D, f: F) -> U
143 where
144 D: FnOnce() -> U,
145 F: FnOnce(&mut T) -> U,
146 {
147 let maybe_val = self.take();
148 maybe_val.map_or_else(
149 || default(),
150 |val| {
151 let res = f(val);
152 self.replace(val);
153 res
154 },
155 )
156 }
157
158 /// Behaves the same as `map`, except the closure is allowed to return
159 /// an `Option`.
160 pub fn and_then<F, R>(&self, closure: F) -> Option<R>
161 where
162 F: FnOnce(&mut T) -> Option<R>,
163 {
164 let maybe_val = self.take();
165 maybe_val.and_then(|val| {
166 let res = closure(val);
167 self.replace(val);
168 res
169 })
170 }
171
172 /// Uses the first closure (`modify`) to modify the value in the `TakeCell`
173 /// if it is present, otherwise, fills the `TakeCell` with the result of
174 /// `mkval`.
175 pub fn modify_or_replace<F, G>(&self, modify: F, mkval: G)
176 where
177 F: FnOnce(&mut T),
178 G: FnOnce() -> &'a mut T,
179 {
180 let val = match self.take() {
181 Some(val) => {
182 modify(val);
183 val
184 }
185 None => mkval(),
186 };
187 self.replace(val);
188 }
189}