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