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}