with_cell/lib.rs
1#![no_std]
2#![doc = include_str!("../README.md")]
3#![forbid(unsafe_code)] // :)
4#![deny(missing_docs)]
5
6use core::{cell::Cell, fmt, ops};
7
8/// `Cell`-like container for making shared structures with mutable methods more convenient to use.
9///
10/// Unlike [`Cell`], this wrapper does not require [`Copy`] in the general case.
11/// Instead, it relies on [`Default`].
12///
13/// Internally, it uses [`Cell`].
14#[derive(Default)]
15pub struct WithCell<T>(Cell<T>);
16
17impl<T> WithCell<T> {
18 /// Create a new `WithCell` containing the given value.
19 pub const fn new(value: T) -> Self {
20 Self(Cell::new(value))
21 }
22}
23
24impl<T> WithCell<T>
25where
26 T: Default,
27{
28 /// Perform an operation on the contained value.
29 ///
30 /// This takes the value out of the cell and replaces it with its [`Default`] variant.
31 /// This value is then passed by reference to `f`.
32 /// When `f` returns, the value is put back in the cell,
33 /// discarding the stub variant.
34 pub fn with<F, R>(&self, f: F) -> R
35 where
36 F: FnOnce(&mut T) -> R,
37 {
38 let mut v = self.0.take();
39 let ret = (f)(&mut v);
40 self.0.set(v);
41 ret
42 }
43
44 /// Perform an operation on the contained value.
45 ///
46 /// This takes the value out of the cell and replaces it with its [`Default`] variant.
47 /// This value is then passed by reference to `f`.
48 /// When `f` returns, the value is put back in the cell,
49 /// discarding the stub variant.
50 ///
51 /// This method is almost identical to [`with`](Self::with),
52 /// except it returns a reference to `self`.
53 pub fn inspect<F>(&self, f: F) -> &Self
54 where
55 F: FnOnce(&mut T),
56 {
57 self.with(f);
58 self
59 }
60
61 /// Perform an operation on the contained value.
62 ///
63 /// Like [`with`](Self::with), it replaces the value with its [`Default`] variant.
64 /// This value is then passed by value to `f`.
65 /// The value returned from `f` is put in the cell,
66 /// discarding the stub variant.
67 ///
68 /// This function can be chained:
69 /// ```
70 /// let abcd = with_cell::WithCell::new(String::new());
71 ///
72 /// abcd.map(|x| x + "a")
73 /// .map(|x| x + "b")
74 /// .map(|x| x + "cd")
75 /// .map(|x| dbg!(x))
76 /// .with(|x| x.clear());
77 /// ```
78 pub fn map<F>(&self, f: F) -> &Self
79 where
80 F: FnOnce(T) -> T,
81 {
82 self.0.set((f)(self.0.take()));
83 self
84 }
85}
86
87impl<T> ops::Deref for WithCell<T> {
88 type Target = Cell<T>;
89
90 fn deref(&self) -> &Self::Target {
91 &self.0
92 }
93}
94
95impl<T> ops::DerefMut for WithCell<T> {
96 fn deref_mut(&mut self) -> &mut Self::Target {
97 &mut self.0
98 }
99}
100
101impl<T> fmt::Debug for WithCell<T>
102where
103 T: Default + fmt::Debug,
104{
105 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106 self.with(|x| x.fmt(f))
107 }
108}
109
110impl<T> Clone for WithCell<T>
111where
112 T: Default + Clone,
113{
114 fn clone(&self) -> Self {
115 self.with(|x| x.clone()).into()
116 }
117}
118
119impl<T> From<T> for WithCell<T> {
120 fn from(x: T) -> Self {
121 Self(x.into())
122 }
123}