netidx_bscript/stdfn/
mod.rs

1use crate::{
2    typ::FnType, Apply, BuiltIn, BuiltInInitFn, Ctx, Event, ExecCtx, Node, UserEvent,
3};
4use netidx::subscriber::Value;
5use netidx_core::utils::Either;
6use std::{
7    fmt::Debug,
8    iter,
9    sync::{Arc, LazyLock},
10};
11
12pub mod core;
13pub mod net;
14pub mod rand;
15pub mod re;
16pub mod str;
17#[cfg(test)]
18mod test;
19pub mod time;
20
21#[macro_export]
22macro_rules! deftype {
23    ($scope:literal, $s:literal) => {
24        const TYP: ::std::sync::LazyLock<$crate::typ::FnType> =
25            ::std::sync::LazyLock::new(|| {
26                let scope = $crate::expr::ModPath(::netidx::path::Path::from($scope));
27                $crate::expr::parser::parse_fn_type($s)
28                    .expect("failed to parse fn type {s}")
29                    .scope_refs(&scope)
30            });
31    };
32}
33
34#[macro_export]
35macro_rules! arity1 {
36    ($from:expr, $updates:expr) => {
37        match (&*$from, &*$updates) {
38            ([arg], [arg_up]) => (arg, arg_up),
39            (_, _) => unreachable!(),
40        }
41    };
42}
43
44#[macro_export]
45macro_rules! arity2 {
46    ($from:expr, $updates:expr) => {
47        match (&*$from, &*$updates) {
48            ([arg0, arg1], [arg0_up, arg1_up]) => ((arg0, arg1), (arg0_up, arg1_up)),
49            (_, _) => unreachable!(),
50        }
51    };
52}
53
54#[derive(Debug)]
55pub struct CachedVals(pub Box<[Option<Value>]>);
56
57impl CachedVals {
58    pub fn new<C: Ctx, E: UserEvent>(from: &[Node<C, E>]) -> CachedVals {
59        CachedVals(from.into_iter().map(|_| None).collect())
60    }
61
62    pub fn update<C: Ctx, E: UserEvent>(
63        &mut self,
64        ctx: &mut ExecCtx<C, E>,
65        from: &mut [Node<C, E>],
66        event: &mut Event<E>,
67    ) -> bool {
68        from.into_iter().enumerate().fold(false, |res, (i, src)| {
69            match src.update(ctx, event) {
70                None => res,
71                v @ Some(_) => {
72                    self.0[i] = v;
73                    true
74                }
75            }
76        })
77    }
78
79    /// Like update, but return the indexes of the nodes that updated
80    /// instead of a consolidated bool
81    pub fn update_diff<C: Ctx, E: UserEvent>(
82        &mut self,
83        up: &mut [bool],
84        ctx: &mut ExecCtx<C, E>,
85        from: &mut [Node<C, E>],
86        event: &mut Event<E>,
87    ) {
88        for (i, n) in from.iter_mut().enumerate() {
89            match n.update(ctx, event) {
90                None => (),
91                v => {
92                    self.0[i] = v;
93                    up[i] = true
94                }
95            }
96        }
97    }
98
99    pub fn flat_iter<'a>(&'a self) -> impl Iterator<Item = Option<Value>> + 'a {
100        self.0.iter().flat_map(|v| match v {
101            None => Either::Left(iter::once(None)),
102            Some(v) => Either::Right(v.clone().flatten().map(Some)),
103        })
104    }
105}
106
107pub trait EvalCached: Debug + Default + Send + Sync + 'static {
108    const NAME: &str;
109    const TYP: LazyLock<FnType>;
110
111    fn eval(&mut self, from: &CachedVals) -> Option<Value>;
112}
113
114#[derive(Debug)]
115pub struct CachedArgs<T: EvalCached> {
116    cached: CachedVals,
117    t: T,
118}
119
120impl<C: Ctx, E: UserEvent, T: EvalCached> BuiltIn<C, E> for CachedArgs<T> {
121    const NAME: &str = T::NAME;
122    const TYP: LazyLock<FnType> = T::TYP;
123
124    fn init(_: &mut ExecCtx<C, E>) -> BuiltInInitFn<C, E> {
125        Arc::new(|_, _, _, from, _| {
126            let t = CachedArgs::<T> { cached: CachedVals::new(from), t: T::default() };
127            Ok(Box::new(t))
128        })
129    }
130}
131
132impl<C: Ctx, E: UserEvent, T: EvalCached> Apply<C, E> for CachedArgs<T> {
133    fn update(
134        &mut self,
135        ctx: &mut ExecCtx<C, E>,
136        from: &mut [Node<C, E>],
137        event: &mut Event<E>,
138    ) -> Option<Value> {
139        if self.cached.update(ctx, from, event) {
140            self.t.eval(&self.cached)
141        } else {
142            None
143        }
144    }
145}