retentive_lender/
lib.rs

1use std::{
2    cell::{Ref as StdRef, RefCell, RefMut as StdRefMut},
3    ops::{Deref, DerefMut},
4    rc::Rc,
5};
6
7/// Remembers the borrower and removes it when Ref / RefMut is dropped.
8#[derive(Debug)]
9struct Dropper {
10    borrower: String,
11    borrowers: Rc<RefCell<Vec<String>>>,
12}
13
14impl Drop for Dropper {
15    fn drop(&mut self) {
16        let index = self
17            .borrowers
18            .borrow()
19            .iter()
20            .position(|b| *b == self.borrower)
21            .expect(&format!(
22                "Cannot find a borrower with name: {}",
23                self.borrower
24            ));
25        self.borrowers.borrow_mut().remove(index);
26    }
27}
28
29/// Wraps Ref with Dropper to remove the borrower from the borrowers list automatically.
30#[derive(Debug)]
31pub struct Ref<'a, T> {
32    value: StdRef<'a, T>,
33    _dropper: Dropper,
34}
35
36impl<'a, T> Ref<'a, T> {
37    pub fn new(value: StdRef<'a, T>, borrower: &str, borrowers: Rc<RefCell<Vec<String>>>) -> Self {
38        Self {
39            value,
40            _dropper: Dropper {
41                borrower: borrower.to_string(),
42                borrowers,
43            },
44        }
45    }
46}
47
48impl<'a, T> Deref for Ref<'a, T> {
49    type Target = T;
50
51    fn deref(&self) -> &T {
52        &self.value
53    }
54}
55
56/// Wraps RefMut with Dropper to remove the borrower from the borrowers list automatically.
57#[derive(Debug)]
58pub struct RefMut<'a, T> {
59    value: StdRefMut<'a, T>,
60    _dropper: Dropper,
61}
62
63impl<'a, T> RefMut<'a, T> {
64    pub fn new(
65        value: StdRefMut<'a, T>,
66        borrower: &str,
67        borrowers: Rc<RefCell<Vec<String>>>,
68    ) -> Self {
69        Self {
70            value,
71            _dropper: Dropper {
72                borrower: borrower.to_string(),
73                borrowers,
74            },
75        }
76    }
77}
78
79impl<'a, T> Deref for RefMut<'a, T> {
80    type Target = T;
81
82    fn deref(&self) -> &T {
83        &self.value
84    }
85}
86
87impl<'a, T> DerefMut for RefMut<'a, T> {
88    fn deref_mut(&mut self) -> &mut T {
89        &mut self.value
90    }
91}
92
93/// Allow users to borrow / borrow_mut the value while keeping the name of the borrower until it's dropped.
94/// When the borrow / borrow_mut violates the borrow rule, it returns an Err containing the name of the previous borrower.
95#[derive(Debug)]
96pub struct Lender<T> {
97    value: Rc<RefCell<T>>,
98    borrowers: Rc<RefCell<Vec<String>>>,
99}
100
101impl<T> Lender<T> {
102    /// Creates a new Lender containing value.
103    pub fn new(value: T) -> Self {
104        Self {
105            value: Rc::new(RefCell::new(value)),
106            borrowers: Rc::new(RefCell::new(vec![])),
107        }
108    }
109
110    /// Immutably borrows the wrapped value, returning an error if the value is currently mutably borrowed.
111    /// The borrow lasts until the returned Ref exits scope. Multiple immutable borrows can be taken out at the same time.
112    pub fn borrow(&self, borrower: &str) -> Result<Ref<T>, String> {
113        if let Ok(value) = self.value.try_borrow() {
114            self.borrowers.borrow_mut().push(borrower.to_string());
115            Ok(Ref::new(value, borrower, self.borrowers.clone()))
116        } else {
117            Err(format!(
118                "Failed to borrow immutable reference. Currently borrowed by: {:?}",
119                self.borrowers.borrow()
120            ))
121        }
122    }
123
124    /// Mutably borrows the wrapped value, returning an error if the value is currently borrowed.
125    /// The error message includes information of the previous borrower.
126    /// The borrow lasts until the returned RefMut or all RefMuts derived from it exit scope. The value cannot be borrowed while this borrow is active.
127    pub fn borrow_mut(&self, borrower: &str) -> Result<RefMut<T>, String> {
128        if let Ok(value) = self.value.try_borrow_mut() {
129            self.borrowers.borrow_mut().push(borrower.to_string());
130            Ok(RefMut::new(value, borrower, self.borrowers.clone()))
131        } else {
132            Err(format!(
133                "Failed to borrow mutable reference. Currently borrowed by: {:?}",
134                self.borrowers.borrow()
135            ))
136        }
137    }
138}
139
140// We can't derive(Clone) because we don't want T to be cloned.
141impl<T> Clone for Lender<T> {
142    fn clone(&self) -> Self {
143        Self {
144            value: self.value.clone(),
145            borrowers: self.borrowers.clone(),
146        }
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use super::Lender;
153
154    #[test]
155    fn borrow_twice() -> Result<(), String> {
156        let d = Lender::new(1);
157
158        let b1 = d.borrow("b1")?;
159        let b2 = d.borrow("b2")?;
160
161        assert_eq!(*b1, 1);
162        assert_eq!(*b2, 1);
163
164        Ok(())
165    }
166
167    #[test]
168    fn borrow_once_borrow_mut_once() -> Result<(), String> {
169        let d = Lender::new(1);
170
171        let _b1 = d.borrow("b1")?;
172        let b2 = d.borrow_mut("b2");
173
174        assert!(b2.is_err());
175        if let Err(b) = b2 {
176            b.contains("Currently borrowed by: [\"b1\"]");
177        }
178
179        Ok(())
180    }
181
182    #[test]
183    fn borrow_twice_borrow_mut_once() -> Result<(), String> {
184        let d = Lender::new(1);
185
186        let _b1 = d.borrow("b1")?;
187        let _b2 = d.borrow("b2")?;
188        let b3 = d.borrow_mut("b3");
189
190        assert!(b3.is_err());
191        if let Err(b) = b3 {
192            b.contains("Currently borrowed by: [\"b1\", \"b2\"]");
193        }
194
195        Ok(())
196    }
197
198    #[test]
199    fn borrow_mut_once_borrow_once() -> Result<(), String> {
200        let d = Lender::new(1);
201
202        let _b1 = d.borrow_mut("b1")?;
203        let b2 = d.borrow("b2");
204
205        assert!(b2.is_err());
206        if let Err(b) = b2 {
207            b.contains("Currently borrowed by: [\"b1\"]");
208        }
209
210        Ok(())
211    }
212
213    #[test]
214    fn borrow_mut_twice() -> Result<(), String> {
215        let d = Lender::new(1);
216
217        let _b1 = d.borrow_mut("b1")?;
218        let b2 = d.borrow_mut("b2");
219
220        assert!(b2.is_err());
221        if let Err(b) = b2 {
222            b.contains("Currently borrowed by: [\"b1\"]");
223        }
224
225        Ok(())
226    }
227
228    #[test]
229    fn clone_and_borrow_mut() -> Result<(), String> {
230        let d = Lender::new(1);
231        let _b1 = d.borrow_mut("b1")?;
232
233        let _d2 = d.clone();
234        let b2 = d.borrow_mut("b2");
235
236        assert!(b2.is_err());
237        if let Err(b) = b2 {
238            b.contains("Currently borrowed by: [\"b1\"]");
239        }
240
241        Ok(())
242    }
243}