cljrs_value/collections/
transient_vector.rs1use crate::hash::hash_combine_ordered;
2use crate::{ClojureHash, PersistentVector, Value, ValueError, ValueResult};
3use std::sync::{
4 Mutex,
5 atomic::{AtomicBool, Ordering},
6};
7
8#[derive(Debug)]
9pub struct TransientVector {
10 vector: Mutex<rpds::VectorSync<Value>>,
11 persisted: Mutex<bool>,
12 scalar_only: AtomicBool,
13 #[cfg(feature = "no-gc")]
14 initial: std::cell::RefCell<crate::publish::ValueLease>,
15}
16
17impl TransientVector {
18 pub fn new() -> TransientVector {
19 TransientVector {
20 vector: Mutex::new(Default::default()),
21 #[cfg(feature = "no-gc")]
22 initial: Default::default(),
23 persisted: Mutex::new(false),
24 scalar_only: AtomicBool::new(true),
25 }
26 }
27
28 pub fn new_from_vector(vector: &rpds::VectorSync<Value>) -> TransientVector {
29 TransientVector {
30 vector: Mutex::new(vector.clone()),
31 #[cfg(feature = "no-gc")]
32 initial: std::cell::RefCell::new(crate::publish::ValueLease::for_trace(
33 &PersistentVector::from_vector_summary(vector.clone(), false),
34 &Default::default(),
35 )),
36 persisted: Mutex::new(false),
37 scalar_only: AtomicBool::new(false),
38 }
39 }
40
41 pub fn from_persistent(vector: &PersistentVector) -> Self {
43 let result = Self::new_from_vector(vector.inner());
44 result
45 .scalar_only
46 .store(vector.scalar_only(), Ordering::Relaxed);
47 result
48 }
49
50 pub fn append(&self, v: Value) -> ValueResult<()> {
51 if *self.persisted.lock().unwrap() {
52 return Err(ValueError::TransientAlreadyPersisted);
53 }
54 if !super::vector::scalar(&v) {
55 self.scalar_only.store(false, Ordering::Relaxed);
56 }
57 let v = crate::publish::publish_for_slot(v, self as *const _ as usize, self.count());
58 let mut vector = self.vector.lock().unwrap();
59 vector.push_back_mut(v);
60 Ok(())
61 }
62
63 pub fn pop(&self) -> ValueResult<()> {
64 if *self.persisted.lock().unwrap() {
65 return Err(ValueError::TransientAlreadyPersisted);
66 }
67 let mut vector = self.vector.lock().unwrap();
68 if vector.drop_last_mut() {
69 let index = vector.len();
70 drop(vector);
71 crate::publish::publish_for_slot(Value::Nil, self as *const _ as usize, index);
72 Ok(())
73 } else {
74 Err(ValueError::OutOfRange)
75 }
76 }
77
78 pub fn set(&self, index: usize, v: Value) -> ValueResult<()> {
79 if *self.persisted.lock().unwrap() {
80 return Err(ValueError::TransientAlreadyPersisted);
81 }
82 let count = self.count();
83 if index > count {
84 return Err(ValueError::IndexOutOfBounds { idx: index, count });
85 }
86 if !super::vector::scalar(&v) {
87 self.scalar_only.store(false, Ordering::Relaxed);
88 }
89 let v = crate::publish::publish_for_slot(v, self as *const _ as usize, index);
90 let mut vector = self.vector.lock().unwrap();
91 if index == count {
92 vector.push_back_mut(v);
93 } else {
94 vector.set_mut(index, v);
95 }
96 Ok(())
97 }
98
99 pub fn count(&self) -> usize {
100 self.vector.lock().unwrap().len()
101 }
102
103 pub fn get(&self, index: usize) -> Option<Value> {
104 #[cfg(feature = "no-gc")]
105 self.initial.borrow().protect_read();
106 crate::publish::read_slot(self as *const _ as usize, index);
107 self.vector.lock().unwrap().get(index).cloned()
108 }
109
110 pub fn persistent(&self) -> ValueResult<PersistentVector> {
111 let vector = self.vector.lock().unwrap();
112 let mut persisted = self.persisted.lock().unwrap();
113 if *persisted {
114 return Err(ValueError::TransientAlreadyPersisted);
115 }
116 *persisted = true;
117 let result = PersistentVector::from_vector_summary(
118 vector.clone(),
119 self.scalar_only.load(Ordering::Relaxed),
120 );
121 #[cfg(feature = "no-gc")]
122 {
123 let address = self as *const _ as usize;
124 if cljrs_gc::region::AllocationOwner::for_address(address).is_permanent() {
125 cljrs_gc::region::RegionLease::for_value(&result).protect_read();
127 } else {
128 cljrs_gc::region::RegionLease::for_address(address).protect_read();
129 }
130 }
131 Ok(result)
132 }
133}
134
135impl ClojureHash for TransientVector {
136 fn clojure_hash(&self) -> u32 {
137 let mut hash: u32 = 0;
138 let values = self.vector.lock().unwrap().clone();
139 let snapshot = super::Snapshot::new(crate::PersistentVector::from_vector(values));
140 for v in snapshot.get().iter() {
141 hash = hash_combine_ordered(hash, v.clojure_hash());
142 }
143 hash
144 }
145}
146
147impl Clone for TransientVector {
148 fn clone(&self) -> Self {
149 Self {
150 vector: Mutex::new(self.vector.lock().unwrap().clone()),
151 #[cfg(feature = "no-gc")]
152 initial: std::cell::RefCell::new(crate::publish::ValueLease::for_trace(
153 &PersistentVector::from_vector_summary(self.vector.lock().unwrap().clone(), false),
154 &Default::default(),
155 )),
156 persisted: Mutex::new(*self.persisted.lock().unwrap()),
157 scalar_only: AtomicBool::new(self.scalar_only.load(Ordering::Relaxed)),
158 }
159 }
160}
161
162impl cljrs_gc::Trace for TransientVector {
163 #[cfg(feature = "no-gc")]
164 fn init_ownership(&self) {
165 let address = self as *const _ as usize;
166 let owner = cljrs_gc::region::AllocationOwner::for_address(address);
167 let lease = self.initial.borrow().reparent(&owner);
168 *self.initial.borrow_mut() = lease;
169 }
170 #[cfg(feature = "no-gc")]
171 fn trace(&self, _: &mut cljrs_gc::MarkVisitor) {}
172 #[cfg(not(feature = "no-gc"))]
173 fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
174 {
175 let vec = self.vector.lock().unwrap();
176 for v in vec.iter() {
177 v.trace(visitor);
178 }
179 }
180 }
181
182 fn gc_size_extra(&self) -> usize {
183 let n = self.vector.lock().unwrap().len();
184 n * (24 + std::mem::size_of::<crate::Value>())
185 }
186}
187
188impl Default for TransientVector {
189 fn default() -> Self {
190 Self::new()
191 }
192}
193
194impl Drop for TransientVector {
195 fn drop(&mut self) {
196 crate::publish::clear_slots(self as *const _ as usize);
197 }
198}