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