1use crate::{
2 deftype,
3 expr::{ExprId, ModPath},
4 node::genn,
5 stdfn::{CachedArgs, CachedVals, EvalCached},
6 typ::{FnType, Type},
7 Apply, BindId, BuiltIn, BuiltInInitFn, Ctx, Event, ExecCtx, LambdaId, Node,
8 UserEvent,
9};
10use anyhow::{anyhow, bail};
11use compact_str::format_compact;
12use netidx::{publisher::Typ, subscriber::Value, utils::Either};
13use netidx_netproto::valarray::ValArray;
14use smallvec::{smallvec, SmallVec};
15use std::{
16 collections::VecDeque,
17 fmt::Debug,
18 iter,
19 sync::{Arc, LazyLock},
20};
21use triomphe::Arc as TArc;
22
23pub trait MapFn<C: Ctx, E: UserEvent>: Debug + Default + Send + Sync + 'static {
24 const NAME: &str;
25 const TYP: LazyLock<FnType>;
26
27 fn finish(&mut self, slots: &[Slot<C, E>], a: &ValArray) -> Option<Value>;
33}
34
35#[derive(Debug)]
36pub struct Slot<C: Ctx, E: UserEvent> {
37 id: BindId,
38 pred: Node<C, E>,
39 pub cur: Option<Value>,
40}
41
42#[derive(Debug)]
43pub struct MapQ<C: Ctx, E: UserEvent, T: MapFn<C, E>> {
44 scope: ModPath,
45 predid: BindId,
46 top_id: ExprId,
47 ftyp: TArc<FnType>,
48 mftyp: TArc<FnType>,
49 etyp: Type,
50 slots: Vec<Slot<C, E>>,
51 cur: ValArray,
52 t: T,
53}
54
55impl<C: Ctx, E: UserEvent, T: MapFn<C, E>> BuiltIn<C, E> for MapQ<C, E, T> {
56 const NAME: &str = T::NAME;
57 const TYP: LazyLock<FnType> = T::TYP;
58
59 fn init(_: &mut ExecCtx<C, E>) -> BuiltInInitFn<C, E> {
60 Arc::new(|_ctx, typ, scope, from, top_id| match from {
61 [_, _] => Ok(Box::new(Self {
62 scope: ModPath(
63 scope.0.append(format_compact!("fn{}", LambdaId::new().0).as_str()),
64 ),
65 predid: BindId::new(),
66 top_id,
67 ftyp: TArc::new(typ.clone()),
68
69 etyp: match &typ.args[0].typ {
70 Type::Array(et) => (**et).clone(),
71 t => bail!("expected array not {t}"),
72 },
73 mftyp: match &typ.args[1].typ {
74 Type::Fn(ft) => ft.clone(),
75 t => bail!("expected a function not {t}"),
76 },
77 slots: vec![],
78 cur: ValArray::from([]),
79 t: T::default(),
80 })),
81 _ => bail!("expected two arguments"),
82 })
83 }
84}
85
86impl<C: Ctx, E: UserEvent, T: MapFn<C, E>> Apply<C, E> for MapQ<C, E, T> {
87 fn update(
88 &mut self,
89 ctx: &mut ExecCtx<C, E>,
90 from: &mut [Node<C, E>],
91 event: &mut Event<E>,
92 ) -> Option<Value> {
93 let slen = self.slots.len();
94 if let Some(v) = from[1].update(ctx, event) {
95 ctx.cached.insert(self.predid, v.clone());
96 event.variables.insert(self.predid, v);
97 }
98 let up = match from[0].update(ctx, event) {
99 Some(Value::Array(a)) if a.len() == self.slots.len() => Some(a),
100 Some(Value::Array(a)) if a.len() < self.slots.len() => {
101 while self.slots.len() > a.len() {
102 if let Some(mut s) = self.slots.pop() {
103 s.pred.delete(ctx);
104 ctx.env.unbind_variable(s.id);
105 }
106 }
107 Some(a)
108 }
109 Some(Value::Array(a)) => {
110 while self.slots.len() < a.len() {
111 let (id, node) =
112 genn::bind(ctx, &self.scope, "x", self.etyp.clone(), self.top_id);
113 let fargs = vec![node];
114 let fnode = genn::reference(
115 ctx,
116 self.predid,
117 Type::Fn(self.mftyp.clone()),
118 self.top_id,
119 );
120 let pred = genn::apply(fnode, fargs, self.mftyp.clone(), self.top_id);
121 self.slots.push(Slot { id, pred, cur: None });
122 }
123 Some(a)
124 }
125 Some(_) | None => None,
126 };
127 if let Some(a) = up {
128 for (s, v) in self.slots.iter().zip(a.iter()) {
129 event.variables.insert(s.id, v.clone());
130 }
131 self.cur = a.clone();
132 if a.len() == 0 {
133 return Some(Value::Array(a));
134 }
135 }
136 let init = event.init;
137 let mut up = false;
138 for (i, s) in self.slots.iter_mut().enumerate() {
139 if i == slen {
140 event.init = true;
142 if !event.variables.contains_key(&self.predid) {
143 if let Some(v) = ctx.cached.get(&self.predid) {
144 event.variables.insert(self.predid, v.clone());
145 }
146 }
147 }
148 if let Some(v) = s.pred.update(ctx, event) {
149 s.cur = Some(v);
150 up = true;
151 }
152 }
153 event.init = init;
154 if up && self.slots.iter().all(|s| s.cur.is_some()) {
155 self.t.finish(&mut &self.slots, &self.cur)
156 } else {
157 None
158 }
159 }
160
161 fn typecheck(
162 &mut self,
163 ctx: &mut ExecCtx<C, E>,
164 from: &mut [Node<C, E>],
165 ) -> anyhow::Result<()> {
166 for n in from.iter_mut() {
167 n.typecheck(ctx)?;
168 }
169 self.ftyp
170 .args
171 .get(0)
172 .map(|a| a.typ.clone())
173 .ok_or_else(|| anyhow!("expected 2 arguments"))?
174 .check_contains(&ctx.env, &from[0].typ())?;
175 Type::Fn(self.mftyp.clone()).check_contains(&ctx.env, &from[1].typ())?;
176 let (_, node) = genn::bind(ctx, &self.scope, "x", self.etyp.clone(), self.top_id);
177 let fargs = vec![node];
178 let ft = self.mftyp.clone();
179 let fnode = genn::reference(ctx, self.predid, Type::Fn(ft.clone()), self.top_id);
180 let mut node = genn::apply(fnode, fargs, ft, self.top_id);
181 let r = node.typecheck(ctx);
182 node.delete(ctx);
183 r
184 }
185
186 fn refs<'a>(&'a self, f: &'a mut (dyn FnMut(BindId) + 'a)) {
187 for s in &self.slots {
188 s.pred.refs(f)
189 }
190 }
191}
192
193#[derive(Debug, Default)]
194pub(super) struct MapImpl;
195
196impl<C: Ctx, E: UserEvent> MapFn<C, E> for MapImpl {
197 const NAME: &str = "array_map";
198 deftype!("core::array", "fn(Array<'a>, fn('a) -> 'b) -> Array<'b>");
199
200 fn finish(&mut self, slots: &[Slot<C, E>], _: &ValArray) -> Option<Value> {
201 Some(Value::Array(ValArray::from_iter_exact(
202 slots.iter().map(|s| s.cur.clone().unwrap()),
203 )))
204 }
205}
206
207pub(super) type Map<C, E> = MapQ<C, E, MapImpl>;
208
209#[derive(Debug, Default)]
210pub(super) struct FilterImpl;
211
212impl<C: Ctx, E: UserEvent> MapFn<C, E> for FilterImpl {
213 const NAME: &str = "array_filter";
214 deftype!("core::array", "fn(Array<'a>, fn('a) -> bool) -> Array<'a>");
215
216 fn finish(&mut self, slots: &[Slot<C, E>], a: &ValArray) -> Option<Value> {
217 Some(Value::Array(ValArray::from_iter(slots.iter().zip(a.iter()).filter_map(
218 |(p, v)| match p.cur {
219 Some(Value::Bool(true)) => Some(v.clone()),
220 _ => None,
221 },
222 ))))
223 }
224}
225
226pub(super) type Filter<C, E> = MapQ<C, E, FilterImpl>;
227
228#[derive(Debug, Default)]
229pub(super) struct FlatMapImpl;
230
231impl<C: Ctx, E: UserEvent> MapFn<C, E> for FlatMapImpl {
232 const NAME: &str = "array_flat_map";
233 deftype!("core::array", "fn(Array<'a>, fn('a) -> ['b, Array<'b>]) -> Array<'b>");
234
235 fn finish(&mut self, slots: &[Slot<C, E>], _: &ValArray) -> Option<Value> {
236 Some(Value::Array(ValArray::from_iter(slots.iter().flat_map(|s| {
237 match s.cur.as_ref().unwrap() {
238 Value::Array(a) => Either::Left(a.clone().into_iter()),
239 v => Either::Right(iter::once(v.clone())),
240 }
241 }))))
242 }
243}
244
245pub(super) type FlatMap<C, E> = MapQ<C, E, FlatMapImpl>;
246
247#[derive(Debug, Default)]
248pub(super) struct FilterMapImpl;
249
250impl<C: Ctx, E: UserEvent> MapFn<C, E> for FilterMapImpl {
251 const NAME: &str = "array_filter_map";
252 deftype!("core::array", "fn(Array<'a>, fn('a) -> ['b, null]) -> Array<'b>");
253
254 fn finish(&mut self, slots: &[Slot<C, E>], _: &ValArray) -> Option<Value> {
255 Some(Value::Array(ValArray::from_iter(slots.iter().filter_map(|s| {
256 match s.cur.as_ref().unwrap() {
257 Value::Null => None,
258 v => Some(v.clone()),
259 }
260 }))))
261 }
262}
263
264pub(super) type FilterMap<C, E> = MapQ<C, E, FilterMapImpl>;
265
266#[derive(Debug, Default)]
267pub(super) struct FindImpl;
268
269impl<C: Ctx, E: UserEvent> MapFn<C, E> for FindImpl {
270 const NAME: &str = "array_find";
271 deftype!("core::array", "fn(Array<'a>, fn('a) -> bool) -> ['a, null]");
272
273 fn finish(&mut self, slots: &[Slot<C, E>], a: &ValArray) -> Option<Value> {
274 let r = slots
275 .iter()
276 .enumerate()
277 .find(|(_, s)| match s.cur.as_ref() {
278 Some(Value::Bool(true)) => true,
279 _ => false,
280 })
281 .map(|(i, _)| a[i].clone())
282 .unwrap_or(Value::Null);
283 Some(r)
284 }
285}
286
287pub(super) type Find<C, E> = MapQ<C, E, FindImpl>;
288
289#[derive(Debug, Default)]
290pub(super) struct FindMapImpl;
291
292impl<C: Ctx, E: UserEvent> MapFn<C, E> for FindMapImpl {
293 const NAME: &str = "array_find_map";
294 deftype!("core::array", "fn(Array<'a>, fn('a) -> ['b, null]) -> ['b, null]");
295
296 fn finish(&mut self, slots: &[Slot<C, E>], _: &ValArray) -> Option<Value> {
297 let r = slots
298 .iter()
299 .find_map(|s| match s.cur.as_ref().unwrap() {
300 Value::Null => None,
301 v => Some(v.clone()),
302 })
303 .unwrap_or(Value::Null);
304 Some(r)
305 }
306}
307
308pub(super) type FindMap<C, E> = MapQ<C, E, FindMapImpl>;
309
310#[derive(Debug)]
311pub(super) struct Fold<C: Ctx, E: UserEvent> {
312 top_id: ExprId,
313 fid: BindId,
314 initid: BindId,
315 binds: Vec<BindId>,
316 nodes: Vec<Node<C, E>>,
317 inits: Vec<Option<Value>>,
318 mftype: TArc<FnType>,
319 etyp: Type,
320 ityp: Type,
321 init: Option<Value>,
322}
323
324impl<C: Ctx, E: UserEvent> BuiltIn<C, E> for Fold<C, E> {
325 const NAME: &str = "array_fold";
326 deftype!("core::array", "fn(Array<'a>, 'b, fn('b, 'a) -> 'b) -> 'b");
327
328 fn init(_: &mut ExecCtx<C, E>) -> BuiltInInitFn<C, E> {
329 Arc::new(|_ctx, typ, _, from, top_id| match from {
330 [_, _, _] => Ok(Box::new(Self {
331 top_id,
332 binds: vec![],
333 nodes: vec![],
334 inits: vec![],
335 fid: BindId::new(),
336 initid: BindId::new(),
337 etyp: match &typ.args[0].typ {
338 Type::Array(et) => (**et).clone(),
339 t => bail!("expected array not {t}"),
340 },
341 ityp: typ.args[1].typ.clone(),
342 mftype: match &typ.args[2].typ {
343 Type::Fn(ft) => ft.clone(),
344 t => bail!("expected a function not {t}"),
345 },
346 init: None,
347 })),
348 _ => bail!("expected three arguments"),
349 })
350 }
351}
352
353impl<C: Ctx, E: UserEvent> Apply<C, E> for Fold<C, E> {
354 fn update(
355 &mut self,
356 ctx: &mut ExecCtx<C, E>,
357 from: &mut [Node<C, E>],
358 event: &mut Event<E>,
359 ) -> Option<Value> {
360 let init = match from[0].update(ctx, event) {
361 None => self.nodes.len(),
362 Some(Value::Array(a)) if a.len() == self.binds.len() => {
363 for (id, v) in self.binds.iter().zip(a.iter()) {
364 event.variables.insert(*id, v.clone());
365 }
366 self.nodes.len()
367 }
368 Some(Value::Array(a)) => {
369 while self.binds.len() < a.len() {
370 self.binds.push(BindId::new());
371 self.inits.push(None);
372 }
373 while a.len() < self.binds.len() {
374 self.binds.pop();
375 self.inits.pop();
376 if let Some(mut n) = self.nodes.pop() {
377 n.delete(ctx);
378 }
379 }
380 let init = self.nodes.len();
381 for i in 0..self.binds.len() {
382 event.variables.insert(self.binds[i], a[i].clone());
383 if i >= self.nodes.len() {
384 let n = genn::reference(
385 ctx,
386 self.initid,
387 self.ityp.clone(),
388 self.top_id,
389 );
390 let x = genn::reference(
391 ctx,
392 self.binds[i],
393 self.etyp.clone(),
394 self.top_id,
395 );
396 let fnode = genn::reference(
397 ctx,
398 self.fid,
399 Type::Fn(self.mftype.clone()),
400 self.top_id,
401 );
402 let node = genn::apply(
403 fnode,
404 vec![n, x],
405 self.mftype.clone(),
406 self.top_id,
407 );
408 self.nodes.push(node);
409 }
410 }
411 init
412 }
413 _ => self.nodes.len(),
414 };
415 if let Some(v) = from[1].update(ctx, event) {
416 event.variables.insert(self.initid, v.clone());
417 self.init = Some(v);
418 }
419 if let Some(v) = from[2].update(ctx, event) {
420 ctx.cached.insert(self.fid, v.clone());
421 event.variables.insert(self.fid, v);
422 }
423 let old_init = event.init;
424 for i in 0..self.nodes.len() {
425 if i == init {
426 event.init = true;
427 if let Some(v) = ctx.cached.get(&self.fid) {
428 if !event.variables.contains_key(&self.fid) {
429 event.variables.insert(self.fid, v.clone());
430 }
431 }
432 if i == 0 {
433 if !event.variables.contains_key(&self.initid) {
434 if let Some(v) = self.init.as_ref() {
435 event.variables.insert(self.initid, v.clone());
436 }
437 }
438 } else {
439 if let Some(v) = self.inits[i - 1].clone() {
440 event.variables.insert(self.initid, v);
441 }
442 }
443 }
444 match self.nodes[i].update(ctx, event) {
445 Some(v) => {
446 event.variables.insert(self.initid, v.clone());
447 self.inits[i] = Some(v);
448 }
449 None => {
450 event.variables.remove(&self.initid);
451 self.inits[i] = None;
452 }
453 }
454 }
455 event.init = old_init;
456 self.inits.last().and_then(|v| v.clone())
457 }
458
459 fn typecheck(
460 &mut self,
461 ctx: &mut ExecCtx<C, E>,
462 from: &mut [Node<C, E>],
463 ) -> anyhow::Result<()> {
464 for n in from.iter_mut() {
465 n.typecheck(ctx)?;
466 }
467 Type::Array(triomphe::Arc::new(self.etyp.clone()))
468 .check_contains(&ctx.env, &from[0].typ())?;
469 self.ityp.check_contains(&ctx.env, &from[1].typ())?;
470 Type::Fn(self.mftype.clone()).check_contains(&ctx.env, &from[2].typ())?;
471 let mut n = genn::reference(ctx, self.initid, self.ityp.clone(), self.top_id);
472 let x = genn::reference(ctx, BindId::new(), self.etyp.clone(), self.top_id);
473 let fnode =
474 genn::reference(ctx, self.fid, Type::Fn(self.mftype.clone()), self.top_id);
475 n = genn::apply(fnode, vec![n, x], self.mftype.clone(), self.top_id);
476 let r = n.typecheck(ctx);
477 n.delete(ctx);
478 r
479 }
480
481 fn refs<'a>(&'a self, f: &'a mut (dyn FnMut(BindId) + 'a)) {
482 for n in &self.nodes {
483 n.refs(f)
484 }
485 }
486}
487
488#[derive(Debug, Default)]
489pub(super) struct ConcatEv(SmallVec<[Value; 32]>);
490
491impl EvalCached for ConcatEv {
492 const NAME: &str = "array_concat";
493 deftype!("core::array", "fn(Array<'a>, @args: [Array<'a>, 'a]) -> Array<'a>");
494
495 fn eval(&mut self, from: &CachedVals) -> Option<Value> {
496 let mut present = true;
497 for v in from.0.iter() {
498 match v {
499 Some(Value::Array(a)) => {
500 for v in a.iter() {
501 self.0.push(v.clone())
502 }
503 }
504 Some(v) => self.0.push(v.clone()),
505 None => present = false,
506 }
507 }
508 if present {
509 let a = ValArray::from_iter_exact(self.0.drain(..));
510 Some(Value::Array(a))
511 } else {
512 self.0.clear();
513 None
514 }
515 }
516}
517
518pub(super) type Concat = CachedArgs<ConcatEv>;
519
520#[derive(Debug, Default)]
521pub(super) struct LenEv;
522
523impl EvalCached for LenEv {
524 const NAME: &str = "array_len";
525 deftype!("core::array", "fn(Array<'a>) -> u64");
526
527 fn eval(&mut self, from: &CachedVals) -> Option<Value> {
528 match &from.0[0] {
529 Some(Value::Array(a)) => Some(Value::U64(a.len() as u64)),
530 Some(_) | None => None,
531 }
532 }
533}
534
535pub(super) type Len = CachedArgs<LenEv>;
536
537#[derive(Debug, Default)]
538pub(super) struct FlattenEv(SmallVec<[Value; 32]>);
539
540impl EvalCached for FlattenEv {
541 const NAME: &str = "array_flatten";
542 deftype!("core::array", "fn(Array<Array<'a>>) -> Array<'a>");
543
544 fn eval(&mut self, from: &CachedVals) -> Option<Value> {
545 match &from.0[0] {
546 Some(Value::Array(a)) => {
547 for v in a.iter() {
548 match v {
549 Value::Array(a) => self.0.extend(a.iter().map(|v| v.clone())),
550 v => self.0.push(v.clone()),
551 }
552 }
553 let a = ValArray::from_iter_exact(self.0.drain(..));
554 Some(Value::Array(a))
555 }
556 Some(_) | None => None,
557 }
558 }
559}
560
561pub(super) type Flatten = CachedArgs<FlattenEv>;
562
563#[derive(Debug, Default)]
564pub(super) struct SortEv(SmallVec<[Value; 32]>);
565
566impl EvalCached for SortEv {
567 const NAME: &str = "array_sort";
568 deftype!("core::array", "fn(Array<'a>) -> Array<'a>");
569
570 fn eval(&mut self, from: &CachedVals) -> Option<Value> {
571 if let Some(Value::Array(a)) = &from.0[0] {
572 self.0.extend(a.iter().cloned());
573 self.0.sort();
574 return Some(Value::Array(ValArray::from_iter_exact(self.0.drain(..))));
575 }
576 None
577 }
578}
579
580pub(super) type Sort = CachedArgs<SortEv>;
581
582#[derive(Debug)]
583pub(super) struct Group<C: Ctx, E: UserEvent> {
584 queue: VecDeque<Value>,
585 buf: SmallVec<[Value; 16]>,
586 pred: Node<C, E>,
587 mftyp: TArc<FnType>,
588 etyp: Type,
589 ready: bool,
590 pid: BindId,
591 nid: BindId,
592 xid: BindId,
593}
594
595impl<C: Ctx, E: UserEvent> BuiltIn<C, E> for Group<C, E> {
596 const NAME: &str = "group";
597 deftype!("core::array", "fn('a, fn(u64, 'a) -> bool) -> Array<'a>");
598
599 fn init(_: &mut ExecCtx<C, E>) -> BuiltInInitFn<C, E> {
600 Arc::new(|ctx, typ, scope, from, top_id| match from {
601 [arg, _] => {
602 let scope = ModPath(
603 scope.0.append(format_compact!("fn{}", LambdaId::new().0).as_str()),
604 );
605 let n_typ = Type::Primitive(Typ::U64.into());
606 let etyp = arg.typ().clone();
607 let mftyp = match &typ.args[1].typ {
608 Type::Fn(ft) => ft.clone(),
609 t => bail!("expected function not {t}"),
610 };
611 let (nid, n) = genn::bind(ctx, &scope, "n", n_typ.clone(), top_id);
612 let (xid, x) = genn::bind(ctx, &scope, "x", etyp.clone(), top_id);
613 let pid = BindId::new();
614 let fnode = genn::reference(ctx, pid, Type::Fn(mftyp.clone()), top_id);
615 let pred = genn::apply(fnode, vec![n, x], mftyp.clone(), top_id);
616 Ok(Box::new(Self {
617 queue: VecDeque::new(),
618 buf: smallvec![],
619 mftyp,
620 etyp,
621 pred,
622 ready: true,
623 pid,
624 nid,
625 xid,
626 }))
627 }
628 _ => bail!("expected two arguments"),
629 })
630 }
631}
632
633impl<C: Ctx, E: UserEvent> Apply<C, E> for Group<C, E> {
634 fn update(
635 &mut self,
636 ctx: &mut ExecCtx<C, E>,
637 from: &mut [Node<C, E>],
638 event: &mut Event<E>,
639 ) -> Option<Value> {
640 macro_rules! set {
641 ($v:expr) => {{
642 self.ready = false;
643 self.buf.push($v.clone());
644 event.variables.insert(self.nid, Value::U64(self.buf.len() as u64));
645 event.variables.insert(self.xid, $v);
646 }};
647 }
648 if let Some(v) = from[0].update(ctx, event) {
649 self.queue.push_back(v);
650 }
651 if let Some(v) = from[1].update(ctx, event) {
652 event.variables.insert(self.pid, v);
653 }
654 if self.ready && self.queue.len() > 0 {
655 let v = self.queue.pop_front().unwrap();
656 set!(v);
657 }
658 loop {
659 match self.pred.update(ctx, event) {
660 None => break None,
661 Some(v) => {
662 self.ready = true;
663 match v {
664 Value::Bool(true) => {
665 break Some(Value::Array(ValArray::from_iter_exact(
666 self.buf.drain(..),
667 )))
668 }
669 _ => match self.queue.pop_front() {
670 None => break None,
671 Some(v) => set!(v),
672 },
673 }
674 }
675 }
676 }
677 }
678
679 fn typecheck(
680 &mut self,
681 ctx: &mut ExecCtx<C, E>,
682 from: &mut [Node<C, E>],
683 ) -> anyhow::Result<()> {
684 for n in from.iter_mut() {
685 n.typecheck(ctx)?
686 }
687 self.etyp.check_contains(&ctx.env, &from[0].typ())?;
688 Type::Fn(self.mftyp.clone()).check_contains(&ctx.env, &from[1].typ())?;
689 self.pred.typecheck(ctx)?;
690 Ok(())
691 }
692}
693
694#[derive(Debug)]
695pub(super) struct Iter(BindId, ExprId);
696
697impl<C: Ctx, E: UserEvent> BuiltIn<C, E> for Iter {
698 const NAME: &str = "iter";
699 deftype!("core::array", "fn(Array<'a>) -> 'a");
700
701 fn init(_: &mut ExecCtx<C, E>) -> BuiltInInitFn<C, E> {
702 Arc::new(|ctx, _, _, _, top_id| {
703 let id = BindId::new();
704 ctx.user.ref_var(id, top_id);
705 Ok(Box::new(Iter(id, top_id)))
706 })
707 }
708}
709
710impl<C: Ctx, E: UserEvent> Apply<C, E> for Iter {
711 fn update(
712 &mut self,
713 ctx: &mut ExecCtx<C, E>,
714 from: &mut [Node<C, E>],
715 event: &mut Event<E>,
716 ) -> Option<Value> {
717 if let Some(Value::Array(a)) = from[0].update(ctx, event) {
718 for v in a.iter() {
719 ctx.user.set_var(self.0, v.clone());
720 }
721 }
722 event.variables.get(&self.0).map(|v| v.clone())
723 }
724
725 fn delete(&mut self, ctx: &mut ExecCtx<C, E>) {
726 ctx.user.unref_var(self.0, self.1)
727 }
728}
729
730#[derive(Debug)]
731pub(super) struct IterQ {
732 triggered: usize,
733 queue: VecDeque<(usize, ValArray)>,
734 id: BindId,
735 top_id: ExprId,
736}
737
738impl<C: Ctx, E: UserEvent> BuiltIn<C, E> for IterQ {
739 const NAME: &str = "iterq";
740 deftype!("core::array", "fn(#trigger:Any, Array<'a>) -> 'a");
741
742 fn init(_: &mut ExecCtx<C, E>) -> BuiltInInitFn<C, E> {
743 Arc::new(|ctx, _, _, _, top_id| {
744 let id = BindId::new();
745 ctx.user.ref_var(id, top_id);
746 Ok(Box::new(IterQ { triggered: 0, queue: VecDeque::new(), id, top_id }))
747 })
748 }
749}
750
751impl<C: Ctx, E: UserEvent> Apply<C, E> for IterQ {
752 fn update(
753 &mut self,
754 ctx: &mut ExecCtx<C, E>,
755 from: &mut [Node<C, E>],
756 event: &mut Event<E>,
757 ) -> Option<Value> {
758 if from[0].update(ctx, event).is_some() {
759 self.triggered += 1;
760 }
761 if let Some(Value::Array(a)) = from[1].update(ctx, event) {
762 if a.len() > 0 {
763 self.queue.push_back((0, a));
764 }
765 }
766 while self.triggered > 0 && self.queue.len() > 0 {
767 let (i, a) = self.queue.front_mut().unwrap();
768 while self.triggered > 0 && *i < a.len() {
769 ctx.user.set_var(self.id, a[*i].clone());
770 *i += 1;
771 self.triggered -= 1;
772 }
773 if *i == a.len() {
774 self.queue.pop_front();
775 }
776 }
777 event.variables.get(&self.id).cloned()
778 }
779
780 fn delete(&mut self, ctx: &mut ExecCtx<C, E>) {
781 ctx.user.unref_var(self.id, self.top_id)
782 }
783}