1use std::sync::{Arc, Mutex};
2
3use sim_kernel::{
4 CORE_SEQUENCE_CLASS_ID, ClassRef, Cx, Error, ListSequence, Object, ObjectCompat, Result,
5 Sequence, SequenceItem, Symbol, Value, seq_next_value,
6};
7
8pub type SequenceProducer =
13 Arc<dyn Fn(&mut Cx, usize) -> Result<Option<Value>> + Send + Sync + 'static>;
14
15#[sim_citizen_derive::non_citizen(
16 reason = "live lazy sequence producer; reconstruct from the source sequence expression",
17 kind = "handle",
18 descriptor = "core/Sequence"
19)]
20#[derive(Clone)]
26pub struct LazySequence {
27 producer: SequenceProducer,
28 state: Arc<Mutex<LazySequenceState>>,
29}
30
31#[derive(Debug, Default)]
32struct LazySequenceState {
33 index: usize,
34 pending: Option<SequenceItem>,
35 done: bool,
36 closed: bool,
37}
38
39impl LazySequence {
40 pub fn new(producer: SequenceProducer) -> Self {
42 Self {
43 producer,
44 state: Arc::new(Mutex::new(LazySequenceState::default())),
45 }
46 }
47
48 fn produce(&self, cx: &mut Cx) -> Result<Option<SequenceItem>> {
49 let index = {
50 let mut state = self
51 .state
52 .lock()
53 .map_err(|_| Error::PoisonedLock("lazy sequence"))?;
54 if state.closed || state.done {
55 return Ok(None);
56 }
57 let index = state.index;
58 state.index += 1;
59 index
60 };
61 match (self.producer)(cx, index)? {
62 Some(value) => Ok(Some(SequenceItem::new(value))),
63 None => {
64 self.mark_done()?;
65 Ok(None)
66 }
67 }
68 }
69
70 fn mark_done(&self) -> Result<()> {
71 let mut state = self
72 .state
73 .lock()
74 .map_err(|_| Error::PoisonedLock("lazy sequence"))?;
75 state.done = true;
76 Ok(())
77 }
78}
79
80impl Object for LazySequence {
81 fn display(&self, _cx: &mut Cx) -> Result<String> {
82 Ok("#<lazy-sequence>".to_owned())
83 }
84
85 fn as_any(&self) -> &dyn std::any::Any {
86 self
87 }
88}
89
90impl ObjectCompat for LazySequence {
91 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
92 cx.factory().class_stub(
93 CORE_SEQUENCE_CLASS_ID,
94 Symbol::qualified("core", "Sequence"),
95 )
96 }
97
98 fn as_sequence(&self) -> Option<&dyn Sequence> {
99 Some(self)
100 }
101}
102
103impl Sequence for LazySequence {
104 fn next_item(&self, cx: &mut Cx) -> Result<Option<SequenceItem>> {
105 {
106 let mut state = self
107 .state
108 .lock()
109 .map_err(|_| Error::PoisonedLock("lazy sequence"))?;
110 if state.closed {
111 return Ok(None);
112 }
113 if let Some(item) = state.pending.take() {
114 return Ok(Some(item));
115 }
116 }
117 self.produce(cx)
118 }
119
120 fn close(&self, _cx: &mut Cx) -> Result<()> {
121 let mut state = self
122 .state
123 .lock()
124 .map_err(|_| Error::PoisonedLock("lazy sequence"))?;
125 state.pending = None;
126 state.closed = true;
127 state.done = true;
128 Ok(())
129 }
130
131 fn peek_item(&self, cx: &mut Cx) -> Result<Option<SequenceItem>> {
132 {
133 let state = self
134 .state
135 .lock()
136 .map_err(|_| Error::PoisonedLock("lazy sequence"))?;
137 if state.closed {
138 return Ok(None);
139 }
140 if let Some(item) = state.pending.clone() {
141 return Ok(Some(item));
142 }
143 }
144 let item = self.produce(cx)?;
145 if let Some(item) = item.clone() {
146 let mut state = self
147 .state
148 .lock()
149 .map_err(|_| Error::PoisonedLock("lazy sequence"))?;
150 state.pending = Some(item);
151 }
152 Ok(item)
153 }
154
155 fn is_done(&self, _cx: &mut Cx) -> Result<bool> {
156 let state = self
157 .state
158 .lock()
159 .map_err(|_| Error::PoisonedLock("lazy sequence"))?;
160 Ok((state.done || state.closed) && state.pending.is_none())
161 }
162}
163
164pub fn lazy_sequence_value(cx: &mut Cx, producer: SequenceProducer) -> Result<Value> {
193 cx.factory().opaque(Arc::new(LazySequence::new(producer)))
194}
195
196pub fn sequence_from_list_value(cx: &mut Cx, list: Value) -> Result<Value> {
201 cx.factory().opaque(Arc::new(ListSequence::new(list)))
202}
203
204pub fn force_sequence_bounded(
210 cx: &mut Cx,
211 sequence: &Value,
212 max: usize,
213 context: &str,
214) -> Result<Vec<Value>> {
215 let mut out = Vec::new();
216 for _ in 0..max {
217 let Some(item) = seq_next_value(cx, sequence)? else {
218 return Ok(out);
219 };
220 out.push(item.into_value(cx)?);
221 }
222 if sequence_has_more(cx, sequence)? {
223 return Err(Error::Eval(format!(
224 "{context}: sequence exceeds force bound {max}"
225 )));
226 }
227 Ok(out)
228}
229
230fn sequence_has_more(cx: &mut Cx, sequence: &Value) -> Result<bool> {
231 if let Some(sequence) = sequence.object().as_sequence() {
232 return sequence.peek_item(cx).map(|item| item.is_some());
233 }
234 seq_next_value(cx, sequence).map(|item| item.is_some())
235}