instance_copy_on_write/
cow_refcell.rs

1/*-
2 * instance-copy-on-write - a synchronization primitive based on copy-on-write.
3 * 
4 * Copyright (C) 2025 Aleksandr Morozov alex@4neko.org
5 * 
6 * The instance-copy-on-write crate can be redistributed and/or modified
7 * under the terms of either of the following licenses:
8 *
9 *   1. The MIT License (MIT)
10 */
11
12
13use std::
14{
15    cell::RefCell, fmt, ops::{Deref, DerefMut}, rc::{Rc, Weak}
16};
17
18use crate::{ICoWLockTypes, ICowType};
19
20/// A Single thread realization.
21
22/// A read only guard. Implements [Deref] only. The guarded value is valid
23/// all the time, even if the inner value was updated. The updated value
24/// will not be visible in the current instance until `re-read` is 
25/// performed.
26#[derive(Debug)]
27pub struct ICoWRead<'read, ITEM: Sized>
28{
29    /// Guarded value.
30    pub(crate) item: Rc<ITEM>,
31
32    /// A bind to base.
33    bind: &'read ICoW<ITEM>
34}
35
36impl<'read, ITEM: Sized> Deref for ICoWRead<'read, ITEM>
37{
38    type Target = ITEM;
39
40    fn deref(&self) -> &Self::Target
41    {
42        return &self.item;
43    }
44}
45
46impl<'read, ITEM: Sized> ICoWRead<'read, ITEM>
47{
48    /// Consumes the itance and returns the read-only value.
49    pub 
50    fn into_inner(self) -> Rc<ITEM>
51    {
52        return self.item;
53    }
54
55    /// Returns the weak reference.
56    pub 
57    fn weak(&self) -> Weak<ITEM>
58    {
59        return Rc::downgrade(&self.item);
60    }
61}
62
63impl<'read, ITEM: Sized + fmt::Debug + Copy> ICoWRead<'read, ITEM>
64{
65    /// Upgrades from [ICoWRead] `the self` to copy [ICoWCopy] which can 
66    /// be commited to mainstream by using [Copy].
67    pub 
68    fn upgrade_copy(self) -> ICoWCopy<'read, ITEM> 
69    {
70        let new_item = *self.item;
71        let bind = self.bind;
72
73        return 
74            ICoWCopy
75            {
76                prev_item: self, 
77                new_item: new_item,
78                inst: bind
79            };
80    }
81}
82
83impl<'read, ITEM: Sized + fmt::Debug + Clone> ICoWRead<'read, ITEM>
84{
85    /// Upgrades from [ICoWRead] `the self` to copy [ICoWCopy] which can 
86    /// be commited to mainstream by using [Clone].
87    pub 
88    fn upgrade_clone_copy(self) -> ICoWCopy<'read, ITEM> 
89    {
90        let new_item = self.item.as_ref().clone();
91        let bind = self.bind;
92
93         return 
94            ICoWCopy
95            {
96                prev_item: self, 
97                new_item: new_item,
98                inst: bind
99            };
100    }
101}
102
103impl<'read, ITEM: Sized + fmt::Debug + Default> ICoWRead<'read, ITEM>
104{
105    /// Upgrades from [ICoWRead] `the self` to copy [ICoWCopy] which can 
106    /// be commited to mainstream by using [Default].
107    pub 
108    fn upgrade_default(self) -> ICoWCopy<'read, ITEM> 
109    {
110        let new_item = ITEM::default();
111        let bind = self.bind;
112
113         return 
114            ICoWCopy
115            {
116                prev_item: self, 
117                new_item: new_item,
118                inst: bind
119            };
120    }
121}
122
123/// A write-guard which holds new value to which the new data is written. And
124/// previous value too. This type of guard is not exclusive, so multiple
125/// CoW operations may be performed in parallel which is not normally needed.
126/// 
127/// The changes made in the current instance becomes visible for the rest
128/// of the threads only after commit.
129#[derive(Debug)]
130pub struct ICoWCopy<'copy, ITEM: Sized>
131{
132    /// A reference to previous value
133    prev_item: ICoWRead<'copy, ITEM>,
134    
135    /// A freshly createc/copied/clonned item
136    new_item: ITEM,
137
138    /// A reference to base to avoid Send.
139    inst: &'copy ICoW<ITEM>
140}
141
142impl<'copy, ITEM: Sized> Deref for ICoWCopy<'copy, ITEM>
143{
144    type Target = ITEM;
145
146    fn deref(&self) -> &Self::Target
147    {
148        return &self.new_item;
149    }
150}
151
152impl<'copy, ITEM: Sized> DerefMut for ICoWCopy<'copy, ITEM>
153{
154    fn deref_mut(&mut self) -> &mut Self::Target
155    {
156        return &mut self.new_item
157    }
158}
159
160impl<'copy, ITEM: Sized> ICoWCopy<'copy, ITEM>
161{
162    /// Returns a reference to previous value. To access modified version use
163    /// [Deref] or [DerefMut].
164    pub 
165    fn prev_val(&self) -> &ITEM
166    {
167        return &self.prev_item;
168    }
169
170    /// Commits the changes made in the guarded variable. A non-blocking
171    /// function. It will not block the thread completly and returns the
172    /// [ICoWError::WouldBlock] if attempt to grab the pointer atomically 
173    /// fails in reasonable time. for blocking `commit` use 
174    /// [Self::commit_blocking].
175    pub 
176    fn commit(self)
177    {
178        *self.inst.inner.borrow_mut() = Rc::new(self.new_item);
179
180        return;
181    }
182
183    /// Drops the instance without commiting changes returning 
184    /// a copy, clone, default, or new i.e what was in the `new` field
185    /// of the instance.
186    pub 
187    fn into_inner(self) -> ITEM
188    {
189        return self.new_item;
190    }
191}
192
193/// A main structure which implements CoW approach based on [RwLock]. The object 
194/// stored inside can be read directly, but  modifying the `inner` value is 
195/// performed using `CoW` copy-on-write approach. 
196/// 
197/// The `read` operations are faster than `write`, because in order to `write` a
198/// more operations needs to be performed.
199/// 
200/// This is for Mutlithreading environment only. It will be usedless when using
201/// in single-thread programs. For the single thread, use a `SICoW` which would
202/// improve the performance.
203/// 
204/// The inner value must be either [Copy], [Clone], [Default], or provide 
205/// new value manually. The copied value is modified and stored back either
206/// shared or exclusive method. The exclusive lock prevents other CoW operations
207/// guaranteeing the uniq write access.
208/// 
209/// ```ignore
210/// #[derive(Debug, Clone)]
211/// struct TestStruct { s: u32 }
212/// 
213/// let cow_val = ICoW::new(TestStruct{ s: 2 });
214/// 
215/// // read
216/// let read0 = cow_val.read().unwrap();
217/// // ...
218/// drop(read0);
219/// 
220/// // write new non-exclusivly
221/// let mut write0 = cow_val.try_clone_copy().unwrap();
222/// write0.s = 3;
223/// 
224/// write0.commit().unwrap();
225/// 
226/// // write new exclusivly
227/// let mut write0 = cow_val.try_clone_copy_exclusivly().unwrap();
228/// write0.s = 3;
229/// 
230/// write0.commit().unwrap(); 
231/// 
232/// ```
233#[derive(Debug)]
234pub struct ICoW<ITEM: Sized>
235{
236    /// A rwlock protected CoW.
237    inner: RefCell<Rc<ITEM>>,
238}
239
240impl<ITEM> ICowType for ICoW<ITEM>
241{
242    fn get_lock_type() -> ICoWLockTypes 
243    {
244        return ICoWLockTypes::RwLock;
245    }
246}
247
248impl<ITEM> ICoW<ITEM>
249{
250    /// Initalizes a new instance.
251    pub 
252    fn new(item: ITEM) -> Self
253    {
254        return 
255            Self
256            { 
257                inner: 
258                    RefCell::new(Rc::new(item)),
259            }
260    }
261
262    /// Attempts to read the inner value returning the guard. This function 
263    /// blocks the current thread until the value becomes available. This
264    /// can happen if exclusive copy-on-write is in progress.
265    /// 
266    /// # Returns 
267    /// 
268    /// An instance with clonned reference is returned.
269    pub 
270    fn read(&self) -> ICoWRead<'_, ITEM>
271    {
272        let lock = 
273            self
274                .inner
275                .borrow();
276
277        return ICoWRead{ item: lock.clone(), bind: self };
278    }
279
280    /// Updates old value to new value for the inner.
281    pub 
282    fn new_inplace(&self, new_item: ITEM)
283    {
284        let read = self.read();
285
286        let ret = 
287            ICoWCopy
288            { 
289                prev_item: read, 
290                new_item: new_item, 
291                inst: self 
292            };
293
294        ret.commit();
295
296        return;
297    }
298}
299
300impl<ITEM: fmt::Debug + Copy> ICoW<ITEM>
301{
302    /// Performs the copy of the inner value for writing.
303    /// 
304    /// Blocking function i.e always retruns the result.
305    /// 
306    /// # Returns
307    /// 
308    /// An [ICoWCopy] is returned.
309    pub 
310    fn copy(&self) -> ICoWCopy<'_, ITEM>
311    {
312        let read = self.read();
313
314        let new_item = *read.item.as_ref();
315
316        let ret = 
317            ICoWCopy
318            { 
319                prev_item: read, 
320                new_item: new_item, 
321                inst: self 
322            };
323
324        return ret;
325    }
326}
327
328impl<ITEM: fmt::Debug + Clone> ICoW<ITEM>
329{
330    /// > [!IMPORTANT]
331    /// > Previously `clone()`. renamed to `clone_copy()` due to the 
332    /// > conflict with [Clone].
333    /// 
334    /// Attempts to perform the clone of the inner value for writing.
335    /// 
336    /// Blocking function i.e always retruns the result.
337    /// 
338    /// # Returns
339    /// 
340    /// An [ICoWCopy] is returned.
341    pub 
342    fn clone_copy(&self) -> ICoWCopy<'_, ITEM>
343    {
344        let read = self.read();
345
346        let new_item = read.item.as_ref().clone();
347
348        let ret = 
349            ICoWCopy
350            { 
351                prev_item: read, 
352                new_item: new_item, 
353                inst: self 
354            };
355
356        return ret;
357    }
358}
359
360impl<ITEM: fmt::Debug + Default> ICoW<ITEM>
361{
362    /// Construct the guard from the [Default] of the inner value for writing.
363    /// 
364    /// Blocking function i.e always retruns the result.
365    /// 
366    /// # Returns
367    /// 
368    /// An [Option] is returned where the [Option::None] is returned if
369    /// it failed.
370    pub 
371    fn from_default(&self) -> ICoWCopy<'_, ITEM>
372    {
373        let read = self.read();
374
375        let new_item = ITEM::default();
376
377        let ret = 
378            ICoWCopy
379            { 
380                prev_item: read, 
381                new_item: new_item, 
382                inst: self 
383            };
384
385        return ret;
386    }
387}
388
389
390#[cfg(test)]
391mod test
392{
393    // mutex based specific tests goes there
394}