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