Skip to main content

graphix_package_map/
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 graphix_compiler::{
7    expr::ExprId,
8    node::genn,
9    typ::{FnType, Type},
10    Apply, BindId, BuiltIn, Event, ExecCtx, Node, Refs, Rt, Scope, TypecheckPhase,
11    UserEvent,
12};
13use graphix_package_core::{
14    CachedArgs, CachedVals, EvalCached, FoldFn, FoldQ, MapFn, MapQ, Slot,
15};
16use graphix_rt::GXRt;
17use immutable_chunkmap::map::Map as CMap;
18use netidx::subscriber::Value;
19use netidx_value::ValArray;
20use poolshark::local::LPooled;
21use std::collections::VecDeque;
22use std::fmt::Debug;
23
24#[derive(Debug, Default)]
25struct MapImpl;
26
27impl<R: Rt, E: UserEvent> MapFn<R, E> for MapImpl {
28    type Collection = CMap<Value, Value, 32>;
29
30    const NAME: &str = "map_map";
31
32    fn finish(&mut self, slots: &[Slot<R, E>], _: &Self::Collection) -> Option<Value> {
33        Some(Value::Map(CMap::from_iter(
34            slots
35                .iter()
36                .map(|s| s.cur.clone().unwrap().cast_to::<(Value, Value)>().unwrap()),
37        )))
38    }
39}
40
41type Map<R, E> = MapQ<R, E, MapImpl>;
42
43#[derive(Debug, Default)]
44struct FilterImpl;
45
46impl<R: Rt, E: UserEvent> MapFn<R, E> for FilterImpl {
47    type Collection = CMap<Value, Value, 32>;
48
49    const NAME: &str = "map_filter";
50
51    fn finish(
52        &mut self,
53        slots: &[Slot<R, E>],
54        m: &CMap<Value, Value, 32>,
55    ) -> Option<Value> {
56        Some(Value::Map(CMap::from_iter(slots.iter().zip(m.into_iter()).filter_map(
57            |(p, (k, v))| match p.cur {
58                Some(Value::Bool(true)) => Some((k.clone(), v.clone())),
59                _ => None,
60            },
61        ))))
62    }
63}
64
65type Filter<R, E> = MapQ<R, E, FilterImpl>;
66
67#[derive(Debug, Default)]
68struct FilterMapImpl;
69
70impl<R: Rt, E: UserEvent> MapFn<R, E> for FilterMapImpl {
71    type Collection = CMap<Value, Value, 32>;
72
73    const NAME: &str = "map_filter_map";
74
75    fn finish(
76        &mut self,
77        slots: &[Slot<R, E>],
78        _: &CMap<Value, Value, 32>,
79    ) -> Option<Value> {
80        Some(Value::Map(CMap::from_iter(slots.iter().filter_map(|s| {
81            match s.cur.as_ref().unwrap() {
82                Value::Null => None,
83                v => Some(v.clone().cast_to::<(Value, Value)>().unwrap()),
84            }
85        }))))
86    }
87}
88
89type FilterMap<R, E> = MapQ<R, E, FilterMapImpl>;
90
91#[derive(Debug)]
92struct FoldImpl;
93
94impl<R: Rt, E: UserEvent> FoldFn<R, E> for FoldImpl {
95    type Collection = CMap<Value, Value, 32>;
96
97    const NAME: &str = "map_fold";
98}
99
100type Fold<R, E> = FoldQ<R, E, FoldImpl>;
101
102#[derive(Debug, Default)]
103struct LenEv;
104
105impl<R: Rt, E: UserEvent> EvalCached<R, E> for LenEv {
106    const NAME: &str = "map_len";
107    const NEEDS_CALLSITE: bool = false;
108
109    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
110        match &from.0[0] {
111            Some(Value::Map(m)) => Some(Value::I64(m.len() as i64)),
112            Some(_) | None => None,
113        }
114    }
115}
116
117type Len = CachedArgs<LenEv>;
118
119#[derive(Debug, Default)]
120struct GetEv;
121
122impl<R: Rt, E: UserEvent> EvalCached<R, E> for GetEv {
123    const NAME: &str = "map_get";
124    const NEEDS_CALLSITE: bool = false;
125
126    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
127        match (&from.0[0], &from.0[1]) {
128            (Some(Value::Map(m)), Some(key)) => {
129                Some(m.get(key).cloned().unwrap_or(Value::Null))
130            }
131            _ => None,
132        }
133    }
134}
135
136type Get = CachedArgs<GetEv>;
137
138#[derive(Debug, Default)]
139struct GetOrEv;
140
141impl<R: Rt, E: UserEvent> EvalCached<R, E> for GetOrEv {
142    const NAME: &str = "map_get_or";
143    const NEEDS_CALLSITE: bool = false;
144
145    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
146        match (&from.0[0], &from.0[1], &from.0[2]) {
147            (Some(Value::Map(m)), Some(key), Some(default)) => {
148                Some(m.get(key).cloned().unwrap_or_else(|| default.clone()))
149            }
150            _ => None,
151        }
152    }
153}
154
155type GetOr = CachedArgs<GetOrEv>;
156
157#[derive(Debug, Default)]
158struct InsertEv;
159
160impl<R: Rt, E: UserEvent> EvalCached<R, E> for InsertEv {
161    const NAME: &str = "map_insert";
162    const NEEDS_CALLSITE: bool = false;
163
164    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
165        match (&from.0[0], &from.0[1], &from.0[2]) {
166            (Some(Value::Map(m)), Some(key), Some(value)) => {
167                Some(Value::Map(m.insert(key.clone(), value.clone()).0))
168            }
169            _ => None,
170        }
171    }
172}
173
174type Insert = CachedArgs<InsertEv>;
175
176#[derive(Debug, Default)]
177struct RemoveEv;
178
179impl<R: Rt, E: UserEvent> EvalCached<R, E> for RemoveEv {
180    const NAME: &str = "map_remove";
181    const NEEDS_CALLSITE: bool = false;
182
183    fn eval(&mut self, _ctx: &mut ExecCtx<R, E>, from: &CachedVals) -> Option<Value> {
184        match (&from.0[0], &from.0[1]) {
185            (Some(Value::Map(m)), Some(key)) => Some(Value::Map(m.remove(key).0)),
186            _ => None,
187        }
188    }
189}
190
191type Remove = CachedArgs<RemoveEv>;
192
193#[derive(Debug)]
194struct Iter {
195    id: BindId,
196    top_id: ExprId,
197}
198
199impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Iter {
200    const NAME: &str = "map_iter";
201    const NEEDS_CALLSITE: bool = false;
202
203    fn init<'a, 'b, 'c, 'd>(
204        ctx: &'a mut ExecCtx<R, E>,
205        _typ: &'a FnType,
206        _resolved: Option<&'d FnType>,
207        _scope: &'b Scope,
208        _from: &'c [Node<R, E>],
209        top_id: ExprId,
210    ) -> Result<Box<dyn Apply<R, E>>> {
211        let id = BindId::new();
212        ctx.rt.ref_var(id, top_id);
213        Ok(Box::new(Self { id, top_id }))
214    }
215}
216
217impl<R: Rt, E: UserEvent> Apply<R, E> for Iter {
218    fn update(
219        &mut self,
220        ctx: &mut ExecCtx<R, E>,
221        from: &mut [Node<R, E>],
222        event: &mut Event<E>,
223    ) -> Option<Value> {
224        if let Some(Value::Map(m)) = from[0].update(ctx, event) {
225            for (k, v) in m.into_iter() {
226                let pair = Value::Array(ValArray::from_iter_exact(
227                    [k.clone(), v.clone()].into_iter(),
228                ));
229                ctx.rt.set_var(self.id, pair);
230            }
231        }
232        event.variables.get(&self.id).map(|v| v.clone())
233    }
234
235    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
236        ctx.rt.unref_var(self.id, self.top_id)
237    }
238
239    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
240        ctx.rt.unref_var(self.id, self.top_id);
241        self.id = BindId::new();
242        ctx.rt.ref_var(self.id, self.top_id);
243    }
244}
245
246#[derive(Debug)]
247struct IterQ {
248    triggered: usize,
249    queue: VecDeque<(usize, LPooled<Vec<(Value, Value)>>)>,
250    id: BindId,
251    top_id: ExprId,
252}
253
254impl<R: Rt, E: UserEvent> BuiltIn<R, E> for IterQ {
255    const NAME: &str = "map_iterq";
256    const NEEDS_CALLSITE: bool = false;
257
258    fn init<'a, 'b, 'c, 'd>(
259        ctx: &'a mut ExecCtx<R, E>,
260        _typ: &'a FnType,
261        _resolved: Option<&'d FnType>,
262        _scope: &'b Scope,
263        _from: &'c [Node<R, E>],
264        top_id: ExprId,
265    ) -> Result<Box<dyn Apply<R, E>>> {
266        let id = BindId::new();
267        ctx.rt.ref_var(id, top_id);
268        Ok(Box::new(IterQ { triggered: 0, queue: VecDeque::new(), id, top_id }))
269    }
270}
271
272impl<R: Rt, E: UserEvent> Apply<R, E> for IterQ {
273    fn update(
274        &mut self,
275        ctx: &mut ExecCtx<R, E>,
276        from: &mut [Node<R, E>],
277        event: &mut Event<E>,
278    ) -> Option<Value> {
279        if from[0].update(ctx, event).is_some() {
280            self.triggered += 1;
281        }
282        if let Some(Value::Map(m)) = from[1].update(ctx, event) {
283            let pairs: LPooled<Vec<(Value, Value)>> =
284                m.into_iter().map(|(k, v)| (k.clone(), v.clone())).collect();
285            if !pairs.is_empty() {
286                self.queue.push_back((0, pairs));
287            }
288        }
289        while self.triggered > 0 && !self.queue.is_empty() {
290            let (i, pairs) = self.queue.front_mut().unwrap();
291            while self.triggered > 0 && *i < pairs.len() {
292                let (k, v) = pairs[*i].clone();
293                let pair = Value::Array(ValArray::from_iter_exact([k, v].into_iter()));
294                ctx.rt.set_var(self.id, pair);
295                *i += 1;
296                self.triggered -= 1;
297            }
298            if *i == pairs.len() {
299                self.queue.pop_front();
300            }
301        }
302        event.variables.get(&self.id).cloned()
303    }
304
305    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
306        ctx.rt.unref_var(self.id, self.top_id)
307    }
308
309    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
310        ctx.rt.unref_var(self.id, self.top_id);
311        self.id = BindId::new();
312        ctx.rt.ref_var(self.id, self.top_id);
313        self.queue.clear();
314        self.triggered = 0;
315    }
316}
317
318#[derive(Debug)]
319struct Change<R: Rt, E: UserEvent> {
320    inner: Node<R, E>,
321    fid: BindId,
322    x: BindId,
323    last_m: Option<CMap<Value, Value, 32>>,
324    last_k: Option<Value>,
325    last_d: Option<Value>,
326    last_f: Option<Value>,
327}
328
329impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Change<R, E> {
330    const NAME: &str = "map_change";
331    const NEEDS_CALLSITE: bool = false;
332
333    fn init<'a, 'b, 'c, 'd>(
334        ctx: &'a mut ExecCtx<R, E>,
335        typ: &'a FnType,
336        resolved: Option<&'d FnType>,
337        scope: &'b Scope,
338        from: &'c [Node<R, E>],
339        top_id: ExprId,
340    ) -> Result<Box<dyn Apply<R, E>>> {
341        if from.len() != 4 {
342            bail!("expected four arguments");
343        }
344        let typ = resolved.unwrap_or(typ);
345        let ptyp = match &typ.args[3].typ {
346            Type::Fn(ft) => ft.clone(),
347            t => bail!("expected a function not {t}"),
348        };
349        if ptyp.args.is_empty() {
350            bail!("expected unary callback");
351        }
352        let x_typ = ptyp.args[0].typ.clone();
353        let (x, xn) = genn::bind(ctx, &scope.lexical, "x", x_typ, top_id);
354        let fid = BindId::new();
355        let fnode = genn::reference(ctx, fid, Type::Fn(ptyp.clone()), top_id);
356        let inner = genn::apply(fnode, scope.clone(), vec![xn], &ptyp, top_id);
357        Ok(Box::new(Self {
358            inner,
359            fid,
360            x,
361            last_m: None,
362            last_k: None,
363            last_d: None,
364            last_f: None,
365        }))
366    }
367}
368
369impl<R: Rt, E: UserEvent> Apply<R, E> for Change<R, E> {
370    fn update(
371        &mut self,
372        ctx: &mut ExecCtx<R, E>,
373        from: &mut [Node<R, E>],
374        event: &mut Event<E>,
375    ) -> Option<Value> {
376        if let Some(v) = from[3].update(ctx, event) {
377            ctx.cached.insert(self.fid, v.clone());
378            event.variables.insert(self.fid, v);
379        }
380        let mut changed = false;
381        if let Some(Value::Map(m)) = from[0].update(ctx, event) {
382            self.last_m = Some(m);
383            changed = true;
384        }
385        if let Some(k) = from[1].update(ctx, event) {
386            self.last_k = Some(k);
387            changed = true;
388        }
389        if let Some(d) = from[2].update(ctx, event) {
390            self.last_d = Some(d);
391            changed = true;
392        }
393        if changed {
394            if let (Some(m), Some(k), Some(d)) =
395                (&self.last_m, &self.last_k, &self.last_d)
396            {
397                let current = m.get(k).cloned().unwrap_or_else(|| d.clone());
398                ctx.cached.insert(self.x, current.clone());
399                event.variables.insert(self.x, current);
400            }
401        }
402        let f_fired = if let Some(v) = self.inner.update(ctx, event) {
403            self.last_f = Some(v);
404            true
405        } else {
406            false
407        };
408        if changed || f_fired {
409            if let (Some(m), Some(k), Some(fv)) =
410                (&self.last_m, &self.last_k, &self.last_f)
411            {
412                return Some(Value::Map(m.insert(k.clone(), fv.clone()).0));
413            }
414        }
415        None
416    }
417
418    fn typecheck(
419        &mut self,
420        ctx: &mut ExecCtx<R, E>,
421        _from: &mut [Node<R, E>],
422        _phase: TypecheckPhase<'_>,
423    ) -> Result<()> {
424        self.inner.typecheck(ctx)
425    }
426
427    fn refs(&self, refs: &mut Refs) {
428        self.inner.refs(refs);
429    }
430
431    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
432        ctx.cached.remove(&self.fid);
433        ctx.cached.remove(&self.x);
434        ctx.env.unbind_variable(self.x);
435        self.inner.delete(ctx);
436    }
437
438    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
439        self.last_m = None;
440        self.last_k = None;
441        self.last_d = None;
442        self.last_f = None;
443        self.inner.sleep(ctx);
444    }
445}
446
447graphix_derive::defpackage! {
448    builtins => [
449        Map as Map<GXRt<X>, X::UserEvent>,
450        Filter as Filter<GXRt<X>, X::UserEvent>,
451        FilterMap as FilterMap<GXRt<X>, X::UserEvent>,
452        Fold as Fold<GXRt<X>, X::UserEvent>,
453        Len,
454        Get,
455        GetOr,
456        Insert,
457        Remove,
458        Iter,
459        IterQ,
460        Change as Change<GXRt<X>, X::UserEvent>,
461    ],
462}