Skip to main content

jpx_core/extensions/
array.rs

1//! Array manipulation functions.
2
3use std::collections::HashSet;
4
5use serde_json::{Number, Value};
6
7use crate::functions::{Function, custom_error};
8use crate::interpreter::SearchResult;
9use crate::registry::register_if_enabled;
10use crate::{Context, Runtime, arg, defn};
11
12/// Register only the array functions that are in the enabled set.
13pub fn register_filtered(runtime: &mut Runtime, enabled: &HashSet<&str>) {
14    register_if_enabled(runtime, "unique", enabled, Box::new(UniqueFn::new()));
15    register_if_enabled(runtime, "zip", enabled, Box::new(ZipFn::new()));
16    register_if_enabled(runtime, "chunk", enabled, Box::new(ChunkFn::new()));
17    register_if_enabled(runtime, "take", enabled, Box::new(TakeFn::new()));
18    register_if_enabled(runtime, "drop", enabled, Box::new(DropFn::new()));
19    register_if_enabled(
20        runtime,
21        "flatten_deep",
22        enabled,
23        Box::new(FlattenDeepFn::new()),
24    );
25    register_if_enabled(runtime, "flatten", enabled, Box::new(FlattenFn::new()));
26    register_if_enabled(runtime, "compact", enabled, Box::new(CompactFn::new()));
27    register_if_enabled(runtime, "range", enabled, Box::new(RangeFn::new()));
28    register_if_enabled(runtime, "index_at", enabled, Box::new(IndexAtFn::new()));
29    register_if_enabled(runtime, "includes", enabled, Box::new(IncludesFn::new()));
30    register_if_enabled(runtime, "find_index", enabled, Box::new(FindIndexFn::new()));
31    register_if_enabled(runtime, "first", enabled, Box::new(FirstFn::new()));
32    register_if_enabled(runtime, "last", enabled, Box::new(LastFn::new()));
33    register_if_enabled(runtime, "group_by", enabled, Box::new(GroupByFn::new()));
34    register_if_enabled(runtime, "index_by", enabled, Box::new(IndexByFn::new()));
35    register_if_enabled(runtime, "nth", enabled, Box::new(NthFn::new()));
36    register_if_enabled(
37        runtime,
38        "interleave",
39        enabled,
40        Box::new(InterleaveFn::new()),
41    );
42    register_if_enabled(runtime, "rotate", enabled, Box::new(RotateFn::new()));
43    register_if_enabled(runtime, "partition", enabled, Box::new(PartitionFn::new()));
44    register_if_enabled(
45        runtime,
46        "difference",
47        enabled,
48        Box::new(DifferenceFn::new()),
49    );
50    register_if_enabled(
51        runtime,
52        "intersection",
53        enabled,
54        Box::new(IntersectionFn::new()),
55    );
56    register_if_enabled(runtime, "union", enabled, Box::new(UnionFn::new()));
57    register_if_enabled(
58        runtime,
59        "frequencies",
60        enabled,
61        Box::new(FrequenciesFn::new()),
62    );
63    register_if_enabled(runtime, "mode", enabled, Box::new(ModeFn::new()));
64    register_if_enabled(runtime, "cartesian", enabled, Box::new(CartesianFn::new()));
65    register_if_enabled(runtime, "initial", enabled, Box::new(InitialFn::new()));
66    // Alias for initial (Clojure-style name)
67    register_if_enabled(runtime, "butlast", enabled, Box::new(InitialFn::new()));
68    // Clojure-inspired functions
69    register_if_enabled(runtime, "interpose", enabled, Box::new(InterposeFn::new()));
70    register_if_enabled(runtime, "zipmap", enabled, Box::new(ZipmapFn::new()));
71    register_if_enabled(
72        runtime,
73        "partition_by",
74        enabled,
75        Box::new(PartitionByFn::new()),
76    );
77    register_if_enabled(runtime, "dedupe", enabled, Box::new(DedupeFn::new()));
78    register_if_enabled(runtime, "tail", enabled, Box::new(TailFn::new()));
79    register_if_enabled(runtime, "without", enabled, Box::new(WithoutFn::new()));
80    register_if_enabled(runtime, "xor", enabled, Box::new(XorFn::new()));
81    register_if_enabled(runtime, "fill", enabled, Box::new(FillFn::new()));
82    register_if_enabled(runtime, "pull_at", enabled, Box::new(PullAtFn::new()));
83    register_if_enabled(runtime, "window", enabled, Box::new(WindowFn::new()));
84    register_if_enabled(
85        runtime,
86        "combinations",
87        enabled,
88        Box::new(CombinationsFn::new()),
89    );
90    register_if_enabled(runtime, "transpose", enabled, Box::new(TransposeFn::new()));
91    register_if_enabled(runtime, "pairwise", enabled, Box::new(PairwiseFn::new()));
92    // Alias for window (sliding_window is a common name)
93    register_if_enabled(
94        runtime,
95        "sliding_window",
96        enabled,
97        Box::new(WindowFn::new()),
98    );
99    // jq-parity functions
100    register_if_enabled(
101        runtime,
102        "indices_array",
103        enabled,
104        Box::new(IndicesArrayFn::new()),
105    );
106    register_if_enabled(
107        runtime,
108        "inside_array",
109        enabled,
110        Box::new(InsideArrayFn::new()),
111    );
112    register_if_enabled(runtime, "bsearch", enabled, Box::new(BsearchFn::new()));
113    // Clojure-inspired functions (Phase 3)
114    register_if_enabled(
115        runtime,
116        "repeat_array",
117        enabled,
118        Box::new(RepeatArrayFn::new()),
119    );
120    register_if_enabled(runtime, "cycle", enabled, Box::new(CycleFn::new()));
121}
122
123// =============================================================================
124// unique(array) -> array
125// =============================================================================
126
127defn!(UniqueFn, vec![arg!(array)], None);
128
129impl Function for UniqueFn {
130    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
131        self.signature.validate(args, ctx)?;
132
133        let arr = args[0]
134            .as_array()
135            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
136
137        let mut seen = HashSet::new();
138        let mut result = Vec::new();
139
140        for item in arr {
141            let key = serde_json::to_string(item).unwrap_or_default();
142            if seen.insert(key) {
143                result.push(item.clone());
144            }
145        }
146
147        Ok(Value::Array(result))
148    }
149}
150
151// =============================================================================
152// zip(array1, array2) -> array of pairs
153// =============================================================================
154
155defn!(ZipFn, vec![arg!(array), arg!(array)], None);
156
157impl Function for ZipFn {
158    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
159        self.signature.validate(args, ctx)?;
160
161        let arr1 = args[0]
162            .as_array()
163            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
164
165        let arr2 = args[1]
166            .as_array()
167            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
168
169        let result: Vec<Value> = arr1
170            .iter()
171            .zip(arr2.iter())
172            .map(|(a, b)| Value::Array(vec![a.clone(), b.clone()]))
173            .collect();
174
175        Ok(Value::Array(result))
176    }
177}
178
179// =============================================================================
180// chunk(array, size) -> array of arrays
181// =============================================================================
182
183defn!(ChunkFn, vec![arg!(array), arg!(number)], None);
184
185impl Function for ChunkFn {
186    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
187        self.signature.validate(args, ctx)?;
188
189        let arr = args[0]
190            .as_array()
191            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
192
193        let size = args[1]
194            .as_f64()
195            .map(|n| n as usize)
196            .ok_or_else(|| custom_error(ctx, "Expected positive number for size"))?;
197
198        if size == 0 {
199            return Ok(Value::Array(vec![]));
200        }
201
202        let chunks: Vec<Value> = arr
203            .chunks(size)
204            .map(|chunk| Value::Array(chunk.to_vec()))
205            .collect();
206
207        Ok(Value::Array(chunks))
208    }
209}
210
211// =============================================================================
212// take(array, n) -> array (first n elements)
213// =============================================================================
214
215defn!(TakeFn, vec![arg!(array), arg!(number)], None);
216
217impl Function for TakeFn {
218    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
219        self.signature.validate(args, ctx)?;
220
221        let arr = args[0]
222            .as_array()
223            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
224
225        let n = args[1]
226            .as_f64()
227            .map(|n| n as usize)
228            .ok_or_else(|| custom_error(ctx, "Expected positive number"))?;
229
230        let result: Vec<Value> = arr.iter().take(n).cloned().collect();
231
232        Ok(Value::Array(result))
233    }
234}
235
236// =============================================================================
237// drop(array, n) -> array (skip first n elements)
238// =============================================================================
239
240defn!(DropFn, vec![arg!(array), arg!(number)], None);
241
242impl Function for DropFn {
243    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
244        self.signature.validate(args, ctx)?;
245
246        let arr = args[0]
247            .as_array()
248            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
249
250        let n = args[1]
251            .as_f64()
252            .map(|n| n as usize)
253            .ok_or_else(|| custom_error(ctx, "Expected positive number"))?;
254
255        let result: Vec<Value> = arr.iter().skip(n).cloned().collect();
256
257        Ok(Value::Array(result))
258    }
259}
260
261// =============================================================================
262// flatten_deep(array) -> array (recursively flatten)
263// =============================================================================
264
265defn!(FlattenDeepFn, vec![arg!(array)], None);
266
267fn flatten_recursive(arr: &[Value]) -> Vec<Value> {
268    let mut result = Vec::new();
269    for item in arr {
270        if let Some(inner) = item.as_array() {
271            result.extend(flatten_recursive(inner));
272        } else {
273            result.push(item.clone());
274        }
275    }
276    result
277}
278
279impl Function for FlattenDeepFn {
280    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
281        self.signature.validate(args, ctx)?;
282
283        let arr = args[0]
284            .as_array()
285            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
286
287        Ok(Value::Array(flatten_recursive(arr)))
288    }
289}
290
291// =============================================================================
292// flatten(array) -> array (single-level flatten)
293// =============================================================================
294
295defn!(FlattenFn, vec![arg!(array)], None);
296
297impl Function for FlattenFn {
298    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
299        self.signature.validate(args, ctx)?;
300
301        let arr = args[0]
302            .as_array()
303            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
304
305        let mut result = Vec::new();
306        for item in arr {
307            if let Some(inner) = item.as_array() {
308                result.extend(inner.iter().cloned());
309            } else {
310                result.push(item.clone());
311            }
312        }
313
314        Ok(Value::Array(result))
315    }
316}
317
318// =============================================================================
319// compact(array) -> array (remove null/false values)
320// =============================================================================
321
322defn!(CompactFn, vec![arg!(array)], None);
323
324impl Function for CompactFn {
325    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
326        self.signature.validate(args, ctx)?;
327
328        let arr = args[0]
329            .as_array()
330            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
331
332        let result: Vec<Value> = arr
333            .iter()
334            .filter(|v| !v.is_null() && !matches!(v, Value::Bool(false)))
335            .cloned()
336            .collect();
337
338        Ok(Value::Array(result))
339    }
340}
341
342// =============================================================================
343// range(start, end, step?) -> array
344// =============================================================================
345
346defn!(
347    RangeFn,
348    vec![arg!(number), arg!(number)],
349    Some(arg!(number))
350);
351
352impl Function for RangeFn {
353    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
354        self.signature.validate(args, ctx)?;
355
356        let start = args[0]
357            .as_f64()
358            .map(|n| n as i64)
359            .ok_or_else(|| custom_error(ctx, "Expected start number"))?;
360
361        let end = args[1]
362            .as_f64()
363            .map(|n| n as i64)
364            .ok_or_else(|| custom_error(ctx, "Expected end number"))?;
365
366        let step = if args.len() > 2 {
367            args[2]
368                .as_f64()
369                .map(|n| n as i64)
370                .ok_or_else(|| custom_error(ctx, "Expected step number"))?
371        } else {
372            1
373        };
374
375        if step == 0 {
376            return Err(custom_error(ctx, "Step cannot be zero"));
377        }
378
379        let mut result = Vec::new();
380        let mut current = start;
381
382        const MAX_RANGE: usize = 10000;
383
384        if step > 0 {
385            while current < end && result.len() < MAX_RANGE {
386                result.push(Value::Number(Number::from(current)));
387                current += step;
388            }
389        } else {
390            while current > end && result.len() < MAX_RANGE {
391                result.push(Value::Number(Number::from(current)));
392                current += step;
393            }
394        }
395
396        Ok(Value::Array(result))
397    }
398}
399
400// =============================================================================
401// index_at(array, index) -> element (supports negative index)
402// =============================================================================
403
404defn!(IndexAtFn, vec![arg!(array), arg!(number)], None);
405
406impl Function for IndexAtFn {
407    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
408        self.signature.validate(args, ctx)?;
409
410        let arr = args[0]
411            .as_array()
412            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
413
414        let index = args[1]
415            .as_f64()
416            .map(|n| n as i64)
417            .ok_or_else(|| custom_error(ctx, "Expected number for index"))?;
418
419        let len = arr.len() as i64;
420        let actual_index = if index < 0 {
421            (len + index) as usize
422        } else {
423            index as usize
424        };
425
426        if actual_index < arr.len() {
427            Ok(arr[actual_index].clone())
428        } else {
429            Ok(Value::Null)
430        }
431    }
432}
433
434// =============================================================================
435// includes(array, value) -> boolean
436// =============================================================================
437
438defn!(IncludesFn, vec![arg!(array), arg!(any)], None);
439
440impl Function for IncludesFn {
441    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
442        self.signature.validate(args, ctx)?;
443
444        let arr = args[0]
445            .as_array()
446            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
447
448        let search_key = serde_json::to_string(&args[1]).unwrap_or_default();
449
450        let found = arr.iter().any(|item| {
451            let item_key = serde_json::to_string(item).unwrap_or_default();
452            item_key == search_key
453        });
454
455        Ok(Value::Bool(found))
456    }
457}
458
459// =============================================================================
460// find_index(array, value) -> number (-1 if not found)
461// =============================================================================
462
463defn!(FindIndexFn, vec![arg!(array), arg!(any)], None);
464
465impl Function for FindIndexFn {
466    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
467        self.signature.validate(args, ctx)?;
468
469        let arr = args[0]
470            .as_array()
471            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
472
473        let search_key = serde_json::to_string(&args[1]).unwrap_or_default();
474
475        let index = arr
476            .iter()
477            .position(|item| {
478                let item_key = serde_json::to_string(item).unwrap_or_default();
479                item_key == search_key
480            })
481            .map(|i| i as i64)
482            .unwrap_or(-1);
483
484        Ok(Value::Number(Number::from(index)))
485    }
486}
487
488// =============================================================================
489// first(array) -> any (first element or null)
490// =============================================================================
491
492defn!(FirstFn, vec![arg!(array)], None);
493
494impl Function for FirstFn {
495    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
496        self.signature.validate(args, ctx)?;
497
498        let arr = args[0]
499            .as_array()
500            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
501
502        Ok(arr.first().cloned().unwrap_or(Value::Null))
503    }
504}
505
506// =============================================================================
507// last(array) -> any (last element or null)
508// =============================================================================
509
510defn!(LastFn, vec![arg!(array)], None);
511
512impl Function for LastFn {
513    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
514        self.signature.validate(args, ctx)?;
515
516        let arr = args[0]
517            .as_array()
518            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
519
520        Ok(arr.last().cloned().unwrap_or(Value::Null))
521    }
522}
523
524// =============================================================================
525// group_by(array, field_name) -> object
526// =============================================================================
527
528defn!(GroupByFn, vec![arg!(array), arg!(string)], None);
529
530impl Function for GroupByFn {
531    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
532        self.signature.validate(args, ctx)?;
533
534        let arr = args[0]
535            .as_array()
536            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
537
538        let field_name = args[1]
539            .as_str()
540            .ok_or_else(|| custom_error(ctx, "Expected field name string"))?;
541
542        let mut groups: std::collections::BTreeMap<String, Vec<Value>> =
543            std::collections::BTreeMap::new();
544
545        for item in arr {
546            let key = if let Some(obj) = item.as_object() {
547                if let Some(field_value) = obj.get(field_name) {
548                    match field_value {
549                        Value::String(s) => s.clone(),
550                        Value::Number(n) => n.to_string(),
551                        Value::Bool(b) => b.to_string(),
552                        Value::Null => "null".to_string(),
553                        _ => continue,
554                    }
555                } else {
556                    "null".to_string()
557                }
558            } else {
559                continue;
560            };
561            groups.entry(key).or_default().push(item.clone());
562        }
563
564        let mut result = serde_json::Map::new();
565        for (k, v) in groups {
566            result.insert(k, Value::Array(v));
567        }
568
569        Ok(Value::Object(result))
570    }
571}
572
573// =============================================================================
574// index_by(array, field_name) -> object (last value wins for duplicates)
575// =============================================================================
576
577defn!(IndexByFn, vec![arg!(array), arg!(string)], None);
578
579impl Function for IndexByFn {
580    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
581        self.signature.validate(args, ctx)?;
582
583        let arr = args[0]
584            .as_array()
585            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
586
587        let field_name = args[1]
588            .as_str()
589            .ok_or_else(|| custom_error(ctx, "Expected field name string"))?;
590
591        let mut result = serde_json::Map::new();
592
593        for item in arr {
594            let key = if let Some(obj) = item.as_object() {
595                if let Some(field_value) = obj.get(field_name) {
596                    match field_value {
597                        Value::String(s) => s.clone(),
598                        Value::Number(n) => n.to_string(),
599                        Value::Bool(b) => b.to_string(),
600                        Value::Null => "null".to_string(),
601                        _ => continue,
602                    }
603                } else {
604                    // Skip items without the key field
605                    continue;
606                }
607            } else {
608                continue;
609            };
610            // Last value wins for duplicate keys
611            result.insert(key, item.clone());
612        }
613
614        Ok(Value::Object(result))
615    }
616}
617
618// =============================================================================
619// nth(array, n) -> array (every nth element)
620// =============================================================================
621
622defn!(NthFn, vec![arg!(array), arg!(number)], None);
623
624impl Function for NthFn {
625    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
626        self.signature.validate(args, ctx)?;
627
628        let arr = args[0]
629            .as_array()
630            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
631
632        let n = args[1]
633            .as_f64()
634            .ok_or_else(|| custom_error(ctx, "Expected number argument"))? as usize;
635
636        if n == 0 {
637            return Ok(Value::Null);
638        }
639
640        let result: Vec<Value> = arr.iter().step_by(n).cloned().collect();
641        Ok(Value::Array(result))
642    }
643}
644
645// =============================================================================
646// interleave(array1, array2) -> array (alternate elements)
647// =============================================================================
648
649defn!(InterleaveFn, vec![arg!(array), arg!(array)], None);
650
651impl Function for InterleaveFn {
652    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
653        self.signature.validate(args, ctx)?;
654
655        let arr1 = args[0]
656            .as_array()
657            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
658
659        let arr2 = args[1]
660            .as_array()
661            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
662
663        let mut result = Vec::with_capacity(arr1.len() + arr2.len());
664        let mut iter1 = arr1.iter();
665        let mut iter2 = arr2.iter();
666
667        loop {
668            match (iter1.next(), iter2.next()) {
669                (Some(a), Some(b)) => {
670                    result.push(a.clone());
671                    result.push(b.clone());
672                }
673                (Some(a), None) => {
674                    result.push(a.clone());
675                    result.extend(iter1.cloned());
676                    break;
677                }
678                (None, Some(b)) => {
679                    result.push(b.clone());
680                    result.extend(iter2.cloned());
681                    break;
682                }
683                (None, None) => break,
684            }
685        }
686
687        Ok(Value::Array(result))
688    }
689}
690
691// =============================================================================
692// rotate(array, n) -> array (rotate elements by n positions)
693// =============================================================================
694
695defn!(RotateFn, vec![arg!(array), arg!(number)], None);
696
697impl Function for RotateFn {
698    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
699        self.signature.validate(args, ctx)?;
700
701        let arr = args[0]
702            .as_array()
703            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
704
705        if arr.is_empty() {
706            return Ok(Value::Array(vec![]));
707        }
708
709        let n = args[1]
710            .as_f64()
711            .ok_or_else(|| custom_error(ctx, "Expected number argument"))? as i64;
712
713        let len = arr.len() as i64;
714        let rotation = ((n % len) + len) % len;
715        let rotation = rotation as usize;
716
717        let mut result = Vec::with_capacity(arr.len());
718        result.extend(arr[rotation..].iter().cloned());
719        result.extend(arr[..rotation].iter().cloned());
720
721        Ok(Value::Array(result))
722    }
723}
724
725// =============================================================================
726// partition(array, n) -> array (split into n equal parts)
727// =============================================================================
728
729defn!(PartitionFn, vec![arg!(array), arg!(number)], None);
730
731impl Function for PartitionFn {
732    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
733        self.signature.validate(args, ctx)?;
734
735        let arr = args[0]
736            .as_array()
737            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
738
739        let n = args[1]
740            .as_f64()
741            .ok_or_else(|| custom_error(ctx, "Expected number argument"))? as usize;
742
743        if n == 0 {
744            return Ok(Value::Null);
745        }
746
747        let len = arr.len();
748        let base_size = len / n;
749        let remainder = len % n;
750
751        let mut result = Vec::with_capacity(n);
752        let mut start = 0;
753
754        for i in 0..n {
755            let size = base_size + if i < remainder { 1 } else { 0 };
756            if size > 0 {
757                result.push(Value::Array(arr[start..start + size].to_vec()));
758            } else {
759                result.push(Value::Array(vec![]));
760            }
761            start += size;
762        }
763
764        Ok(Value::Array(result))
765    }
766}
767
768// =============================================================================
769// difference(arr1, arr2) -> array (set difference)
770// =============================================================================
771
772defn!(DifferenceFn, vec![arg!(array), arg!(array)], None);
773
774impl Function for DifferenceFn {
775    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
776        self.signature.validate(args, ctx)?;
777
778        let arr1 = args[0]
779            .as_array()
780            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
781
782        let arr2 = args[1]
783            .as_array()
784            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
785
786        let set2: HashSet<String> = arr2
787            .iter()
788            .map(|v| serde_json::to_string(v).unwrap_or_default())
789            .collect();
790
791        let result: Vec<Value> = arr1
792            .iter()
793            .filter(|v| {
794                let key = serde_json::to_string(*v).unwrap_or_default();
795                !set2.contains(&key)
796            })
797            .cloned()
798            .collect();
799
800        Ok(Value::Array(result))
801    }
802}
803
804// =============================================================================
805// intersection(arr1, arr2) -> array (set intersection)
806// =============================================================================
807
808defn!(IntersectionFn, vec![arg!(array), arg!(array)], None);
809
810impl Function for IntersectionFn {
811    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
812        self.signature.validate(args, ctx)?;
813
814        let arr1 = args[0]
815            .as_array()
816            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
817
818        let arr2 = args[1]
819            .as_array()
820            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
821
822        let set2: HashSet<String> = arr2
823            .iter()
824            .map(|v| serde_json::to_string(v).unwrap_or_default())
825            .collect();
826
827        let mut seen: HashSet<String> = HashSet::new();
828        let result: Vec<Value> = arr1
829            .iter()
830            .filter(|v| {
831                let key = serde_json::to_string(*v).unwrap_or_default();
832                set2.contains(&key) && seen.insert(key)
833            })
834            .cloned()
835            .collect();
836
837        Ok(Value::Array(result))
838    }
839}
840
841// =============================================================================
842// union(arr1, arr2) -> array (set union)
843// =============================================================================
844
845defn!(UnionFn, vec![arg!(array), arg!(array)], None);
846
847impl Function for UnionFn {
848    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
849        self.signature.validate(args, ctx)?;
850
851        let arr1 = args[0]
852            .as_array()
853            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
854
855        let arr2 = args[1]
856            .as_array()
857            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
858
859        let mut seen: HashSet<String> = HashSet::new();
860        let mut result: Vec<Value> = Vec::new();
861
862        for item in arr1.iter().chain(arr2.iter()) {
863            let key = serde_json::to_string(item).unwrap_or_default();
864            if seen.insert(key) {
865                result.push(item.clone());
866            }
867        }
868
869        Ok(Value::Array(result))
870    }
871}
872
873// =============================================================================
874// frequencies(array) -> object (count occurrences)
875// =============================================================================
876
877defn!(FrequenciesFn, vec![arg!(array)], None);
878
879impl Function for FrequenciesFn {
880    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
881        self.signature.validate(args, ctx)?;
882
883        let arr = args[0]
884            .as_array()
885            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
886
887        let mut counts: std::collections::HashMap<String, i64> = std::collections::HashMap::new();
888
889        for item in arr {
890            let key = match item {
891                Value::String(s) => s.clone(),
892                Value::Number(n) => n.to_string(),
893                Value::Bool(b) => b.to_string(),
894                Value::Null => "null".to_string(),
895                _ => serde_json::to_string(item).unwrap_or_else(|_| "null".to_string()),
896            };
897            *counts.entry(key).or_insert(0) += 1;
898        }
899
900        let mut result = serde_json::Map::new();
901        // Use BTreeMap for sorted output
902        let sorted: std::collections::BTreeMap<String, i64> = counts.into_iter().collect();
903        for (k, v) in sorted {
904            result.insert(k, Value::Number(Number::from(v)));
905        }
906
907        Ok(Value::Object(result))
908    }
909}
910
911// =============================================================================
912// mode(array) -> any (most frequent value)
913// =============================================================================
914
915defn!(ModeFn, vec![arg!(array)], None);
916
917impl Function for ModeFn {
918    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
919        self.signature.validate(args, ctx)?;
920
921        let arr = args[0]
922            .as_array()
923            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
924
925        if arr.is_empty() {
926            return Ok(Value::Null);
927        }
928
929        let mut counts: std::collections::HashMap<String, (i64, Value)> =
930            std::collections::HashMap::new();
931
932        for item in arr {
933            let key = serde_json::to_string(item).unwrap_or_default();
934            counts
935                .entry(key)
936                .and_modify(|(count, _)| *count += 1)
937                .or_insert((1, item.clone()));
938        }
939
940        let (_, (_, mode_value)) = counts
941            .into_iter()
942            .max_by_key(|(_, (count, _))| *count)
943            .unwrap();
944
945        Ok(mode_value)
946    }
947}
948
949// =============================================================================
950// cartesian(arr1, arr2) -> array (cartesian product of 2 arrays)
951// cartesian(array_of_arrays) -> array (cartesian product of N arrays, jq parity)
952// =============================================================================
953
954defn!(CartesianFn, vec![arg!(array)], Some(arg!(array)));
955
956impl Function for CartesianFn {
957    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
958        self.signature.validate(args, ctx)?;
959
960        let first = args[0]
961            .as_array()
962            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
963
964        // Two modes:
965        // 1. cartesian(arr1, arr2) - two separate arrays (original behavior)
966        // 2. cartesian(array_of_arrays) - single array containing arrays (jq-style)
967
968        if args.len() == 2 {
969            // Original two-argument mode
970            let arr2 = args[1]
971                .as_array()
972                .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
973
974            let mut result = Vec::with_capacity(first.len() * arr2.len());
975            for a in first {
976                for b in arr2 {
977                    result.push(Value::Array(vec![a.clone(), b.clone()]));
978                }
979            }
980            Ok(Value::Array(result))
981        } else {
982            // Single argument mode - check if it's an array of arrays
983            // If all elements are arrays, do N-way cartesian product
984            let arrays: Vec<&Vec<Value>> =
985                first.iter().filter_map(|item| item.as_array()).collect();
986
987            if arrays.len() != first.len() || arrays.is_empty() {
988                // Not all elements are arrays, or empty - return empty
989                return Ok(Value::Array(vec![]));
990            }
991
992            // N-way cartesian product
993            let result = cartesian_product_n(&arrays);
994            Ok(Value::Array(result))
995        }
996    }
997}
998
999/// Compute N-way cartesian product of arrays.
1000fn cartesian_product_n(arrays: &[&Vec<Value>]) -> Vec<Value> {
1001    if arrays.is_empty() {
1002        return vec![];
1003    }
1004
1005    if arrays.len() == 1 {
1006        // Single array - each element becomes a 1-element tuple
1007        return arrays[0]
1008            .iter()
1009            .map(|item| Value::Array(vec![item.clone()]))
1010            .collect();
1011    }
1012
1013    // Calculate total size for pre-allocation
1014    let total_size: usize = arrays.iter().map(|a| a.len()).product();
1015    if total_size == 0 {
1016        return vec![];
1017    }
1018
1019    let mut result = Vec::with_capacity(total_size);
1020
1021    // Iterative cartesian product using indices
1022    let mut indices = vec![0usize; arrays.len()];
1023
1024    loop {
1025        // Build current combination
1026        let combo: Vec<Value> = indices
1027            .iter()
1028            .enumerate()
1029            .map(|(arr_idx, &elem_idx)| arrays[arr_idx][elem_idx].clone())
1030            .collect();
1031        result.push(Value::Array(combo));
1032
1033        // Increment indices (like counting in mixed radix)
1034        let mut carry = true;
1035        for i in (0..arrays.len()).rev() {
1036            if carry {
1037                indices[i] += 1;
1038                if indices[i] >= arrays[i].len() {
1039                    indices[i] = 0;
1040                } else {
1041                    carry = false;
1042                }
1043            }
1044        }
1045
1046        // If we carried all the way through, we're done
1047        if carry {
1048            break;
1049        }
1050    }
1051
1052    result
1053}
1054
1055// =============================================================================
1056// initial(array) -> array (all elements except the last)
1057// =============================================================================
1058
1059defn!(InitialFn, vec![arg!(array)], None);
1060
1061impl Function for InitialFn {
1062    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1063        self.signature.validate(args, ctx)?;
1064
1065        let arr = args[0]
1066            .as_array()
1067            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1068
1069        if arr.is_empty() {
1070            return Ok(Value::Array(vec![]));
1071        }
1072
1073        let result: Vec<Value> = arr[..arr.len() - 1].to_vec();
1074        Ok(Value::Array(result))
1075    }
1076}
1077
1078// =============================================================================
1079// interpose(array, separator) -> array (insert separator between elements)
1080// =============================================================================
1081
1082defn!(InterposeFn, vec![arg!(array), arg!(any)], None);
1083
1084impl Function for InterposeFn {
1085    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1086        self.signature.validate(args, ctx)?;
1087
1088        let arr = args[0]
1089            .as_array()
1090            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1091
1092        let separator = args[1].clone();
1093
1094        if arr.is_empty() {
1095            return Ok(Value::Array(vec![]));
1096        }
1097
1098        if arr.len() == 1 {
1099            return Ok(Value::Array(arr.clone()));
1100        }
1101
1102        let mut result = Vec::with_capacity(arr.len() * 2 - 1);
1103        for (i, item) in arr.iter().enumerate() {
1104            if i > 0 {
1105                result.push(separator.clone());
1106            }
1107            result.push(item.clone());
1108        }
1109
1110        Ok(Value::Array(result))
1111    }
1112}
1113
1114// =============================================================================
1115// zipmap(keys, values) -> object (create object from parallel arrays)
1116// =============================================================================
1117
1118defn!(ZipmapFn, vec![arg!(array), arg!(array)], None);
1119
1120impl Function for ZipmapFn {
1121    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1122        self.signature.validate(args, ctx)?;
1123
1124        let keys = args[0]
1125            .as_array()
1126            .ok_or_else(|| custom_error(ctx, "Expected array argument for keys"))?;
1127
1128        let values = args[1]
1129            .as_array()
1130            .ok_or_else(|| custom_error(ctx, "Expected array argument for values"))?;
1131
1132        let len = keys.len().min(values.len());
1133        let mut result = serde_json::Map::new();
1134
1135        for i in 0..len {
1136            let key = keys[i]
1137                .as_str()
1138                .ok_or_else(|| custom_error(ctx, "Keys must be strings"))?;
1139            result.insert(key.to_string(), values[i].clone());
1140        }
1141
1142        Ok(Value::Object(result))
1143    }
1144}
1145
1146// =============================================================================
1147// partition_by(array, field_name) -> array (split when field value changes)
1148// =============================================================================
1149
1150defn!(PartitionByFn, vec![arg!(array), arg!(string)], None);
1151
1152impl Function for PartitionByFn {
1153    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1154        self.signature.validate(args, ctx)?;
1155
1156        let arr = args[0]
1157            .as_array()
1158            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1159
1160        let field_name = args[1]
1161            .as_str()
1162            .ok_or_else(|| custom_error(ctx, "Expected field name string"))?;
1163
1164        if arr.is_empty() {
1165            return Ok(Value::Array(vec![]));
1166        }
1167
1168        let mut result: Vec<Value> = Vec::new();
1169        let mut current_partition: Vec<Value> = Vec::new();
1170        let mut last_key: Option<String> = None;
1171
1172        for item in arr {
1173            // Extract key from object field, or serialize the item itself for primitives
1174            let key = if let Some(obj) = item.as_object() {
1175                if let Some(field_value) = obj.get(field_name) {
1176                    serde_json::to_string(field_value).unwrap_or_default()
1177                } else {
1178                    "null".to_string()
1179                }
1180            } else {
1181                // For non-objects, use the value itself as the key
1182                serde_json::to_string(item).unwrap_or_default()
1183            };
1184
1185            match &last_key {
1186                Some(prev_key) if *prev_key == key => {
1187                    current_partition.push(item.clone());
1188                }
1189                _ => {
1190                    if !current_partition.is_empty() {
1191                        result.push(Value::Array(current_partition));
1192                    }
1193                    current_partition = vec![item.clone()];
1194                    last_key = Some(key);
1195                }
1196            }
1197        }
1198
1199        // Don't forget the last partition
1200        if !current_partition.is_empty() {
1201            result.push(Value::Array(current_partition));
1202        }
1203
1204        Ok(Value::Array(result))
1205    }
1206}
1207
1208// =============================================================================
1209// dedupe(array) -> array (remove consecutive duplicates)
1210// =============================================================================
1211
1212defn!(DedupeFn, vec![arg!(array)], None);
1213
1214impl Function for DedupeFn {
1215    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1216        self.signature.validate(args, ctx)?;
1217
1218        let arr = args[0]
1219            .as_array()
1220            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1221
1222        if arr.is_empty() {
1223            return Ok(Value::Array(vec![]));
1224        }
1225
1226        let mut result: Vec<Value> = Vec::with_capacity(arr.len());
1227        let mut last_key: Option<String> = None;
1228
1229        for item in arr {
1230            let key = serde_json::to_string(item).unwrap_or_default();
1231            match &last_key {
1232                Some(prev_key) if *prev_key == key => {
1233                    // Skip consecutive duplicate
1234                }
1235                _ => {
1236                    result.push(item.clone());
1237                    last_key = Some(key);
1238                }
1239            }
1240        }
1241
1242        Ok(Value::Array(result))
1243    }
1244}
1245
1246// =============================================================================
1247// tail(array) -> array (all elements except the first)
1248// =============================================================================
1249
1250defn!(TailFn, vec![arg!(array)], None);
1251
1252impl Function for TailFn {
1253    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1254        self.signature.validate(args, ctx)?;
1255
1256        let arr = args[0]
1257            .as_array()
1258            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1259
1260        if arr.is_empty() {
1261            return Ok(Value::Array(vec![]));
1262        }
1263
1264        let result: Vec<Value> = arr[1..].to_vec();
1265        Ok(Value::Array(result))
1266    }
1267}
1268
1269// =============================================================================
1270// without(array, values_array) -> array (remove specified values)
1271// =============================================================================
1272
1273defn!(WithoutFn, vec![arg!(array), arg!(array)], None);
1274
1275impl Function for WithoutFn {
1276    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1277        self.signature.validate(args, ctx)?;
1278
1279        let arr = args[0]
1280            .as_array()
1281            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1282
1283        let exclude = args[1]
1284            .as_array()
1285            .ok_or_else(|| custom_error(ctx, "Expected array argument for values to exclude"))?;
1286
1287        // Create a set of serialized values to exclude for efficient lookup
1288        let exclude_set: HashSet<String> = exclude
1289            .iter()
1290            .map(|v| serde_json::to_string(v).unwrap_or_default())
1291            .collect();
1292
1293        let result: Vec<Value> = arr
1294            .iter()
1295            .filter(|item| {
1296                let key = serde_json::to_string(*item).unwrap_or_default();
1297                !exclude_set.contains(&key)
1298            })
1299            .cloned()
1300            .collect();
1301
1302        Ok(Value::Array(result))
1303    }
1304}
1305
1306// =============================================================================
1307// xor(array1, array2) -> array (symmetric difference)
1308// =============================================================================
1309
1310defn!(XorFn, vec![arg!(array), arg!(array)], None);
1311
1312impl Function for XorFn {
1313    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1314        self.signature.validate(args, ctx)?;
1315
1316        let arr1 = args[0]
1317            .as_array()
1318            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1319
1320        let arr2 = args[1]
1321            .as_array()
1322            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1323
1324        // Create sets of serialized values
1325        let set1: HashSet<String> = arr1
1326            .iter()
1327            .map(|v| serde_json::to_string(v).unwrap_or_default())
1328            .collect();
1329
1330        let set2: HashSet<String> = arr2
1331            .iter()
1332            .map(|v| serde_json::to_string(v).unwrap_or_default())
1333            .collect();
1334
1335        let mut result = Vec::new();
1336
1337        // Add elements from arr1 that are not in arr2
1338        for item in arr1 {
1339            let key = serde_json::to_string(item).unwrap_or_default();
1340            if !set2.contains(&key) {
1341                result.push(item.clone());
1342            }
1343        }
1344
1345        // Add elements from arr2 that are not in arr1
1346        for item in arr2 {
1347            let key = serde_json::to_string(item).unwrap_or_default();
1348            if !set1.contains(&key) {
1349                result.push(item.clone());
1350            }
1351        }
1352
1353        Ok(Value::Array(result))
1354    }
1355}
1356
1357// =============================================================================
1358// window(array, size, step?) -> array (sliding window)
1359// =============================================================================
1360
1361defn!(
1362    WindowFn,
1363    vec![arg!(array), arg!(number)],
1364    Some(arg!(number))
1365);
1366
1367impl Function for WindowFn {
1368    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1369        self.signature.validate(args, ctx)?;
1370
1371        let arr = args[0]
1372            .as_array()
1373            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1374
1375        let size = args[1]
1376            .as_f64()
1377            .ok_or_else(|| custom_error(ctx, "Expected number for window size"))?
1378            as usize;
1379
1380        if size == 0 {
1381            return Ok(Value::Array(vec![]));
1382        }
1383
1384        // Default step is 1
1385        let step = if args.len() > 2 {
1386            args[2]
1387                .as_f64()
1388                .ok_or_else(|| custom_error(ctx, "Expected number for step"))? as usize
1389        } else {
1390            1
1391        };
1392
1393        if step == 0 {
1394            return Err(custom_error(ctx, "Step cannot be zero"));
1395        }
1396
1397        let len = arr.len();
1398        if len < size {
1399            return Ok(Value::Array(vec![]));
1400        }
1401
1402        let mut result = Vec::new();
1403        let mut i = 0;
1404
1405        while i + size <= len {
1406            let window: Vec<Value> = arr[i..i + size].to_vec();
1407            result.push(Value::Array(window));
1408            i += step;
1409        }
1410
1411        Ok(Value::Array(result))
1412    }
1413}
1414
1415// =============================================================================
1416// combinations(array, k) -> array (k-combinations of array)
1417// =============================================================================
1418
1419defn!(CombinationsFn, vec![arg!(array), arg!(number)], None);
1420
1421fn generate_combinations(arr: &[Value], k: usize) -> Vec<Vec<Value>> {
1422    if k == 0 {
1423        return vec![vec![]];
1424    }
1425    if arr.len() < k {
1426        return vec![];
1427    }
1428
1429    let mut result = Vec::new();
1430
1431    // Include first element in combination
1432    let first = arr[0].clone();
1433    let rest = &arr[1..];
1434    for mut combo in generate_combinations(rest, k - 1) {
1435        let mut new_combo = vec![first.clone()];
1436        new_combo.append(&mut combo);
1437        result.push(new_combo);
1438    }
1439
1440    // Exclude first element
1441    result.extend(generate_combinations(rest, k));
1442
1443    result
1444}
1445
1446impl Function for CombinationsFn {
1447    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1448        self.signature.validate(args, ctx)?;
1449
1450        let arr = args[0]
1451            .as_array()
1452            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1453
1454        let k = args[1]
1455            .as_f64()
1456            .ok_or_else(|| custom_error(ctx, "Expected number for k"))? as usize;
1457
1458        // Limit to prevent excessive computation
1459        const MAX_COMBINATIONS: usize = 10000;
1460
1461        // Quick check: if C(n, k) would be too large, return error
1462        let n = arr.len();
1463        if n > 20 && k > 3 && k < n - 3 {
1464            return Err(custom_error(ctx, "Combination size too large"));
1465        }
1466
1467        let combinations = generate_combinations(arr, k);
1468
1469        if combinations.len() > MAX_COMBINATIONS {
1470            return Err(custom_error(ctx, "Too many combinations generated"));
1471        }
1472
1473        let result: Vec<Value> = combinations.into_iter().map(Value::Array).collect();
1474
1475        Ok(Value::Array(result))
1476    }
1477}
1478
1479// =============================================================================
1480// fill(array, value, start?, end?) -> array (fill range with value)
1481// =============================================================================
1482
1483defn!(FillFn, vec![arg!(array), arg!(any)], Some(arg!(number)));
1484
1485impl Function for FillFn {
1486    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1487        self.signature.validate(args, ctx)?;
1488
1489        let arr = args[0]
1490            .as_array()
1491            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1492
1493        let fill_value = args[1].clone();
1494
1495        let len = arr.len();
1496        if len == 0 {
1497            return Ok(Value::Array(vec![]));
1498        }
1499
1500        // Default start is 0, default end is array length
1501        let start = if args.len() > 2 {
1502            let s = args[2]
1503                .as_f64()
1504                .ok_or_else(|| custom_error(ctx, "Expected number for start index"))?
1505                as i64;
1506            // Handle negative indices
1507            if s < 0 {
1508                (len as i64 + s).max(0) as usize
1509            } else {
1510                (s as usize).min(len)
1511            }
1512        } else {
1513            0
1514        };
1515
1516        let end = if args.len() > 3 {
1517            let e = args[3]
1518                .as_f64()
1519                .ok_or_else(|| custom_error(ctx, "Expected number for end index"))?
1520                as i64;
1521            // Handle negative indices
1522            if e < 0 {
1523                (len as i64 + e).max(0) as usize
1524            } else {
1525                (e as usize).min(len)
1526            }
1527        } else {
1528            len
1529        };
1530
1531        let mut result: Vec<Value> = arr.clone();
1532
1533        for item in result.iter_mut().take(end.min(len)).skip(start) {
1534            *item = fill_value.clone();
1535        }
1536
1537        Ok(Value::Array(result))
1538    }
1539}
1540
1541// =============================================================================
1542// pull_at(array, indices_array) -> array (get elements at specified indices)
1543// =============================================================================
1544
1545defn!(PullAtFn, vec![arg!(array), arg!(array)], None);
1546
1547impl Function for PullAtFn {
1548    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1549        self.signature.validate(args, ctx)?;
1550
1551        let arr = args[0]
1552            .as_array()
1553            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1554
1555        let indices = args[1]
1556            .as_array()
1557            .ok_or_else(|| custom_error(ctx, "Expected array of indices"))?;
1558
1559        let len = arr.len();
1560        let mut result = Vec::new();
1561
1562        for idx_var in indices {
1563            let idx = idx_var
1564                .as_f64()
1565                .ok_or_else(|| custom_error(ctx, "Expected number in indices array"))?
1566                as i64;
1567
1568            // Handle negative indices
1569            let actual_idx = if idx < 0 {
1570                (len as i64 + idx).max(0) as usize
1571            } else {
1572                idx as usize
1573            };
1574
1575            if actual_idx < len {
1576                result.push(arr[actual_idx].clone());
1577            }
1578        }
1579
1580        Ok(Value::Array(result))
1581    }
1582}
1583
1584// =============================================================================
1585// transpose(array) -> array
1586// =============================================================================
1587
1588defn!(TransposeFn, vec![arg!(array)], None);
1589
1590impl Function for TransposeFn {
1591    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1592        self.signature.validate(args, ctx)?;
1593
1594        let arr = args[0]
1595            .as_array()
1596            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1597
1598        if arr.is_empty() {
1599            return Ok(Value::Array(vec![]));
1600        }
1601
1602        // Get all inner arrays and find the minimum length
1603        let mut inner_arrays: Vec<&Vec<Value>> = Vec::new();
1604        let mut min_len = usize::MAX;
1605
1606        for item in arr {
1607            if let Some(inner) = item.as_array() {
1608                min_len = min_len.min(inner.len());
1609                inner_arrays.push(inner);
1610            } else {
1611                // If any element is not an array, return empty
1612                return Ok(Value::Array(vec![]));
1613            }
1614        }
1615
1616        if inner_arrays.is_empty() || min_len == 0 {
1617            return Ok(Value::Array(vec![]));
1618        }
1619
1620        // Transpose: create new arrays where each contains the i-th element from each inner array
1621        let mut result = Vec::with_capacity(min_len);
1622        for i in 0..min_len {
1623            let mut row = Vec::with_capacity(inner_arrays.len());
1624            for inner in &inner_arrays {
1625                row.push(inner[i].clone());
1626            }
1627            result.push(Value::Array(row));
1628        }
1629
1630        Ok(Value::Array(result))
1631    }
1632}
1633
1634// =============================================================================
1635// pairwise(array) -> array
1636// =============================================================================
1637
1638defn!(PairwiseFn, vec![arg!(array)], None);
1639
1640impl Function for PairwiseFn {
1641    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1642        self.signature.validate(args, ctx)?;
1643
1644        let arr = args[0]
1645            .as_array()
1646            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1647
1648        if arr.len() < 2 {
1649            return Ok(Value::Array(vec![]));
1650        }
1651
1652        let mut result = Vec::with_capacity(arr.len() - 1);
1653        for i in 0..arr.len() - 1 {
1654            let pair = vec![arr[i].clone(), arr[i + 1].clone()];
1655            result.push(Value::Array(pair));
1656        }
1657
1658        Ok(Value::Array(result))
1659    }
1660}
1661
1662// =============================================================================
1663// indices_array(array, value) -> array of indices
1664// =============================================================================
1665
1666defn!(IndicesArrayFn, vec![arg!(array), arg!(any)], None);
1667
1668impl Function for IndicesArrayFn {
1669    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1670        self.signature.validate(args, ctx)?;
1671
1672        let arr = args[0]
1673            .as_array()
1674            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1675
1676        let search_key = serde_json::to_string(&args[1]).unwrap_or_default();
1677
1678        let mut indices: Vec<Value> = Vec::new();
1679        for (i, item) in arr.iter().enumerate() {
1680            let item_key = serde_json::to_string(item).unwrap_or_default();
1681            if item_key == search_key {
1682                indices.push(Value::Number(Number::from(i as i64)));
1683            }
1684        }
1685
1686        Ok(Value::Array(indices))
1687    }
1688}
1689
1690// =============================================================================
1691// inside_array(needle, haystack) -> boolean
1692// =============================================================================
1693
1694defn!(InsideArrayFn, vec![arg!(array), arg!(array)], None);
1695
1696impl Function for InsideArrayFn {
1697    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1698        self.signature.validate(args, ctx)?;
1699
1700        let needle = args[0]
1701            .as_array()
1702            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1703
1704        let haystack = args[1]
1705            .as_array()
1706            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1707
1708        // Build a set of serialized haystack values for efficient lookup
1709        let haystack_set: HashSet<String> = haystack
1710            .iter()
1711            .map(|item| serde_json::to_string(item).unwrap_or_default())
1712            .collect();
1713
1714        // Check if all needle elements are in the haystack
1715        let result = needle.iter().all(|item| {
1716            let item_key = serde_json::to_string(item).unwrap_or_default();
1717            haystack_set.contains(&item_key)
1718        });
1719
1720        Ok(Value::Bool(result))
1721    }
1722}
1723
1724// =============================================================================
1725// bsearch(sorted_array, value) -> number
1726// =============================================================================
1727
1728defn!(BsearchFn, vec![arg!(array), arg!(any)], None);
1729
1730impl Function for BsearchFn {
1731    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1732        self.signature.validate(args, ctx)?;
1733
1734        let arr = args[0]
1735            .as_array()
1736            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1737
1738        let target = &args[1];
1739
1740        if arr.is_empty() {
1741            return Ok(Value::Number(Number::from(-1)));
1742        }
1743
1744        // Helper to compare two Value values
1745        // Returns Ordering based on type-aware comparison
1746        fn compare_values(a: &Value, b: &Value) -> std::cmp::Ordering {
1747            match (a, b) {
1748                // Numbers: compare numerically
1749                (Value::Number(n1), Value::Number(n2)) => {
1750                    let f1 = n1.as_f64().unwrap_or(0.0);
1751                    let f2 = n2.as_f64().unwrap_or(0.0);
1752                    f1.partial_cmp(&f2).unwrap_or(std::cmp::Ordering::Equal)
1753                }
1754                // Strings: compare lexicographically
1755                (Value::String(s1), Value::String(s2)) => s1.cmp(s2),
1756                // Booleans: false < true
1757                (Value::Bool(b1), Value::Bool(b2)) => b1.cmp(b2),
1758                // Different types or complex types: fall back to JSON string comparison
1759                _ => {
1760                    let s1 = serde_json::to_string(a).unwrap_or_default();
1761                    let s2 = serde_json::to_string(b).unwrap_or_default();
1762                    s1.cmp(&s2)
1763                }
1764            }
1765        }
1766
1767        let mut left = 0i64;
1768        let mut right = arr.len() as i64 - 1;
1769
1770        while left <= right {
1771            let mid = left + (right - left) / 2;
1772
1773            match compare_values(&arr[mid as usize], target) {
1774                std::cmp::Ordering::Equal => {
1775                    return Ok(Value::Number(Number::from(mid)));
1776                }
1777                std::cmp::Ordering::Less => {
1778                    left = mid + 1;
1779                }
1780                std::cmp::Ordering::Greater => {
1781                    right = mid - 1;
1782                }
1783            }
1784        }
1785
1786        // Not found - return -(insertion_point) - 1
1787        // At this point, left is the insertion point
1788        let result = -(left) - 1;
1789        Ok(Value::Number(Number::from(result)))
1790    }
1791}
1792
1793// =============================================================================
1794// repeat_array(value, n) -> array (create array with value repeated n times)
1795// =============================================================================
1796
1797defn!(RepeatArrayFn, vec![arg!(any), arg!(number)], None);
1798
1799impl Function for RepeatArrayFn {
1800    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1801        self.signature.validate(args, ctx)?;
1802
1803        let value = &args[0];
1804        let n = args[1]
1805            .as_f64()
1806            .ok_or_else(|| custom_error(ctx, "Expected number for count argument"))?
1807            as i64;
1808
1809        if n < 0 {
1810            return Err(custom_error(ctx, "Count must be non-negative"));
1811        }
1812
1813        let result: Vec<Value> = (0..n).map(|_| value.clone()).collect();
1814        Ok(Value::Array(result))
1815    }
1816}
1817
1818// =============================================================================
1819// cycle(array, n) -> array (cycle through array n times)
1820// =============================================================================
1821
1822defn!(CycleFn, vec![arg!(array), arg!(number)], None);
1823
1824impl Function for CycleFn {
1825    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
1826        self.signature.validate(args, ctx)?;
1827
1828        let arr = args[0]
1829            .as_array()
1830            .ok_or_else(|| custom_error(ctx, "Expected array argument"))?;
1831
1832        let n = args[1]
1833            .as_f64()
1834            .ok_or_else(|| custom_error(ctx, "Expected number for count argument"))?
1835            as i64;
1836
1837        if n < 0 {
1838            return Err(custom_error(ctx, "Count must be non-negative"));
1839        }
1840
1841        if arr.is_empty() || n == 0 {
1842            return Ok(Value::Array(vec![]));
1843        }
1844
1845        let mut result: Vec<Value> = Vec::with_capacity(arr.len() * n as usize);
1846        for _ in 0..n {
1847            result.extend(arr.iter().cloned());
1848        }
1849        Ok(Value::Array(result))
1850    }
1851}