1use std::collections::HashMap;
2use std::ops::Rem;
3
4use gitql_ast::types::dynamic::DynamicType;
5use gitql_ast::types::float::FloatType;
6use gitql_ast::types::integer::IntType;
7use gitql_ast::types::optional::OptionType;
8use gitql_ast::types::variant::VariantType;
9use gitql_core::signature::Signature;
10use gitql_core::signature::StandardFunction;
11use gitql_core::values::float::FloatValue;
12use gitql_core::values::integer::IntValue;
13use gitql_core::values::null::NullValue;
14use gitql_core::values::Value;
15
16use crate::meta_types::first_element_type;
17
18use rand::distributions::Uniform;
19use rand::rngs::StdRng;
20use rand::Rng;
21use rand::SeedableRng;
22
23#[inline(always)]
24pub fn register_std_number_functions(map: &mut HashMap<&'static str, StandardFunction>) {
25 map.insert("abs", numeric_abs);
26 map.insert("pi", numeric_pi);
27 map.insert("floor", numeric_floor);
28 map.insert("round", numeric_round);
29 map.insert("square", numeric_square);
30 map.insert("sin", numeric_sin);
31 map.insert("asin", numeric_asin);
32 map.insert("cos", numeric_cos);
33 map.insert("acos", numeric_acos);
34 map.insert("tan", numeric_tan);
35 map.insert("atan", numeric_atan);
36 map.insert("atn2", numeric_atn2);
37 map.insert("sign", numeric_sign);
38 map.insert("mod", numeric_mod);
39 map.insert("rand", numeric_rand);
40}
41
42#[inline(always)]
43pub fn register_std_number_function_signatures(map: &mut HashMap<&'static str, Signature>) {
44 map.insert(
45 "abs",
46 Signature {
47 parameters: vec![Box::new(VariantType {
48 variants: vec![Box::new(IntType), Box::new(FloatType)],
49 })],
50 return_type: Box::new(DynamicType {
51 function: first_element_type,
52 }),
53 },
54 );
55 map.insert(
56 "pi",
57 Signature {
58 parameters: vec![],
59 return_type: Box::new(FloatType),
60 },
61 );
62 map.insert(
63 "floor",
64 Signature {
65 parameters: vec![Box::new(FloatType)],
66 return_type: Box::new(IntType),
67 },
68 );
69 map.insert(
70 "round",
71 Signature {
72 parameters: vec![
73 Box::new(FloatType),
74 Box::new(OptionType {
75 base: Some(Box::new(IntType)),
76 }),
77 ],
78 return_type: Box::new(FloatType),
79 },
80 );
81 map.insert(
82 "square",
83 Signature {
84 parameters: vec![Box::new(IntType)],
85 return_type: Box::new(IntType),
86 },
87 );
88 map.insert(
89 "sin",
90 Signature {
91 parameters: vec![Box::new(FloatType)],
92 return_type: Box::new(FloatType),
93 },
94 );
95 map.insert(
96 "asin",
97 Signature {
98 parameters: vec![Box::new(FloatType)],
99 return_type: Box::new(FloatType),
100 },
101 );
102 map.insert(
103 "cos",
104 Signature {
105 parameters: vec![Box::new(FloatType)],
106 return_type: Box::new(FloatType),
107 },
108 );
109 map.insert(
110 "acos",
111 Signature {
112 parameters: vec![Box::new(FloatType)],
113 return_type: Box::new(FloatType),
114 },
115 );
116 map.insert(
117 "tan",
118 Signature {
119 parameters: vec![Box::new(FloatType)],
120 return_type: Box::new(FloatType),
121 },
122 );
123 map.insert(
124 "atan",
125 Signature {
126 parameters: vec![Box::new(FloatType)],
127 return_type: Box::new(FloatType),
128 },
129 );
130 map.insert(
131 "atn2",
132 Signature {
133 parameters: vec![Box::new(FloatType), Box::new(FloatType)],
134 return_type: Box::new(FloatType),
135 },
136 );
137 map.insert(
138 "sign",
139 Signature {
140 parameters: vec![Box::new(VariantType {
141 variants: vec![Box::new(IntType), Box::new(FloatType)],
142 })],
143 return_type: Box::new(IntType),
144 },
145 );
146 map.insert(
147 "mod",
148 Signature {
149 parameters: vec![Box::new(IntType), Box::new(IntType)],
150 return_type: Box::new(IntType),
151 },
152 );
153 map.insert(
154 "rand",
155 Signature {
156 parameters: vec![Box::new(OptionType {
157 base: Some(Box::new(FloatType)),
158 })],
159 return_type: Box::new(FloatType),
160 },
161 );
162}
163
164pub fn numeric_abs(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
165 let input_type = inputs[0].data_type();
166 if input_type.is_float() {
167 let value = inputs[0].as_float().unwrap().abs();
168 return Box::new(FloatValue::new(value));
169 }
170 Box::new(IntValue::new(inputs[0].as_int().unwrap().abs()))
171}
172
173pub fn numeric_pi(_inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
174 let pi = std::f64::consts::PI;
175 Box::new(FloatValue { value: pi })
176}
177
178pub fn numeric_floor(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
179 let float_value = inputs[0].as_float().unwrap();
180 Box::new(IntValue {
181 value: float_value.floor() as i64,
182 })
183}
184
185pub fn numeric_round(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
186 let number = inputs[0].as_float().unwrap();
187 let decimal_places = if inputs.len() == 2 {
188 inputs[1].as_int().unwrap()
189 } else {
190 0
191 };
192 let multiplier = 10_f64.powi(decimal_places.try_into().unwrap());
193 let result = (number * multiplier).round() / multiplier;
194 Box::new(FloatValue { value: result })
195}
196
197pub fn numeric_square(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
198 let int_value = inputs[0].as_int().unwrap();
199 Box::new(IntValue {
200 value: int_value * int_value,
201 })
202}
203
204pub fn numeric_sin(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
205 let float_value = inputs[0].as_float().unwrap();
206 Box::new(FloatValue {
207 value: f64::sin(float_value),
208 })
209}
210
211pub fn numeric_asin(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
212 let float_value = inputs[0].as_float().unwrap();
213 Box::new(FloatValue {
214 value: f64::asin(float_value),
215 })
216}
217
218pub fn numeric_cos(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
219 let float_value = inputs[0].as_float().unwrap();
220 Box::new(FloatValue {
221 value: f64::cos(float_value),
222 })
223}
224
225pub fn numeric_acos(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
226 let float_value = inputs[0].as_float().unwrap();
227 Box::new(FloatValue {
228 value: f64::acos(float_value),
229 })
230}
231
232pub fn numeric_tan(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
233 let float_value = inputs[0].as_float().unwrap();
234 Box::new(FloatValue {
235 value: f64::tan(float_value),
236 })
237}
238
239pub fn numeric_atan(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
240 let float_value = inputs[0].as_float().unwrap();
241 Box::new(FloatValue {
242 value: f64::atan(float_value),
243 })
244}
245
246pub fn numeric_atn2(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
247 let first = inputs[0].as_float().unwrap();
248 let other = inputs[1].as_float().unwrap();
249 Box::new(FloatValue {
250 value: f64::atan2(first, other),
251 })
252}
253
254pub fn numeric_sign(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
255 let value = &inputs[0];
256 if value.data_type().is_int() {
257 let value = value.as_int().unwrap().signum();
258 return Box::new(IntValue { value });
259 }
260
261 let float_value = value.as_float().unwrap();
262 let value = if float_value == 0.0 {
263 0
264 } else if float_value > 0.0 {
265 1
266 } else {
267 -1
268 };
269 Box::new(IntValue { value })
270}
271
272pub fn numeric_mod(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
273 let other = inputs[1].as_int().unwrap();
274 if other == 0 {
275 return Box::new(NullValue);
276 }
277
278 let first = inputs[0].as_int().unwrap();
279 let value = first.rem(other);
280 Box::new(IntValue { value })
281}
282
283pub fn numeric_rand(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
284 let mut rng: StdRng = match inputs.first() {
285 Some(s) => SeedableRng::seed_from_u64(s.as_int().unwrap().try_into().unwrap()),
286 None => SeedableRng::from_entropy(),
287 };
288
289 Box::new(FloatValue {
290 value: rng.sample(Uniform::from(0.0..1.0)),
291 })
292}