use crate::{
typ::FnType, Apply, BuiltIn, BuiltInInitFn, Ctx, Event, ExecCtx, Node, UserEvent,
};
use netidx::subscriber::Value;
use netidx_core::utils::Either;
use std::{
fmt::Debug,
iter,
sync::{Arc, LazyLock},
};
pub mod core;
pub mod net;
pub mod rand;
pub mod re;
pub mod str;
#[cfg(test)]
mod test;
pub mod time;
#[macro_export]
macro_rules! deftype {
($scope:literal, $s:literal) => {
const TYP: ::std::sync::LazyLock<$crate::typ::FnType> =
::std::sync::LazyLock::new(|| {
let scope = $crate::expr::ModPath(::netidx::path::Path::from($scope));
$crate::expr::parser::parse_fn_type($s)
.expect("failed to parse fn type {s}")
.scope_refs(&scope)
});
};
}
#[macro_export]
macro_rules! arity1 {
($from:expr, $updates:expr) => {
match (&*$from, &*$updates) {
([arg], [arg_up]) => (arg, arg_up),
(_, _) => unreachable!(),
}
};
}
#[macro_export]
macro_rules! arity2 {
($from:expr, $updates:expr) => {
match (&*$from, &*$updates) {
([arg0, arg1], [arg0_up, arg1_up]) => ((arg0, arg1), (arg0_up, arg1_up)),
(_, _) => unreachable!(),
}
};
}
#[derive(Debug)]
pub struct CachedVals(pub Box<[Option<Value>]>);
impl CachedVals {
pub fn new<C: Ctx, E: UserEvent>(from: &[Node<C, E>]) -> CachedVals {
CachedVals(from.into_iter().map(|_| None).collect())
}
pub fn update<C: Ctx, E: UserEvent>(
&mut self,
ctx: &mut ExecCtx<C, E>,
from: &mut [Node<C, E>],
event: &mut Event<E>,
) -> bool {
from.into_iter().enumerate().fold(false, |res, (i, src)| {
match src.update(ctx, event) {
None => res,
v @ Some(_) => {
self.0[i] = v;
true
}
}
})
}
pub fn update_diff<C: Ctx, E: UserEvent>(
&mut self,
up: &mut [bool],
ctx: &mut ExecCtx<C, E>,
from: &mut [Node<C, E>],
event: &mut Event<E>,
) {
for (i, n) in from.iter_mut().enumerate() {
match n.update(ctx, event) {
None => (),
v => {
self.0[i] = v;
up[i] = true
}
}
}
}
pub fn flat_iter<'a>(&'a self) -> impl Iterator<Item = Option<Value>> + 'a {
self.0.iter().flat_map(|v| match v {
None => Either::Left(iter::once(None)),
Some(v) => Either::Right(v.clone().flatten().map(Some)),
})
}
}
pub trait EvalCached: Debug + Default + Send + Sync + 'static {
const NAME: &str;
const TYP: LazyLock<FnType>;
fn eval(&mut self, from: &CachedVals) -> Option<Value>;
}
#[derive(Debug)]
pub struct CachedArgs<T: EvalCached> {
cached: CachedVals,
t: T,
}
impl<C: Ctx, E: UserEvent, T: EvalCached> BuiltIn<C, E> for CachedArgs<T> {
const NAME: &str = T::NAME;
const TYP: LazyLock<FnType> = T::TYP;
fn init(_: &mut ExecCtx<C, E>) -> BuiltInInitFn<C, E> {
Arc::new(|_, _, _, from, _| {
let t = CachedArgs::<T> { cached: CachedVals::new(from), t: T::default() };
Ok(Box::new(t))
})
}
}
impl<C: Ctx, E: UserEvent, T: EvalCached> Apply<C, E> for CachedArgs<T> {
fn update(
&mut self,
ctx: &mut ExecCtx<C, E>,
from: &mut [Node<C, E>],
event: &mut Event<E>,
) -> Option<Value> {
if self.cached.update(ctx, from, event) {
self.t.eval(&self.cached)
} else {
None
}
}
}