Skip to main content

graphix_package_rand/
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, typ::FnType, Apply, BuiltIn, Event, ExecCtx, Node, Rt, Scope, UserEvent,
8};
9use graphix_package_core::CachedVals;
10use netidx::subscriber::Value;
11use netidx_value::ValArray;
12use rand::{rng, seq::SliceRandom, RngExt};
13use smallvec::{smallvec, SmallVec};
14
15#[derive(Debug)]
16struct Rand {
17    args: CachedVals,
18}
19
20impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Rand {
21    const NAME: &str = "rand";
22    const NEEDS_CALLSITE: bool = false;
23
24    fn init<'a, 'b, 'c, 'd>(
25        _ctx: &'a mut ExecCtx<R, E>,
26        _typ: &'a FnType,
27        _resolved: Option<&'d FnType>,
28        _scope: &'b Scope,
29        from: &'c [Node<R, E>],
30        _top_id: ExprId,
31    ) -> Result<Box<dyn Apply<R, E>>> {
32        Ok(Box::new(Rand { args: CachedVals::new(from) }))
33    }
34}
35
36impl<R: Rt, E: UserEvent> Apply<R, E> for Rand {
37    fn update(
38        &mut self,
39        ctx: &mut ExecCtx<R, E>,
40        from: &mut [Node<R, E>],
41        event: &mut Event<E>,
42    ) -> Option<Value> {
43        macro_rules! gen_cases {
44            ($start:expr, $end:expr, $($typ:ident),+) => {
45                match ($start, $end) {
46                    $(
47                        (Value::$typ(start), Value::$typ(end)) if start < end => {
48                            Some(Value::$typ(rng().random_range(*start..*end)))
49                        }
50                    ),+
51                    _ => None
52                }
53            };
54        }
55        let up = self.args.update(ctx, from, event);
56        if up {
57            match &self.args.0[..] {
58                [Some(start), Some(end), Some(_)] => gen_cases!(
59                    start, end, F32, F64, I32, I64, Z32, Z64, U32, U64, V32, V64
60                ),
61                _ => None,
62            }
63        } else {
64            None
65        }
66    }
67
68    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {
69        self.args.clear()
70    }
71}
72
73#[derive(Debug)]
74struct Pick;
75
76impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Pick {
77    const NAME: &str = "rand_pick";
78    const NEEDS_CALLSITE: bool = false;
79
80    fn init<'a, 'b, 'c, 'd>(
81        _ctx: &'a mut ExecCtx<R, E>,
82        _typ: &'a FnType,
83        _resolved: Option<&'d FnType>,
84        _scope: &'b Scope,
85        _from: &'c [Node<R, E>],
86        _top_id: ExprId,
87    ) -> Result<Box<dyn Apply<R, E>>> {
88        Ok(Box::new(Pick))
89    }
90}
91
92impl<R: Rt, E: UserEvent> Apply<R, E> for Pick {
93    fn update(
94        &mut self,
95        ctx: &mut ExecCtx<R, E>,
96        from: &mut [Node<R, E>],
97        event: &mut Event<E>,
98    ) -> Option<Value> {
99        from[0].update(ctx, event).and_then(|a| match a {
100            Value::Array(a) if a.len() > 0 => {
101                Some(a[rng().random_range(0..a.len())].clone())
102            }
103            _ => None,
104        })
105    }
106
107    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {}
108}
109
110#[derive(Debug)]
111struct Shuffle(SmallVec<[Value; 32]>);
112
113impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Shuffle {
114    const NAME: &str = "rand_shuffle";
115    const NEEDS_CALLSITE: bool = false;
116
117    fn init<'a, 'b, 'c, 'd>(
118        _ctx: &'a mut ExecCtx<R, E>,
119        _typ: &'a FnType,
120        _resolved: Option<&'d FnType>,
121        _scope: &'b Scope,
122        _from: &'c [Node<R, E>],
123        _top_id: ExprId,
124    ) -> Result<Box<dyn Apply<R, E>>> {
125        Ok(Box::new(Shuffle(smallvec![])))
126    }
127}
128
129impl<R: Rt, E: UserEvent> Apply<R, E> for Shuffle {
130    fn update(
131        &mut self,
132        ctx: &mut ExecCtx<R, E>,
133        from: &mut [Node<R, E>],
134        event: &mut Event<E>,
135    ) -> Option<Value> {
136        from[0].update(ctx, event).and_then(|a| match a {
137            Value::Array(a) => {
138                self.0.extend(a.iter().cloned());
139                self.0.shuffle(&mut rng());
140                Some(Value::Array(ValArray::from_iter_exact(self.0.drain(..))))
141            }
142            _ => None,
143        })
144    }
145
146    fn sleep(&mut self, _ctx: &mut ExecCtx<R, E>) {
147        self.0.clear()
148    }
149}
150
151#[cfg(test)]
152mod test;
153
154graphix_derive::defpackage! {
155    builtins => [
156        Rand,
157        Pick,
158        Shuffle,
159    ],
160}