cow_arc/lib.rs
1//! CowArc can be useful for decreasing memory allocations by sharing immutable memory.
2//! It saves some RAM by sharing immutable values between CowArc clones.
3//! Memory allocates only in case of changing value.
4//! CowArc can be usefull for creating builders.
5
6use std::{
7 sync::{
8 Arc
9 },
10 ops::{
11 Deref
12 }
13};
14
15#[derive(Debug, Default)]
16pub struct CowArc<T: Clone>{
17 inner: Arc<T>
18}
19impl<T: Clone> CowArc<T> {
20 /// Creates new CowArc value
21 pub fn new(val: T) -> CowArc<T>{
22 CowArc{
23 inner: Arc::new(val)
24 }
25 }
26
27 /// Method sets new value for inner Arc value.
28 /// Performs new allocation.
29 /// All previous values are still available over previous clones.
30 /// # Examples
31 /// ```
32 /// use cow_arc::CowArc;
33 /// use std::ops::Deref;
34 ///
35 /// let source = CowArc::new(vec![1, 2, 3]);
36 ///
37 /// // Still shared memory
38 /// let mut changed = source.clone();
39 /// assert!(std::ptr::eq(source.deref(), changed.deref()) == true);
40 /// assert!(changed.eq(&vec![1, 2, 3]));
41 ///
42 /// // New memory allocation
43 /// changed.set_val(vec![1, 2, 3, 4]);
44 /// assert!(std::ptr::eq(source.deref(), changed.deref()) == false);
45 /// assert!(changed.eq(&vec![1, 2, 3, 4]));
46 /// ```
47 pub fn set_val(&mut self, val: T){
48 self.inner = Arc::new(val);
49 }
50
51 /// Method updates inner Arc value by replacing it with new value.
52 /// Performs new allocation.
53 /// All previous values are still available over previous clones.
54 /// # Examples
55 /// ```
56 /// use cow_arc::CowArc;
57 /// use std::ops::Deref;
58 ///
59 /// let source = CowArc::new(vec![1, 2, 3]);
60 ///
61 /// // Still shared memory
62 /// let mut updated = source.clone();
63 /// assert!(std::ptr::eq(source.deref(), updated.deref()) == true);
64 /// assert!(updated.eq(&vec![1, 2, 3]));
65 ///
66 /// // New memory allocation
67 /// updated.update_val(|val|{
68 /// val.push(4);
69 /// });
70 /// assert!(std::ptr::eq(source.deref(), updated.deref()) == false);
71 /// assert!(updated.eq(&vec![1, 2, 3, 4]));
72 /// ```
73 pub fn update_val<F: FnOnce(&mut T)>(&mut self, f: F) {
74 let mut v: T = self.inner.deref().clone();
75 f(&mut v);
76 self.inner = Arc::new(v);
77 }
78}
79impl<T: Clone> Deref for CowArc<T>{
80 type Target = T;
81 fn deref(&self) -> &Self::Target {
82 self.inner.deref()
83 }
84}
85impl<T: Clone> Clone for CowArc<T>{
86 fn clone(&self) -> Self {
87 CowArc{
88 inner: self.inner.clone()
89 }
90 }
91}
92
93#[cfg(test)]
94mod tests{
95 use super::*;
96
97 #[test]
98 fn test_cow_arc(){
99 {
100 let test_str = "Test string";
101 let new_val_str = "New value";
102
103 let source = CowArc::new(test_str.to_owned());
104 let cloned = source.clone();
105 let mut changed = cloned.clone();
106 changed.set_val(new_val_str.to_owned());
107 let changed_cloned = changed.clone();
108
109 let source_ptr: &String = source.deref();
110 let cloned_ptr: &String = cloned.deref();
111 let changed_ptr: &String = changed.deref();
112 let changed_cloned_ptr: &String = changed_cloned.deref();
113
114 assert!(std::ptr::eq(source_ptr, cloned_ptr));
115 assert!(std::ptr::eq(source_ptr, changed_ptr) == false);
116 assert!(std::ptr::eq(changed_ptr, changed_cloned_ptr));
117 assert!(cloned_ptr.eq(test_str));
118 assert!(changed.eq(new_val_str));
119 }
120
121 {
122 let source = CowArc::new(vec![1, 2, 3]);
123 let cloned = source.clone();
124 let mut changed = cloned.clone();
125 changed.set_val(vec![1, 2, 3, 4]);
126 let changed_cloned = changed.clone();
127 let mut updated = changed_cloned.clone();
128 updated.update_val(|val|{
129 val.push(5);
130 });
131
132 let source_ptr: &Vec<i32> = source.deref();
133 let cloned_ptr: &Vec<i32> = cloned.deref();
134 let changed_ptr: &Vec<i32> = changed.deref();
135 let changed_cloned_ptr: &Vec<i32> = changed_cloned.deref();
136 let updated_ptr: &Vec<i32> = updated.deref();
137
138 assert!(std::ptr::eq(source_ptr, cloned_ptr));
139 assert!(std::ptr::eq(source_ptr, changed_ptr) == false);
140 assert!(std::ptr::eq(changed_ptr, changed_cloned_ptr));
141 assert!(std::ptr::eq(changed_ptr, updated_ptr) == false);
142 assert!(changed.eq(&vec![1, 2, 3, 4]));
143 assert!(updated.eq(&vec![1, 2, 3, 4, 5]));
144 }
145 }
146}