gitql_std/array/
mod.rs

1use std::collections::HashMap;
2
3use gitql_ast::types::any::AnyType;
4use gitql_ast::types::array::ArrayType;
5use gitql_ast::types::dynamic::DynamicType;
6use gitql_ast::types::integer::IntType;
7use gitql_ast::types::text::TextType;
8use gitql_core::signature::Signature;
9use gitql_core::signature::StandardFunction;
10use gitql_core::values::array::ArrayValue;
11use gitql_core::values::integer::IntValue;
12use gitql_core::values::null::NullValue;
13use gitql_core::values::text::TextValue;
14use gitql_core::values::Value;
15
16use crate::meta_types::array_element_type;
17use crate::meta_types::array_of_type;
18use crate::meta_types::first_element_type;
19use crate::meta_types::second_element_type;
20
21use rand::seq::SliceRandom;
22
23#[inline(always)]
24pub fn register_std_array_functions(map: &mut HashMap<&'static str, StandardFunction>) {
25    map.insert("array_append", array_append);
26    map.insert("array_prepend", array_prepend);
27    map.insert("array_remove", array_remove);
28    map.insert("array_cat", array_cat);
29    map.insert("array_length", array_length);
30    map.insert("array_shuffle", array_shuffle);
31    map.insert("array_position", array_position);
32    map.insert("array_positions", array_positions);
33    map.insert("array_dims", array_dims);
34    map.insert("array_replace", array_replace);
35    map.insert("trim_array", array_trim);
36}
37
38#[inline(always)]
39pub fn register_std_array_function_signatures(map: &mut HashMap<&'static str, Signature>) {
40    map.insert(
41        "array_append",
42        Signature {
43            parameters: vec![
44                Box::new(ArrayType {
45                    base: Box::new(AnyType),
46                }),
47                Box::new(DynamicType {
48                    function: |elements| array_element_type(first_element_type(elements)),
49                }),
50            ],
51            return_type: Box::new(DynamicType {
52                function: first_element_type,
53            }),
54        },
55    );
56    map.insert(
57        "array_prepend",
58        Signature {
59            parameters: vec![
60                Box::new(AnyType),
61                Box::new(DynamicType {
62                    function: |elements| array_of_type(first_element_type(elements)),
63                }),
64            ],
65            return_type: Box::new(DynamicType {
66                function: second_element_type,
67            }),
68        },
69    );
70    map.insert(
71        "array_remove",
72        Signature {
73            parameters: vec![
74                Box::new(ArrayType {
75                    base: Box::new(AnyType),
76                }),
77                Box::new(DynamicType {
78                    function: |elements| array_element_type(first_element_type(elements)),
79                }),
80            ],
81            return_type: Box::new(DynamicType {
82                function: first_element_type,
83            }),
84        },
85    );
86    map.insert(
87        "array_cat",
88        Signature {
89            parameters: vec![
90                Box::new(ArrayType {
91                    base: Box::new(AnyType),
92                }),
93                Box::new(DynamicType {
94                    function: first_element_type,
95                }),
96            ],
97            return_type: Box::new(DynamicType {
98                function: first_element_type,
99            }),
100        },
101    );
102    map.insert(
103        "array_length",
104        Signature {
105            parameters: vec![Box::new(ArrayType {
106                base: Box::new(AnyType),
107            })],
108            return_type: Box::new(IntType),
109        },
110    );
111    map.insert(
112        "array_shuffle",
113        Signature {
114            parameters: vec![Box::new(ArrayType {
115                base: Box::new(AnyType),
116            })],
117            return_type: Box::new(DynamicType {
118                function: first_element_type,
119            }),
120        },
121    );
122    map.insert(
123        "array_position",
124        Signature {
125            parameters: vec![
126                Box::new(ArrayType {
127                    base: Box::new(AnyType),
128                }),
129                Box::new(DynamicType {
130                    function: |elements| array_element_type(first_element_type(elements)),
131                }),
132            ],
133            return_type: Box::new(IntType),
134        },
135    );
136    map.insert(
137        "array_dims",
138        Signature {
139            parameters: vec![Box::new(ArrayType {
140                base: Box::new(AnyType),
141            })],
142            return_type: Box::new(TextType),
143        },
144    );
145    map.insert(
146        "array_replace",
147        Signature {
148            parameters: vec![
149                Box::new(ArrayType {
150                    base: Box::new(AnyType),
151                }),
152                Box::new(DynamicType {
153                    function: |elements| array_element_type(first_element_type(elements)),
154                }),
155                Box::new(DynamicType {
156                    function: |elements| array_element_type(first_element_type(elements)),
157                }),
158            ],
159            return_type: Box::new(DynamicType {
160                function: first_element_type,
161            }),
162        },
163    );
164    map.insert(
165        "trim_array",
166        Signature {
167            parameters: vec![
168                Box::new(ArrayType {
169                    base: Box::new(AnyType),
170                }),
171                Box::new(IntType),
172            ],
173            return_type: Box::new(DynamicType {
174                function: first_element_type,
175            }),
176        },
177    );
178}
179
180pub fn array_append(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
181    let mut array = inputs[0].as_array().unwrap();
182    let element = &inputs[1];
183    array.push(element.to_owned());
184    Box::new(ArrayValue {
185        values: array,
186        base_type: inputs[0].data_type().clone(),
187    })
188}
189
190pub fn array_prepend(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
191    let element = &inputs[0];
192    let mut array = inputs[1].as_array().unwrap();
193    array.insert(0, element.clone());
194    Box::new(ArrayValue {
195        values: array,
196        base_type: inputs[1].data_type().clone(),
197    })
198}
199
200pub fn array_remove(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
201    let array = inputs[0].as_array().unwrap();
202    let element_to_remove = &inputs[1];
203    let array_after_remove = array
204        .into_iter()
205        .filter(|element| !element_to_remove.equals(element))
206        .collect();
207    Box::new(ArrayValue {
208        values: array_after_remove,
209        base_type: inputs[0].data_type().clone(),
210    })
211}
212
213pub fn array_cat(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
214    let mut first = inputs[0].as_array().unwrap();
215    let mut other = inputs[1].as_array().unwrap();
216    let mut result = Vec::with_capacity(first.len() + other.len());
217    result.append(&mut first);
218    result.append(&mut other);
219    Box::new(ArrayValue {
220        values: result,
221        base_type: inputs[0].data_type().clone(),
222    })
223}
224
225pub fn array_length(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
226    let array = inputs[0].as_array().unwrap();
227    let value = array.len() as i64;
228    Box::new(IntValue { value })
229}
230
231pub fn array_shuffle(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
232    let array_type = &inputs[0].data_type();
233    let element_type = &array_type
234        .as_any()
235        .downcast_ref::<ArrayType>()
236        .unwrap()
237        .base;
238
239    let mut array = inputs[0].as_array().unwrap();
240    array.shuffle(&mut rand::thread_rng());
241    Box::new(ArrayValue {
242        values: array,
243        base_type: element_type.clone(),
244    })
245}
246
247pub fn array_position(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
248    let array = inputs[0].as_array().unwrap();
249    let elemnet = &inputs[1];
250    if let Some(index) = array.iter().position(|r| r.equals(elemnet)) {
251        return Box::new(IntValue {
252            value: (index + 1) as i64,
253        });
254    }
255
256    Box::new(NullValue)
257}
258
259pub fn array_positions(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
260    let array = inputs[0].as_array().unwrap();
261    let target = &inputs[1];
262    let mut positions: Vec<Box<dyn Value>> = vec![];
263    for (index, element) in array.into_iter().enumerate() {
264        if element.equals(target) {
265            positions.push(Box::new(IntValue {
266                value: (index + 1) as i64,
267            }));
268        }
269    }
270    Box::new(ArrayValue {
271        values: positions,
272        base_type: Box::new(IntType),
273    })
274}
275
276pub fn array_dims(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
277    let array_type = inputs[0].data_type();
278    Box::new(TextValue {
279        value: array_type.to_string(),
280    })
281}
282
283pub fn array_replace(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
284    let array_type = inputs[0].data_type();
285    let mut array_values = inputs[0].as_array().unwrap();
286    let from = &inputs[1];
287    let to = &inputs[2];
288    for element in &mut array_values {
289        if element.equals(from) {
290            *element = to.clone();
291        }
292    }
293
294    Box::new(ArrayValue {
295        values: array_values,
296        base_type: array_type,
297    })
298}
299
300pub fn array_trim(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
301    let mut array = inputs[0].as_array().unwrap();
302    let array_type = inputs[0].data_type();
303    let array_len = array.len();
304    let n = i64::min(array.len().try_into().unwrap(), inputs[1].as_int().unwrap());
305    array.truncate(array_len - n as usize);
306    Box::new(ArrayValue {
307        values: array,
308        base_type: array_type,
309    })
310}