cell_ref/
lib.rs

1/*
2 * Copyright 2022 taylor.fish <contact@taylor.fish>
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#![no_std]
18#![forbid(unsafe_code)]
19
20//! This crate provides a [`Cell`] type (like the standard library’s
21//! [`Cell`][std-cell]) with methods for safely mutating and inspecting the
22//! inner value by reference ([`with`] and [`with_mut`]).
23//!
24//! For [`Copy`] types, this is implemented with [`get`][std-get] and
25//! [`set`][std-set], but [through an extension trait][cell-ext], this crate
26//! provides those same operations for types that are [`Default`] but not
27//! [`Copy`]. A [`get`] method is also available for types that are both
28//! [`Default`] and [`Clone`].
29//!
30//! This crate depends only on [`core`], so it can be used inside `no_std`
31//! environments.
32//!
33//! Example
34//! -------
35//!
36//! ```rust
37//! use cell_ref::{Cell, CellExt};
38//!
39//! let c1 = Cell::new(2_u8);
40//! c1.with_mut(|x| *x += 3);
41//! assert!(c1.get() == 5);
42//!
43//! let c2 = Cell::new(vec![1, 2, 3]);
44//! c2.with_mut(|v| v.push(4)); // Works even though `Vec` isn't `Copy`
45//! assert_eq!(c2.with(Vec::len), 4);
46//! let v = c2.get(); // Clones the vector
47//! ```
48//!
49//! [std-cell]: StdCell
50//! [cell-ext]: CellExt
51//! [`with`]: Cell::with
52//! [`with_mut`]: Cell::with_mut
53//! [std-get]: StdCell::get
54//! [std-set]: StdCell::set
55//! [`get`]: Cell::get
56
57use core::cell::Cell as StdCell;
58use core::cmp::Ordering;
59use core::fmt;
60use core::ops::{Deref, DerefMut};
61
62#[cfg(test)]
63mod tests;
64
65/// A `Cell` type with methods for by-reference mutation and inspection.
66#[derive(Default)]
67pub struct Cell<T>(StdCell<T>);
68
69impl<T> Cell<T> {
70    /// Creates a new [`Cell`] with the given value.
71    pub fn new(value: T) -> Self {
72        Self(StdCell::new(value))
73    }
74}
75
76impl<T> Deref for Cell<T> {
77    type Target = StdCell<T>;
78
79    fn deref(&self) -> &Self::Target {
80        &self.0
81    }
82}
83
84impl<T> DerefMut for Cell<T> {
85    fn deref_mut(&mut self) -> &mut Self::Target {
86        &mut self.0
87    }
88}
89
90impl<T> From<T> for Cell<T> {
91    fn from(value: T) -> Self {
92        Self::new(value)
93    }
94}
95
96impl<T> From<StdCell<T>> for Cell<T> {
97    fn from(cell: StdCell<T>) -> Self {
98        Self(cell)
99    }
100}
101
102impl<T> From<Cell<T>> for StdCell<T> {
103    fn from(cell: Cell<T>) -> Self {
104        cell.0
105    }
106}
107
108impl<T: Copy> Cell<T> {
109    /// Gets the value held by the cell.
110    pub fn get(&self) -> T {
111        self.0.get()
112    }
113
114    /// Calls `f` with a reference to the contents of the cell.
115    pub fn with<F, R>(&self, f: F) -> R
116    where
117        F: FnOnce(&T) -> R,
118    {
119        f(&self.get())
120    }
121
122    /// Calls `f` with a mutable reference to the contents of the cell.
123    pub fn with_mut<F, R>(&self, f: F) -> R
124    where
125        F: FnOnce(&mut T) -> R,
126    {
127        let mut value = self.get();
128        let result = f(&mut value);
129        self.set(value);
130        result
131    }
132}
133
134mod sealed {
135    pub trait Sealed {}
136}
137
138/// Provides additional methods for non-[`Copy`] types.
139pub trait CellExt<T>: sealed::Sealed {
140    /// Gets the value held by the cell.
141    fn get(&self) -> T
142    where
143        T: Clone + Default;
144
145    /// Calls `f` with a reference to the contents of the cell.
146    fn with<F, R>(&self, f: F) -> R
147    where
148        T: Default,
149        F: FnOnce(&T) -> R;
150
151    /// Calls `f` with a mutable reference to the contents of the cell.
152    fn with_mut<F, R>(&self, f: F) -> R
153    where
154        T: Default,
155        F: FnOnce(&mut T) -> R;
156}
157
158impl<T> sealed::Sealed for Cell<T> {}
159
160impl<T> CellExt<T> for Cell<T> {
161    fn get(&self) -> T
162    where
163        T: Clone + Default,
164    {
165        self.with(T::clone)
166    }
167
168    fn with<F, R>(&self, f: F) -> R
169    where
170        T: Default,
171        F: FnOnce(&T) -> R,
172    {
173        let value = self.take();
174        let result = f(&value);
175        self.set(value);
176        result
177    }
178
179    fn with_mut<F, R>(&self, f: F) -> R
180    where
181        T: Default,
182        F: FnOnce(&mut T) -> R,
183    {
184        let mut value = self.take();
185        let result = f(&mut value);
186        self.set(value);
187        result
188    }
189}
190
191impl<T: Copy> Clone for Cell<T> {
192    fn clone(&self) -> Self {
193        Self(self.0.clone())
194    }
195}
196
197impl<T: fmt::Debug + Copy> fmt::Debug for Cell<T> {
198    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
199        self.0.fmt(fmt)
200    }
201}
202
203impl<T: Ord + Copy> Ord for Cell<T> {
204    fn cmp(&self, other: &Self) -> Ordering {
205        self.0.cmp(other)
206    }
207}
208
209impl<T: PartialOrd + Copy> PartialOrd for Cell<T> {
210    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
211        self.0.partial_cmp(other)
212    }
213}
214
215impl<T: PartialEq + Copy> PartialEq for Cell<T> {
216    fn eq(&self, other: &Self) -> bool {
217        self.0.eq(other)
218    }
219}
220
221impl<T: Eq + Copy> Eq for Cell<T> {}