Skip to main content

graphix_package_rand/
lib.rs

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