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::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}