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 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}