1#[macro_use]
2extern crate netidx_core;
3#[macro_use]
4extern crate combine;
5#[macro_use]
6extern crate serde_derive;
7
8pub mod env;
9pub mod expr;
10pub mod node;
11pub mod rt;
12pub mod stdfn;
13pub mod typ;
14
15use crate::{
16 env::Env,
17 expr::{ExprId, ExprKind, ModPath},
18 node::Node,
19 typ::{FnType, NoRefs, Refs, Type},
20};
21use anyhow::{bail, Result};
22use arcstr::ArcStr;
23use fxhash::FxHashMap;
24use netidx::{
25 path::Path,
26 publisher::{Id, Val, WriteRequest},
27 subscriber::{self, Dval, SubId, UpdatesFlags, Value},
28};
29use netidx_protocols::rpc::server::{ArgSpec, RpcCall};
30use parking_lot::RwLock;
31use std::{
32 collections::{hash_map::Entry, HashMap},
33 fmt::Debug,
34 marker::PhantomData,
35 sync::{self, LazyLock},
36 time::Duration,
37};
38use triomphe::Arc;
39
40#[cfg(test)]
41#[macro_use]
42mod tests;
43
44atomic_id!(BindId);
45atomic_id!(LambdaId);
46
47#[macro_export]
48macro_rules! errf {
49 ($pat:expr, $($arg:expr),*) => {
50 Some(Value::Error(ArcStr::from(format_compact!($pat, $($arg),*).as_str())))
51 };
52 ($pat:expr) => { Some(Value::Error(ArcStr::from(format_compact!($pat).as_str()))) };
53}
54
55#[macro_export]
56macro_rules! err {
57 ($pat:literal) => {
58 Some(Value::Error(literal!($pat)))
59 };
60}
61
62pub trait UserEvent: Clone + Debug + 'static {
63 fn clear(&mut self);
64}
65
66#[derive(Debug, Clone)]
67pub struct NoUserEvent;
68
69impl UserEvent for NoUserEvent {
70 fn clear(&mut self) {}
71}
72
73#[derive(Debug)]
79pub struct Event<E: UserEvent> {
80 pub init: bool,
81 pub variables: FxHashMap<BindId, Value>,
82 pub netidx: FxHashMap<SubId, subscriber::Event>,
83 pub writes: FxHashMap<Id, WriteRequest>,
84 pub rpc_calls: FxHashMap<BindId, RpcCall>,
85 pub user: E,
86}
87
88impl<E: UserEvent> Event<E> {
89 pub fn new(user: E) -> Self {
90 Event {
91 init: false,
92 variables: HashMap::default(),
93 netidx: HashMap::default(),
94 writes: HashMap::default(),
95 rpc_calls: HashMap::default(),
96 user,
97 }
98 }
99
100 pub fn clear(&mut self) {
101 let Self { init, variables, netidx, rpc_calls, writes, user } = self;
102 *init = false;
103 variables.clear();
104 netidx.clear();
105 rpc_calls.clear();
106 writes.clear();
107 user.clear();
108 }
109}
110
111pub type BuiltInInitFn<C, E> = sync::Arc<
112 dyn for<'a, 'b, 'c> Fn(
113 &'a mut ExecCtx<C, E>,
114 &'a FnType<NoRefs>,
115 &'b ModPath,
116 &'c [Node<C, E>],
117 ExprId,
118 ) -> Result<Box<dyn Apply<C, E> + Send + Sync>>
119 + Send
120 + Sync,
121>;
122
123pub type InitFn<C, E> = sync::Arc<
124 dyn for<'a, 'b> Fn(
125 &'a mut ExecCtx<C, E>,
126 &'b [Node<C, E>],
127 ExprId,
128 ) -> Result<Box<dyn Apply<C, E> + Send + Sync>>
129 + Send
130 + Sync,
131>;
132
133pub trait Apply<C: Ctx, E: UserEvent> {
134 fn update(
135 &mut self,
136 ctx: &mut ExecCtx<C, E>,
137 from: &mut [Node<C, E>],
138 event: &mut Event<E>,
139 ) -> Option<Value>;
140
141 fn delete(&mut self, _ctx: &mut ExecCtx<C, E>) {
144 ()
145 }
146
147 fn typecheck(
150 &mut self,
151 _ctx: &mut ExecCtx<C, E>,
152 _from: &mut [Node<C, E>],
153 ) -> Result<()> {
154 Ok(())
155 }
156
157 fn typ(&self) -> Arc<FnType<NoRefs>> {
160 const EMPTY: LazyLock<Arc<FnType<NoRefs>>> = LazyLock::new(|| {
161 Arc::new(FnType {
162 args: Arc::from_iter([]),
163 constraints: Arc::new(RwLock::new(vec![])),
164 rtype: Type::Bottom(PhantomData),
165 vargs: None,
166 })
167 });
168 Arc::clone(&*EMPTY)
169 }
170
171 fn refs<'a>(&'a self, _f: &'a mut (dyn FnMut(BindId) + 'a)) {
176 ()
177 }
178}
179
180pub trait BuiltIn<C: Ctx, E: UserEvent> {
181 const NAME: &str;
182 const TYP: LazyLock<FnType<Refs>>;
183
184 fn init(ctx: &mut ExecCtx<C, E>) -> BuiltInInitFn<C, E>;
185}
186
187pub trait Ctx: Debug + 'static {
188 fn clear(&mut self);
189
190 fn subscribe(&mut self, flags: UpdatesFlags, path: Path, ref_by: ExprId) -> Dval;
194
195 fn unsubscribe(&mut self, path: Path, dv: Dval, ref_by: ExprId);
197
198 fn list(&mut self, id: BindId, path: Path);
203
204 fn list_table(&mut self, id: BindId, path: Path);
207
208 fn stop_list(&mut self, id: BindId);
211
212 fn publish(&mut self, path: Path, value: Value, ref_by: ExprId) -> Result<Val>;
216
217 fn update(&mut self, id: &Val, value: Value);
219
220 fn unpublish(&mut self, id: Val, ref_by: ExprId);
222
223 fn ref_var(&mut self, id: BindId, ref_by: ExprId);
233 fn unref_var(&mut self, id: BindId, ref_by: ExprId);
234
235 fn set_var(&mut self, id: BindId, value: Value);
247
248 fn call_rpc(&mut self, name: Path, args: Vec<(ArcStr, Value)>, id: BindId);
254
255 fn publish_rpc(
264 &mut self,
265 name: Path,
266 doc: Value,
267 spec: Vec<ArgSpec>,
268 id: BindId,
269 ) -> Result<()>;
270
271 fn unpublish_rpc(&mut self, name: Path);
273
274 fn set_timer(&mut self, id: BindId, timeout: Duration);
278}
279
280pub struct ExecCtx<C: Ctx, E: UserEvent> {
281 builtins: FxHashMap<&'static str, (FnType<Refs>, BuiltInInitFn<C, E>)>,
282 std: Vec<Node<C, E>>,
283 pub env: Env<C, E>,
284 pub cached: FxHashMap<BindId, Value>,
285 pub user: C,
286}
287
288impl<C: Ctx, E: UserEvent> ExecCtx<C, E> {
289 pub fn clear(&mut self) {
290 self.env.clear();
291 self.user.clear();
292 }
293
294 pub fn new_no_std(user: C) -> Self {
296 let mut t = ExecCtx {
297 env: Env::new(),
298 builtins: FxHashMap::default(),
299 std: vec![],
300 cached: HashMap::default(),
301 user,
302 };
303 let core = stdfn::core::register(&mut t);
304 let root = ModPath(Path::root());
305 let node = Node::compile(&mut t, &root, core).expect("error compiling core");
306 t.std.push(node);
307 let node = Node::compile(
308 &mut t,
309 &root,
310 ExprKind::Use { name: ModPath::from(["core"]) }.to_expr(Default::default()),
311 )
312 .expect("error compiling use core");
313 t.std.push(node);
314 t
315 }
316
317 pub fn new(user: C) -> Self {
319 let mut t = Self::new_no_std(user);
320 let root = ModPath(Path::root());
321 let net = stdfn::net::register(&mut t);
322 let node =
323 Node::compile(&mut t, &root, net).expect("failed to compile the net module");
324 t.std.push(node);
325 let str = stdfn::str::register(&mut t);
326 let node =
327 Node::compile(&mut t, &root, str).expect("failed to compile the str module");
328 t.std.push(node);
329 let re = stdfn::re::register(&mut t);
330 let node =
331 Node::compile(&mut t, &root, re).expect("failed to compile the re module");
332 t.std.push(node);
333 let time = stdfn::time::register(&mut t);
334 let node = Node::compile(&mut t, &root, time)
335 .expect("failed to compile the time module");
336 t.std.push(node);
337 let rand = stdfn::rand::register(&mut t);
338 let node =
339 Node::compile(&mut t, &root, rand).expect("failed to compile rand module");
340 t.std.push(node);
341 t
342 }
343
344 pub fn register_builtin<T: BuiltIn<C, E>>(&mut self) -> Result<()> {
345 let f = T::init(self);
346 match self.builtins.entry(T::NAME) {
347 Entry::Vacant(e) => {
348 e.insert((T::TYP.clone(), f));
349 }
350 Entry::Occupied(_) => bail!("builtin {} is already registered", T::NAME),
351 }
352 Ok(())
353 }
354
355 pub fn set_var(&mut self, id: BindId, v: Value) {
358 self.cached.insert(id, v.clone());
359 self.user.set_var(id, v)
360 }
361}