1use std::{cmp::Ordering, collections::BTreeMap, sync::Arc};
8
9use crate::{
10 capability::list_force_unbounded_capability,
11 env::Cx,
12 error::{Error, Result},
13 expr::Expr,
14 id::{CORE_LIST_CLASS_ID, Symbol},
15 object::{ClassRef, Object},
16 value::{RuntimeObject, Value},
17};
18
19pub const DEFAULT_FORCE_BOUND: usize = 1 << 20;
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub enum LengthResult {
26 Known(usize),
28 Unknown,
30}
31
32pub trait ListValue: RuntimeObject {
34 fn is_empty(&self, cx: &mut Cx) -> Result<bool>;
36
37 fn car(&self, cx: &mut Cx) -> Result<Option<Value>>;
39
40 fn cdr(&self, cx: &mut Cx) -> Result<Option<Value>>;
42
43 fn len(&self, cx: &mut Cx) -> Result<LengthResult>;
45
46 fn len_cmp(&self, cx: &mut Cx, n: usize) -> Result<Ordering> {
48 spine_len_cmp_impl(cx, self, n)
49 }
50
51 fn get(&self, cx: &mut Cx, index: usize) -> Result<Option<Value>> {
53 let mut node = self.cdr_self(cx)?;
54 let mut i = index;
55 while let Some(list) = node.as_ref().and_then(|value| value.object().as_list()) {
56 if list.is_empty(cx)? {
57 return Ok(None);
58 }
59 if i == 0 {
60 return list.car(cx);
61 }
62 i -= 1;
63 node = list.cdr(cx)?;
64 }
65 Ok(None)
66 }
67
68 fn for_each(
70 &self,
71 cx: &mut Cx,
72 limit: Option<usize>,
73 visit: &mut dyn FnMut(&Value),
74 ) -> Result<()> {
75 if matches!(limit, Some(0)) {
76 return Ok(());
77 }
78
79 let mut count = 0usize;
80 let mut head = self.car(cx)?;
81 let mut tail = self.cdr(cx)?;
82 while let Some(value) = head {
83 if matches!(limit, Some(max) if count >= max) {
84 return Ok(());
85 }
86 visit(&value);
87 count += 1;
88 match tail.as_ref().and_then(|node| node.object().as_list()) {
89 Some(list) if !list.is_empty(cx)? => {
90 head = list.car(cx)?;
91 tail = list.cdr(cx)?;
92 }
93 _ => break,
94 }
95 }
96 Ok(())
97 }
98
99 fn to_vec(&self, cx: &mut Cx, limit: Option<usize>) -> Result<Vec<Value>> {
101 let mut out = Vec::new();
102 self.for_each(cx, limit, &mut |value| out.push(value.clone()))?;
103 Ok(out)
104 }
105
106 fn cdr_self(&self, _cx: &mut Cx) -> Result<Option<Value>> {
108 Ok(self.as_self_value())
109 }
110
111 fn as_self_value(&self) -> Option<Value> {
113 None
114 }
115}
116
117pub fn spine_len_cmp(cx: &mut Cx, head: &dyn ListValue, n: usize) -> Result<Ordering> {
119 spine_len_cmp_impl(cx, head, n)
120}
121
122pub fn force_list_bound(cx: &mut Cx) -> Option<usize> {
125 if cx.require(&list_force_unbounded_capability()).is_ok() {
126 None
127 } else {
128 Some(DEFAULT_FORCE_BOUND)
129 }
130}
131
132pub fn force_list_to_vec(cx: &mut Cx, list: &dyn ListValue, context: &str) -> Result<Vec<Value>> {
134 let bound = force_list_bound(cx);
135 if let Some(max) = bound
136 && list.len_cmp(cx, max)? == Ordering::Greater
137 {
138 return Err(Error::Eval(format!(
139 "{context}: list exceeds force bound {max}; lazy/endless list cannot be materialized in v1"
140 )));
141 }
142 list.to_vec(cx, bound)
143}
144
145fn spine_len_cmp_impl<T: ListValue + ?Sized>(cx: &mut Cx, head: &T, n: usize) -> Result<Ordering> {
146 if head.is_empty(cx)? {
147 return Ok(0usize.cmp(&n));
148 }
149
150 let mut count = 1usize;
151 if count > n {
152 return Ok(Ordering::Greater);
153 }
154
155 let mut node = head.cdr(cx)?;
156 while let Some(value) = node {
157 let Some(list) = value.object().as_list() else {
158 return Err(Error::Eval("list cdr did not yield a list".to_owned()));
159 };
160 if list.is_empty(cx)? {
161 break;
162 }
163 count += 1;
164 if count > n {
165 return Ok(Ordering::Greater);
166 }
167 node = list.cdr(cx)?;
168 }
169 Ok(count.cmp(&n))
170}
171
172#[derive(Clone)]
188pub struct VecList {
189 values: Arc<[Value]>,
190}
191
192impl VecList {
193 pub fn from_vec(values: Vec<Value>) -> Self {
195 Self {
196 values: Arc::from(values),
197 }
198 }
199
200 pub fn from_arc(values: Arc<[Value]>) -> Self {
202 Self { values }
203 }
204
205 pub fn as_slice(&self) -> &[Value] {
207 &self.values
208 }
209}
210
211impl Object for VecList {
212 fn display(&self, _cx: &mut Cx) -> Result<String> {
213 Ok(format!("list[{}]", self.values.len()))
214 }
215
216 fn as_any(&self) -> &dyn std::any::Any {
217 self
218 }
219}
220
221impl crate::ObjectCompat for VecList {
222 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
223 let symbol = Symbol::qualified("core", "List");
224 if let Some(value) = cx.registry().class_by_symbol(&symbol) {
225 return Ok(value.clone());
226 }
227 cx.factory().class_stub(CORE_LIST_CLASS_ID, symbol)
228 }
229 fn as_expr(&self, cx: &mut Cx) -> Result<Expr> {
230 Ok(Expr::List(
231 self.values
232 .iter()
233 .map(|value| value.object().as_expr(cx))
234 .collect::<Result<Vec<_>>>()?,
235 ))
236 }
237 fn truth(&self, _cx: &mut Cx) -> Result<bool> {
238 Ok(!self.values.is_empty())
239 }
240 fn as_list(&self) -> Option<&dyn ListValue> {
241 Some(self)
242 }
243}
244
245impl ListValue for VecList {
246 fn is_empty(&self, _cx: &mut Cx) -> Result<bool> {
247 Ok(self.values.is_empty())
248 }
249
250 fn car(&self, _cx: &mut Cx) -> Result<Option<Value>> {
251 Ok(self.values.first().cloned())
252 }
253
254 fn cdr(&self, cx: &mut Cx) -> Result<Option<Value>> {
255 if self.values.is_empty() {
256 return Ok(None);
257 }
258
259 let tail = self.values[1..].to_vec();
260 Ok(Some(cx.factory().opaque(Arc::new(Self::from_vec(tail)))?))
261 }
262
263 fn len(&self, _cx: &mut Cx) -> Result<LengthResult> {
264 Ok(LengthResult::Known(self.values.len()))
265 }
266
267 fn len_cmp(&self, _cx: &mut Cx, n: usize) -> Result<Ordering> {
268 Ok(self.values.len().cmp(&n))
269 }
270
271 fn get(&self, _cx: &mut Cx, index: usize) -> Result<Option<Value>> {
272 Ok(self.values.get(index).cloned())
273 }
274
275 fn for_each(
276 &self,
277 _cx: &mut Cx,
278 limit: Option<usize>,
279 visit: &mut dyn FnMut(&Value),
280 ) -> Result<()> {
281 let stop = limit.unwrap_or(self.values.len()).min(self.values.len());
282 for value in &self.values[..stop] {
283 visit(value);
284 }
285 Ok(())
286 }
287
288 fn to_vec(&self, _cx: &mut Cx, limit: Option<usize>) -> Result<Vec<Value>> {
289 match limit {
290 Some(max) => Ok(self.values.iter().take(max).cloned().collect()),
291 None => Ok(self.values.to_vec()),
292 }
293 }
294}
295
296pub trait ListBackend: Send + Sync {
298 fn name(&self) -> &str;
300
301 fn new_list(&self, cx: &mut Cx, items: Vec<Value>) -> Result<Value>;
303
304 fn new_cons(&self, cx: &mut Cx, car: Value, cdr: Value) -> Result<Value>;
306}
307
308pub struct ListRegistry {
310 backends: BTreeMap<String, Arc<dyn ListBackend>>,
311 active: String,
312}
313
314impl ListRegistry {
315 pub fn new() -> Self {
317 let mut registry = Self {
318 backends: BTreeMap::new(),
319 active: "vec".to_owned(),
320 };
321 registry.register(Arc::new(VecBackend));
322 registry
323 }
324
325 pub fn register(&mut self, backend: Arc<dyn ListBackend>) {
327 self.backends.insert(backend.name().to_owned(), backend);
328 }
329
330 pub fn set_active(&mut self, name: &str) -> Result<()> {
332 if self.backends.contains_key(name) {
333 self.active = name.to_owned();
334 Ok(())
335 } else {
336 Err(Error::Eval(format!("unknown list backend: {name}")))
337 }
338 }
339
340 pub fn active(&self) -> &str {
342 &self.active
343 }
344
345 pub fn new_list(&self, cx: &mut Cx, items: Vec<Value>) -> Result<Value> {
347 self.backend()?.new_list(cx, items)
348 }
349
350 pub fn new_cons(&self, cx: &mut Cx, car: Value, cdr: Value) -> Result<Value> {
352 self.backend()?.new_cons(cx, car, cdr)
353 }
354
355 fn backend(&self) -> Result<&Arc<dyn ListBackend>> {
356 self.backends
357 .get(&self.active)
358 .ok_or_else(|| Error::Eval("active list backend missing".to_owned()))
359 }
360}
361
362impl Default for ListRegistry {
363 fn default() -> Self {
364 Self::new()
365 }
366}
367
368struct VecBackend;
369
370impl ListBackend for VecBackend {
371 fn name(&self) -> &str {
372 "vec"
373 }
374
375 fn new_list(&self, cx: &mut Cx, items: Vec<Value>) -> Result<Value> {
376 cx.factory().opaque(Arc::new(VecList::from_vec(items)))
377 }
378
379 fn new_cons(&self, cx: &mut Cx, car: Value, cdr: Value) -> Result<Value> {
380 let Some(list) = cdr.object().as_list() else {
381 return Err(Error::TypeMismatch {
382 expected: "list",
383 found: "non-list",
384 });
385 };
386 let mut items = vec![car];
387 items.extend(list.to_vec(cx, None)?);
388 cx.factory().opaque(Arc::new(VecList::from_vec(items)))
389 }
390}
391
392#[cfg(test)]
393#[path = "list_tests.rs"]
394mod list_tests;