cel-cxx 0.2.5

A high-performance, type-safe Rust interface for Common Expression Language (CEL), build on top of cel-cpp with zero-cost FFI bindings via cxx
Documentation
# Lists Extension

The lists extension provides advanced list processing functions that extend CEL's built-in list capabilities.

## Table of Contents

- [Lists Extension]#lists-extension
  - [Table of Contents]#table-of-contents
  - [1. Overview]#1-overview
  - [2. List Slicing - `slice()`]#2-list-slicing---slice
  - [3. List Flattening - `flatten()`]#3-list-flattening---flatten
  - [4. List Deduplication - `distinct()`]#4-list-deduplication---distinct
  - [5. List Reversal - `reverse()`]#5-list-reversal---reverse
  - [6. List Sorting]#6-list-sorting
    - [6.1 sort()]#61-sort
    - [6.2 sortBy()]#62-sortby
  - [7. Number Ranges - `range()`]#7-number-ranges---range
  - [8. Usage Examples]#8-usage-examples
    - [Data Deduplication and Cleaning]#data-deduplication-and-cleaning
    - [Nested Data Processing]#nested-data-processing
    - [Pagination and Slicing]#pagination-and-slicing
    - [Complex Data Transformation]#complex-data-transformation
    - [Multi-level Flattening]#multi-level-flattening
    - [Range-based Operations]#range-based-operations
    - [Statistical Analysis]#statistical-analysis

## 1. Overview

The lists extension enhances CEL with powerful list manipulation capabilities. All functions maintain CEL's immutability guarantees and return new lists rather than modifying existing ones. All indices are zero-based.

**Enabling the Extension**:
```rust
let env = Env::builder()
    .with_ext_lists(true)
    .build()?;
```

## 2. List Slicing - `slice()`

**Introduced in version:** 0

Returns a new sub-list using the indexes provided.

**Syntax:** `list.slice(start, end)`

**Parameters:**
- `list`: Input list
- `start`: Starting index (inclusive)
- `end`: Ending index (exclusive)

**Return Type:** List of the same type

**Examples:**
```cel
[1, 2, 3, 4].slice(1, 3)           // [2, 3]
[1, 2, 3, 4].slice(2, 4)           // [3, 4]
["a", "b", "c", "d"].slice(0, 2)   // ["a", "b"]
[1, 2, 3, 4, 5].slice(2, 10)       // [3, 4, 5] (clamped)
[1, 2, 3].slice(1, 1)              // []
```

**Behavior:**
- Negative indices are not supported
- Out-of-bounds indices are clamped to valid ranges
- If `start >= end`, returns empty list

## 3. List Flattening - `flatten()`

**Introduced in version:** 1

Flattens a list recursively. If an optional depth is provided, the list is flattened to the specified level. A negative depth value will result in an error.

**Syntax:**
- `list.flatten()` (flatten completely)
- `list.flatten(depth)` (flatten to specified depth)

**Parameters:**
- `list`: Input list containing nested lists
- `depth`: Optional maximum depth to flatten (default: complete flattening)

**Return Type:** Flattened list

**Examples:**
```cel
[1, [2, 3], [4]].flatten()          // [1, 2, 3, 4]
[1, [2, [3, 4]]].flatten()          // [1, 2, [3, 4]]
[1, 2, [], [], [3, 4]].flatten()    // [1, 2, 3, 4]
[1, [2, [3, [4]]]].flatten(2)       // [1, 2, 3, [4]]
[1, [2, [3, [4]]]].flatten(-1)      // error
```

**Behavior:**
- Flattens only lists, not other nested structures
- Preserves element order
- Non-list elements are preserved as-is
- Negative depth values result in an error

## 4. List Deduplication - `distinct()`

**Introduced in version:** 2

Returns the distinct elements of a list, preserving the order of first occurrence.

**Syntax:** `<list(T)>.distinct() -> <list(T)>`

**Parameters:**
- `list`: Input list of any type

**Return Type:** List of the same type with duplicates removed

**Examples:**
```cel
[1, 2, 2, 3, 3, 3].distinct()      // [1, 2, 3]
["b", "b", "c", "a", "c"].distinct() // ["b", "c", "a"]
[1, "b", 2, "b"].distinct()         // [1, "b", 2]
[true, false, true].distinct()      // [true, false]
[].distinct()                       // []
```

**Behavior:**
- Preserves the order of first occurrences
- Works with any comparable type (strings, numbers, booleans)
- Empty lists return empty lists
- Mixed types are supported

## 5. List Reversal - `reverse()`

**Introduced in version:** 2

Returns the elements of a list in reverse order.

**Syntax:** `<list(T)>.reverse() -> <list(T)>`

**Parameters:**
- `list`: Input list of any type

**Return Type:** List with elements in reverse order

**Examples:**
```cel
[5, 3, 1, 2].reverse()              // [2, 1, 3, 5]
["a", "b", "c"].reverse()           // ["c", "b", "a"]
[].reverse()                        // []
[42].reverse()                      // [42]
[[1, 2], [3, 4]].reverse()          // [[3, 4], [1, 2]]
```

## 6. List Sorting

**Introduced in version:** 2

### 6.1 sort()

