classicube_helpers\traits/
with_borrow.rs

1use std::{
2    cell::RefCell,
3    sync::{Mutex, RwLock},
4    thread::LocalKey,
5};
6
7pub trait WithBorrow<'a, O> {
8    fn with_borrow<F, R>(&'a self, f: F) -> R
9    where
10        F: FnOnce(&O) -> R;
11
12    fn with_borrow_mut<F, R>(&'a self, f: F) -> R
13    where
14        F: FnOnce(&mut O) -> R;
15}
16
17impl<O> WithBorrow<'static, O> for LocalKey<RefCell<O>> {
18    fn with_borrow<F, T>(&'static self, f: F) -> T
19    where
20        F: FnOnce(&O) -> T,
21    {
22        self.with(|cell| f(&cell.borrow()))
23    }
24
25    fn with_borrow_mut<F, T>(&'static self, f: F) -> T
26    where
27        F: FnOnce(&mut O) -> T,
28    {
29        self.with(|cell| f(&mut cell.borrow_mut()))
30    }
31}
32
33impl<O> WithBorrow<'_, O> for Mutex<O> {
34    fn with_borrow<F, R>(&self, f: F) -> R
35    where
36        F: FnOnce(&O) -> R,
37    {
38        let guard = self.lock().unwrap();
39        f(&*guard)
40    }
41
42    fn with_borrow_mut<F, R>(&self, f: F) -> R
43    where
44        F: FnOnce(&mut O) -> R,
45    {
46        let mut guard = self.lock().unwrap();
47        f(&mut *guard)
48    }
49}
50
51impl<O> WithBorrow<'_, O> for RwLock<O> {
52    fn with_borrow<F, R>(&self, f: F) -> R
53    where
54        F: FnOnce(&O) -> R,
55    {
56        let guard = self.read().unwrap();
57        f(&*guard)
58    }
59
60    fn with_borrow_mut<F, R>(&self, f: F) -> R
61    where
62        F: FnOnce(&mut O) -> R,
63    {
64        let mut guard = self.write().unwrap();
65        f(&mut *guard)
66    }
67}
68
69#[test]
70fn test_with_borrow_thread_local() {
71    use std::cell::RefCell;
72    thread_local!(
73        static THREAD_LOCAL: RefCell<u8> = RefCell::default();
74    );
75    assert_eq!(
76        THREAD_LOCAL.with_borrow_mut(|o| {
77            *o += 2;
78            *o
79        }),
80        2
81    );
82    assert_eq!(THREAD_LOCAL.with_borrow(|o| o + 2), 4);
83}
84
85#[test]
86fn test_with_borrow_static_mutex() {
87    use std::sync::LazyLock;
88
89    static STATIC_MUTEX: LazyLock<Mutex<u8>> = LazyLock::new(Mutex::default);
90
91    assert_eq!(
92        STATIC_MUTEX.with_borrow_mut(|o| {
93            *o += 2;
94            *o
95        }),
96        2
97    );
98    assert_eq!(STATIC_MUTEX.with_borrow(|o| o + 2), 4);
99}
100
101#[test]
102fn test_with_borrow_static_rwlock() {
103    use std::sync::LazyLock;
104
105    static STATIC_RWLOCK: LazyLock<RwLock<u8>> = LazyLock::new(RwLock::default);
106
107    assert_eq!(
108        STATIC_RWLOCK.with_borrow_mut(|o| {
109            *o += 2;
110            *o
111        }),
112        2
113    );
114    assert_eq!(STATIC_RWLOCK.with_borrow(|o| o + 2), 4);
115}
116
117#[test]
118fn test_with_borrow_non_static_mutex() {
119    let mutex: Mutex<u8> = Mutex::default();
120    assert_eq!(
121        mutex.with_borrow_mut(|o| {
122            *o += 2;
123            *o
124        }),
125        2
126    );
127    assert_eq!(mutex.with_borrow(|o| o + 2), 4);
128}