Skip to main content

graphix_package_core/
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 arcstr::{literal, ArcStr};
7use compact_str::format_compact;
8use graphix_compiler::{
9    err, errf,
10    expr::{Expr, ExprId},
11    node::genn,
12    typ::{FnType, TVal, Type},
13    Apply, BindId, BuiltIn, Event, ExecCtx, LambdaId, Node, Refs, Rt, Scope,
14    TypecheckPhase, UserEvent,
15};
16use graphix_rt::GXRt;
17use immutable_chunkmap::map::Map as CMap;
18use netidx::path::Path;
19use netidx::subscriber::Value;
20use netidx_core::utils::Either;
21use netidx_value::{FromValue, ValArray};
22use poolshark::local::LPooled;
23use std::{
24    any::Any,
25    collections::{hash_map::Entry, VecDeque},
26    fmt::Debug,
27    iter,
28    marker::PhantomData,
29    time::Duration,
30};
31use tokio::time::Instant;
32use triomphe::Arc as TArc;
33
34pub(crate) mod buffer;
35
36// ── Cast context for typed deserialization ────────────────────────
37
38/// Extract the success type from a resolved `Result<T, E>` return type.
39/// Returns `None` if `resolved_typ` is absent or `T` contains free tvars.
40pub fn extract_cast_type(resolved_typ: Option<&FnType>) -> Option<Type> {
41    let ft = resolved_typ?;
42    let typ = match &ft.rtype {
43        Type::Ref { name, params, .. }
44            if Path::basename(&**name) == Some("Result") && params.len() == 2 =>
45        {
46            params[0].clone()
47        }
48        // Handle the expanded form [T, Error<E>] — this occurs when the
49        // Result type alias was expanded during TVar binding in contains().
50        Type::Set(elements) if elements.len() == 2 => {
51            let mut success = None;
52            for elem in elements.iter() {
53                if !matches!(elem, Type::Error(_)) {
54                    success = Some(elem.clone());
55                }
56            }
57            success?
58        }
59        _ => return None,
60    };
61    if typ.has_unbound() {
62        return None;
63    }
64    Some(typ)
65}
66
67// ── Program arguments ─────────────────────────────────────────────
68
69/// Program arguments stored in LibState. Index 0 is the script filename.
70#[derive(Default)]
71pub struct ProgramArgs(pub Vec<ArcStr>);
72
73// ── Shared macros ──────────────────────────────────────────────────
74
75/// Implement `netidx_core::pack::Pack` as a non-serializable stub.
76/// Use this for abstract wrapper types that should never be encoded/decoded.
77#[macro_export]
78macro_rules! impl_no_pack {
79    ($t:ty) => {
80        impl ::netidx_core::pack::Pack for $t {
81            fn encoded_len(&self) -> usize {
82                0
83            }
84
85            fn encode(
86                &self,
87                _buf: &mut impl ::bytes::BufMut,
88            ) -> Result<(), ::netidx_core::pack::PackError> {
89                Err(::netidx_core::pack::PackError::Application(0))
90            }
91
92            fn decode(
93                _buf: &mut impl ::bytes::Buf,
94            ) -> Result<Self, ::netidx_core::pack::PackError> {
95                Err(::netidx_core::pack::PackError::Application(0))
96            }
97        }
98    };
99}
100
101/// Generates `PartialEq`, `Eq`, `PartialOrd`, `Ord`, `Hash`, `impl_no_pack!`,
102/// and the `LazyLock<AbstractWrapper<T>>` static for an abstract value type
103/// whose identity is determined by `Arc::as_ptr(&self.inner)`.
104#[macro_export]
105macro_rules! impl_abstract_arc {
106    ($name:ident, $wrapper_vis:vis static $wrapper:ident = [$($uuid:expr),* $(,)?]) => {
107        impl PartialEq for $name {
108            fn eq(&self, other: &Self) -> bool {
109                std::sync::Arc::ptr_eq(&self.inner, &other.inner)
110            }
111        }
112        impl Eq for $name {}
113        impl PartialOrd for $name {
114            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
115                Some(self.cmp(other))
116            }
117        }
118        impl Ord for $name {
119            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
120                std::sync::Arc::as_ptr(&self.inner).addr().cmp(&std::sync::Arc::as_ptr(&other.inner).addr())
121            }
122        }
123        impl std::hash::Hash for $name {
124            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
125                std::sync::Arc::as_ptr(&self.inner).hash(state)
126            }
127        }
128        $crate::impl_no_pack!($name);
129        $wrapper_vis static $wrapper: std::sync::LazyLock<
130            netidx_value::abstract_type::AbstractWrapper<$name>,
131        > = std::sync::LazyLock::new(|| {
132            let id = uuid::Uuid::from_bytes([$($uuid),*]);
133            netidx_value::Abstract::register::<$name>(id)
134                .expect(concat!("failed to register ", stringify!($name)))
135        });
136    };
137}
138
139#[macro_export]
140macro_rules! arity1 {
141    ($from:expr, $updates:expr) => {
142        match (&*$from, &*$updates) {
143            ([arg], [arg_up]) => (arg, arg_up),
144            (_, _) => unreachable!(),
145        }
146    };
147}
148
149#[macro_export]
150macro_rules! arity2 {
151    ($from:expr, $updates:expr) => {
152        match (&*$from, &*$updates) {
153            ([arg0, arg1], [arg0_up, arg1_up]) => ((arg0, arg1), (arg0_up, arg1_up)),
154            (_, _) => unreachable!(),
155        }
156    };
157}
158
159// ── Testing infrastructure ─────────────────────────────────────────
160
161pub mod testing;
162
163// ── Shared helpers ────────────────────────────────────────────────
164
165/// Check if a Value is a struct-shaped array: non-empty, every element is
166/// a 2-element array with a string first element, keys sorted ascending.
167pub fn is_struct(arr: &ValArray) -> bool {
168    if arr.is_empty() {
169        return false;
170    }
171    let mut prev: Option<&ArcStr> = None;
172    for v in arr.iter() {
173        match v {
174            Value::Array(pair) if pair.len() == 2 => match &pair[0] {
175                Value::String(k) => {
176                    if let Some(p) = prev {
177                        if k <= p {
178                            return false;
179                        }
180                    }
181                    prev = Some(k);
182                }
183                _ => return false,
184            },
185            _ => return false,
186        }
187    }
188    true
189}
190
191// ── Shared traits and structs ──────────────────────────────────────
192
193#[derive(Debug)]
194pub struct CachedVals(pub Box<[Option<Value>]>);
195
196impl CachedVals {
197    pub fn new<R: Rt, E: UserEvent>(from: &[Node<R, E>]) -> CachedVals {
198        CachedVals(from.into_iter().map(|_| None).collect())
199    }
200
201    pub fn clear(&mut self) {
202        for v in &mut self.0 {
203            *v = None
204        }
205    }
206
207    pub fn update<R: Rt, E: UserEvent>(
208        &mut self,
209        ctx: &mut ExecCtx<R, E>,
210        from: &mut [Node<R, E>],
211        event: &mut Event<E>,
212    ) -> bool {
213        from.into_iter().enumerate().fold(false, |res, (i, src)| {
214            match src.update(ctx, event) {
215                None => res,
216                v @ Some(_) => {
217                    self.0[i] = v;
218                    true
219                }
220            }
221        })
222    }
223
224    /// Like update, but return the indexes of the nodes that updated
225    /// instead of a consolidated bool
226    pub fn update_diff<R: Rt, E: UserEvent>(
227        &mut self,
228        up: &mut [bool],
229        ctx: &mut ExecCtx<R, E>,
230        from: &mut [Node<R, E>],
231        event: &mut Event<E>,
232    ) {
233        for (i, n) in from.iter_mut().enumerate() {
234            match n.update(ctx, event) {
235                None => (),
236                v => {
237                    self.0[i] = v;
238                    up[i] = true
239                }
240            }
241        }
242    }
243
244    pub fn flat_iter<'a>(&'a self) -> impl Iterator<Item = Option<Value>> + 'a {
245        self.0.iter().flat_map(|v| match v {
246            None => Either::Left(iter::once(None)),
247            Some(v) => Either::Right(v.clone().flatten().map(Some)),
248        })
249    }
250
251    pub fn get<T: FromValue>(&self, i: usize) -> Option<T> {
252        self.0.get(i).and_then(|v| v.as_ref()).and_then(|v| v.clone().cast_to::<T>().ok())
253    }
254}
255
256pub type ByRefChain = immutable_chunkmap::map::MapS<BindId, BindId>;
257
258pub trait EvalCached<R: Rt, E: UserEvent>:
259    Debug + Default + Send + Sync + 'static
260{
261    const NAME: &str;
262    const NEEDS_CALLSITE: bool;
263
264    fn init(
265        _ctx: &mut ExecCtx<R, E>,
266        _typ: &FnType,
267        _resolved: Option<&FnType>,
268        _scope: &Scope,
269        _from: &[Node<R, E>],
270        _top_id: ExprId,
271    ) -> Self {
272        Self::default()
273    }
274
275    fn eval(&mut self, ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value>;
276
277    fn typecheck(
278        &mut self,
279        _ctx: &mut ExecCtx<R, E>,
280        _from: &mut [Node<R, E>],
281        _phase: TypecheckPhase<'_>,
282    ) -> Result<()> {
283        Ok(())
284    }
285}
286
287#[derive(Debug)]
288pub struct CachedArgs<T> {
289    cached: CachedVals,
290    t: T,
291}
292
293impl<R: Rt, E: UserEvent, T: EvalCached<R, E>> BuiltIn<R, E> for CachedArgs<T> {
294    const NAME: &str = T::NAME;
295    const NEEDS_CALLSITE: bool = T::NEEDS_CALLSITE;
296
297    fn init<'a, 'b, 'c, 'd>(
298        ctx: &'a mut ExecCtx<R, E>,
299        typ: &'a graphix_compiler::typ::FnType,
300        resolved: Option<&'d FnType>,
301        scope: &'b Scope,
302        from: &'c [Node<R, E>],
303        top_id: ExprId,
304    ) -> Result<Box<dyn Apply<R, E>>> {
305        let t = CachedArgs::<T> {
306            cached: CachedVals::new(from),
307            t: T::init(ctx, typ, resolved, scope, from, top_id),
308        };
309        Ok(Box::new(t))
310    }
311}
312
313impl<R: Rt, E: UserEvent, T: EvalCached<R, E>> Apply<R, E> for CachedArgs<T> {
314    fn update(
315        &mut self,
316        ctx: &mut ExecCtx<R, E>,
317        from: &mut [Node<R, E>],
318        event: &mut Event<E>,
319    ) -> Option<Value> {
320        if self.cached.update(ctx, from, event) {
321            self.t.eval(ctx, &self.cached)
322        } else {
323            None
324        }
325    }
326
327    fn typecheck(
328        &mut self,
329        ctx: &mut ExecCtx<R, E>,
330        from: &mut [Node<R, E>],
331        phase: TypecheckPhase<'_>,
332    ) -> Result<()> {
333        self.t.typecheck(ctx, from, phase)
334    }
335
336    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {
337        self.cached.clear()
338    }
339}
340
341pub trait EvalCachedAsync: Debug + Default + Send + Sync + 'static {
342    const NAME: &str;
343    const NEEDS_CALLSITE: bool;
344
345    type Args: Debug + Any + Send + Sync;
346
347    fn init<R: Rt, E: UserEvent>(
348        _ctx: &mut ExecCtx<R, E>,
349        _typ: &FnType,
350        _resolved: Option<&FnType>,
351        _scope: &Scope,
352        _from: &[Node<R, E>],
353        _top_id: ExprId,
354    ) -> Self {
355        Self::default()
356    }
357
358    /// map the final value with access to self and ctx
359    fn map_value<R: Rt, E: UserEvent>(
360        &mut self,
361        _ctx: &mut ExecCtx<R, E>,
362        v: Value,
363    ) -> Option<Value> {
364        Some(v)
365    }
366
367    fn typecheck<R: Rt, E: UserEvent>(
368        &mut self,
369        _ctx: &mut ExecCtx<R, E>,
370        _from: &mut [Node<R, E>],
371        _phase: TypecheckPhase<'_>,
372    ) -> Result<()> {
373        Ok(())
374    }
375
376    fn prepare_args(&mut self, cached: &CachedVals) -> Option<Self::Args>;
377    fn eval(args: Self::Args) -> impl Future<Output = Value> + Send;
378}
379
380#[derive(Debug)]
381pub struct CachedArgsAsync<T: EvalCachedAsync> {
382    cached: CachedVals,
383    id: BindId,
384    top_id: ExprId,
385    queued: VecDeque<T::Args>,
386    running: bool,
387    t: T,
388}
389
390impl<R: Rt, E: UserEvent, T: EvalCachedAsync> BuiltIn<R, E> for CachedArgsAsync<T> {
391    const NAME: &str = T::NAME;
392    const NEEDS_CALLSITE: bool = T::NEEDS_CALLSITE;
393
394    fn init<'a, 'b, 'c, 'd>(
395        ctx: &'a mut ExecCtx<R, E>,
396        typ: &'a FnType,
397        resolved: Option<&'d FnType>,
398        scope: &'b Scope,
399        from: &'c [Node<R, E>],
400        top_id: ExprId,
401    ) -> Result<Box<dyn Apply<R, E>>> {
402        let id = BindId::new();
403        ctx.rt.ref_var(id, top_id);
404        let t = CachedArgsAsync::<T> {
405            id,
406            top_id,
407            cached: CachedVals::new(from),
408            queued: VecDeque::new(),
409            running: false,
410            t: T::init(ctx, typ, resolved, scope, from, top_id),
411        };
412        Ok(Box::new(t))
413    }
414}
415
416impl<R: Rt, E: UserEvent, T: EvalCachedAsync> Apply<R, E> for CachedArgsAsync<T> {
417    fn update(
418        &mut self,
419        ctx: &mut ExecCtx<R, E>,
420        from: &mut [Node<R, E>],
421        event: &mut Event<E>,
422    ) -> Option<Value> {
423        if self.cached.update(ctx, from, event)
424            && let Some(args) = self.t.prepare_args(&self.cached)
425        {
426            self.queued.push_back(args);
427        }
428        let res = event.variables.remove(&self.id).and_then(|v| {
429            self.running = false;
430            self.t.map_value(ctx, v)
431        });
432        if !self.running
433            && let Some(args) = self.queued.pop_front()
434        {
435            self.running = true;
436            let id = self.id;
437            ctx.rt.spawn_var(async move { (id, T::eval(args).await) });
438        }
439        res
440    }
441
442    fn typecheck(
443        &mut self,
444        ctx: &mut ExecCtx<R, E>,
445        from: &mut [Node<R, E>],
446        phase: TypecheckPhase<'_>,
447    ) -> Result<()> {
448        self.t.typecheck(ctx, from, phase)
449    }
450
451    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
452        ctx.rt.unref_var(self.id, self.top_id);
453        self.queued.clear();
454        self.cached.clear();
455    }
456
457    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
458        self.delete(ctx);
459        self.running = false;
460        let id = BindId::new();
461        ctx.rt.ref_var(id, self.top_id);
462        self.id = id;
463    }
464}
465
466pub trait MapCollection: Debug + Clone + Default + Send + Sync + 'static {
467    /// return the length of the collection
468    fn len(&self) -> usize;
469
470    /// iterate the collection elements as values
471    fn iter_values(&self) -> impl Iterator<Item = Value>;
472
473    /// given a value, return Some if the value is the collection type
474    /// we are mapping.
475    fn select(v: Value) -> Option<Self>;
476
477    /// given a collection wrap it in a value
478    fn project(self) -> Value;
479
480    /// return the element type given the function type
481    fn etyp(ft: &FnType) -> Result<Type>;
482}
483
484impl MapCollection for ValArray {
485    fn iter_values(&self) -> impl Iterator<Item = Value> {
486        (**self).iter().cloned()
487    }
488
489    fn len(&self) -> usize {
490        (**self).len()
491    }
492
493    fn select(v: Value) -> Option<Self> {
494        match v {
495            Value::Array(a) => Some(a.clone()),
496            _ => None,
497        }
498    }
499
500    fn project(self) -> Value {
501        Value::Array(self)
502    }
503
504    fn etyp(ft: &FnType) -> Result<Type> {
505        match &ft.args[0].typ {
506            Type::Array(et) => Ok((**et).clone()),
507            _ => bail!("expected array"),
508        }
509    }
510}
511
512impl MapCollection for CMap<Value, Value, 32> {
513    fn iter_values(&self) -> impl Iterator<Item = Value> {
514        self.into_iter().map(|(k, v)| {
515            Value::Array(ValArray::from_iter_exact([k.clone(), v.clone()].into_iter()))
516        })
517    }
518
519    fn len(&self) -> usize {
520        CMap::len(self)
521    }
522
523    fn select(v: Value) -> Option<Self> {
524        match v {
525            Value::Map(m) => Some(m.clone()),
526            _ => None,
527        }
528    }
529
530    fn project(self) -> Value {
531        Value::Map(self)
532    }
533
534    fn etyp(ft: &FnType) -> Result<Type> {
535        match &ft.args[0].typ {
536            Type::Map { key, value } => {
537                Ok(Type::Tuple(TArc::from_iter([(**key).clone(), (**value).clone()])))
538            }
539            _ => bail!("expected Map, got {:?}", ft.args[0].typ),
540        }
541    }
542}
543
544pub trait MapFn<R: Rt, E: UserEvent>: Debug + Default + Send + Sync + 'static {
545    type Collection: MapCollection;
546
547    const NAME: &str;
548
549    /// finish will be called when every lambda instance has produced
550    /// a value for the updated array. Out contains the output of the
551    /// predicate lambda for each index i, and a is the array. out and
552    /// a are guaranteed to have the same length. out\[i\].cur is
553    /// guaranteed to be Some.
554    fn finish(&mut self, slots: &[Slot<R, E>], a: &Self::Collection) -> Option<Value>;
555}
556
557#[derive(Debug)]
558pub struct Slot<R: Rt, E: UserEvent> {
559    pub id: BindId,
560    pub pred: Node<R, E>,
561    pub cur: Option<Value>,
562}
563
564impl<R: Rt, E: UserEvent> Slot<R, E> {
565    pub fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
566        self.pred.delete(ctx);
567        ctx.cached.remove(&self.id);
568        ctx.env.unbind_variable(self.id);
569    }
570}
571
572#[derive(Debug)]
573pub struct MapQ<R: Rt, E: UserEvent, T: MapFn<R, E>> {
574    scope: Scope,
575    predid: BindId,
576    top_id: ExprId,
577    mftyp: TArc<FnType>,
578    etyp: Type,
579    slots: Vec<Slot<R, E>>,
580    cur: T::Collection,
581    t: T,
582}
583
584impl<R: Rt, E: UserEvent, T: MapFn<R, E>> BuiltIn<R, E> for MapQ<R, E, T> {
585    const NAME: &str = T::NAME;
586    const NEEDS_CALLSITE: bool = false;
587
588    fn init<'a, 'b, 'c, 'd>(
589        _ctx: &'a mut ExecCtx<R, E>,
590        typ: &'a graphix_compiler::typ::FnType,
591        resolved: Option<&'d FnType>,
592        scope: &'b Scope,
593        from: &'c [Node<R, E>],
594        top_id: ExprId,
595    ) -> Result<Box<dyn Apply<R, E>>> {
596        match from {
597            [_, _] => {
598                let typ = resolved.unwrap_or(typ);
599                Ok(Box::new(Self {
600                    scope: scope
601                        .append(&format_compact!("fn{}", LambdaId::new().inner())),
602                    predid: BindId::new(),
603                    top_id,
604                    etyp: T::Collection::etyp(typ)?,
605                    mftyp: match &typ.args[1].typ {
606                        Type::Fn(ft) => ft.clone(),
607                        t => bail!("expected a function not {t}"),
608                    },
609                    slots: vec![],
610                    cur: Default::default(),
611                    t: T::default(),
612                }))
613            }
614            _ => bail!("expected two arguments"),
615        }
616    }
617}
618
619impl<R: Rt, E: UserEvent, T: MapFn<R, E>> Apply<R, E> for MapQ<R, E, T> {
620    fn update(
621        &mut self,
622        ctx: &mut ExecCtx<R, E>,
623        from: &mut [Node<R, E>],
624        event: &mut Event<E>,
625    ) -> Option<Value> {
626        let slen = self.slots.len();
627        if let Some(v) = from[1].update(ctx, event) {
628            ctx.cached.insert(self.predid, v.clone());
629            event.variables.insert(self.predid, v);
630        }
631        let (up, resized) =
632            match from[0].update(ctx, event).and_then(|v| T::Collection::select(v)) {
633                Some(a) if a.len() == slen => (Some(a), false),
634                Some(a) if a.len() < slen => {
635                    while self.slots.len() > a.len() {
636                        if let Some(mut s) = self.slots.pop() {
637                            s.delete(ctx)
638                        }
639                    }
640                    (Some(a), true)
641                }
642                Some(a) => {
643                    while self.slots.len() < a.len() {
644                        let (id, node) = genn::bind(
645                            ctx,
646                            &self.scope.lexical,
647                            "x",
648                            self.etyp.clone(),
649                            self.top_id,
650                        );
651                        let fargs = vec![node];
652                        let fnode = genn::reference(
653                            ctx,
654                            self.predid,
655                            Type::Fn(self.mftyp.clone()),
656                            self.top_id,
657                        );
658                        let pred = genn::apply(
659                            fnode,
660                            self.scope.clone(),
661                            fargs,
662                            &self.mftyp,
663                            self.top_id,
664                        );
665                        self.slots.push(Slot { id, pred, cur: None });
666                    }
667                    (Some(a), true)
668                }
669                None => (None, false),
670            };
671        if let Some(a) = up {
672            for (s, v) in self.slots.iter().zip(a.iter_values()) {
673                ctx.cached.insert(s.id, v.clone());
674                event.variables.insert(s.id, v);
675            }
676            self.cur = a.clone();
677            if a.len() == 0 {
678                return Some(T::Collection::project(a));
679            }
680        }
681        let init = event.init;
682        let mut up = resized;
683        for (i, s) in self.slots.iter_mut().enumerate() {
684            if i == slen {
685                // new nodes were added starting here
686                event.init = true;
687                if let Entry::Vacant(e) = event.variables.entry(self.predid)
688                    && let Some(v) = ctx.cached.get(&self.predid)
689                {
690                    e.insert(v.clone());
691                }
692            }
693            if let Some(v) = s.pred.update(ctx, event) {
694                s.cur = Some(v);
695                up = true;
696            }
697        }
698        event.init = init;
699        if up && self.slots.iter().all(|s| s.cur.is_some()) {
700            self.t.finish(&mut &self.slots, &self.cur)
701        } else {
702            None
703        }
704    }
705
706    fn typecheck(
707        &mut self,
708        ctx: &mut ExecCtx<R, E>,
709        from: &mut [Node<R, E>],
710        _phase: TypecheckPhase<'_>,
711    ) -> anyhow::Result<()> {
712        let mftyp = match &from[1].typ() {
713            Type::Fn(ft) => ft.clone(),
714            t => bail!("expected a function not {t}"),
715        };
716        let (_, node) =
717            genn::bind(ctx, &self.scope.lexical, "x", self.etyp.clone(), self.top_id);
718        let fargs = vec![node];
719        let ft = mftyp.clone();
720        let fnode = genn::reference(ctx, self.predid, Type::Fn(ft.clone()), self.top_id);
721        let mut node = genn::apply(fnode, self.scope.clone(), fargs, &ft, self.top_id);
722        node.typecheck(ctx)?;
723        node.delete(ctx);
724        Ok(())
725    }
726
727    fn refs(&self, refs: &mut Refs) {
728        for s in &self.slots {
729            s.pred.refs(refs)
730        }
731    }
732
733    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
734        ctx.cached.remove(&self.predid);
735        for sl in &mut self.slots {
736            sl.delete(ctx)
737        }
738    }
739
740    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
741        self.cur = Default::default();
742        for sl in &mut self.slots {
743            sl.cur = None;
744            sl.pred.sleep(ctx);
745        }
746    }
747}
748
749pub trait FoldFn<R: Rt, E: UserEvent>: Debug + Send + Sync + 'static {
750    type Collection: MapCollection;
751
752    const NAME: &str;
753}
754
755#[derive(Debug)]
756pub struct FoldQ<R: Rt, E: UserEvent, T: FoldFn<R, E>> {
757    top_id: ExprId,
758    fid: BindId,
759    scope: Scope,
760    binds: Vec<BindId>,
761    nodes: Vec<Node<R, E>>,
762    inits: Vec<Option<Value>>,
763    initids: Vec<BindId>,
764    initid: BindId,
765    mftype: TArc<FnType>,
766    etyp: Type,
767    ityp: Type,
768    init: Option<Value>,
769    t: PhantomData<T>,
770}
771
772impl<R: Rt, E: UserEvent, T: FoldFn<R, E>> BuiltIn<R, E> for FoldQ<R, E, T> {
773    const NAME: &str = T::NAME;
774    const NEEDS_CALLSITE: bool = false;
775
776    fn init<'a, 'b, 'c, 'd>(
777        _ctx: &'a mut ExecCtx<R, E>,
778        typ: &'a FnType,
779        resolved: Option<&'d FnType>,
780        scope: &'b Scope,
781        from: &'c [Node<R, E>],
782        top_id: ExprId,
783    ) -> Result<Box<dyn Apply<R, E>>> {
784        match from {
785            [_, _, _] => {
786                let typ = resolved.unwrap_or(typ);
787                Ok(Box::new(Self {
788                    top_id,
789                    scope: scope.clone(),
790                    binds: vec![],
791                    nodes: vec![],
792                    inits: vec![],
793                    initids: vec![],
794                    initid: BindId::new(),
795                    fid: BindId::new(),
796                    etyp: T::Collection::etyp(typ)?,
797                    ityp: typ.args[1].typ.clone(),
798                    mftype: match &typ.args[2].typ {
799                        Type::Fn(ft) => ft.clone(),
800                        t => bail!("expected a function not {t}"),
801                    },
802                    init: None,
803                    t: PhantomData,
804                }))
805            }
806            _ => bail!("expected three arguments"),
807        }
808    }
809}
810
811impl<R: Rt, E: UserEvent, T: FoldFn<R, E>> Apply<R, E> for FoldQ<R, E, T> {
812    fn update(
813        &mut self,
814        ctx: &mut ExecCtx<R, E>,
815        from: &mut [Node<R, E>],
816        event: &mut Event<E>,
817    ) -> Option<Value> {
818        let init = match from[0].update(ctx, event).and_then(|v| T::Collection::select(v))
819        {
820            None => self.nodes.len(),
821            Some(a) if a.len() == self.binds.len() => {
822                for (id, v) in self.binds.iter().zip(a.iter_values()) {
823                    ctx.cached.insert(*id, v.clone());
824                    event.variables.insert(*id, v.clone());
825                }
826                self.nodes.len()
827            }
828            Some(a) => {
829                let vals = a.iter_values().collect::<LPooled<Vec<Value>>>();
830                while self.binds.len() < a.len() {
831                    self.binds.push(BindId::new());
832                    self.inits.push(None);
833                    self.initids.push(BindId::new());
834                }
835                while a.len() < self.binds.len() {
836                    if let Some(id) = self.binds.pop() {
837                        ctx.cached.remove(&id);
838                    }
839                    if let Some(id) = self.initids.pop() {
840                        ctx.cached.remove(&id);
841                    }
842                    self.inits.pop();
843                    if let Some(mut n) = self.nodes.pop() {
844                        n.delete(ctx);
845                    }
846                }
847                let init = self.nodes.len();
848                for i in 0..self.binds.len() {
849                    ctx.cached.insert(self.binds[i], vals[i].clone());
850                    event.variables.insert(self.binds[i], vals[i].clone());
851                    if i >= self.nodes.len() {
852                        let n = genn::reference(
853                            ctx,
854                            if i == 0 { self.initid } else { self.initids[i - 1] },
855                            self.ityp.clone(),
856                            self.top_id,
857                        );
858                        let x = genn::reference(
859                            ctx,
860                            self.binds[i],
861                            self.etyp.clone(),
862                            self.top_id,
863                        );
864                        let fnode = genn::reference(
865                            ctx,
866                            self.fid,
867                            Type::Fn(self.mftype.clone()),
868                            self.top_id,
869                        );
870                        let node = genn::apply(
871                            fnode,
872                            self.scope.clone(),
873                            vec![n, x],
874                            &self.mftype,
875                            self.top_id,
876                        );
877                        self.nodes.push(node);
878                    }
879                }
880                init
881            }
882        };
883        if let Some(v) = from[1].update(ctx, event) {
884            ctx.cached.insert(self.initid, v.clone());
885            event.variables.insert(self.initid, v.clone());
886            self.init = Some(v);
887        }
888        if let Some(v) = from[2].update(ctx, event) {
889            ctx.cached.insert(self.fid, v.clone());
890            event.variables.insert(self.fid, v);
891        }
892        let old_init = event.init;
893        for i in 0..self.nodes.len() {
894            if i == init {
895                event.init = true;
896                if let Some(v) = ctx.cached.get(&self.fid)
897                    && let Entry::Vacant(e) = event.variables.entry(self.fid)
898                {
899                    e.insert(v.clone());
900                }
901                if i == 0 {
902                    if let Some(v) = self.init.as_ref()
903                        && let Entry::Vacant(e) = event.variables.entry(self.initid)
904                    {
905                        e.insert(v.clone());
906                    }
907                } else {
908                    if let Some(v) = self.inits[i - 1].clone() {
909                        event.variables.insert(self.initids[i - 1], v);
910                    }
911                }
912            }
913            match self.nodes[i].update(ctx, event) {
914                Some(v) => {
915                    ctx.cached.insert(self.initids[i], v.clone());
916                    event.variables.insert(self.initids[i], v.clone());
917                    self.inits[i] = Some(v);
918                }
919                None => {
920                    ctx.cached.remove(&self.initids[i]);
921                    event.variables.remove(&self.initids[i]);
922                    self.inits[i] = None;
923                }
924            }
925        }
926        event.init = old_init;
927        self.inits.last().and_then(|v| v.clone())
928    }
929
930    fn typecheck(
931        &mut self,
932        ctx: &mut ExecCtx<R, E>,
933        _from: &mut [Node<R, E>],
934        _phase: TypecheckPhase<'_>,
935    ) -> anyhow::Result<()> {
936        let mut n = genn::reference(ctx, self.initid, self.ityp.clone(), self.top_id);
937        let x = genn::reference(ctx, BindId::new(), self.etyp.clone(), self.top_id);
938        let fnode =
939            genn::reference(ctx, self.fid, Type::Fn(self.mftype.clone()), self.top_id);
940        n = genn::apply(fnode, self.scope.clone(), vec![n, x], &self.mftype, self.top_id);
941        n.typecheck(ctx)?;
942        n.delete(ctx);
943        Ok(())
944    }
945
946    fn refs(&self, refs: &mut Refs) {
947        for n in &self.nodes {
948            n.refs(refs)
949        }
950    }
951
952    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
953        let i =
954            iter::once(&self.initid).chain(self.binds.iter()).chain(self.initids.iter());
955        for id in i {
956            ctx.cached.remove(id);
957        }
958        for n in &mut self.nodes {
959            n.delete(ctx);
960        }
961    }
962
963    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
964        self.init = None;
965        for v in &mut self.inits {
966            *v = None
967        }
968        for n in &mut self.nodes {
969            n.sleep(ctx)
970        }
971    }
972}
973
974// ── Core builtins ──────────────────────────────────────────────────
975
976#[derive(Debug)]
977struct IsErr;
978
979impl<R: Rt, E: UserEvent> BuiltIn<R, E> for IsErr {
980    const NAME: &str = "core_is_err";
981    const NEEDS_CALLSITE: bool = false;
982
983    fn init<'a, 'b, 'c, 'd>(
984        _ctx: &'a mut ExecCtx<R, E>,
985        _typ: &'a FnType,
986        _resolved: Option<&'d FnType>,
987        _scope: &'b Scope,
988        _from: &'c [Node<R, E>],
989        _top_id: ExprId,
990    ) -> Result<Box<dyn Apply<R, E>>> {
991        Ok(Box::new(IsErr))
992    }
993}
994
995impl<R: Rt, E: UserEvent> Apply<R, E> for IsErr {
996    fn update(
997        &mut self,
998        ctx: &mut ExecCtx<R, E>,
999        from: &mut [Node<R, E>],
1000        event: &mut Event<E>,
1001    ) -> Option<Value> {
1002        from[0].update(ctx, event).map(|v| match v {
1003            Value::Error(_) => Value::Bool(true),
1004            _ => Value::Bool(false),
1005        })
1006    }
1007
1008    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {}
1009}
1010
1011#[derive(Debug)]
1012struct FilterErr;
1013
1014impl<R: Rt, E: UserEvent> BuiltIn<R, E> for FilterErr {
1015    const NAME: &str = "core_filter_err";
1016    const NEEDS_CALLSITE: bool = false;
1017
1018    fn init<'a, 'b, 'c, 'd>(
1019        _ctx: &'a mut ExecCtx<R, E>,
1020        _typ: &'a FnType,
1021        _resolved: Option<&'d FnType>,
1022        _scope: &'b Scope,
1023        _from: &'c [Node<R, E>],
1024        _top_id: ExprId,
1025    ) -> Result<Box<dyn Apply<R, E>>> {
1026        Ok(Box::new(FilterErr))
1027    }
1028}
1029
1030impl<R: Rt, E: UserEvent> Apply<R, E> for FilterErr {
1031    fn update(
1032        &mut self,
1033        ctx: &mut ExecCtx<R, E>,
1034        from: &mut [Node<R, E>],
1035        event: &mut Event<E>,
1036    ) -> Option<Value> {
1037        from[0].update(ctx, event).and_then(|v| match v {
1038            v @ Value::Error(_) => Some(v),
1039            _ => None,
1040        })
1041    }
1042
1043    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {}
1044}
1045
1046#[derive(Debug)]
1047struct ToError;
1048
1049impl<R: Rt, E: UserEvent> BuiltIn<R, E> for ToError {
1050    const NAME: &str = "core_error";
1051    const NEEDS_CALLSITE: bool = false;
1052
1053    fn init<'a, 'b, 'c, 'd>(
1054        _ctx: &'a mut ExecCtx<R, E>,
1055        _typ: &'a FnType,
1056        _resolved: Option<&'d FnType>,
1057        _scope: &'b Scope,
1058        _from: &'c [Node<R, E>],
1059        _top_id: ExprId,
1060    ) -> Result<Box<dyn Apply<R, E>>> {
1061        Ok(Box::new(ToError))
1062    }
1063}
1064
1065impl<R: Rt, E: UserEvent> Apply<R, E> for ToError {
1066    fn update(
1067        &mut self,
1068        ctx: &mut ExecCtx<R, E>,
1069        from: &mut [Node<R, E>],
1070        event: &mut Event<E>,
1071    ) -> Option<Value> {
1072        from[0].update(ctx, event).map(|e| Value::Error(triomphe::Arc::new(e)))
1073    }
1074
1075    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {}
1076}
1077
1078#[derive(Debug)]
1079struct Once {
1080    val: bool,
1081}
1082
1083impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Once {
1084    const NAME: &str = "core_once";
1085    const NEEDS_CALLSITE: bool = false;
1086
1087    fn init<'a, 'b, 'c, 'd>(
1088        _ctx: &'a mut ExecCtx<R, E>,
1089        _typ: &'a FnType,
1090        _resolved: Option<&'d FnType>,
1091        _scope: &'b Scope,
1092        _from: &'c [Node<R, E>],
1093        _top_id: ExprId,
1094    ) -> Result<Box<dyn Apply<R, E>>> {
1095        Ok(Box::new(Once { val: false }))
1096    }
1097}
1098
1099impl<R: Rt, E: UserEvent> Apply<R, E> for Once {
1100    fn update(
1101        &mut self,
1102        ctx: &mut ExecCtx<R, E>,
1103        from: &mut [Node<R, E>],
1104        event: &mut Event<E>,
1105    ) -> Option<Value> {
1106        match from {
1107            [s] => s.update(ctx, event).and_then(|v| {
1108                if self.val {
1109                    None
1110                } else {
1111                    self.val = true;
1112                    Some(v)
1113                }
1114            }),
1115            _ => None,
1116        }
1117    }
1118
1119    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {
1120        self.val = false
1121    }
1122}
1123
1124#[derive(Debug)]
1125struct Take {
1126    n: Option<usize>,
1127}
1128
1129impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Take {
1130    const NAME: &str = "core_take";
1131    const NEEDS_CALLSITE: bool = false;
1132
1133    fn init<'a, 'b, 'c, 'd>(
1134        _ctx: &'a mut ExecCtx<R, E>,
1135        _typ: &'a FnType,
1136        _resolved: Option<&'d FnType>,
1137        _scope: &'b Scope,
1138        _from: &'c [Node<R, E>],
1139        _top_id: ExprId,
1140    ) -> Result<Box<dyn Apply<R, E>>> {
1141        Ok(Box::new(Take { n: None }))
1142    }
1143}
1144
1145impl<R: Rt, E: UserEvent> Apply<R, E> for Take {
1146    fn update(
1147        &mut self,
1148        ctx: &mut ExecCtx<R, E>,
1149        from: &mut [Node<R, E>],
1150        event: &mut Event<E>,
1151    ) -> Option<Value> {
1152        if let Some(n) =
1153            from[0].update(ctx, event).and_then(|v| v.cast_to::<usize>().ok())
1154        {
1155            self.n = Some(n)
1156        }
1157        match from[1].update(ctx, event) {
1158            None => None,
1159            Some(v) => match &mut self.n {
1160                None => None,
1161                Some(n) if *n > 0 => {
1162                    *n -= 1;
1163                    return Some(v);
1164                }
1165                Some(_) => None,
1166            },
1167        }
1168    }
1169
1170    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {
1171        self.n = None
1172    }
1173}
1174
1175#[derive(Debug)]
1176struct Skip {
1177    n: Option<usize>,
1178}
1179
1180impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Skip {
1181    const NAME: &str = "core_skip";
1182    const NEEDS_CALLSITE: bool = false;
1183
1184    fn init<'a, 'b, 'c, 'd>(
1185        _ctx: &'a mut ExecCtx<R, E>,
1186        _typ: &'a FnType,
1187        _resolved: Option<&'d FnType>,
1188        _scope: &'b Scope,
1189        _from: &'c [Node<R, E>],
1190        _top_id: ExprId,
1191    ) -> Result<Box<dyn Apply<R, E>>> {
1192        Ok(Box::new(Skip { n: None }))
1193    }
1194}
1195
1196impl<R: Rt, E: UserEvent> Apply<R, E> for Skip {
1197    fn update(
1198        &mut self,
1199        ctx: &mut ExecCtx<R, E>,
1200        from: &mut [Node<R, E>],
1201        event: &mut Event<E>,
1202    ) -> Option<Value> {
1203        if let Some(n) =
1204            from[0].update(ctx, event).and_then(|v| v.cast_to::<usize>().ok())
1205        {
1206            self.n = Some(n)
1207        }
1208        match from[1].update(ctx, event) {
1209            None => None,
1210            Some(v) => match &mut self.n {
1211                None => Some(v),
1212                Some(n) if *n > 0 => {
1213                    *n -= 1;
1214                    None
1215                }
1216                Some(_) => Some(v),
1217            },
1218        }
1219    }
1220
1221    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {
1222        self.n = None
1223    }
1224}
1225
1226#[derive(Debug, Default)]
1227struct AllEv;
1228
1229impl<R: Rt, E: UserEvent> EvalCached<R, E> for AllEv {
1230    const NAME: &str = "core_all";
1231    const NEEDS_CALLSITE: bool = false;
1232
1233    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
1234        match &*from.0 {
1235            [] => None,
1236            [hd, tl @ ..] => match hd {
1237                None => None,
1238                v @ Some(_) => {
1239                    if tl.into_iter().all(|v1| v1 == v) {
1240                        v.clone()
1241                    } else {
1242                        None
1243                    }
1244                }
1245            },
1246        }
1247    }
1248}
1249
1250type All = CachedArgs<AllEv>;
1251
1252fn add_vals(lhs: Option<Value>, rhs: Option<Value>) -> Option<Value> {
1253    match (lhs, rhs) {
1254        (None, None) | (Some(_), None) => None,
1255        (None, r @ Some(_)) => r,
1256        (Some(l), Some(r)) => Some(l + r),
1257    }
1258}
1259
1260#[derive(Debug, Default)]
1261struct SumEv;
1262
1263impl<R: Rt, E: UserEvent> EvalCached<R, E> for SumEv {
1264    const NAME: &str = "core_sum";
1265    const NEEDS_CALLSITE: bool = false;
1266
1267    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
1268        from.flat_iter().fold(None, |res, v| match res {
1269            res @ Some(Value::Error(_)) => res,
1270            res => add_vals(res, v.clone()),
1271        })
1272    }
1273}
1274
1275type Sum = CachedArgs<SumEv>;
1276
1277#[derive(Debug, Default)]
1278struct ProductEv;
1279
1280fn prod_vals(lhs: Option<Value>, rhs: Option<Value>) -> Option<Value> {
1281    match (lhs, rhs) {
1282        (None, None) | (Some(_), None) => None,
1283        (None, r @ Some(_)) => r,
1284        (Some(l), Some(r)) => Some(l * r),
1285    }
1286}
1287
1288impl<R: Rt, E: UserEvent> EvalCached<R, E> for ProductEv {
1289    const NAME: &str = "core_product";
1290    const NEEDS_CALLSITE: bool = false;
1291
1292    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
1293        from.flat_iter().fold(None, |res, v| match res {
1294            res @ Some(Value::Error(_)) => res,
1295            res => prod_vals(res, v.clone()),
1296        })
1297    }
1298}
1299
1300type Product = CachedArgs<ProductEv>;
1301
1302#[derive(Debug, Default)]
1303struct DivideEv;
1304
1305fn div_vals(lhs: Option<Value>, rhs: Option<Value>) -> Option<Value> {
1306    match (lhs, rhs) {
1307        (None, None) | (Some(_), None) => None,
1308        (None, r @ Some(_)) => r,
1309        (Some(l), Some(r)) => Some(l / r),
1310    }
1311}
1312
1313impl<R: Rt, E: UserEvent> EvalCached<R, E> for DivideEv {
1314    const NAME: &str = "core_divide";
1315    const NEEDS_CALLSITE: bool = false;
1316
1317    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
1318        from.flat_iter().fold(None, |res, v| match res {
1319            res @ Some(Value::Error(_)) => res,
1320            res => div_vals(res, v.clone()),
1321        })
1322    }
1323}
1324
1325type Divide = CachedArgs<DivideEv>;
1326
1327#[derive(Debug, Default)]
1328struct MinEv;
1329
1330impl<R: Rt, E: UserEvent> EvalCached<R, E> for MinEv {
1331    const NAME: &str = "core_min";
1332    const NEEDS_CALLSITE: bool = false;
1333
1334    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
1335        let mut res = None;
1336        for v in from.flat_iter() {
1337            match (res, v) {
1338                (None, None) | (Some(_), None) => return None,
1339                (None, Some(v)) => {
1340                    res = Some(v);
1341                }
1342                (Some(v0), Some(v)) => {
1343                    res = if v < v0 { Some(v) } else { Some(v0) };
1344                }
1345            }
1346        }
1347        res
1348    }
1349}
1350
1351type Min = CachedArgs<MinEv>;
1352
1353#[derive(Debug, Default)]
1354struct MaxEv;
1355
1356impl<R: Rt, E: UserEvent> EvalCached<R, E> for MaxEv {
1357    const NAME: &str = "core_max";
1358    const NEEDS_CALLSITE: bool = false;
1359
1360    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
1361        let mut res = None;
1362        for v in from.flat_iter() {
1363            match (res, v) {
1364                (None, None) | (Some(_), None) => return None,
1365                (None, Some(v)) => {
1366                    res = Some(v);
1367                }
1368                (Some(v0), Some(v)) => {
1369                    res = if v > v0 { Some(v) } else { Some(v0) };
1370                }
1371            }
1372        }
1373        res
1374    }
1375}
1376
1377type Max = CachedArgs<MaxEv>;
1378
1379#[derive(Debug, Default)]
1380struct AndEv;
1381
1382impl<R: Rt, E: UserEvent> EvalCached<R, E> for AndEv {
1383    const NAME: &str = "core_and";
1384    const NEEDS_CALLSITE: bool = false;
1385
1386    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
1387        let mut res = Some(Value::Bool(true));
1388        for v in from.flat_iter() {
1389            match v {
1390                None => return None,
1391                Some(Value::Bool(true)) => (),
1392                Some(_) => {
1393                    res = Some(Value::Bool(false));
1394                }
1395            }
1396        }
1397        res
1398    }
1399}
1400
1401type And = CachedArgs<AndEv>;
1402
1403#[derive(Debug, Default)]
1404struct OrEv;
1405
1406impl<R: Rt, E: UserEvent> EvalCached<R, E> for OrEv {
1407    const NAME: &str = "core_or";
1408    const NEEDS_CALLSITE: bool = false;
1409
1410    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
1411        let mut res = Some(Value::Bool(false));
1412        for v in from.flat_iter() {
1413            match v {
1414                None => return None,
1415                Some(Value::Bool(true)) => {
1416                    res = Some(Value::Bool(true));
1417                }
1418                Some(_) => (),
1419            }
1420        }
1421        res
1422    }
1423}
1424
1425type Or = CachedArgs<OrEv>;
1426
1427// ── Bitwise operations ──────────────────────────────────────────
1428
1429macro_rules! int_binop {
1430    ($from:expr, $op:tt) => {
1431        match (&$from.0[0], &$from.0[1]) {
1432            (Some(Value::U8(l)), Some(Value::U8(r))) => Some(Value::U8(l $op r)),
1433            (Some(Value::I8(l)), Some(Value::I8(r))) => Some(Value::I8(l $op r)),
1434            (Some(Value::U16(l)), Some(Value::U16(r))) => Some(Value::U16(l $op r)),
1435            (Some(Value::I16(l)), Some(Value::I16(r))) => Some(Value::I16(l $op r)),
1436            (Some(Value::U32(l)), Some(Value::U32(r))) => Some(Value::U32(l $op r)),
1437            (Some(Value::V32(l)), Some(Value::V32(r))) => Some(Value::V32(l $op r)),
1438            (Some(Value::I32(l)), Some(Value::I32(r))) => Some(Value::I32(l $op r)),
1439            (Some(Value::Z32(l)), Some(Value::Z32(r))) => Some(Value::Z32(l $op r)),
1440            (Some(Value::U64(l)), Some(Value::U64(r))) => Some(Value::U64(l $op r)),
1441            (Some(Value::V64(l)), Some(Value::V64(r))) => Some(Value::V64(l $op r)),
1442            (Some(Value::I64(l)), Some(Value::I64(r))) => Some(Value::I64(l $op r)),
1443            (Some(Value::Z64(l)), Some(Value::Z64(r))) => Some(Value::Z64(l $op r)),
1444            _ => None,
1445        }
1446    };
1447}
1448
1449macro_rules! int_shift {
1450    ($from:expr, $method:ident) => {
1451        match (&$from.0[0], &$from.0[1]) {
1452            (Some(Value::U8(l)), Some(Value::U8(r))) => {
1453                Some(Value::U8(l.$method(*r as u32)))
1454            }
1455            (Some(Value::I8(l)), Some(Value::I8(r))) => {
1456                Some(Value::I8(l.$method(*r as u32)))
1457            }
1458            (Some(Value::U16(l)), Some(Value::U16(r))) => {
1459                Some(Value::U16(l.$method(*r as u32)))
1460            }
1461            (Some(Value::I16(l)), Some(Value::I16(r))) => {
1462                Some(Value::I16(l.$method(*r as u32)))
1463            }
1464            (Some(Value::U32(l)), Some(Value::U32(r))) => {
1465                Some(Value::U32(l.$method(*r as u32)))
1466            }
1467            (Some(Value::V32(l)), Some(Value::V32(r))) => {
1468                Some(Value::V32(l.$method(*r as u32)))
1469            }
1470            (Some(Value::I32(l)), Some(Value::I32(r))) => {
1471                Some(Value::I32(l.$method(*r as u32)))
1472            }
1473            (Some(Value::Z32(l)), Some(Value::Z32(r))) => {
1474                Some(Value::Z32(l.$method(*r as u32)))
1475            }
1476            (Some(Value::U64(l)), Some(Value::U64(r))) => {
1477                Some(Value::U64(l.$method(*r as u32)))
1478            }
1479            (Some(Value::V64(l)), Some(Value::V64(r))) => {
1480                Some(Value::V64(l.$method(*r as u32)))
1481            }
1482            (Some(Value::I64(l)), Some(Value::I64(r))) => {
1483                Some(Value::I64(l.$method(*r as u32)))
1484            }
1485            (Some(Value::Z64(l)), Some(Value::Z64(r))) => {
1486                Some(Value::Z64(l.$method(*r as u32)))
1487            }
1488            _ => None,
1489        }
1490    };
1491}
1492
1493#[derive(Debug, Default)]
1494struct BitAndEv;
1495
1496impl<R: Rt, E: UserEvent> EvalCached<R, E> for BitAndEv {
1497    const NAME: &str = "core_bit_and";
1498    const NEEDS_CALLSITE: bool = false;
1499
1500    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
1501        int_binop!(from, &)
1502    }
1503}
1504
1505type BitAnd = CachedArgs<BitAndEv>;
1506
1507#[derive(Debug, Default)]
1508struct BitOrEv;
1509
1510impl<R: Rt, E: UserEvent> EvalCached<R, E> for BitOrEv {
1511    const NAME: &str = "core_bit_or";
1512    const NEEDS_CALLSITE: bool = false;
1513
1514    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
1515        int_binop!(from, |)
1516    }
1517}
1518
1519type BitOr = CachedArgs<BitOrEv>;
1520
1521#[derive(Debug, Default)]
1522struct BitXorEv;
1523
1524impl<R: Rt, E: UserEvent> EvalCached<R, E> for BitXorEv {
1525    const NAME: &str = "core_bit_xor";
1526    const NEEDS_CALLSITE: bool = false;
1527
1528    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
1529        int_binop!(from, ^)
1530    }
1531}
1532
1533type BitXor = CachedArgs<BitXorEv>;
1534
1535#[derive(Debug, Default)]
1536struct BitNotEv;
1537
1538impl<R: Rt, E: UserEvent> EvalCached<R, E> for BitNotEv {
1539    const NAME: &str = "core_bit_not";
1540    const NEEDS_CALLSITE: bool = false;
1541
1542    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
1543        match &from.0[0] {
1544            Some(Value::U8(v)) => Some(Value::U8(!v)),
1545            Some(Value::I8(v)) => Some(Value::I8(!v)),
1546            Some(Value::U16(v)) => Some(Value::U16(!v)),
1547            Some(Value::I16(v)) => Some(Value::I16(!v)),
1548            Some(Value::U32(v)) => Some(Value::U32(!v)),
1549            Some(Value::V32(v)) => Some(Value::V32(!v)),
1550            Some(Value::I32(v)) => Some(Value::I32(!v)),
1551            Some(Value::Z32(v)) => Some(Value::Z32(!v)),
1552            Some(Value::U64(v)) => Some(Value::U64(!v)),
1553            Some(Value::V64(v)) => Some(Value::V64(!v)),
1554            Some(Value::I64(v)) => Some(Value::I64(!v)),
1555            Some(Value::Z64(v)) => Some(Value::Z64(!v)),
1556            _ => None,
1557        }
1558    }
1559}
1560
1561type BitNot = CachedArgs<BitNotEv>;
1562
1563#[derive(Debug, Default)]
1564struct ShlEv;
1565
1566impl<R: Rt, E: UserEvent> EvalCached<R, E> for ShlEv {
1567    const NAME: &str = "core_shl";
1568    const NEEDS_CALLSITE: bool = false;
1569
1570    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
1571        int_shift!(from, wrapping_shl)
1572    }
1573}
1574
1575type Shl = CachedArgs<ShlEv>;
1576
1577#[derive(Debug, Default)]
1578struct ShrEv;
1579
1580impl<R: Rt, E: UserEvent> EvalCached<R, E> for ShrEv {
1581    const NAME: &str = "core_shr";
1582    const NEEDS_CALLSITE: bool = false;
1583
1584    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
1585        int_shift!(from, wrapping_shr)
1586    }
1587}
1588
1589type Shr = CachedArgs<ShrEv>;
1590
1591#[derive(Debug)]
1592struct Filter<R: Rt, E: UserEvent> {
1593    ready: bool,
1594    queue: VecDeque<Value>,
1595    pred: Node<R, E>,
1596    top_id: ExprId,
1597    fid: BindId,
1598    x: BindId,
1599    out: BindId,
1600}
1601
1602impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Filter<R, E> {
1603    const NAME: &str = "core_filter";
1604    const NEEDS_CALLSITE: bool = false;
1605
1606    fn init<'a, 'b, 'c, 'd>(
1607        ctx: &'a mut ExecCtx<R, E>,
1608        typ: &'a graphix_compiler::typ::FnType,
1609        resolved: Option<&'d FnType>,
1610        scope: &'b Scope,
1611        from: &'c [Node<R, E>],
1612        top_id: ExprId,
1613    ) -> Result<Box<dyn Apply<R, E>>> {
1614        match from {
1615            [_, _] => {
1616                let typ = resolved.unwrap_or(typ);
1617                let (x, xn) =
1618                    genn::bind(ctx, &scope.lexical, "x", typ.args[0].typ.clone(), top_id);
1619                let fid = BindId::new();
1620                let ptyp = match &typ.args[1].typ {
1621                    Type::Fn(ft) => ft.clone(),
1622                    t => bail!("expected a function not {t}"),
1623                };
1624                let fnode = genn::reference(ctx, fid, Type::Fn(ptyp.clone()), top_id);
1625                let pred = genn::apply(fnode, scope.clone(), vec![xn], &ptyp, top_id);
1626                let queue = VecDeque::new();
1627                let out = BindId::new();
1628                ctx.rt.ref_var(out, top_id);
1629                Ok(Box::new(Self { ready: true, queue, pred, fid, x, out, top_id }))
1630            }
1631            _ => bail!("expected two arguments"),
1632        }
1633    }
1634}
1635
1636impl<R: Rt, E: UserEvent> Apply<R, E> for Filter<R, E> {
1637    fn update(
1638        &mut self,
1639        ctx: &mut ExecCtx<R, E>,
1640        from: &mut [Node<R, E>],
1641        event: &mut Event<E>,
1642    ) -> Option<Value> {
1643        macro_rules! set {
1644            ($v:expr) => {{
1645                self.ready = false;
1646                ctx.cached.insert(self.x, $v.clone());
1647                event.variables.insert(self.x, $v);
1648            }};
1649        }
1650        macro_rules! maybe_cont {
1651            () => {{
1652                if let Some(v) = self.queue.front().cloned() {
1653                    set!(v);
1654                    continue;
1655                }
1656                break;
1657            }};
1658        }
1659        if let Some(v) = from[0].update(ctx, event) {
1660            self.queue.push_back(v);
1661        }
1662        if let Some(v) = from[1].update(ctx, event) {
1663            ctx.cached.insert(self.fid, v.clone());
1664            event.variables.insert(self.fid, v);
1665        }
1666        if self.ready && self.queue.len() > 0 {
1667            let v = self.queue.front().unwrap().clone();
1668            set!(v);
1669        }
1670        loop {
1671            match self.pred.update(ctx, event) {
1672                None => break,
1673                Some(v) => {
1674                    self.ready = true;
1675                    match v {
1676                        Value::Bool(true) => {
1677                            ctx.rt.set_var(self.out, self.queue.pop_front().unwrap());
1678                            maybe_cont!();
1679                        }
1680                        _ => {
1681                            let _ = self.queue.pop_front();
1682                            maybe_cont!();
1683                        }
1684                    }
1685                }
1686            }
1687        }
1688        event.variables.get(&self.out).map(|v| v.clone())
1689    }
1690
1691    fn typecheck(
1692        &mut self,
1693        ctx: &mut ExecCtx<R, E>,
1694        _from: &mut [Node<R, E>],
1695        _phase: TypecheckPhase<'_>,
1696    ) -> anyhow::Result<()> {
1697        self.pred.typecheck(ctx)?;
1698        Ok(())
1699    }
1700
1701    fn refs(&self, refs: &mut Refs) {
1702        self.pred.refs(refs)
1703    }
1704
1705    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
1706        ctx.cached.remove(&self.fid);
1707        ctx.cached.remove(&self.out);
1708        ctx.cached.remove(&self.x);
1709        ctx.env.unbind_variable(self.x);
1710        self.pred.delete(ctx);
1711        ctx.rt.unref_var(self.out, self.top_id)
1712    }
1713
1714    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
1715        ctx.rt.unref_var(self.out, self.top_id);
1716        self.out = BindId::new();
1717        ctx.rt.ref_var(self.out, self.top_id);
1718        self.queue.clear();
1719        self.pred.sleep(ctx);
1720    }
1721}
1722
1723#[derive(Debug)]
1724struct Queue {
1725    triggered: usize,
1726    queue: VecDeque<Value>,
1727    id: BindId,
1728    top_id: ExprId,
1729}
1730
1731impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Queue {
1732    const NAME: &str = "core_queue";
1733    const NEEDS_CALLSITE: bool = false;
1734
1735    fn init<'a, 'b, 'c, 'd>(
1736        ctx: &'a mut ExecCtx<R, E>,
1737        _typ: &'a FnType,
1738        _resolved: Option<&'d FnType>,
1739        _scope: &'b Scope,
1740        from: &'c [Node<R, E>],
1741        top_id: ExprId,
1742    ) -> Result<Box<dyn Apply<R, E>>> {
1743        match from {
1744            [_, _] => {
1745                let id = BindId::new();
1746                ctx.rt.ref_var(id, top_id);
1747                Ok(Box::new(Self { triggered: 0, queue: VecDeque::new(), id, top_id }))
1748            }
1749            _ => bail!("expected two arguments"),
1750        }
1751    }
1752}
1753
1754impl<R: Rt, E: UserEvent> Apply<R, E> for Queue {
1755    fn update(
1756        &mut self,
1757        ctx: &mut ExecCtx<R, E>,
1758        from: &mut [Node<R, E>],
1759        event: &mut Event<E>,
1760    ) -> Option<Value> {
1761        if from[0].update(ctx, event).is_some() {
1762            self.triggered += 1;
1763        }
1764        if let Some(v) = from[1].update(ctx, event) {
1765            self.queue.push_back(v);
1766        }
1767        while self.triggered > 0 && self.queue.len() > 0 {
1768            self.triggered -= 1;
1769            ctx.rt.set_var(self.id, self.queue.pop_front().unwrap());
1770        }
1771        event.variables.get(&self.id).cloned()
1772    }
1773
1774    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
1775        ctx.rt.unref_var(self.id, self.top_id);
1776    }
1777
1778    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
1779        ctx.rt.unref_var(self.id, self.top_id);
1780        self.id = BindId::new();
1781        ctx.rt.ref_var(self.id, self.top_id);
1782        self.triggered = 0;
1783        self.queue.clear();
1784    }
1785}
1786
1787#[derive(Debug)]
1788struct Hold {
1789    triggered: usize,
1790    current: Option<Value>,
1791}
1792
1793impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Hold {
1794    const NAME: &str = "core_hold";
1795    const NEEDS_CALLSITE: bool = false;
1796
1797    fn init<'a, 'b, 'c, 'd>(
1798        _ctx: &'a mut ExecCtx<R, E>,
1799        _typ: &'a FnType,
1800        _resolved: Option<&'d FnType>,
1801        _scope: &'b Scope,
1802        from: &'c [Node<R, E>],
1803        _top_id: ExprId,
1804    ) -> Result<Box<dyn Apply<R, E>>> {
1805        match from {
1806            [_, _] => Ok(Box::new(Self { triggered: 0, current: None })),
1807            _ => bail!("expected two arguments"),
1808        }
1809    }
1810}
1811
1812impl<R: Rt, E: UserEvent> Apply<R, E> for Hold {
1813    fn update(
1814        &mut self,
1815        ctx: &mut ExecCtx<R, E>,
1816        from: &mut [Node<R, E>],
1817        event: &mut Event<E>,
1818    ) -> Option<Value> {
1819        if from[0].update(ctx, event).is_some() {
1820            self.triggered += 1;
1821        }
1822        if let Some(v) = from[1].update(ctx, event) {
1823            self.current = Some(v);
1824        }
1825        if self.triggered > 0
1826            && let Some(v) = self.current.take()
1827        {
1828            self.triggered -= 1;
1829            Some(v)
1830        } else {
1831            None
1832        }
1833    }
1834
1835    fn delete(&mut self, _: &mut ExecCtx<R, E>) {}
1836
1837    fn sleep(&mut self, _: &mut ExecCtx<R, E>) {
1838        self.triggered = 0;
1839        self.current = None;
1840    }
1841}
1842
1843#[derive(Debug)]
1844struct Seq {
1845    id: BindId,
1846    top_id: ExprId,
1847    args: CachedVals,
1848}
1849
1850impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Seq {
1851    const NAME: &str = "core_seq";
1852    const NEEDS_CALLSITE: bool = false;
1853
1854    fn init<'a, 'b, 'c, 'd>(
1855        ctx: &'a mut ExecCtx<R, E>,
1856        _typ: &'a FnType,
1857        _resolved: Option<&'d FnType>,
1858        _scope: &'b Scope,
1859        from: &'c [Node<R, E>],
1860        top_id: ExprId,
1861    ) -> Result<Box<dyn Apply<R, E>>> {
1862        let id = BindId::new();
1863        ctx.rt.ref_var(id, top_id);
1864        let args = CachedVals::new(from);
1865        Ok(Box::new(Self { id, top_id, args }))
1866    }
1867}
1868
1869impl<R: Rt, E: UserEvent> Apply<R, E> for Seq {
1870    fn update(
1871        &mut self,
1872        ctx: &mut ExecCtx<R, E>,
1873        from: &mut [Node<R, E>],
1874        event: &mut Event<E>,
1875    ) -> Option<Value> {
1876        if self.args.update(ctx, from, event) {
1877            match &self.args.0[..] {
1878                [Some(Value::I64(i)), Some(Value::I64(j))] if i <= j => {
1879                    for v in *i..*j {
1880                        ctx.rt.set_var(self.id, Value::I64(v));
1881                    }
1882                }
1883                _ => {
1884                    let e = literal!("SeqError");
1885                    return Some(err!(e, "invalid args i must be <= j"));
1886                }
1887            }
1888        }
1889        event.variables.get(&self.id).cloned()
1890    }
1891
1892    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
1893        ctx.rt.unref_var(self.id, self.top_id);
1894    }
1895
1896    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
1897        ctx.rt.unref_var(self.id, self.top_id);
1898        self.id = BindId::new();
1899        ctx.rt.ref_var(self.id, self.top_id);
1900    }
1901}
1902
1903#[derive(Debug)]
1904struct Throttle {
1905    wait: Duration,
1906    last: Option<Instant>,
1907    tid: Option<BindId>,
1908    top_id: ExprId,
1909    args: CachedVals,
1910}
1911
1912impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Throttle {
1913    const NAME: &str = "core_throttle";
1914    const NEEDS_CALLSITE: bool = false;
1915
1916    fn init<'a, 'b, 'c, 'd>(
1917        _ctx: &'a mut ExecCtx<R, E>,
1918        _typ: &'a FnType,
1919        _resolved: Option<&'d FnType>,
1920        _scope: &'b Scope,
1921        from: &'c [Node<R, E>],
1922        top_id: ExprId,
1923    ) -> Result<Box<dyn Apply<R, E>>> {
1924        let args = CachedVals::new(from);
1925        Ok(Box::new(Self { wait: Duration::ZERO, last: None, tid: None, top_id, args }))
1926    }
1927}
1928
1929impl<R: Rt, E: UserEvent> Apply<R, E> for Throttle {
1930    fn update(
1931        &mut self,
1932        ctx: &mut ExecCtx<R, E>,
1933        from: &mut [Node<R, E>],
1934        event: &mut Event<E>,
1935    ) -> Option<Value> {
1936        macro_rules! maybe_schedule {
1937            ($last:expr) => {{
1938                let now = Instant::now();
1939                if now - *$last >= self.wait {
1940                    *$last = now;
1941                    return self.args.0[1].clone();
1942                } else {
1943                    let id = BindId::new();
1944                    ctx.rt.ref_var(id, self.top_id);
1945                    ctx.rt.set_timer(id, self.wait - (now - *$last));
1946                    self.tid = Some(id);
1947                    return None;
1948                }
1949            }};
1950        }
1951        let mut up = [false; 2];
1952        self.args.update_diff(&mut up, ctx, from, event);
1953        if up[0]
1954            && let Some(Value::Duration(d)) = &self.args.0[0]
1955        {
1956            self.wait = **d;
1957            if let Some(id) = self.tid.take()
1958                && let Some(last) = &mut self.last
1959            {
1960                ctx.rt.unref_var(id, self.top_id);
1961                maybe_schedule!(last)
1962            }
1963        }
1964        if up[1] && self.tid.is_none() {
1965            match &mut self.last {
1966                Some(last) => maybe_schedule!(last),
1967                None => {
1968                    self.last = Some(Instant::now());
1969                    return self.args.0[1].clone();
1970                }
1971            }
1972        }
1973        if let Some(id) = self.tid
1974            && let Some(_) = event.variables.get(&id)
1975        {
1976            ctx.rt.unref_var(id, self.top_id);
1977            self.tid = None;
1978            self.last = Some(Instant::now());
1979            return self.args.0[1].clone();
1980        }
1981        None
1982    }
1983
1984    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
1985        if let Some(id) = self.tid.take() {
1986            ctx.rt.unref_var(id, self.top_id);
1987        }
1988    }
1989
1990    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
1991        self.delete(ctx);
1992        self.last = None;
1993        self.wait = Duration::ZERO;
1994        self.args.clear();
1995    }
1996}
1997
1998#[derive(Debug)]
1999struct Count {
2000    count: i64,
2001}
2002
2003impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Count {
2004    const NAME: &str = "core_count";
2005    const NEEDS_CALLSITE: bool = false;
2006
2007    fn init<'a, 'b, 'c, 'd>(
2008        _ctx: &'a mut ExecCtx<R, E>,
2009        _typ: &'a FnType,
2010        _resolved: Option<&'d FnType>,
2011        _scope: &'b Scope,
2012        _from: &'c [Node<R, E>],
2013        _top_id: ExprId,
2014    ) -> Result<Box<dyn Apply<R, E>>> {
2015        Ok(Box::new(Count { count: 0 }))
2016    }
2017}
2018
2019impl<R: Rt, E: UserEvent> Apply<R, E> for Count {
2020    fn update(
2021        &mut self,
2022        ctx: &mut ExecCtx<R, E>,
2023        from: &mut [Node<R, E>],
2024        event: &mut Event<E>,
2025    ) -> Option<Value> {
2026        if from.into_iter().fold(false, |u, n| u || n.update(ctx, event).is_some()) {
2027            self.count += 1;
2028            Some(Value::I64(self.count))
2029        } else {
2030            None
2031        }
2032    }
2033
2034    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {
2035        self.count = 0
2036    }
2037}
2038
2039#[derive(Debug, Default)]
2040struct MeanEv;
2041
2042impl<R: Rt, E: UserEvent> EvalCached<R, E> for MeanEv {
2043    const NAME: &str = "core_mean";
2044    const NEEDS_CALLSITE: bool = false;
2045
2046    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
2047        static TAG: ArcStr = literal!("MeanError");
2048        let mut total = 0.;
2049        let mut samples = 0;
2050        let mut error = None;
2051        for v in from.flat_iter() {
2052            if let Some(v) = v {
2053                match v.cast_to::<f64>() {
2054                    Err(e) => error = Some(errf!(TAG, "{e:?}")),
2055                    Ok(v) => {
2056                        total += v;
2057                        samples += 1;
2058                    }
2059                }
2060            }
2061        }
2062        if let Some(e) = error {
2063            Some(e)
2064        } else if samples == 0 {
2065            Some(err!(TAG, "mean requires at least one argument"))
2066        } else {
2067            Some(Value::F64(total / samples as f64))
2068        }
2069    }
2070}
2071
2072type Mean = CachedArgs<MeanEv>;
2073
2074#[derive(Debug)]
2075struct Uniq(Option<Value>);
2076
2077impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Uniq {
2078    const NAME: &str = "core_uniq";
2079    const NEEDS_CALLSITE: bool = false;
2080
2081    fn init<'a, 'b, 'c, 'd>(
2082        _ctx: &'a mut ExecCtx<R, E>,
2083        _typ: &'a FnType,
2084        _resolved: Option<&'d FnType>,
2085        _scope: &'b Scope,
2086        _from: &'c [Node<R, E>],
2087        _top_id: ExprId,
2088    ) -> Result<Box<dyn Apply<R, E>>> {
2089        Ok(Box::new(Uniq(None)))
2090    }
2091}
2092
2093impl<R: Rt, E: UserEvent> Apply<R, E> for Uniq {
2094    fn update(
2095        &mut self,
2096        ctx: &mut ExecCtx<R, E>,
2097        from: &mut [Node<R, E>],
2098        event: &mut Event<E>,
2099    ) -> Option<Value> {
2100        from[0].update(ctx, event).and_then(|v| {
2101            if Some(&v) != self.0.as_ref() {
2102                self.0 = Some(v.clone());
2103                Some(v)
2104            } else {
2105                None
2106            }
2107        })
2108    }
2109
2110    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {
2111        self.0 = None
2112    }
2113}
2114
2115#[derive(Debug)]
2116struct Never;
2117
2118impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Never {
2119    const NAME: &str = "core_never";
2120    const NEEDS_CALLSITE: bool = false;
2121
2122    fn init<'a, 'b, 'c, 'd>(
2123        _ctx: &'a mut ExecCtx<R, E>,
2124        _typ: &'a FnType,
2125        _resolved: Option<&'d FnType>,
2126        _scope: &'b Scope,
2127        _from: &'c [Node<R, E>],
2128        _top_id: ExprId,
2129    ) -> Result<Box<dyn Apply<R, E>>> {
2130        Ok(Box::new(Never))
2131    }
2132}
2133
2134impl<R: Rt, E: UserEvent> Apply<R, E> for Never {
2135    fn update(
2136        &mut self,
2137        ctx: &mut ExecCtx<R, E>,
2138        from: &mut [Node<R, E>],
2139        event: &mut Event<E>,
2140    ) -> Option<Value> {
2141        for n in from {
2142            n.update(ctx, event);
2143        }
2144        None
2145    }
2146
2147    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {}
2148}
2149
2150#[derive(Debug, Clone, Copy)]
2151enum Level {
2152    Trace,
2153    Debug,
2154    Info,
2155    Warn,
2156    Error,
2157}
2158
2159impl FromValue for Level {
2160    fn from_value(v: Value) -> Result<Self> {
2161        match &*v.cast_to::<ArcStr>()? {
2162            "Trace" => Ok(Self::Trace),
2163            "Debug" => Ok(Self::Debug),
2164            "Info" => Ok(Self::Info),
2165            "Warn" => Ok(Self::Warn),
2166            "Error" => Ok(Self::Error),
2167            v => bail!("invalid log level {v}"),
2168        }
2169    }
2170}
2171
2172#[derive(Debug, Clone, Copy)]
2173enum LogDest {
2174    Stdout,
2175    Stderr,
2176    Log(Level),
2177}
2178
2179impl FromValue for LogDest {
2180    fn from_value(v: Value) -> Result<Self> {
2181        match &*v.clone().cast_to::<ArcStr>()? {
2182            "Stdout" => Ok(Self::Stdout),
2183            "Stderr" => Ok(Self::Stderr),
2184            _ => Ok(Self::Log(v.cast_to()?)),
2185        }
2186    }
2187}
2188
2189#[derive(Debug)]
2190struct Dbg {
2191    spec: Expr,
2192    dest: LogDest,
2193    typ: Type,
2194}
2195
2196impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Dbg {
2197    const NAME: &str = "core_dbg";
2198    const NEEDS_CALLSITE: bool = false;
2199
2200    fn init<'a, 'b, 'c, 'd>(
2201        _ctx: &'a mut ExecCtx<R, E>,
2202        _typ: &'a graphix_compiler::typ::FnType,
2203        _resolved: Option<&'d FnType>,
2204        _scope: &'b Scope,
2205        from: &'c [Node<R, E>],
2206        _top_id: ExprId,
2207    ) -> Result<Box<dyn Apply<R, E>>> {
2208        Ok(Box::new(Dbg {
2209            spec: from[1].spec().clone(),
2210            dest: LogDest::Stderr,
2211            typ: Type::Bottom,
2212        }))
2213    }
2214}
2215
2216impl<R: Rt, E: UserEvent> Apply<R, E> for Dbg {
2217    fn update(
2218        &mut self,
2219        ctx: &mut ExecCtx<R, E>,
2220        from: &mut [Node<R, E>],
2221        event: &mut Event<E>,
2222    ) -> Option<Value> {
2223        if let Some(v) = from[0].update(ctx, event)
2224            && let Ok(d) = v.cast_to::<LogDest>()
2225        {
2226            self.dest = d;
2227        }
2228        from[1].update(ctx, event).map(|v| {
2229            let tv = TVal { env: &ctx.env, typ: &self.typ, v: &v };
2230            match self.dest {
2231                LogDest::Stderr => {
2232                    eprintln!("{} dbg({}): {}", self.spec.pos, self.spec, tv)
2233                }
2234                LogDest::Stdout => {
2235                    println!("{} dbg({}): {}", self.spec.pos, self.spec, tv)
2236                }
2237                LogDest::Log(level) => match level {
2238                    Level::Trace => {
2239                        log::trace!("{} dbg({}): {}", self.spec.pos, self.spec, tv)
2240                    }
2241                    Level::Debug => {
2242                        log::debug!("{} dbg({}): {}", self.spec.pos, self.spec, tv)
2243                    }
2244                    Level::Info => {
2245                        log::info!("{} dbg({}): {}", self.spec.pos, self.spec, tv)
2246                    }
2247                    Level::Warn => {
2248                        log::warn!("{} dbg({}): {}", self.spec.pos, self.spec, tv)
2249                    }
2250                    Level::Error => {
2251                        log::error!("{} dbg({}): {}", self.spec.pos, self.spec, tv)
2252                    }
2253                },
2254            };
2255            v
2256        })
2257    }
2258
2259    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {}
2260
2261    fn typecheck(
2262        &mut self,
2263        _ctx: &mut ExecCtx<R, E>,
2264        from: &mut [Node<R, E>],
2265        _phase: TypecheckPhase<'_>,
2266    ) -> Result<()> {
2267        self.typ = from[1].typ().clone();
2268        Ok(())
2269    }
2270}
2271
2272#[derive(Debug)]
2273struct Log {
2274    scope: Scope,
2275    dest: LogDest,
2276}
2277
2278impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Log {
2279    const NAME: &str = "core_log";
2280    const NEEDS_CALLSITE: bool = false;
2281
2282    fn init<'a, 'b, 'c, 'd>(
2283        _ctx: &'a mut ExecCtx<R, E>,
2284        _typ: &'a graphix_compiler::typ::FnType,
2285        _resolved: Option<&'d FnType>,
2286        scope: &'b Scope,
2287        _from: &'c [Node<R, E>],
2288        _top_id: ExprId,
2289    ) -> Result<Box<dyn Apply<R, E>>> {
2290        Ok(Box::new(Self { scope: scope.clone(), dest: LogDest::Stdout }))
2291    }
2292}
2293
2294impl<R: Rt, E: UserEvent> Apply<R, E> for Log {
2295    fn update(
2296        &mut self,
2297        ctx: &mut ExecCtx<R, E>,
2298        from: &mut [Node<R, E>],
2299        event: &mut Event<E>,
2300    ) -> Option<Value> {
2301        if let Some(v) = from[0].update(ctx, event)
2302            && let Ok(d) = v.cast_to::<LogDest>()
2303        {
2304            self.dest = d;
2305        }
2306        if let Some(v) = from[1].update(ctx, event) {
2307            let tv = TVal { env: &ctx.env, typ: from[1].typ(), v: &v };
2308            match self.dest {
2309                LogDest::Stdout => println!("{}: {}", self.scope.lexical, tv),
2310                LogDest::Stderr => eprintln!("{}: {}", self.scope.lexical, tv),
2311                LogDest::Log(lvl) => match lvl {
2312                    Level::Trace => log::trace!("{}: {}", self.scope.lexical, tv),
2313                    Level::Debug => log::debug!("{}: {}", self.scope.lexical, tv),
2314                    Level::Info => log::info!("{}: {}", self.scope.lexical, tv),
2315                    Level::Warn => log::warn!("{}: {}", self.scope.lexical, tv),
2316                    Level::Error => log::error!("{}: {}", self.scope.lexical, tv),
2317                },
2318            }
2319        }
2320        None
2321    }
2322
2323    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {}
2324}
2325
2326macro_rules! printfn {
2327    ($type:ident, $name:literal, $print:ident, $eprint:ident) => {
2328        #[derive(Debug)]
2329        struct $type {
2330            dest: LogDest,
2331            buf: String,
2332        }
2333
2334        impl<R: Rt, E: UserEvent> BuiltIn<R, E> for $type {
2335            const NAME: &str = $name;
2336            const NEEDS_CALLSITE: bool = false;
2337
2338            fn init<'a, 'b, 'c, 'd>(
2339                _ctx: &'a mut ExecCtx<R, E>,
2340                _typ: &'a graphix_compiler::typ::FnType,
2341                _resolved: Option<&'d FnType>,
2342                _scope: &'b Scope,
2343                _from: &'c [Node<R, E>],
2344                _top_id: ExprId,
2345            ) -> Result<Box<dyn Apply<R, E>>> {
2346                Ok(Box::new(Self { dest: LogDest::Stdout, buf: String::new() }))
2347            }
2348        }
2349
2350        impl<R: Rt, E: UserEvent> Apply<R, E> for $type {
2351            fn update(
2352                &mut self,
2353                ctx: &mut ExecCtx<R, E>,
2354                from: &mut [Node<R, E>],
2355                event: &mut Event<E>,
2356            ) -> Option<Value> {
2357                use std::fmt::Write;
2358                if let Some(v) = from[0].update(ctx, event)
2359                    && let Ok(d) = v.cast_to::<LogDest>()
2360                {
2361                    self.dest = d;
2362                }
2363                if let Some(v) = from[1].update(ctx, event) {
2364                    self.buf.clear();
2365                    match v {
2366                        Value::String(s) => write!(self.buf, "{s}"),
2367                        v => write!(
2368                            self.buf,
2369                            "{}",
2370                            TVal { env: &ctx.env, typ: &from[1].typ(), v: &v }
2371                        ),
2372                    }
2373                    .unwrap();
2374                    match self.dest {
2375                        LogDest::Stdout => $print!("{}", self.buf),
2376                        LogDest::Stderr => $eprint!("{}", self.buf),
2377                        LogDest::Log(lvl) => match lvl {
2378                            Level::Trace => log::trace!("{}", self.buf),
2379                            Level::Debug => log::debug!("{}", self.buf),
2380                            Level::Info => log::info!("{}", self.buf),
2381                            Level::Warn => log::warn!("{}", self.buf),
2382                            Level::Error => log::error!("{}", self.buf),
2383                        },
2384                    }
2385                }
2386                None
2387            }
2388
2389            fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {}
2390        }
2391    };
2392}
2393
2394printfn!(Print, "core_print", print, eprint);
2395printfn!(Println, "core_println", println, eprintln);
2396
2397// ── Package registration ───────────────────────────────────────────
2398
2399graphix_derive::defpackage! {
2400    builtins => [
2401        IsErr,
2402        FilterErr,
2403        ToError,
2404        Once,
2405        Take,
2406        Skip,
2407        All,
2408        Sum,
2409        Product,
2410        Divide,
2411        Min,
2412        Max,
2413        And,
2414        Or,
2415        BitAnd,
2416        BitOr,
2417        BitXor,
2418        BitNot,
2419        Shl,
2420        Shr,
2421        Filter as Filter<GXRt<X>, X::UserEvent>,
2422        Queue,
2423        Hold,
2424        Seq,
2425        Throttle,
2426        Count,
2427        Mean,
2428        Uniq,
2429        Never,
2430        Dbg,
2431        Log,
2432        Print,
2433        Println,
2434        buffer::BytesToString,
2435        buffer::BytesToStringLossy,
2436        buffer::BytesFromString,
2437        buffer::BytesConcat,
2438        buffer::BytesToArray,
2439        buffer::BytesFromArray,
2440        buffer::BytesLen,
2441        buffer::BufferEncode,
2442        buffer::BufferDecode,
2443    ],
2444}