Sorts a list with comparable elements. If the element type is not comparable or the element types are not the same, the function will produce an error.

**Syntax:** `list.sort()`

**Parameters:**
- `list`: Input list of comparable elements

**Return Type:** Sorted list

**Supported Types:** int, uint, double, bool, duration, timestamp, string, bytes

**Examples:**
```cel
[3, 2, 1].sort()                    // [1, 2, 3]
["b", "c", "a"].sort()              // ["a", "b", "c"]
[true, false, true].sort()          // [false, true, true]
[].sort()                           // []
[1, "b"].sort()                     // error (mixed types)
[[1, 2, 3]].sort()                  // error (non-comparable type)
```

### 6.2 sortBy()

Sorts a list by a key value, i.e., the order is determined by the result of an expression applied to each element of the list. The output of the key expression must be a comparable type.

**Syntax:** `list.sortBy(var, key_expr)`

**Parameters:**
- `list`: Input list
- `var`: Variable name for each element
- `key_expr`: Expression to compute sort key (must return comparable type)

**Return Type:** Sorted list

**Examples:**
```cel
[
  {"name": "foo", "score": 0},
  {"name": "bar", "score": -10},
  {"name": "baz", "score": 1000}
].sortBy(e, e.score).map(e, e.name)
// ["bar", "foo", "baz"]

["apple", "pie", "banana"].sortBy(s, s.size())
// ["pie", "apple", "banana"]

[3, -1, 4, -2].sortBy(n, math.abs(n))
// [-1, -2, 3, 4]
```

## 7. Number Ranges - `range()`

**Introduced in version:** 2

Returns a list of integers from 0 to n-1.

**Syntax:** `lists.range(n)`

**Parameters:**
- `n`: Upper bound (exclusive)

**Return Type:** List of integers

**Examples:**
```cel
lists.range(5)                      // [0, 1, 2, 3, 4]
lists.range(0)                      // []
lists.range(1)                      // [0]
lists.range(3)                      // [0, 1, 2]
```

**Behavior:**
- Creates a list from 0 to n-1 (inclusive)
- If n <= 0, returns empty list
- Only supports non-negative integers

## 8. Usage Examples

### Data Deduplication and Cleaning
```cel
// Remove duplicates and sort user IDs
cel.bind(user_ids, [1, 3, 2, 1, 4, 2, 5],
  user_ids.distinct().sort()
)
// Result: [1, 2, 3, 4, 5]
```

### Nested Data Processing
```cel
// Flatten and process nested categories
cel.bind(categories, [["tech", "ai"], ["health", "fitness"], ["tech", "web"]],
  categories.flatten().distinct().sort()
)
// Result: ["ai", "fitness", "health", "tech", "web"]
```

### Pagination and Slicing
```cel
// Implement pagination
cel.bind(items, lists.range(101),     // [0, 1, 2, ..., 100]
  cel.bind(page, 2,
    cel.bind(page_size, 10,
      cel.bind(start, (page - 1) * page_size,
        items.slice(start, start + page_size)
      )
    )
  )
)
// Result: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
```

### Complex Data Transformation
```cel
// Process and sort player data
cel.bind(players, [
  {"name": "Alice", "scores": [85, 92, 78]},
  {"name": "Bob", "scores": [91, 87, 95]},
  {"name": "Charlie", "scores": [76, 88, 82]}
],
  players.map(player, {
    "name": player.name,
    "avg_score": player.scores.sum() / player.scores.size(),
    "best_score": player.scores.sort().reverse()[0]
  }).sortBy(p, p.avg_score).reverse()
)
// Result: Sorted by average score (descending)
```

### Multi-level Flattening
```cel
// Flatten nested structures with controlled depth
cel.bind(nested, [1, [2, [3, [4, 5]]], [6, [7, 8]]],
  {
    "level_1": nested.flatten(1),     // [1, 2, [3, [4, 5]], 6, [7, 8]]
    "level_2": nested.flatten(2),     // [1, 2, 3, [4, 5], 6, 7, 8]
    "complete": nested.flatten()      // [1, 2, 3, [4, 5], 6, 7, 8]
  }
)
```

### Range-based Operations
```cel
// Generate and process number sequences
cel.bind(range_10, lists.range(10),
  {
    "numbers": range_10,
    "evens": range_10.filter(n, n % 2 == 0),
    "odds": range_10.filter(n, n % 2 == 1),
    "squares": range_10.map(n, n * n),
    "reversed": range_10.reverse()
  }
)
// Result: Various transformations of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
```

### Statistical Analysis
```cel
// Analyze list statistics with sorting
cel.bind(numbers, [1, 5, 3, 9, 2, 7, 4, 8, 6],
  cel.bind(sorted, numbers.sort(),
    cel.bind(unique_sorted, numbers.distinct().sort(),
      {
        "original": numbers,
        "sorted": sorted,
        "unique": unique_sorted,
        "median": sorted[sorted.size() / 2],
        "range": sorted.reverse()[0] - sorted[0],
        "duplicates_removed": numbers.size() - unique_sorted.size()
      }
    )
  )
)
```

The lists extension provides comprehensive list manipulation capabilities, enabling sophisticated data processing and analysis within CEL expressions while maintaining immutability and type safety.