Skip to main content

graphix_package_array/
lib.rs

1#![doc(
2    html_logo_url = "https://graphix-lang.github.io/graphix/graphix-icon.svg",
3    html_favicon_url = "https://graphix-lang.github.io/graphix/graphix-icon.svg"
4)]
5use ahash::AHashSet;
6use anyhow::{bail, Result};
7use compact_str::format_compact;
8use graphix_compiler::{
9    expr::ExprId,
10    node::genn,
11    typ::{FnType, Type},
12    Apply, BindId, BuiltIn, Event, ExecCtx, LambdaId, Node, Refs, Rt, Scope,
13    TypecheckPhase, UserEvent,
14};
15use graphix_package_core::{
16    CachedArgs, CachedVals, EvalCached, FoldFn, FoldQ, MapFn, MapQ, Slot,
17};
18use graphix_rt::GXRt;
19use netidx::{publisher::Typ, subscriber::Value, utils::Either};
20use netidx_value::ValArray;
21use poolshark::local::LPooled;
22use smallvec::{smallvec, SmallVec};
23use std::{collections::hash_map::Entry, collections::VecDeque, fmt::Debug, iter};
24use triomphe::Arc as TArc;
25
26#[derive(Debug, Default)]
27struct MapImpl;
28
29impl<R: Rt, E: UserEvent> MapFn<R, E> for MapImpl {
30    type Collection = ValArray;
31
32    const NAME: &str = "array_map";
33
34    fn finish(&mut self, slots: &[Slot<R, E>], _: &ValArray) -> Option<Value> {
35        Some(Value::Array(ValArray::from_iter_exact(
36            slots.iter().map(|s| s.cur.clone().unwrap()),
37        )))
38    }
39}
40
41type Map<R, E> = MapQ<R, E, MapImpl>;
42
43#[derive(Debug, Default)]
44struct FilterImpl;
45
46impl<R: Rt, E: UserEvent> MapFn<R, E> for FilterImpl {
47    type Collection = ValArray;
48
49    const NAME: &str = "array_filter";
50
51    fn finish(&mut self, slots: &[Slot<R, E>], a: &ValArray) -> Option<Value> {
52        Some(Value::Array(ValArray::from_iter(slots.iter().zip(a.iter()).filter_map(
53            |(p, v)| match p.cur {
54                Some(Value::Bool(true)) => Some(v.clone()),
55                _ => None,
56            },
57        ))))
58    }
59}
60
61type Filter<R, E> = MapQ<R, E, FilterImpl>;
62
63#[derive(Debug, Default)]
64struct FlatMapImpl;
65
66impl<R: Rt, E: UserEvent> MapFn<R, E> for FlatMapImpl {
67    type Collection = ValArray;
68
69    const NAME: &str = "array_flat_map";
70
71    fn finish(&mut self, slots: &[Slot<R, E>], _: &ValArray) -> Option<Value> {
72        Some(Value::Array(ValArray::from_iter(slots.iter().flat_map(|s| {
73            match s.cur.as_ref().unwrap() {
74                Value::Array(a) => Either::Left(a.clone().into_iter()),
75                v => Either::Right(iter::once(v.clone())),
76            }
77        }))))
78    }
79}
80
81type FlatMap<R, E> = MapQ<R, E, FlatMapImpl>;
82
83#[derive(Debug, Default)]
84struct FilterMapImpl;
85
86impl<R: Rt, E: UserEvent> MapFn<R, E> for FilterMapImpl {
87    type Collection = ValArray;
88
89    const NAME: &str = "array_filter_map";
90
91    fn finish(&mut self, slots: &[Slot<R, E>], _: &ValArray) -> Option<Value> {
92        Some(Value::Array(ValArray::from_iter(slots.iter().filter_map(|s| {
93            match s.cur.as_ref().unwrap() {
94                Value::Null => None,
95                v => Some(v.clone()),
96            }
97        }))))
98    }
99}
100
101type FilterMap<R, E> = MapQ<R, E, FilterMapImpl>;
102
103#[derive(Debug, Default)]
104struct FindImpl;
105
106impl<R: Rt, E: UserEvent> MapFn<R, E> for FindImpl {
107    type Collection = ValArray;
108
109    const NAME: &str = "array_find";
110
111    fn finish(&mut self, slots: &[Slot<R, E>], a: &ValArray) -> Option<Value> {
112        let r = slots
113            .iter()
114            .enumerate()
115            .find(|(_, s)| match s.cur.as_ref() {
116                Some(Value::Bool(true)) => true,
117                _ => false,
118            })
119            .map(|(i, _)| a[i].clone())
120            .unwrap_or(Value::Null);
121        Some(r)
122    }
123}
124
125type Find<R, E> = MapQ<R, E, FindImpl>;
126
127#[derive(Debug, Default)]
128struct FindMapImpl;
129
130impl<R: Rt, E: UserEvent> MapFn<R, E> for FindMapImpl {
131    type Collection = ValArray;
132
133    const NAME: &str = "array_find_map";
134
135    fn finish(&mut self, slots: &[Slot<R, E>], _: &ValArray) -> Option<Value> {
136        let r = slots
137            .iter()
138            .find_map(|s| match s.cur.as_ref().unwrap() {
139                Value::Null => None,
140                v => Some(v.clone()),
141            })
142            .unwrap_or(Value::Null);
143        Some(r)
144    }
145}
146
147type FindMap<R, E> = MapQ<R, E, FindMapImpl>;
148
149#[derive(Debug)]
150struct FoldImpl;
151
152impl<R: Rt, E: UserEvent> FoldFn<R, E> for FoldImpl {
153    type Collection = ValArray;
154
155    const NAME: &str = "array_fold";
156}
157
158type Fold<R, E> = FoldQ<R, E, FoldImpl>;
159
160#[derive(Debug, Default)]
161struct ConcatEv(SmallVec<[Value; 32]>);
162
163impl<R: Rt, E: UserEvent> EvalCached<R, E> for ConcatEv {
164    const NAME: &str = "array_concat";
165    const NEEDS_CALLSITE: bool = false;
166
167    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
168        let mut present = true;
169        for v in from.0.iter() {
170            match v {
171                Some(Value::Array(a)) => {
172                    for v in a.iter() {
173                        self.0.push(v.clone())
174                    }
175                }
176                Some(v) => self.0.push(v.clone()),
177                None => present = false,
178            }
179        }
180        if present {
181            let a = ValArray::from_iter_exact(self.0.drain(..));
182            Some(Value::Array(a))
183        } else {
184            self.0.clear();
185            None
186        }
187    }
188}
189
190type Concat = CachedArgs<ConcatEv>;
191
192#[derive(Debug, Default)]
193struct PushBackEv(SmallVec<[Value; 32]>);
194
195impl<R: Rt, E: UserEvent> EvalCached<R, E> for PushBackEv {
196    const NAME: &str = "array_push_back";
197    const NEEDS_CALLSITE: bool = false;
198
199    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
200        let mut present = true;
201        match &from.0[..] {
202            [Some(Value::Array(a)), tl @ ..] => {
203                self.0.extend(a.iter().map(|v| v.clone()));
204                for v in tl {
205                    match v {
206                        Some(v) => self.0.push(v.clone()),
207                        None => present = false,
208                    }
209                }
210            }
211            [] | [None, ..] | [Some(_), ..] => present = false,
212        }
213        if present {
214            let a = ValArray::from_iter_exact(self.0.drain(..));
215            Some(Value::Array(a))
216        } else {
217            self.0.clear();
218            None
219        }
220    }
221}
222
223type PushBack = CachedArgs<PushBackEv>;
224
225#[derive(Debug, Default)]
226struct PushFrontEv(SmallVec<[Value; 32]>);
227
228impl<R: Rt, E: UserEvent> EvalCached<R, E> for PushFrontEv {
229    const NAME: &str = "array_push_front";
230    const NEEDS_CALLSITE: bool = false;
231
232    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
233        let mut present = true;
234        match &from.0[..] {
235            [Some(Value::Array(a)), tl @ ..] => {
236                for v in tl {
237                    match v {
238                        Some(v) => self.0.push(v.clone()),
239                        None => present = false,
240                    }
241                }
242                self.0.extend(a.iter().map(|v| v.clone()));
243            }
244            [] | [None, ..] | [Some(_), ..] => present = false,
245        }
246        if present {
247            let a = ValArray::from_iter_exact(self.0.drain(..));
248            Some(Value::Array(a))
249        } else {
250            self.0.clear();
251            None
252        }
253    }
254}
255
256type PushFront = CachedArgs<PushFrontEv>;
257
258#[derive(Debug, Default)]
259struct WindowEv(SmallVec<[Value; 32]>);
260
261impl<R: Rt, E: UserEvent> EvalCached<R, E> for WindowEv {
262    const NAME: &str = "array_window";
263    const NEEDS_CALLSITE: bool = false;
264
265    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
266        let mut present = true;
267        match &from.0[..] {
268            [Some(Value::I64(window)), Some(Value::Array(a)), tl @ ..] => {
269                let window = *window as usize;
270                let total = a.len() + tl.len();
271                if total <= window {
272                    self.0.extend(a.iter().cloned());
273                    for v in tl {
274                        match v {
275                            Some(v) => self.0.push(v.clone()),
276                            None => present = false,
277                        }
278                    }
279                } else if a.len() >= (total - window) {
280                    self.0.extend(a[(total - window)..].iter().cloned());
281                    for v in tl {
282                        match v {
283                            Some(v) => self.0.push(v.clone()),
284                            None => present = false,
285                        }
286                    }
287                } else {
288                    for v in &tl[tl.len() - window..] {
289                        match v {
290                            Some(v) => self.0.push(v.clone()),
291                            None => present = false,
292                        }
293                    }
294                }
295            }
296            [] | [_] | [_, None, ..] | [None, _, ..] | [Some(_), Some(_), ..] => {
297                present = false
298            }
299        }
300        if present {
301            let a = ValArray::from_iter_exact(self.0.drain(..));
302            Some(Value::Array(a))
303        } else {
304            self.0.clear();
305            None
306        }
307    }
308}
309
310type Window = CachedArgs<WindowEv>;
311
312#[derive(Debug, Default)]
313struct LenEv;
314
315impl<R: Rt, E: UserEvent> EvalCached<R, E> for LenEv {
316    const NAME: &str = "array_len";
317    const NEEDS_CALLSITE: bool = false;
318
319    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
320        match &from.0[0] {
321            Some(Value::Array(a)) => Some(Value::I64(a.len() as i64)),
322            Some(_) | None => None,
323        }
324    }
325}
326
327type Len = CachedArgs<LenEv>;
328
329#[derive(Debug, Default)]
330struct FlattenEv(SmallVec<[Value; 32]>);
331
332impl<R: Rt, E: UserEvent> EvalCached<R, E> for FlattenEv {
333    const NAME: &str = "array_flatten";
334    const NEEDS_CALLSITE: bool = false;
335
336    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
337        match &from.0[0] {
338            Some(Value::Array(a)) => {
339                for v in a.iter() {
340                    match v {
341                        Value::Array(a) => self.0.extend(a.iter().map(|v| v.clone())),
342                        v => self.0.push(v.clone()),
343                    }
344                }
345                let a = ValArray::from_iter_exact(self.0.drain(..));
346                Some(Value::Array(a))
347            }
348            Some(_) | None => None,
349        }
350    }
351}
352
353type Flatten = CachedArgs<FlattenEv>;
354
355#[derive(Debug, Default)]
356struct SortEv(SmallVec<[Value; 32]>);
357
358impl<R: Rt, E: UserEvent> EvalCached<R, E> for SortEv {
359    const NAME: &str = "array_sort";
360    const NEEDS_CALLSITE: bool = false;
361
362    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
363        fn cn(v: &Value) -> Value {
364            v.clone().cast(Typ::F64).unwrap_or_else(|| v.clone())
365        }
366        match &from.0[..] {
367            [Some(Value::String(dir)), Some(Value::Bool(numeric)), Some(Value::Array(a))] => {
368                match &**dir {
369                    "Ascending" => {
370                        self.0.extend(a.iter().cloned());
371                        if *numeric {
372                            self.0.sort_by(|v0, v1| cn(v0).cmp(&cn(v1)))
373                        } else {
374                            self.0.sort();
375                        }
376                        Some(Value::Array(ValArray::from_iter_exact(self.0.drain(..))))
377                    }
378                    "Descending" => {
379                        self.0.extend(a.iter().cloned());
380                        if *numeric {
381                            self.0.sort_by(|a0, a1| cn(a1).cmp(&cn(a0)))
382                        } else {
383                            self.0.sort_by(|a0, a1| a1.cmp(a0));
384                        }
385                        Some(Value::Array(ValArray::from_iter_exact(self.0.drain(..))))
386                    }
387                    _ => None,
388                }
389            }
390            _ => None,
391        }
392    }
393}
394
395type Sort = CachedArgs<SortEv>;
396
397#[derive(Debug, Default)]
398struct DedupEv(SmallVec<[Value; 32]>);
399
400impl<R: Rt, E: UserEvent> EvalCached<R, E> for DedupEv {
401    const NAME: &str = "array_dedup";
402    const NEEDS_CALLSITE: bool = false;
403
404    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
405        match &from.0[0] {
406            Some(Value::Array(a)) => {
407                let mut seen: LPooled<AHashSet<Value>> = LPooled::take();
408                for v in a.iter() {
409                    if !seen.contains(v) {
410                        seen.insert(v.clone());
411                        self.0.push(v.clone());
412                    }
413                }
414                Some(Value::Array(ValArray::from_iter_exact(self.0.drain(..))))
415            }
416            Some(_) | None => None,
417        }
418    }
419}
420
421type Dedup = CachedArgs<DedupEv>;
422
423#[derive(Debug, Default)]
424struct EnumerateEv;
425
426impl<R: Rt, E: UserEvent> EvalCached<R, E> for EnumerateEv {
427    const NAME: &str = "array_enumerate";
428    const NEEDS_CALLSITE: bool = false;
429
430    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
431        if let Some(Value::Array(a)) = &from.0[0] {
432            let a = ValArray::from_iter_exact(
433                a.iter().enumerate().map(|(i, v)| (i, v.clone()).into()),
434            );
435            return Some(Value::Array(a));
436        }
437        None
438    }
439}
440
441type Enumerate = CachedArgs<EnumerateEv>;
442
443#[derive(Debug, Default)]
444struct ZipEv;
445
446impl<R: Rt, E: UserEvent> EvalCached<R, E> for ZipEv {
447    const NAME: &str = "array_zip";
448    const NEEDS_CALLSITE: bool = false;
449
450    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
451        match &from.0[..] {
452            [Some(Value::Array(a0)), Some(Value::Array(a1))] => {
453                Some(Value::Array(ValArray::from_iter_exact(
454                    a0.iter().cloned().zip(a1.iter().cloned()).map(|p| p.into()),
455                )))
456            }
457            _ => None,
458        }
459    }
460}
461
462type Zip = CachedArgs<ZipEv>;
463
464#[derive(Debug, Default)]
465struct UnzipEv {
466    t0: Vec<Value>,
467    t1: Vec<Value>,
468}
469
470impl<R: Rt, E: UserEvent> EvalCached<R, E> for UnzipEv {
471    const NAME: &str = "array_unzip";
472    const NEEDS_CALLSITE: bool = false;
473
474    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
475        match &from.0[..] {
476            [Some(Value::Array(a))] => {
477                for v in a {
478                    if let Value::Array(a) = v {
479                        match &a[..] {
480                            [v0, v1] => {
481                                self.t0.push(v0.clone());
482                                self.t1.push(v1.clone());
483                            }
484                            _ => (),
485                        }
486                    }
487                }
488                let v0 = Value::Array(ValArray::from_iter_exact(self.t0.drain(..)));
489                let v1 = Value::Array(ValArray::from_iter_exact(self.t1.drain(..)));
490                Some(Value::Array(ValArray::from_iter_exact([v0, v1].into_iter())))
491            }
492            _ => None,
493        }
494    }
495}
496
497type Unzip = CachedArgs<UnzipEv>;
498
499#[derive(Debug)]
500struct Group<R: Rt, E: UserEvent> {
501    queue: VecDeque<Value>,
502    buf: SmallVec<[Value; 16]>,
503    pred: Node<R, E>,
504    ready: bool,
505    pid: BindId,
506    nid: BindId,
507    xid: BindId,
508}
509
510impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Group<R, E> {
511    const NAME: &str = "array_group";
512    const NEEDS_CALLSITE: bool = false;
513
514    fn init<'a, 'b, 'c, 'd>(
515        ctx: &'a mut ExecCtx<R, E>,
516        typ: &'a FnType,
517        resolved: Option<&'d FnType>,
518        scope: &'b graphix_compiler::Scope,
519        from: &'c [Node<R, E>],
520        top_id: ExprId,
521    ) -> Result<Box<dyn Apply<R, E>>> {
522        match from {
523            [_, _] => {
524                let typ = resolved.unwrap_or(typ);
525                let scope =
526                    scope.append(&format_compact!("fn{}", LambdaId::new().inner()));
527                let n_typ = Type::Primitive(Typ::I64.into());
528                let etyp = typ.args[0].typ.clone();
529                let mftyp = match &typ.args[1].typ {
530                    Type::Fn(ft) => ft.clone(),
531                    t => bail!("expected function not {t}"),
532                };
533                let (nid, n) =
534                    genn::bind(ctx, &scope.lexical, "n", n_typ.clone(), top_id);
535                let (xid, x) = genn::bind(ctx, &scope.lexical, "x", etyp.clone(), top_id);
536                let pid = BindId::new();
537                let fnode = genn::reference(ctx, pid, Type::Fn(mftyp.clone()), top_id);
538                let pred = genn::apply(fnode, scope, vec![n, x], &mftyp, top_id);
539                Ok(Box::new(Self {
540                    queue: VecDeque::new(),
541                    buf: smallvec![],
542                    pred,
543                    ready: true,
544                    pid,
545                    nid,
546                    xid,
547                }))
548            }
549            _ => bail!("expected two arguments"),
550        }
551    }
552}
553
554impl<R: Rt, E: UserEvent> Apply<R, E> for Group<R, E> {
555    fn update(
556        &mut self,
557        ctx: &mut ExecCtx<R, E>,
558        from: &mut [Node<R, E>],
559        event: &mut Event<E>,
560    ) -> Option<Value> {
561        macro_rules! set {
562            ($v:expr) => {{
563                self.ready = false;
564                self.buf.push($v.clone());
565                let len = Value::I64(self.buf.len() as i64);
566                ctx.cached.insert(self.nid, len.clone());
567                event.variables.insert(self.nid, len);
568                ctx.cached.insert(self.xid, $v.clone());
569                event.variables.insert(self.xid, $v);
570            }};
571        }
572        if let Some(v) = from[0].update(ctx, event) {
573            self.queue.push_back(v);
574        }
575        if let Some(v) = from[1].update(ctx, event) {
576            ctx.cached.insert(self.pid, v.clone());
577            event.variables.insert(self.pid, v);
578        }
579        if self.ready && self.queue.len() > 0 {
580            let v = self.queue.pop_front().unwrap();
581            set!(v);
582        }
583        loop {
584            match self.pred.update(ctx, event) {
585                None => break None,
586                Some(v) => {
587                    self.ready = true;
588                    match v {
589                        Value::Bool(true) => {
590                            break Some(Value::Array(ValArray::from_iter_exact(
591                                self.buf.drain(..),
592                            )))
593                        }
594                        _ => match self.queue.pop_front() {
595                            None => break None,
596                            Some(v) => set!(v),
597                        },
598                    }
599                }
600            }
601        }
602    }
603
604    fn typecheck(
605        &mut self,
606        ctx: &mut ExecCtx<R, E>,
607        _from: &mut [Node<R, E>],
608        _phase: TypecheckPhase<'_>,
609    ) -> anyhow::Result<()> {
610        self.pred.typecheck(ctx)?;
611        Ok(())
612    }
613
614    fn refs(&self, refs: &mut Refs) {
615        self.pred.refs(refs)
616    }
617
618    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
619        ctx.cached.remove(&self.nid);
620        ctx.cached.remove(&self.pid);
621        ctx.cached.remove(&self.xid);
622        self.pred.delete(ctx);
623    }
624
625    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
626        self.pred.sleep(ctx);
627    }
628}
629
630#[derive(Debug)]
631struct Iter(BindId, ExprId);
632
633impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Iter {
634    const NAME: &str = "array_iter";
635    const NEEDS_CALLSITE: bool = false;
636
637    fn init<'a, 'b, 'c, 'd>(
638        ctx: &'a mut ExecCtx<R, E>,
639        _typ: &'a FnType,
640        _resolved: Option<&'d FnType>,
641        _scope: &'b graphix_compiler::Scope,
642        _from: &'c [Node<R, E>],
643        top_id: ExprId,
644    ) -> Result<Box<dyn Apply<R, E>>> {
645        let id = BindId::new();
646        ctx.rt.ref_var(id, top_id);
647        Ok(Box::new(Iter(id, top_id)))
648    }
649}
650
651impl<R: Rt, E: UserEvent> Apply<R, E> for Iter {
652    fn update(
653        &mut self,
654        ctx: &mut ExecCtx<R, E>,
655        from: &mut [Node<R, E>],
656        event: &mut Event<E>,
657    ) -> Option<Value> {
658        if let Some(Value::Array(a)) = from[0].update(ctx, event) {
659            for v in a.iter() {
660                ctx.rt.set_var(self.0, v.clone());
661            }
662        }
663        event.variables.get(&self.0).map(|v| v.clone())
664    }
665
666    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
667        ctx.rt.unref_var(self.0, self.1)
668    }
669
670    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
671        ctx.rt.unref_var(self.0, self.1);
672        self.0 = BindId::new();
673        ctx.rt.ref_var(self.0, self.1);
674    }
675}
676
677#[derive(Debug)]
678struct IterQ {
679    triggered: usize,
680    queue: VecDeque<(usize, ValArray)>,
681    id: BindId,
682    top_id: ExprId,
683}
684
685impl<R: Rt, E: UserEvent> BuiltIn<R, E> for IterQ {
686    const NAME: &str = "array_iterq";
687    const NEEDS_CALLSITE: bool = false;
688
689    fn init<'a, 'b, 'c, 'd>(
690        ctx: &'a mut ExecCtx<R, E>,
691        _typ: &'a FnType,
692        _resolved: Option<&'d FnType>,
693        _scope: &'b graphix_compiler::Scope,
694        _from: &'c [Node<R, E>],
695        top_id: ExprId,
696    ) -> Result<Box<dyn Apply<R, E>>> {
697        let id = BindId::new();
698        ctx.rt.ref_var(id, top_id);
699        Ok(Box::new(IterQ { triggered: 0, queue: VecDeque::new(), id, top_id }))
700    }
701}
702
703impl<R: Rt, E: UserEvent> Apply<R, E> for IterQ {
704    fn update(
705        &mut self,
706        ctx: &mut ExecCtx<R, E>,
707        from: &mut [Node<R, E>],
708        event: &mut Event<E>,
709    ) -> Option<Value> {
710        if from[0].update(ctx, event).is_some() {
711            self.triggered += 1;
712        }
713        if let Some(Value::Array(a)) = from[1].update(ctx, event) {
714            if a.len() > 0 {
715                self.queue.push_back((0, a));
716            }
717        }
718        while self.triggered > 0 && self.queue.len() > 0 {
719            let (i, a) = self.queue.front_mut().unwrap();
720            while self.triggered > 0 && *i < a.len() {
721                ctx.rt.set_var(self.id, a[*i].clone());
722                *i += 1;
723                self.triggered -= 1;
724            }
725            if *i == a.len() {
726                self.queue.pop_front();
727            }
728        }
729        event.variables.get(&self.id).cloned()
730    }
731
732    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
733        ctx.rt.unref_var(self.id, self.top_id)
734    }
735
736    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
737        ctx.rt.unref_var(self.id, self.top_id);
738        self.id = BindId::new();
739        self.queue.clear();
740        self.triggered = 0;
741    }
742}
743
744#[derive(Debug)]
745struct Init<R: Rt, E: UserEvent> {
746    scope: Scope,
747    fid: BindId,
748    top_id: ExprId,
749    mftyp: TArc<FnType>,
750    slots: Vec<Slot<R, E>>,
751}
752
753impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Init<R, E> {
754    const NAME: &str = "array_init";
755    const NEEDS_CALLSITE: bool = false;
756
757    fn init<'a, 'b, 'c, 'd>(
758        _ctx: &'a mut ExecCtx<R, E>,
759        typ: &'a FnType,
760        resolved: Option<&'c FnType>,
761        scope: &'b Scope,
762        from: &'c [Node<R, E>],
763        top_id: ExprId,
764    ) -> Result<Box<dyn Apply<R, E>>> {
765        match from {
766            [_, _] => {
767                let typ = resolved.unwrap_or(typ);
768                Ok(Box::new(Self {
769                    scope: scope
770                        .append(&format_compact!("fn{}", LambdaId::new().inner())),
771                    fid: BindId::new(),
772                    top_id,
773                    mftyp: match &typ.args[1].typ {
774                        Type::Fn(ft) => ft.clone(),
775                        t => bail!("expected a function not {t}"),
776                    },
777                    slots: vec![],
778                }))
779            }
780            _ => bail!("expected two arguments"),
781        }
782    }
783}
784
785impl<R: Rt, E: UserEvent> Apply<R, E> for Init<R, E> {
786    fn update(
787        &mut self,
788        ctx: &mut ExecCtx<R, E>,
789        from: &mut [Node<R, E>],
790        event: &mut Event<E>,
791    ) -> Option<Value> {
792        let slen = self.slots.len();
793        if let Some(v) = from[1].update(ctx, event) {
794            ctx.cached.insert(self.fid, v.clone());
795            event.variables.insert(self.fid, v);
796        }
797        let (size_fired, resized) = match from[0].update(ctx, event) {
798            Some(Value::I64(n)) => {
799                let n = n.max(0) as usize;
800                if n == slen {
801                    (true, false)
802                } else if n < slen {
803                    while self.slots.len() > n {
804                        if let Some(mut s) = self.slots.pop() {
805                            s.delete(ctx)
806                        }
807                    }
808                    (true, true)
809                } else {
810                    let i_typ = Type::Primitive(Typ::I64.into());
811                    while self.slots.len() < n {
812                        let i = self.slots.len();
813                        let (id, node) = genn::bind(
814                            ctx,
815                            &self.scope.lexical,
816                            "i",
817                            i_typ.clone(),
818                            self.top_id,
819                        );
820                        ctx.cached.insert(id, Value::I64(i as i64));
821                        let fnode = genn::reference(
822                            ctx,
823                            self.fid,
824                            Type::Fn(self.mftyp.clone()),
825                            self.top_id,
826                        );
827                        let pred = genn::apply(
828                            fnode,
829                            self.scope.clone(),
830                            vec![node],
831                            &self.mftyp,
832                            self.top_id,
833                        );
834                        self.slots.push(Slot { id, pred, cur: None });
835                    }
836                    (true, true)
837                }
838            }
839            _ => (false, false),
840        };
841        // set index bindings for new slots
842        if resized && self.slots.len() > slen {
843            for i in slen..self.slots.len() {
844                let id = self.slots[i].id;
845                event.variables.insert(id, Value::I64(i as i64));
846            }
847        }
848        if size_fired && self.slots.is_empty() {
849            return Some(Value::Array(ValArray::default()));
850        }
851        let init = event.init;
852        let mut up = resized;
853        for (i, s) in self.slots.iter_mut().enumerate() {
854            if i == slen {
855                event.init = true;
856                if let Entry::Vacant(e) = event.variables.entry(self.fid)
857                    && let Some(v) = ctx.cached.get(&self.fid)
858                {
859                    e.insert(v.clone());
860                }
861            }
862            if let Some(v) = s.pred.update(ctx, event) {
863                s.cur = Some(v);
864                up = true;
865            }
866        }
867        event.init = init;
868        if up && self.slots.iter().all(|s| s.cur.is_some()) {
869            Some(Value::Array(ValArray::from_iter_exact(
870                self.slots.iter().map(|s| s.cur.clone().unwrap()),
871            )))
872        } else {
873            None
874        }
875    }
876
877    fn typecheck(
878        &mut self,
879        ctx: &mut ExecCtx<R, E>,
880        _from: &mut [Node<R, E>],
881        _phase: TypecheckPhase<'_>,
882    ) -> anyhow::Result<()> {
883        let i_typ = Type::Primitive(Typ::I64.into());
884        let (_, node) = genn::bind(ctx, &self.scope.lexical, "i", i_typ, self.top_id);
885        let ft = self.mftyp.clone();
886        let fnode = genn::reference(ctx, self.fid, Type::Fn(ft.clone()), self.top_id);
887        let mut node =
888            genn::apply(fnode, self.scope.clone(), vec![node], &ft, self.top_id);
889        let r = node.typecheck(ctx);
890        node.delete(ctx);
891        r?;
892        Ok(())
893    }
894
895    fn refs(&self, refs: &mut Refs) {
896        for s in &self.slots {
897            s.pred.refs(refs)
898        }
899    }
900
901    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
902        ctx.cached.remove(&self.fid);
903        for sl in &mut self.slots {
904            sl.delete(ctx)
905        }
906    }
907
908    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
909        for sl in &mut self.slots {
910            sl.cur = None;
911            sl.pred.sleep(ctx);
912        }
913    }
914}
915
916graphix_derive::defpackage! {
917    builtins => [
918        Concat,
919        Dedup,
920        Filter as Filter<GXRt<X>, X::UserEvent>,
921        FilterMap as FilterMap<GXRt<X>, X::UserEvent>,
922        Find as Find<GXRt<X>, X::UserEvent>,
923        FindMap as FindMap<GXRt<X>, X::UserEvent>,
924        FlatMap as FlatMap<GXRt<X>, X::UserEvent>,
925        Enumerate,
926        Zip,
927        Unzip,
928        Flatten,
929        Fold as Fold<GXRt<X>, X::UserEvent>,
930        Group as Group<GXRt<X>, X::UserEvent>,
931        Init as Init<GXRt<X>, X::UserEvent>,
932        Iter,
933        IterQ,
934        Len,
935        Map as Map<GXRt<X>, X::UserEvent>,
936        PushBack,
937        PushFront,
938        Sort,
939        Window,
940    ],
941}