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