netidx_bscript/stdfn/core/
array.rs

1use crate::{
2    deftype,
3    expr::{ExprId, ModPath},
4    node::genn,
5    stdfn::{CachedArgs, CachedVals, EvalCached},
6    typ::{FnType, Type},
7    Apply, BindId, BuiltIn, BuiltInInitFn, Ctx, Event, ExecCtx, LambdaId, Node,
8    UserEvent,
9};
10use anyhow::{anyhow, bail};
11use compact_str::format_compact;
12use netidx::{publisher::Typ, subscriber::Value, utils::Either};
13use netidx_netproto::valarray::ValArray;
14use smallvec::{smallvec, SmallVec};
15use std::{
16    collections::VecDeque,
17    fmt::Debug,
18    iter,
19    sync::{Arc, LazyLock},
20};
21use triomphe::Arc as TArc;
22
23pub trait MapFn<C: Ctx, E: UserEvent>: Debug + Default + Send + Sync + 'static {
24    const NAME: &str;
25    const TYP: LazyLock<FnType>;
26
27    /// finish will be called when every lambda instance has produced
28    /// a value for the updated array. Out contains the output of the
29    /// predicate lambda for each index i, and a is the array. out and
30    /// a are guaranteed to have the same length. out[i].cur is
31    /// guaranteed to be Some.
32    fn finish(&mut self, slots: &[Slot<C, E>], a: &ValArray) -> Option<Value>;
33}
34
35#[derive(Debug)]
36pub struct Slot<C: Ctx, E: UserEvent> {
37    id: BindId,
38    pred: Node<C, E>,
39    pub cur: Option<Value>,
40}
41
42#[derive(Debug)]
43pub struct MapQ<C: Ctx, E: UserEvent, T: MapFn<C, E>> {
44    scope: ModPath,
45    predid: BindId,
46    top_id: ExprId,
47    ftyp: TArc<FnType>,
48    mftyp: TArc<FnType>,
49    etyp: Type,
50    slots: Vec<Slot<C, E>>,
51    cur: ValArray,
52    t: T,
53}
54
55impl<C: Ctx, E: UserEvent, T: MapFn<C, E>> BuiltIn<C, E> for MapQ<C, E, T> {
56    const NAME: &str = T::NAME;
57    const TYP: LazyLock<FnType> = T::TYP;
58
59    fn init(_: &mut ExecCtx<C, E>) -> BuiltInInitFn<C, E> {
60        Arc::new(|_ctx, typ, scope, from, top_id| match from {
61            [_, _] => Ok(Box::new(Self {
62                scope: ModPath(
63                    scope.0.append(format_compact!("fn{}", LambdaId::new().0).as_str()),
64                ),
65                predid: BindId::new(),
66                top_id,
67                ftyp: TArc::new(typ.clone()),
68
69                etyp: match &typ.args[0].typ {
70                    Type::Array(et) => (**et).clone(),
71                    t => bail!("expected array not {t}"),
72                },
73                mftyp: match &typ.args[1].typ {
74                    Type::Fn(ft) => ft.clone(),
75                    t => bail!("expected a function not {t}"),
76                },
77                slots: vec![],
78                cur: ValArray::from([]),
79                t: T::default(),
80            })),
81            _ => bail!("expected two arguments"),
82        })
83    }
84}
85
86impl<C: Ctx, E: UserEvent, T: MapFn<C, E>> Apply<C, E> for MapQ<C, E, T> {
87    fn update(
88        &mut self,
89        ctx: &mut ExecCtx<C, E>,
90        from: &mut [Node<C, E>],
91        event: &mut Event<E>,
92    ) -> Option<Value> {
93        let slen = self.slots.len();
94        if let Some(v) = from[1].update(ctx, event) {
95            ctx.cached.insert(self.predid, v.clone());
96            event.variables.insert(self.predid, v);
97        }
98        let up = match from[0].update(ctx, event) {
99            Some(Value::Array(a)) if a.len() == self.slots.len() => Some(a),
100            Some(Value::Array(a)) if a.len() < self.slots.len() => {
101                while self.slots.len() > a.len() {
102                    if let Some(mut s) = self.slots.pop() {
103                        s.pred.delete(ctx);
104                        ctx.env.unbind_variable(s.id);
105                    }
106                }
107                Some(a)
108            }
109            Some(Value::Array(a)) => {
110                while self.slots.len() < a.len() {
111                    let (id, node) =
112                        genn::bind(ctx, &self.scope, "x", self.etyp.clone(), self.top_id);
113                    let fargs = vec![node];
114                    let fnode = genn::reference(
115                        ctx,
116                        self.predid,
117                        Type::Fn(self.mftyp.clone()),
118                        self.top_id,
119                    );
120                    let pred = genn::apply(fnode, fargs, self.mftyp.clone(), self.top_id);
121                    self.slots.push(Slot { id, pred, cur: None });
122                }
123                Some(a)
124            }
125            Some(_) | None => None,
126        };
127        if let Some(a) = up {
128            for (s, v) in self.slots.iter().zip(a.iter()) {
129                event.variables.insert(s.id, v.clone());
130            }
131            self.cur = a.clone();
132            if a.len() == 0 {
133                return Some(Value::Array(a));
134            }
135        }
136        let init = event.init;
137        let mut up = false;
138        for (i, s) in self.slots.iter_mut().enumerate() {
139            if i == slen {
140                // new nodes were added starting here
141                event.init = true;
142                if !event.variables.contains_key(&self.predid) {
143                    if let Some(v) = ctx.cached.get(&self.predid) {
144                        event.variables.insert(self.predid, v.clone());
145                    }
146                }
147            }
148            if let Some(v) = s.pred.update(ctx, event) {
149                s.cur = Some(v);
150                up = true;
151            }
152        }
153        event.init = init;
154        if up && self.slots.iter().all(|s| s.cur.is_some()) {
155            self.t.finish(&mut &self.slots, &self.cur)
156        } else {
157            None
158        }
159    }
160
161    fn typecheck(
162        &mut self,
163        ctx: &mut ExecCtx<C, E>,
164        from: &mut [Node<C, E>],
165    ) -> anyhow::Result<()> {
166        for n in from.iter_mut() {
167            n.typecheck(ctx)?;
168        }
169        self.ftyp
170            .args
171            .get(0)
172            .map(|a| a.typ.clone())
173            .ok_or_else(|| anyhow!("expected 2 arguments"))?
174            .check_contains(&ctx.env, &from[0].typ())?;
175        Type::Fn(self.mftyp.clone()).check_contains(&ctx.env, &from[1].typ())?;
176        let (_, node) = genn::bind(ctx, &self.scope, "x", self.etyp.clone(), self.top_id);
177        let fargs = vec![node];
178        let ft = self.mftyp.clone();
179        let fnode = genn::reference(ctx, self.predid, Type::Fn(ft.clone()), self.top_id);
180        let mut node = genn::apply(fnode, fargs, ft, self.top_id);
181        let r = node.typecheck(ctx);
182        node.delete(ctx);
183        r
184    }
185
186    fn refs<'a>(&'a self, f: &'a mut (dyn FnMut(BindId) + 'a)) {
187        for s in &self.slots {
188            s.pred.refs(f)
189        }
190    }
191}
192
193#[derive(Debug, Default)]
194pub(super) struct MapImpl;
195
196impl<C: Ctx, E: UserEvent> MapFn<C, E> for MapImpl {
197    const NAME: &str = "array_map";
198    deftype!("core::array", "fn(Array<'a>, fn('a) -> 'b) -> Array<'b>");
199
200    fn finish(&mut self, slots: &[Slot<C, E>], _: &ValArray) -> Option<Value> {
201        Some(Value::Array(ValArray::from_iter_exact(
202            slots.iter().map(|s| s.cur.clone().unwrap()),
203        )))
204    }
205}
206
207pub(super) type Map<C, E> = MapQ<C, E, MapImpl>;
208
209#[derive(Debug, Default)]
210pub(super) struct FilterImpl;
211
212impl<C: Ctx, E: UserEvent> MapFn<C, E> for FilterImpl {
213    const NAME: &str = "array_filter";
214    deftype!("core::array", "fn(Array<'a>, fn('a) -> bool) -> Array<'a>");
215
216    fn finish(&mut self, slots: &[Slot<C, E>], a: &ValArray) -> Option<Value> {
217        Some(Value::Array(ValArray::from_iter(slots.iter().zip(a.iter()).filter_map(
218            |(p, v)| match p.cur {
219                Some(Value::Bool(true)) => Some(v.clone()),
220                _ => None,
221            },
222        ))))
223    }
224}
225
226pub(super) type Filter<C, E> = MapQ<C, E, FilterImpl>;
227
228#[derive(Debug, Default)]
229pub(super) struct FlatMapImpl;
230
231impl<C: Ctx, E: UserEvent> MapFn<C, E> for FlatMapImpl {
232    const NAME: &str = "array_flat_map";
233    deftype!("core::array", "fn(Array<'a>, fn('a) -> ['b, Array<'b>]) -> Array<'b>");
234
235    fn finish(&mut self, slots: &[Slot<C, E>], _: &ValArray) -> Option<Value> {
236        Some(Value::Array(ValArray::from_iter(slots.iter().flat_map(|s| {
237            match s.cur.as_ref().unwrap() {
238                Value::Array(a) => Either::Left(a.clone().into_iter()),
239                v => Either::Right(iter::once(v.clone())),
240            }
241        }))))
242    }
243}
244
245pub(super) type FlatMap<C, E> = MapQ<C, E, FlatMapImpl>;
246
247#[derive(Debug, Default)]
248pub(super) struct FilterMapImpl;
249
250impl<C: Ctx, E: UserEvent> MapFn<C, E> for FilterMapImpl {
251    const NAME: &str = "array_filter_map";
252    deftype!("core::array", "fn(Array<'a>, fn('a) -> ['b, null]) -> Array<'b>");
253
254    fn finish(&mut self, slots: &[Slot<C, E>], _: &ValArray) -> Option<Value> {
255        Some(Value::Array(ValArray::from_iter(slots.iter().filter_map(|s| {
256            match s.cur.as_ref().unwrap() {
257                Value::Null => None,
258                v => Some(v.clone()),
259            }
260        }))))
261    }
262}
263
264pub(super) type FilterMap<C, E> = MapQ<C, E, FilterMapImpl>;
265
266#[derive(Debug, Default)]
267pub(super) struct FindImpl;
268
269impl<C: Ctx, E: UserEvent> MapFn<C, E> for FindImpl {
270    const NAME: &str = "array_find";
271    deftype!("core::array", "fn(Array<'a>, fn('a) -> bool) -> ['a, null]");
272
273    fn finish(&mut self, slots: &[Slot<C, E>], a: &ValArray) -> Option<Value> {
274        let r = slots
275            .iter()
276            .enumerate()
277            .find(|(_, s)| match s.cur.as_ref() {
278                Some(Value::Bool(true)) => true,
279                _ => false,
280            })
281            .map(|(i, _)| a[i].clone())
282            .unwrap_or(Value::Null);
283        Some(r)
284    }
285}
286
287pub(super) type Find<C, E> = MapQ<C, E, FindImpl>;
288
289#[derive(Debug, Default)]
290pub(super) struct FindMapImpl;
291
292impl<C: Ctx, E: UserEvent> MapFn<C, E> for FindMapImpl {
293    const NAME: &str = "array_find_map";
294    deftype!("core::array", "fn(Array<'a>, fn('a) -> ['b, null]) -> ['b, null]");
295
296    fn finish(&mut self, slots: &[Slot<C, E>], _: &ValArray) -> Option<Value> {
297        let r = slots
298            .iter()
299            .find_map(|s| match s.cur.as_ref().unwrap() {
300                Value::Null => None,
301                v => Some(v.clone()),
302            })
303            .unwrap_or(Value::Null);
304        Some(r)
305    }
306}
307
308pub(super) type FindMap<C, E> = MapQ<C, E, FindMapImpl>;
309
310#[derive(Debug)]
311pub(super) struct Fold<C: Ctx, E: UserEvent> {
312    top_id: ExprId,
313    fid: BindId,
314    initid: BindId,
315    binds: Vec<BindId>,
316    nodes: Vec<Node<C, E>>,
317    inits: Vec<Option<Value>>,
318    mftype: TArc<FnType>,
319    etyp: Type,
320    ityp: Type,
321    init: Option<Value>,
322}
323
324impl<C: Ctx, E: UserEvent> BuiltIn<C, E> for Fold<C, E> {
325    const NAME: &str = "array_fold";
326    deftype!("core::array", "fn(Array<'a>, 'b, fn('b, 'a) -> 'b) -> 'b");
327
328    fn init(_: &mut ExecCtx<C, E>) -> BuiltInInitFn<C, E> {
329        Arc::new(|_ctx, typ, _, from, top_id| match from {
330            [_, _, _] => Ok(Box::new(Self {
331                top_id,
332                binds: vec![],
333                nodes: vec![],
334                inits: vec![],
335                fid: BindId::new(),
336                initid: BindId::new(),
337                etyp: match &typ.args[0].typ {
338                    Type::Array(et) => (**et).clone(),
339                    t => bail!("expected array not {t}"),
340                },
341                ityp: typ.args[1].typ.clone(),
342                mftype: match &typ.args[2].typ {
343                    Type::Fn(ft) => ft.clone(),
344                    t => bail!("expected a function not {t}"),
345                },
346                init: None,
347            })),
348            _ => bail!("expected three arguments"),
349        })
350    }
351}
352
353impl<C: Ctx, E: UserEvent> Apply<C, E> for Fold<C, E> {
354    fn update(
355        &mut self,
356        ctx: &mut ExecCtx<C, E>,
357        from: &mut [Node<C, E>],
358        event: &mut Event<E>,
359    ) -> Option<Value> {
360        let init = match from[0].update(ctx, event) {
361            None => self.nodes.len(),
362            Some(Value::Array(a)) if a.len() == self.binds.len() => {
363                for (id, v) in self.binds.iter().zip(a.iter()) {
364                    event.variables.insert(*id, v.clone());
365                }
366                self.nodes.len()
367            }
368            Some(Value::Array(a)) => {
369                while self.binds.len() < a.len() {
370                    self.binds.push(BindId::new());
371                    self.inits.push(None);
372                }
373                while a.len() < self.binds.len() {
374                    self.binds.pop();
375                    self.inits.pop();
376                    if let Some(mut n) = self.nodes.pop() {
377                        n.delete(ctx);
378                    }
379                }
380                let init = self.nodes.len();
381                for i in 0..self.binds.len() {
382                    event.variables.insert(self.binds[i], a[i].clone());
383                    if i >= self.nodes.len() {
384                        let n = genn::reference(
385                            ctx,
386                            self.initid,
387                            self.ityp.clone(),
388                            self.top_id,
389                        );
390                        let x = genn::reference(
391                            ctx,
392                            self.binds[i],
393                            self.etyp.clone(),
394                            self.top_id,
395                        );
396                        let fnode = genn::reference(
397                            ctx,
398                            self.fid,
399                            Type::Fn(self.mftype.clone()),
400                            self.top_id,
401                        );
402                        let node = genn::apply(
403                            fnode,
404                            vec![n, x],
405                            self.mftype.clone(),
406                            self.top_id,
407                        );
408                        self.nodes.push(node);
409                    }
410                }
411                init
412            }
413            _ => self.nodes.len(),
414        };
415        if let Some(v) = from[1].update(ctx, event) {
416            event.variables.insert(self.initid, v.clone());
417            self.init = Some(v);
418        }
419        if let Some(v) = from[2].update(ctx, event) {
420            ctx.cached.insert(self.fid, v.clone());
421            event.variables.insert(self.fid, v);
422        }
423        let old_init = event.init;
424        for i in 0..self.nodes.len() {
425            if i == init {
426                event.init = true;
427                if let Some(v) = ctx.cached.get(&self.fid) {
428                    if !event.variables.contains_key(&self.fid) {
429                        event.variables.insert(self.fid, v.clone());
430                    }
431                }
432                if i == 0 {
433                    if !event.variables.contains_key(&self.initid) {
434                        if let Some(v) = self.init.as_ref() {
435                            event.variables.insert(self.initid, v.clone());
436                        }
437                    }
438                } else {
439                    if let Some(v) = self.inits[i - 1].clone() {
440                        event.variables.insert(self.initid, v);
441                    }
442                }
443            }
444            match self.nodes[i].update(ctx, event) {
445                Some(v) => {
446                    event.variables.insert(self.initid, v.clone());
447                    self.inits[i] = Some(v);
448                }
449                None => {
450                    event.variables.remove(&self.initid);
451                    self.inits[i] = None;
452                }
453            }
454        }
455        event.init = old_init;
456        self.inits.last().and_then(|v| v.clone())
457    }
458
459    fn typecheck(
460        &mut self,
461        ctx: &mut ExecCtx<C, E>,
462        from: &mut [Node<C, E>],
463    ) -> anyhow::Result<()> {
464        for n in from.iter_mut() {
465            n.typecheck(ctx)?;
466        }
467        Type::Array(triomphe::Arc::new(self.etyp.clone()))
468            .check_contains(&ctx.env, &from[0].typ())?;
469        self.ityp.check_contains(&ctx.env, &from[1].typ())?;
470        Type::Fn(self.mftype.clone()).check_contains(&ctx.env, &from[2].typ())?;
471        let mut n = genn::reference(ctx, self.initid, self.ityp.clone(), self.top_id);
472        let x = genn::reference(ctx, BindId::new(), self.etyp.clone(), self.top_id);
473        let fnode =
474            genn::reference(ctx, self.fid, Type::Fn(self.mftype.clone()), self.top_id);
475        n = genn::apply(fnode, vec![n, x], self.mftype.clone(), self.top_id);
476        let r = n.typecheck(ctx);
477        n.delete(ctx);
478        r
479    }
480
481    fn refs<'a>(&'a self, f: &'a mut (dyn FnMut(BindId) + 'a)) {
482        for n in &self.nodes {
483            n.refs(f)
484        }
485    }
486}
487
488#[derive(Debug, Default)]
489pub(super) struct ConcatEv(SmallVec<[Value; 32]>);
490
491impl EvalCached for ConcatEv {
492    const NAME: &str = "array_concat";
493    deftype!("core::array", "fn(Array<'a>, @args: [Array<'a>, 'a]) -> Array<'a>");
494
495    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
496        let mut present = true;
497        for v in from.0.iter() {
498            match v {
499                Some(Value::Array(a)) => {
500                    for v in a.iter() {
501                        self.0.push(v.clone())
502                    }
503                }
504                Some(v) => self.0.push(v.clone()),
505                None => present = false,
506            }
507        }
508        if present {
509            let a = ValArray::from_iter_exact(self.0.drain(..));
510            Some(Value::Array(a))
511        } else {
512            self.0.clear();
513            None
514        }
515    }
516}
517
518pub(super) type Concat = CachedArgs<ConcatEv>;
519
520#[derive(Debug, Default)]
521pub(super) struct LenEv;
522
523impl EvalCached for LenEv {
524    const NAME: &str = "array_len";
525    deftype!("core::array", "fn(Array<'a>) -> u64");
526
527    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
528        match &from.0[0] {
529            Some(Value::Array(a)) => Some(Value::U64(a.len() as u64)),
530            Some(_) | None => None,
531        }
532    }
533}
534
535pub(super) type Len = CachedArgs<LenEv>;
536
537#[derive(Debug, Default)]
538pub(super) struct FlattenEv(SmallVec<[Value; 32]>);
539
540impl EvalCached for FlattenEv {
541    const NAME: &str = "array_flatten";
542    deftype!("core::array", "fn(Array<Array<'a>>) -> Array<'a>");
543
544    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
545        match &from.0[0] {
546            Some(Value::Array(a)) => {
547                for v in a.iter() {
548                    match v {
549                        Value::Array(a) => self.0.extend(a.iter().map(|v| v.clone())),
550                        v => self.0.push(v.clone()),
551                    }
552                }
553                let a = ValArray::from_iter_exact(self.0.drain(..));
554                Some(Value::Array(a))
555            }
556            Some(_) | None => None,
557        }
558    }
559}
560
561pub(super) type Flatten = CachedArgs<FlattenEv>;
562
563#[derive(Debug, Default)]
564pub(super) struct SortEv(SmallVec<[Value; 32]>);
565
566impl EvalCached for SortEv {
567    const NAME: &str = "array_sort";
568    deftype!("core::array", "fn(Array<'a>) -> Array<'a>");
569
570    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
571        if let Some(Value::Array(a)) = &from.0[0] {
572            self.0.extend(a.iter().cloned());
573            self.0.sort();
574            return Some(Value::Array(ValArray::from_iter_exact(self.0.drain(..))));
575        }
576        None
577    }
578}
579
580pub(super) type Sort = CachedArgs<SortEv>;
581
582#[derive(Debug)]
583pub(super) struct Group<C: Ctx, E: UserEvent> {
584    queue: VecDeque<Value>,
585    buf: SmallVec<[Value; 16]>,
586    pred: Node<C, E>,
587    mftyp: TArc<FnType>,
588    etyp: Type,
589    ready: bool,
590    pid: BindId,
591    nid: BindId,
592    xid: BindId,
593}
594
595impl<C: Ctx, E: UserEvent> BuiltIn<C, E> for Group<C, E> {
596    const NAME: &str = "group";
597    deftype!("core::array", "fn('a, fn(u64, 'a) -> bool) -> Array<'a>");
598
599    fn init(_: &mut ExecCtx<C, E>) -> BuiltInInitFn<C, E> {
600        Arc::new(|ctx, typ, scope, from, top_id| match from {
601            [arg, _] => {
602                let scope = ModPath(
603                    scope.0.append(format_compact!("fn{}", LambdaId::new().0).as_str()),
604                );
605                let n_typ = Type::Primitive(Typ::U64.into());
606                let etyp = arg.typ().clone();
607                let mftyp = match &typ.args[1].typ {
608                    Type::Fn(ft) => ft.clone(),
609                    t => bail!("expected function not {t}"),
610                };
611                let (nid, n) = genn::bind(ctx, &scope, "n", n_typ.clone(), top_id);
612                let (xid, x) = genn::bind(ctx, &scope, "x", etyp.clone(), top_id);
613                let pid = BindId::new();
614                let fnode = genn::reference(ctx, pid, Type::Fn(mftyp.clone()), top_id);
615                let pred = genn::apply(fnode, vec![n, x], mftyp.clone(), top_id);
616                Ok(Box::new(Self {
617                    queue: VecDeque::new(),
618                    buf: smallvec![],
619                    mftyp,
620                    etyp,
621                    pred,
622                    ready: true,
623                    pid,
624                    nid,
625                    xid,
626                }))
627            }
628            _ => bail!("expected two arguments"),
629        })
630    }
631}
632
633impl<C: Ctx, E: UserEvent> Apply<C, E> for Group<C, E> {
634    fn update(
635        &mut self,
636        ctx: &mut ExecCtx<C, E>,
637        from: &mut [Node<C, E>],
638        event: &mut Event<E>,
639    ) -> Option<Value> {
640        macro_rules! set {
641            ($v:expr) => {{
642                self.ready = false;
643                self.buf.push($v.clone());
644                event.variables.insert(self.nid, Value::U64(self.buf.len() as u64));
645                event.variables.insert(self.xid, $v);
646            }};
647        }
648        if let Some(v) = from[0].update(ctx, event) {
649            self.queue.push_back(v);
650        }
651        if let Some(v) = from[1].update(ctx, event) {
652            event.variables.insert(self.pid, v);
653        }
654        if self.ready && self.queue.len() > 0 {
655            let v = self.queue.pop_front().unwrap();
656            set!(v);
657        }
658        loop {
659            match self.pred.update(ctx, event) {
660                None => break None,
661                Some(v) => {
662                    self.ready = true;
663                    match v {
664                        Value::Bool(true) => {
665                            break Some(Value::Array(ValArray::from_iter_exact(
666                                self.buf.drain(..),
667                            )))
668                        }
669                        _ => match self.queue.pop_front() {
670                            None => break None,
671                            Some(v) => set!(v),
672                        },
673                    }
674                }
675            }
676        }
677    }
678
679    fn typecheck(
680        &mut self,
681        ctx: &mut ExecCtx<C, E>,
682        from: &mut [Node<C, E>],
683    ) -> anyhow::Result<()> {
684        for n in from.iter_mut() {
685            n.typecheck(ctx)?
686        }
687        self.etyp.check_contains(&ctx.env, &from[0].typ())?;
688        Type::Fn(self.mftyp.clone()).check_contains(&ctx.env, &from[1].typ())?;
689        self.pred.typecheck(ctx)?;
690        Ok(())
691    }
692}
693
694#[derive(Debug)]
695pub(super) struct Iter(BindId, ExprId);
696
697impl<C: Ctx, E: UserEvent> BuiltIn<C, E> for Iter {
698    const NAME: &str = "iter";
699    deftype!("core::array", "fn(Array<'a>) -> 'a");
700
701    fn init(_: &mut ExecCtx<C, E>) -> BuiltInInitFn<C, E> {
702        Arc::new(|ctx, _, _, _, top_id| {
703            let id = BindId::new();
704            ctx.user.ref_var(id, top_id);
705            Ok(Box::new(Iter(id, top_id)))
706        })
707    }
708}
709
710impl<C: Ctx, E: UserEvent> Apply<C, E> for Iter {
711    fn update(
712        &mut self,
713        ctx: &mut ExecCtx<C, E>,
714        from: &mut [Node<C, E>],
715        event: &mut Event<E>,
716    ) -> Option<Value> {
717        if let Some(Value::Array(a)) = from[0].update(ctx, event) {
718            for v in a.iter() {
719                ctx.user.set_var(self.0, v.clone());
720            }
721        }
722        event.variables.get(&self.0).map(|v| v.clone())
723    }
724
725    fn delete(&mut self, ctx: &mut ExecCtx<C, E>) {
726        ctx.user.unref_var(self.0, self.1)
727    }
728}
729
730#[derive(Debug)]
731pub(super) struct IterQ {
732    triggered: usize,
733    queue: VecDeque<(usize, ValArray)>,
734    id: BindId,
735    top_id: ExprId,
736}
737
738impl<C: Ctx, E: UserEvent> BuiltIn<C, E> for IterQ {
739    const NAME: &str = "iterq";
740    deftype!("core::array", "fn(#trigger:Any, Array<'a>) -> 'a");
741
742    fn init(_: &mut ExecCtx<C, E>) -> BuiltInInitFn<C, E> {
743        Arc::new(|ctx, _, _, _, top_id| {
744            let id = BindId::new();
745            ctx.user.ref_var(id, top_id);
746            Ok(Box::new(IterQ { triggered: 0, queue: VecDeque::new(), id, top_id }))
747        })
748    }
749}
750
751impl<C: Ctx, E: UserEvent> Apply<C, E> for IterQ {
752    fn update(
753        &mut self,
754        ctx: &mut ExecCtx<C, E>,
755        from: &mut [Node<C, E>],
756        event: &mut Event<E>,
757    ) -> Option<Value> {
758        if from[0].update(ctx, event).is_some() {
759            self.triggered += 1;
760        }
761        if let Some(Value::Array(a)) = from[1].update(ctx, event) {
762            if a.len() > 0 {
763                self.queue.push_back((0, a));
764            }
765        }
766        while self.triggered > 0 && self.queue.len() > 0 {
767            let (i, a) = self.queue.front_mut().unwrap();
768            while self.triggered > 0 && *i < a.len() {
769                ctx.user.set_var(self.id, a[*i].clone());
770                *i += 1;
771                self.triggered -= 1;
772            }
773            if *i == a.len() {
774                self.queue.pop_front();
775            }
776        }
777        event.variables.get(&self.id).cloned()
778    }
779
780    fn delete(&mut self, ctx: &mut ExecCtx<C, E>) {
781        ctx.user.unref_var(self.id, self.top_id)
782    }
783}