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}