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}