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)]
186pub struct VecList {
187 values: Arc<[Value]>,
188}
189
190impl VecList {
191 pub fn from_vec(values: Vec<Value>) -> Self {
193 Self {
194 values: Arc::from(values),
195 }
196 }
197
198 pub fn from_arc(values: Arc<[Value]>) -> Self {
200 Self { values }
201 }
202
203 pub fn as_slice(&self) -> &[Value] {
205 &self.values
206 }
207}
208
209impl Object for VecList {
210 fn display(&self, _cx: &mut Cx) -> Result<String> {
211 Ok(format!("list[{}]", self.values.len()))
212 }
213
214 fn as_any(&self) -> &dyn std::any::Any {
215 self
216 }
217}
218
219impl crate::ObjectCompat for VecList {
220 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
221 let symbol = Symbol::qualified("core", "List");
222 if let Some(value) = cx.registry().class_by_symbol(&symbol) {
223 return Ok(value.clone());
224 }
225 cx.factory().class_stub(CORE_LIST_CLASS_ID, symbol)
226 }
227 fn as_expr(&self, cx: &mut Cx) -> Result<Expr> {
228 Ok(Expr::List(
229 self.values
230 .iter()
231 .map(|value| value.object().as_expr(cx))
232 .collect::<Result<Vec<_>>>()?,
233 ))
234 }
235 fn truth(&self, _cx: &mut Cx) -> Result<bool> {
236 Ok(!self.values.is_empty())
237 }
238 fn as_list(&self) -> Option<&dyn ListValue> {
239 Some(self)
240 }
241}
242
243impl ListValue for VecList {
244 fn is_empty(&self, _cx: &mut Cx) -> Result<bool> {
245 Ok(self.values.is_empty())
246 }
247
248 fn car(&self, _cx: &mut Cx) -> Result<Option<Value>> {
249 Ok(self.values.first().cloned())
250 }
251
252 fn cdr(&self, cx: &mut Cx) -> Result<Option<Value>> {
253 if self.values.is_empty() {
254 return Ok(None);
255 }
256
257 let tail = self.values[1..].to_vec();
258 Ok(Some(cx.factory().opaque(Arc::new(Self::from_vec(tail)))?))
259 }
260
261 fn len(&self, _cx: &mut Cx) -> Result<LengthResult> {
262 Ok(LengthResult::Known(self.values.len()))
263 }
264
265 fn len_cmp(&self, _cx: &mut Cx, n: usize) -> Result<Ordering> {
266 Ok(self.values.len().cmp(&n))
267 }
268
269 fn get(&self, _cx: &mut Cx, index: usize) -> Result<Option<Value>> {
270 Ok(self.values.get(index).cloned())
271 }
272
273 fn for_each(
274 &self,
275 _cx: &mut Cx,
276 limit: Option<usize>,
277 visit: &mut dyn FnMut(&Value),
278 ) -> Result<()> {
279 let stop = limit.unwrap_or(self.values.len()).min(self.values.len());
280 for value in &self.values[..stop] {
281 visit(value);
282 }
283 Ok(())
284 }
285
286 fn to_vec(&self, _cx: &mut Cx, limit: Option<usize>) -> Result<Vec<Value>> {
287 match limit {
288 Some(max) => Ok(self.values.iter().take(max).cloned().collect()),
289 None => Ok(self.values.to_vec()),
290 }
291 }
292}
293
294pub trait ListBackend: Send + Sync {
296 fn name(&self) -> &str;
298
299 fn new_list(&self, cx: &mut Cx, items: Vec<Value>) -> Result<Value>;
301
302 fn new_cons(&self, cx: &mut Cx, car: Value, cdr: Value) -> Result<Value>;
304}
305
306pub struct ListRegistry {
308 backends: BTreeMap<String, Arc<dyn ListBackend>>,
309 active: String,
310}
311
312impl ListRegistry {
313 pub fn new() -> Self {
315 let mut registry = Self {
316 backends: BTreeMap::new(),
317 active: "vec".to_owned(),
318 };
319 registry.register(Arc::new(VecBackend));
320 registry
321 }
322
323 pub fn register(&mut self, backend: Arc<dyn ListBackend>) {
325 self.backends.insert(backend.name().to_owned(), backend);
326 }
327
328 pub fn set_active(&mut self, name: &str) -> Result<()> {
330 if self.backends.contains_key(name) {
331 self.active = name.to_owned();
332 Ok(())
333 } else {
334 Err(Error::Eval(format!("unknown list backend: {name}")))
335 }
336 }
337
338 pub fn active(&self) -> &str {
340 &self.active
341 }
342
343 pub fn new_list(&self, cx: &mut Cx, items: Vec<Value>) -> Result<Value> {
345 self.backend()?.new_list(cx, items)
346 }
347
348 pub fn new_cons(&self, cx: &mut Cx, car: Value, cdr: Value) -> Result<Value> {
350 self.backend()?.new_cons(cx, car, cdr)
351 }
352
353 fn backend(&self) -> Result<&Arc<dyn ListBackend>> {
354 self.backends
355 .get(&self.active)
356 .ok_or_else(|| Error::Eval("active list backend missing".to_owned()))
357 }
358}
359
360impl Default for ListRegistry {
361 fn default() -> Self {
362 Self::new()
363 }
364}
365
366struct VecBackend;
367
368impl ListBackend for VecBackend {
369 fn name(&self) -> &str {
370 "vec"
371 }
372
373 fn new_list(&self, cx: &mut Cx, items: Vec<Value>) -> Result<Value> {
374 cx.factory().opaque(Arc::new(VecList::from_vec(items)))
375 }
376
377 fn new_cons(&self, cx: &mut Cx, car: Value, cdr: Value) -> Result<Value> {
378 let Some(list) = cdr.object().as_list() else {
379 return Err(Error::TypeMismatch {
380 expected: "list",
381 found: "non-list",
382 });
383 };
384 let mut items = vec![car];
385 items.extend(list.to_vec(cx, None)?);
386 cx.factory().opaque(Arc::new(VecList::from_vec(items)))
387 }
388}
389
390#[cfg(test)]
391#[path = "list_tests.rs"]
392mod list_tests;