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> {}