Skip to main content

sim_lib_sequence/
persistent.rs

1use std::sync::Arc;
2
3use sim_kernel::{Cx, Error, Expr, Object, ObjectCompat, Result, Symbol, Value, force_list_to_vec};
4
5#[sim_citizen_derive::non_citizen(
6    reason = "persistent vector wrapper; canonical form is native Expr::Vector data",
7    kind = "marker",
8    descriptor = "core/Expr"
9)]
10/// Immutable, shareable vector object backed by a shared slice.
11///
12/// A persistent sequence container: construction never mutates inputs, and the
13/// canonical form is native [`Expr::Vector`] data per the kernel object
14/// contract.
15#[derive(Clone, Debug)]
16pub struct PersistentVector {
17    items: Arc<[Value]>,
18}
19
20impl PersistentVector {
21    /// Build a persistent vector from the given elements.
22    pub fn new(items: Vec<Value>) -> Self {
23        Self {
24            items: Arc::from(items),
25        }
26    }
27
28    /// Borrow the vector elements in order.
29    pub fn items(&self) -> &[Value] {
30        &self.items
31    }
32}
33
34impl Object for PersistentVector {
35    fn display(&self, _cx: &mut Cx) -> Result<String> {
36        Ok(format!("#<sequence-vector {}>", self.items.len()))
37    }
38
39    fn as_any(&self) -> &dyn std::any::Any {
40        self
41    }
42}
43
44impl ObjectCompat for PersistentVector {
45    fn as_expr(&self, cx: &mut Cx) -> Result<Expr> {
46        Ok(Expr::Vector(
47            self.items
48                .iter()
49                .map(|value| value.object().as_expr(cx))
50                .collect::<Result<Vec<_>>>()?,
51        ))
52    }
53
54    fn truth(&self, _cx: &mut Cx) -> Result<bool> {
55        Ok(!self.items.is_empty())
56    }
57}
58
59#[sim_citizen_derive::non_citizen(
60    reason = "persistent set wrapper; canonical form is native Expr::Set data",
61    kind = "marker",
62    descriptor = "core/Expr"
63)]
64/// Immutable, shareable set object holding canonically distinct elements.
65///
66/// A persistent sequence container that deduplicates by canonical expression
67/// equality; the canonical form is native [`Expr::Set`] data per the kernel
68/// object contract.
69#[derive(Clone, Debug)]
70pub struct PersistentSet {
71    items: Arc<[Value]>,
72}
73
74impl PersistentSet {
75    /// Build a persistent set, dropping canonically duplicate elements.
76    pub fn new(cx: &mut Cx, items: Vec<Value>) -> Result<Self> {
77        let mut unique = Vec::new();
78        for item in items {
79            if !contains_canonical(cx, &unique, &item)? {
80                unique.push(item);
81            }
82        }
83        Ok(Self {
84            items: Arc::from(unique),
85        })
86    }
87
88    /// Borrow the set elements in insertion order.
89    pub fn items(&self) -> &[Value] {
90        &self.items
91    }
92}
93
94impl Object for PersistentSet {
95    fn display(&self, _cx: &mut Cx) -> Result<String> {
96        Ok(format!("#<sequence-set {}>", self.items.len()))
97    }
98
99    fn as_any(&self) -> &dyn std::any::Any {
100        self
101    }
102}
103
104impl ObjectCompat for PersistentSet {
105    fn as_expr(&self, cx: &mut Cx) -> Result<Expr> {
106        Ok(Expr::Set(
107            self.items
108                .iter()
109                .map(|value| value.object().as_expr(cx))
110                .collect::<Result<Vec<_>>>()?,
111        ))
112    }
113
114    fn truth(&self, _cx: &mut Cx) -> Result<bool> {
115        Ok(!self.items.is_empty())
116    }
117}
118
119/// Construct an immutable list [`Value`] from the given elements.
120pub fn persistent_list(cx: &mut Cx, items: Vec<Value>) -> Result<Value> {
121    cx.new_list(items)
122}
123
124/// Return a new list with `item` appended; the input list is unchanged.
125pub fn persistent_list_push(cx: &mut Cx, list: &Value, item: Value) -> Result<Value> {
126    let mut items = list_items(cx, list)?;
127    items.push(item);
128    cx.new_list(items)
129}
130
131/// Construct a [`PersistentVector`] as a runtime [`Value`].
132///
133/// # Examples
134///
135/// ```
136/// use std::sync::Arc;
137/// use sim_kernel::{Cx, DefaultFactory, NoopEvalPolicy, Symbol};
138/// use sim_lib_sequence::{persistent_vector, persistent_vector_push};
139///
140/// let mut cx = Cx::new(Arc::new(NoopEvalPolicy), Arc::new(DefaultFactory));
141/// let one = cx.factory().number_literal(Symbol::qualified("test", "u64"), "1".into())?;
142/// let two = cx.factory().number_literal(Symbol::qualified("test", "u64"), "2".into())?;
143///
144/// let base = persistent_vector(&mut cx, vec![one])?;
145/// // Push returns a new vector; `base` keeps its single element.
146/// let _grown = persistent_vector_push(&mut cx, &base, two)?;
147/// # Ok::<(), sim_kernel::Error>(())
148/// ```
149pub fn persistent_vector(cx: &mut Cx, items: Vec<Value>) -> Result<Value> {
150    cx.factory().opaque(Arc::new(PersistentVector::new(items)))
151}
152
153/// Return a new vector with `item` appended; the input vector is unchanged.
154pub fn persistent_vector_push(cx: &mut Cx, vector: &Value, item: Value) -> Result<Value> {
155    let vector = vector_value(vector)?;
156    let mut items = vector.items().to_vec();
157    items.push(item);
158    persistent_vector(cx, items)
159}
160
161/// Construct a [`PersistentSet`] as a runtime [`Value`], deduplicating elements.
162pub fn persistent_set(cx: &mut Cx, items: Vec<Value>) -> Result<Value> {
163    let set = PersistentSet::new(cx, items)?;
164    cx.factory().opaque(Arc::new(set))
165}
166
167/// Return a new set with `item` inserted if canonically absent; input unchanged.
168pub fn persistent_set_insert(cx: &mut Cx, set: &Value, item: Value) -> Result<Value> {
169    let set = set_value(set)?;
170    let mut items = set.items().to_vec();
171    if !contains_canonical(cx, &items, &item)? {
172        items.push(item);
173    }
174    persistent_set(cx, items)
175}
176
177/// Construct an immutable map (table) [`Value`] from key/value entries.
178pub fn persistent_map(cx: &mut Cx, entries: Vec<(Symbol, Value)>) -> Result<Value> {
179    cx.new_table(entries)
180}
181
182/// Return a new map with `key` bound to `value`; the input map is unchanged.
183///
184/// Replaces an existing binding for `key` or appends a fresh one.
185pub fn persistent_map_assoc(cx: &mut Cx, map: &Value, key: Symbol, value: Value) -> Result<Value> {
186    let table = map.object().as_table_impl().ok_or(Error::TypeMismatch {
187        expected: "table",
188        found: "non-table",
189    })?;
190    let mut entries = table.entries(cx)?;
191    match entries.iter_mut().find(|(candidate, _)| *candidate == key) {
192        Some((_, slot)) => *slot = value,
193        None => entries.push((key, value)),
194    }
195    cx.new_table(entries)
196}
197
198fn list_items(cx: &mut Cx, value: &Value) -> Result<Vec<Value>> {
199    let list = value.object().as_list().ok_or(Error::TypeMismatch {
200        expected: "list",
201        found: "non-list",
202    })?;
203    force_list_to_vec(cx, list, "sequence persistent list")
204}
205
206fn vector_value(value: &Value) -> Result<&PersistentVector> {
207    value
208        .object()
209        .downcast_ref::<PersistentVector>()
210        .ok_or(Error::TypeMismatch {
211            expected: "sequence vector",
212            found: "non-vector",
213        })
214}
215
216fn set_value(value: &Value) -> Result<&PersistentSet> {
217    value
218        .object()
219        .downcast_ref::<PersistentSet>()
220        .ok_or(Error::TypeMismatch {
221            expected: "sequence set",
222            found: "non-set",
223        })
224}
225
226fn contains_canonical(cx: &mut Cx, values: &[Value], candidate: &Value) -> Result<bool> {
227    let candidate = candidate.object().as_expr(cx)?;
228    for value in values {
229        if value.object().as_expr(cx)?.canonical_eq(&candidate) {
230            return Ok(true);
231        }
232    }
233    Ok(false)
234}