tock_cells/optional_cell.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.
//! `OptionalCell` convenience type
use core::cell::Cell;
/// `OptionalCell` is a `Cell` that wraps an `Option`. This is helper type
/// that makes keeping types that can be `None` a little cleaner.
pub struct OptionalCell<T> {
value: Cell<Option<T>>,
}
impl<T> OptionalCell<T> {
/// Create a new OptionalCell.
pub const fn new(val: T) -> OptionalCell<T> {
OptionalCell {
value: Cell::new(Some(val)),
}
}
/// Create an empty `OptionalCell` (contains just `None`).
pub const fn empty() -> OptionalCell<T> {
OptionalCell {
value: Cell::new(None),
}
}
/// Update the stored value.
pub fn set(&self, val: T) {
self.value.set(Some(val));
}
/// Insert the value of the supplied `Option`, or `None` if the supplied
/// `Option` is `None`.
pub fn insert(&self, opt: Option<T>) {
self.value.set(opt);
}
/// Replace the contents with the supplied value.
/// If the cell was not empty, the previous value is returned, otherwise
/// `None` is returned.
pub fn replace(&self, val: T) -> Option<T> {
let prev = self.take();
self.set(val);
prev
}
/// Reset the stored value to `None`.
pub fn clear(&self) {
self.value.set(None);
}
/// Check if the cell contains something.
pub fn is_some(&self) -> bool {
let value = self.value.take();
let out = value.is_some();
self.value.set(value);
out
}
/// Check if the cell is None.
pub fn is_none(&self) -> bool {
let value = self.value.take();
let out = value.is_none();
self.value.set(value);
out
}
/// Returns true if the option is a Some value containing the given value.
pub fn contains(&self, x: &T) -> bool
where
T: PartialEq,
{
let value = self.value.take();
let out = match &value {
Some(y) => y == x,
None => false,
};
self.value.set(value);
out
}
/// Transforms the contained `Option<T>` into a `Result<T, E>`, mapping
/// `Some(v)` to `Ok(v)` and `None` to `Err(err)`.
///
/// Arguments passed to `ok_or` are eagerly evaluated; if you are passing
/// the result of a function call, it is recommended to use `ok_or_else`,
/// which is lazily evaluated.
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
self.value.into_inner().ok_or(err)
}
/// Transforms the contained `Option<T>` into a `Result<T, E>`, mapping
/// `Some(v)` to `Ok(v)` and `None` to `Err(err)`.
pub fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
where
F: FnOnce() -> E,
{
self.value.into_inner().ok_or_else(err)
}
/// Returns `None` if the option is `None`, otherwise returns `optb`.
pub fn and<U>(self, optb: Option<U>) -> Option<U> {
self.value.into_inner().and(optb)
}
/// Returns `None` if the option is `None`, otherwise calls `predicate` with
/// the wrapped value and returns:
///
/// - `Some(t)` if `predicate` returns `true` (where `t` is the wrapped value), and
/// - `None` if `predicate` returns `false`.
pub fn filter<P>(self, predicate: P) -> Option<T>
where
P: FnOnce(&T) -> bool,
{
self.value.into_inner().filter(predicate)
}
/// Returns the option if it contains a value, otherwise returns `optb`.
///
/// Arguments passed to or are eagerly evaluated; if you are passing the
/// result of a function call, it is recommended to use `or_else`, which
/// is lazily evaluated.
pub fn or(self, optb: Option<T>) -> Option<T> {
self.value.into_inner().or(optb)
}
/// Returns the option if it contains a value, otherwise calls `f` and
/// returns the result.
pub fn or_else<F>(self, f: F) -> Option<T>
where
F: FnOnce() -> Option<T>,
{
self.value.into_inner().or_else(f)
}
/// Return the contained value and replace it with None.
pub fn take(&self) -> Option<T> {
self.value.take()
}
/// Returns the contained value or a default
///
/// Consumes the `self` argument then, if `Some`, returns the contained
/// value, otherwise if `None`, returns the default value for that type.
pub fn unwrap_or_default(self) -> T
where
T: Default,
{
self.value.into_inner().unwrap_or_default()
}
}
impl<T: Copy> OptionalCell<T> {
/// Returns a copy of the contained [`Option`].
//
// This was originally introduced in PR #2531 [1], then renamed to `extract`
// in PR #2533 [2], and finally renamed back in PR #3536 [3].
//
// The rationale for including a `get` method is to allow developers to
// treat an `OptionalCell<T>` as what it is underneath: a `Cell<Option<T>>`.
// This is useful to be interoperable with APIs that take an `Option<T>`, or
// to use an *if-let* or *match* expression to perform case-analysis on the
// `OptionalCell`'s state: this avoids using a closure and can thus allow
// Rust to deduce that only a single branch will ever be entered (either the
// `Some(_)` or `None`) branch, avoiding lifetime & move restrictions.
//
// However, there was pushback for that name, as an `OptionalCell`'s `get`
// method might indicate that it should directly return a `T` -- given that
// `OptionalCell<T>` presents itself as to be a wrapper around
// `T`. Furthermore, adding `.get()` might have developers use
// `.get().map(...)` instead, which defeats the purpose of having the
// `OptionalCell` convenience wrapper in the first place. For these reasons,
// `get` was renamed to `extract`.
//
// Unfortunately, `extract` turned out to be a confusing name, as it is not
// an idiomatic method name as found on Rust's standard library types, and
// further suggests that it actually removes a value from the `OptionalCell`
// (as the `take` method does). Thus, it has been renamed back to `get`.
//
// [1]: https://github.com/tock/tock/pull/2531
// [2]: https://github.com/tock/tock/pull/2533
// [3]: https://github.com/tock/tock/pull/3536
pub fn get(&self) -> Option<T> {
self.value.get()
}
/// Returns the contained value or panics if contents is `None`.
/// We do not use the traditional name for this function -- `unwrap()`
/// -- because the Tock kernel discourages panicking, and this name
/// is intended to discourage users from casually adding calls to
/// `unwrap()` without careful consideration.
#[track_caller]
pub fn unwrap_or_panic(&self) -> T {
self.value.get().unwrap()
}
/// Returns the contained value or a default.
pub fn unwrap_or(&self, default: T) -> T {
self.value.get().unwrap_or(default)
}
/// Returns the contained value or computes a default.
pub fn unwrap_or_else<F>(&self, default: F) -> T
where
F: FnOnce() -> T,
{
self.value.get().unwrap_or_else(default)
}
/// Call a closure on the value if the value exists.
pub fn map<F, R>(&self, closure: F) -> Option<R>
where
F: FnOnce(T) -> R,
{
self.value.get().map(|val| closure(val))
}
/// Call a closure on the value if the value exists, or return the
/// default if the value is `None`.
pub fn map_or<F, R>(&self, default: R, closure: F) -> R
where
F: FnOnce(T) -> R,
{
self.value.get().map_or(default, |val| closure(val))
}
/// If the cell contains a value, call a closure supplied with the
/// value of the cell. If the cell contains `None`, call the other
/// closure to return a default value.
pub fn map_or_else<U, D, F>(&self, default: D, closure: F) -> U
where
D: FnOnce() -> U,
F: FnOnce(T) -> U,
{
self.value.get().map_or_else(default, |val| closure(val))
}
/// If the cell is empty, return `None`. Otherwise, call a closure
/// with the value of the cell and return the result.
pub fn and_then<U, F: FnOnce(T) -> Option<U>>(&self, f: F) -> Option<U> {
self.value.get().and_then(f)
}
}
// Manual implementation of the [`Default`] trait, as
// `#[derive(Default)]` incorrectly constraints `T: Default`.
impl<T> Default for OptionalCell<T> {
/// Returns an empty [`OptionalCell`].
fn default() -> Self {
OptionalCell::empty()
}
}