gitql_std/number/
mod.rs

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}