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