Skip to main content

cljrs_value/collections/
transient_vector.rs

1use 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    /// Share a persistent vector and its cached scalar summary.
42    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                // Rust stack containers do not have a containing region to lease.
126                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}