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