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::Result;
6use graphix_compiler::{
7    expr::ExprId, Apply, BindId, BuiltIn, Event, ExecCtx, Node, Rt, Scope, UserEvent,
8};
9use graphix_package_core::{
10    deftype, CachedArgs, CachedVals, EvalCached, FoldFn, FoldQ, MapFn, MapQ, Slot,
11};
12use graphix_rt::GXRt;
13use immutable_chunkmap::map::Map as CMap;
14use netidx::subscriber::Value;
15use netidx_value::ValArray;
16use poolshark::local::LPooled;
17use std::collections::VecDeque;
18use std::fmt::Debug;
19
20#[derive(Debug, Default)]
21struct MapImpl;
22
23impl<R: Rt, E: UserEvent> MapFn<R, E> for MapImpl {
24    type Collection = CMap<Value, Value, 32>;
25
26    const NAME: &str = "map_map";
27    deftype!(
28        "fn(Map<'a, 'b>, fn(('a, 'b)) -> ('c, 'd) throws 'e) -> Map<'c, 'd> throws 'e"
29    );
30
31    fn finish(&mut self, slots: &[Slot<R, E>], _: &Self::Collection) -> Option<Value> {
32        Some(Value::Map(CMap::from_iter(
33            slots
34                .iter()
35                .map(|s| s.cur.clone().unwrap().cast_to::<(Value, Value)>().unwrap()),
36        )))
37    }
38}
39
40type Map<R, E> = MapQ<R, E, MapImpl>;
41
42#[derive(Debug, Default)]
43struct FilterImpl;
44
45impl<R: Rt, E: UserEvent> MapFn<R, E> for FilterImpl {
46    type Collection = CMap<Value, Value, 32>;
47
48    const NAME: &str = "map_filter";
49    deftype!("fn(Map<'a, 'b>, fn(('a, 'b)) -> bool throws 'e) -> Map<'a, 'b> throws 'e");
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    deftype!(
75        "fn(Map<'a, 'b>, fn(('a, 'b)) -> Option<('c, 'd)> throws 'e) -> Map<'c, 'd> throws 'e"
76    );
77
78    fn finish(
79        &mut self,
80        slots: &[Slot<R, E>],
81        _: &CMap<Value, Value, 32>,
82    ) -> Option<Value> {
83        Some(Value::Map(CMap::from_iter(slots.iter().filter_map(|s| {
84            match s.cur.as_ref().unwrap() {
85                Value::Null => None,
86                v => Some(v.clone().cast_to::<(Value, Value)>().unwrap()),
87            }
88        }))))
89    }
90}
91
92type FilterMap<R, E> = MapQ<R, E, FilterMapImpl>;
93
94#[derive(Debug)]
95struct FoldImpl;
96
97impl<R: Rt, E: UserEvent> FoldFn<R, E> for FoldImpl {
98    type Collection = CMap<Value, Value, 32>;
99
100    const NAME: &str = "map_fold";
101    deftype!("fn(Map<'a, 'b>, 'c, fn('c, ('a, 'b)) -> 'c throws 'e) -> 'c throws 'e");
102}
103
104type Fold<R, E> = FoldQ<R, E, FoldImpl>;
105
106#[derive(Debug, Default)]
107struct LenEv;
108
109impl EvalCached for LenEv {
110    const NAME: &str = "map_len";
111    deftype!("fn(Map<'a, 'b>) -> i64");
112
113    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
114        match &from.0[0] {
115            Some(Value::Map(m)) => Some(Value::I64(m.len() as i64)),
116            Some(_) | None => None,
117        }
118    }
119}
120
121type Len = CachedArgs<LenEv>;
122
123#[derive(Debug, Default)]
124struct GetEv;
125
126impl EvalCached for GetEv {
127    const NAME: &str = "map_get";
128    deftype!("fn(Map<'a, 'b>, 'a) -> Option<'b>");
129
130    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
131        match (&from.0[0], &from.0[1]) {
132            (Some(Value::Map(m)), Some(key)) => {
133                Some(m.get(key).cloned().unwrap_or(Value::Null))
134            }
135            _ => None,
136        }
137    }
138}
139
140type Get = CachedArgs<GetEv>;
141
142#[derive(Debug, Default)]
143struct InsertEv;
144
145impl EvalCached for InsertEv {
146    const NAME: &str = "map_insert";
147    deftype!("fn(Map<'a, 'b>, 'a, 'b) -> Map<'a, 'b>");
148
149    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
150        match (&from.0[0], &from.0[1], &from.0[2]) {
151            (Some(Value::Map(m)), Some(key), Some(value)) => {
152                Some(Value::Map(m.insert(key.clone(), value.clone()).0))
153            }
154            _ => None,
155        }
156    }
157}
158
159type Insert = CachedArgs<InsertEv>;
160
161#[derive(Debug, Default)]
162struct RemoveEv;
163
164impl EvalCached for RemoveEv {
165    const NAME: &str = "map_remove";
166    deftype!("fn(Map<'a, 'b>, 'a) -> Map<'a, 'b>");
167
168    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
169        match (&from.0[0], &from.0[1]) {
170            (Some(Value::Map(m)), Some(key)) => Some(Value::Map(m.remove(key).0)),
171            _ => None,
172        }
173    }
174}
175
176type Remove = CachedArgs<RemoveEv>;
177
178#[derive(Debug)]
179struct Iter {
180    id: BindId,
181    top_id: ExprId,
182}
183
184impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Iter {
185    const NAME: &str = "map_iter";
186    deftype!("fn(Map<'a, 'b>) -> ('a, 'b)");
187
188    fn init<'a, 'b, 'c>(
189        ctx: &'a mut ExecCtx<R, E>,
190        _typ: &'a graphix_compiler::typ::FnType,
191        _scope: &'b Scope,
192        _from: &'c [Node<R, E>],
193        top_id: ExprId,
194    ) -> Result<Box<dyn Apply<R, E>>> {
195        let id = BindId::new();
196        ctx.rt.ref_var(id, top_id);
197        Ok(Box::new(Self { id, top_id }))
198    }
199}
200
201impl<R: Rt, E: UserEvent> Apply<R, E> for Iter {
202    fn update(
203        &mut self,
204        ctx: &mut ExecCtx<R, E>,
205        from: &mut [Node<R, E>],
206        event: &mut Event<E>,
207    ) -> Option<Value> {
208        if let Some(Value::Map(m)) = from[0].update(ctx, event) {
209            for (k, v) in m.into_iter() {
210                let pair = Value::Array(ValArray::from_iter_exact(
211                    [k.clone(), v.clone()].into_iter(),
212                ));
213                ctx.rt.set_var(self.id, pair);
214            }
215        }
216        event.variables.get(&self.id).map(|v| v.clone())
217    }
218
219    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
220        ctx.rt.unref_var(self.id, self.top_id)
221    }
222
223    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
224        ctx.rt.unref_var(self.id, self.top_id);
225        self.id = BindId::new();
226        ctx.rt.ref_var(self.id, self.top_id);
227    }
228}
229
230#[derive(Debug)]
231struct IterQ {
232    triggered: usize,
233    queue: VecDeque<(usize, LPooled<Vec<(Value, Value)>>)>,
234    id: BindId,
235    top_id: ExprId,
236}
237
238impl<R: Rt, E: UserEvent> BuiltIn<R, E> for IterQ {
239    const NAME: &str = "map_iterq";
240    deftype!("fn(#clock:Any, Map<'a, 'b>) -> ('a, 'b)");
241
242    fn init<'a, 'b, 'c>(
243        ctx: &'a mut ExecCtx<R, E>,
244        _typ: &'a graphix_compiler::typ::FnType,
245        _scope: &'b Scope,
246        _from: &'c [Node<R, E>],
247        top_id: ExprId,
248    ) -> Result<Box<dyn Apply<R, E>>> {
249        let id = BindId::new();
250        ctx.rt.ref_var(id, top_id);
251        Ok(Box::new(IterQ { triggered: 0, queue: VecDeque::new(), id, top_id }))
252    }
253}
254
255impl<R: Rt, E: UserEvent> Apply<R, E> for IterQ {
256    fn update(
257        &mut self,
258        ctx: &mut ExecCtx<R, E>,
259        from: &mut [Node<R, E>],
260        event: &mut Event<E>,
261    ) -> Option<Value> {
262        if from[0].update(ctx, event).is_some() {
263            self.triggered += 1;
264        }
265        if let Some(Value::Map(m)) = from[1].update(ctx, event) {
266            let pairs: LPooled<Vec<(Value, Value)>> =
267                m.into_iter().map(|(k, v)| (k.clone(), v.clone())).collect();
268            if !pairs.is_empty() {
269                self.queue.push_back((0, pairs));
270            }
271        }
272        while self.triggered > 0 && !self.queue.is_empty() {
273            let (i, pairs) = self.queue.front_mut().unwrap();
274            while self.triggered > 0 && *i < pairs.len() {
275                let (k, v) = pairs[*i].clone();
276                let pair = Value::Array(ValArray::from_iter_exact([k, v].into_iter()));
277                ctx.rt.set_var(self.id, pair);
278                *i += 1;
279                self.triggered -= 1;
280            }
281            if *i == pairs.len() {
282                self.queue.pop_front();
283            }
284        }
285        event.variables.get(&self.id).cloned()
286    }
287
288    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
289        ctx.rt.unref_var(self.id, self.top_id)
290    }
291
292    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
293        ctx.rt.unref_var(self.id, self.top_id);
294        self.id = BindId::new();
295        ctx.rt.ref_var(self.id, self.top_id);
296        self.queue.clear();
297        self.triggered = 0;
298    }
299}
300
301graphix_derive::defpackage! {
302    builtins => [
303        Map as Map<GXRt<X>, X::UserEvent>,
304        Filter as Filter<GXRt<X>, X::UserEvent>,
305        FilterMap as FilterMap<GXRt<X>, X::UserEvent>,
306        Fold as Fold<GXRt<X>, X::UserEvent>,
307        Len,
308        Get,
309        Insert,
310        Remove,
311        Iter,
312        IterQ,
313    ],
314}