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}