rooc/primitives/
iterable.rs

1use core::fmt;
2
3#[allow(unused_imports)]
4use crate::prelude::*;
5use serde::{Deserialize, Serialize};
6
7use super::{
8    graph::{Graph, GraphEdge, GraphNode},
9    primitive::{Primitive, PrimitiveKind},
10    primitive_traits::{ApplyOp, OperatorError, Spreadable},
11    tuple::Tuple,
12};
13use crate::iterable_utils::flatten_primitive_array_values;
14use crate::parser::model_transformer::TransformError;
15use crate::traits::ToLatex;
16use crate::{
17    check_bounds,
18    math::{BinOp, UnOp},
19};
20/// Represents different types of iterable collections in the system.
21///
22/// Each variant stores a vector of values of a specific primitive type.
23/// This allows for type-safe iteration and operations over collections
24/// of homogeneous elements.
25///
26/// # Example
27/// ```rust
28/// use rooc::IterableKind;
29///
30/// let numbers = IterableKind::Numbers(vec![1.0, 2.0, 3.0]);
31/// let strings = IterableKind::Strings(vec!["a".to_string(), "b".to_string()]);
32/// ```
33#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
34#[serde(tag = "type", content = "value")]
35pub enum IterableKind {
36    /// Collection of floating point numbers
37    Numbers(Vec<f64>),
38    /// Collection of signed integers
39    Integers(Vec<i64>),
40    /// Collection of unsigned integers
41    PositiveIntegers(Vec<u64>),
42    /// Collection of strings
43    Strings(Vec<String>),
44    /// Collection of graph edges
45    Edges(Vec<GraphEdge>),
46    /// Collection of graph nodes
47    Nodes(Vec<GraphNode>),
48    /// Collection of graphs
49    Graphs(Vec<Graph>),
50    /// Collection of tuples
51    Tuples(Vec<Tuple>),
52    /// Collection of boolean values
53    Booleans(Vec<bool>),
54    /// Nested collection of iterables
55    Iterables(Vec<IterableKind>),
56    /// Collection of any primitive type
57    Anys(Vec<Primitive>),
58}
59
60#[cfg_attr(target_arch = "wasm32", wasm_bindgen(typescript_custom_section))]
61#[allow(non_upper_case_globals)]
62#[cfg(target_arch = "wasm32")]
63const IIterableKind: &'static str = r#"
64export type SerializedIterable = 
65    | { type: 'Numbers', value: number[] }
66    | { type: 'Integers', value: number[] }
67    | { type: 'PositiveIntegers', value: number[] }
68    | { type: 'Strings', value: string[] }
69    | { type: 'Edges', value: SerializedGraphEdge[] }
70    | { type: 'Nodes', value: SerializedGraphNode[] }
71    | { type: 'Graphs', value: SerializedGraph[] }
72    | { type: 'Tuples', value: SerializedTuple[] }
73    | { type: 'Booleans', value: boolean[] }
74    | { type: 'Iterables', value: SerializedIterable[] }
75    | { type: 'Anys', value: SerializedPrimitive[] }
76"#;
77
78impl IterableKind {
79    /// Gets the primitive type of this iterable collection.
80    ///
81    /// # Returns
82    /// A `PrimitiveKind::Iterable` containing the type of elements in the collection
83    pub fn get_type(&self) -> PrimitiveKind {
84        PrimitiveKind::Iterable(Box::new(self.inner_type()))
85    }
86
87    /// Converts this iterable into a primitive value.
88    pub fn into_primitive(self) -> Primitive {
89        Primitive::Iterable(self)
90    }
91
92    /// tries to flatten an array of primitives into an easier form
93    pub fn flatten(self) -> IterableKind {
94        match self {
95            IterableKind::Anys(v) => flatten_primitive_array_values(v),
96            _ => self,
97        }
98    }
99
100    /// Gets the type of elements contained in this iterable.
101    ///
102    /// For nested iterables, returns the type of the innermost elements.
103    pub fn inner_type(&self) -> PrimitiveKind {
104        match self {
105            IterableKind::Numbers(_) => PrimitiveKind::Number,
106            IterableKind::Integers(_) => PrimitiveKind::Integer,
107            IterableKind::PositiveIntegers(_) => PrimitiveKind::PositiveInteger,
108            IterableKind::Strings(_) => PrimitiveKind::String,
109            IterableKind::Edges(_) => PrimitiveKind::GraphEdge,
110            IterableKind::Nodes(_) => PrimitiveKind::GraphNode,
111            IterableKind::Anys(_) => PrimitiveKind::Any,
112            IterableKind::Tuples(t) => t
113                .first()
114                .map(|e| e.get_type())
115                .unwrap_or(PrimitiveKind::Undefined),
116            IterableKind::Booleans(_) => PrimitiveKind::Boolean,
117            IterableKind::Graphs(_) => PrimitiveKind::Graph,
118            IterableKind::Iterables(i) => PrimitiveKind::Iterable(
119                i.first()
120                    .map(|e| e.inner_type())
121                    .unwrap_or(PrimitiveKind::Undefined)
122                    .into(),
123            ),
124        }
125    }
126    pub fn len(&self) -> usize {
127        match self {
128            IterableKind::Numbers(v) => v.len(),
129            IterableKind::Integers(v) => v.len(),
130            IterableKind::PositiveIntegers(v) => v.len(),
131            IterableKind::Strings(v) => v.len(),
132            IterableKind::Edges(v) => v.len(),
133            IterableKind::Nodes(v) => v.len(),
134            IterableKind::Tuples(v) => v.len(),
135            IterableKind::Iterables(v) => v.len(),
136            IterableKind::Booleans(v) => v.len(),
137            IterableKind::Graphs(v) => v.len(),
138            IterableKind::Anys(v) => v.len(),
139        }
140    }
141    pub fn is_empty(&self) -> bool {
142        self.len() == 0
143    }
144
145    /// Converts this iterable into a vector of primitive values.
146    pub fn to_primitives(self) -> Vec<Primitive> {
147        match self {
148            IterableKind::Numbers(v) => v.iter().map(|n| Primitive::Number(*n)).collect(),
149            IterableKind::Integers(v) => v.iter().map(|n| Primitive::Integer(*n)).collect(),
150            IterableKind::PositiveIntegers(v) => {
151                v.iter().map(|n| Primitive::PositiveInteger(*n)).collect()
152            }
153            IterableKind::Anys(v) => v,
154            IterableKind::Strings(v) => v
155                .into_iter()
156                .map(|s| Primitive::String((*s).to_string()))
157                .collect(),
158            IterableKind::Edges(v) => v
159                .iter()
160                .map(|e| Primitive::GraphEdge(e.to_owned()))
161                .collect(),
162            IterableKind::Nodes(v) => v.into_iter().map(Primitive::GraphNode).collect(),
163            IterableKind::Tuples(v) => v.into_iter().map(Primitive::Tuple).collect(),
164            IterableKind::Iterables(v) => v.into_iter().map(Primitive::Iterable).collect(),
165            IterableKind::Booleans(v) => v.into_iter().map(Primitive::Boolean).collect(),
166            IterableKind::Graphs(v) => v.into_iter().map(Primitive::Graph).collect(),
167        }
168    }
169
170    /// Reads a value from the iterable at the specified indexes.
171    ///
172    /// For nested iterables, the indexes specify the path to the desired element.
173    ///
174    /// # Arguments
175    /// * `indexes` - Vector of indexes specifying the path to the desired element
176    ///
177    /// # Returns
178    /// * `Ok(Primitive)` - The value at the specified indexes
179    /// * `Err(TransformError)` - If the indexes are out of bounds
180    pub fn read(&self, indexes: Vec<usize>) -> Result<Primitive, TransformError> {
181        if indexes.is_empty() {
182            return Ok(Primitive::Undefined);
183        }
184
185        let mut current = self;
186        let mut indexes = indexes;
187        while !indexes.is_empty() {
188            let i = indexes.remove(0);
189            let ended = indexes.is_empty();
190            if ended {
191                let val = match current {
192                    IterableKind::Booleans(v) => {
193                        check_bounds!(i, v, self, Primitive::Boolean(v[i]))
194                    }
195                    IterableKind::Anys(v) => check_bounds!(i, v, self, v[i].clone()),
196                    IterableKind::Numbers(v) => check_bounds!(i, v, self, Primitive::Number(v[i])),
197                    IterableKind::Integers(v) => {
198                        check_bounds!(i, v, self, Primitive::Integer(v[i]))
199                    }
200                    IterableKind::PositiveIntegers(v) => {
201                        check_bounds!(i, v, self, Primitive::PositiveInteger(v[i]))
202                    }
203                    IterableKind::Strings(v) => {
204                        check_bounds!(i, v, self, Primitive::String(v[i].to_string()))
205                    }
206                    IterableKind::Edges(v) => {
207                        check_bounds!(i, v, self, Primitive::GraphEdge(v[i].to_owned()))
208                    }
209                    IterableKind::Nodes(v) => {
210                        check_bounds!(i, v, self, Primitive::GraphNode(v[i].to_owned()))
211                    }
212                    IterableKind::Tuples(v) => {
213                        check_bounds!(i, v, self, Primitive::Tuple(v[i].clone()))
214                    }
215                    IterableKind::Iterables(v) => {
216                        check_bounds!(i, v, self, Primitive::Iterable(v[i].clone()))
217                    }
218                    IterableKind::Graphs(v) => {
219                        check_bounds!(i, v, self, Primitive::Graph(v[i].clone()))
220                    }
221                };
222                return Ok(val);
223            } else {
224                match current {
225                    IterableKind::Iterables(v) => {
226                        if i < v.len() {
227                            current = &v[i];
228                        } else {
229                            return Err(TransformError::OutOfBounds(format!(
230                                "cannot access index {} of {}",
231                                i, self
232                            )));
233                        }
234                    }
235                    _ => {
236                        return Err(TransformError::OutOfBounds(format!(
237                            "cannot access index {} of {}",
238                            i, self
239                        )));
240                    }
241                }
242            }
243        }
244        Err(TransformError::OutOfBounds(format!(
245            "cannot access index {} of {}",
246            indexes[0], self
247        )))
248    }
249
250    /// Returns the nesting depth of this iterable.
251    ///
252    /// For non-nested iterables, returns 1.
253    /// For nested iterables, returns the maximum nesting depth.
254    pub fn depth(&self) -> usize {
255        let mut current = self;
256        let mut depth = 1;
257        while let IterableKind::Iterables(v) = current {
258            depth += 1;
259            match v.first() {
260                Some(i) => current = i,
261                None => break,
262            }
263        }
264        depth
265    }
266
267    /// Returns a string representation of the iterable with proper indentation.
268    ///
269    /// # Arguments
270    /// * `depth` - The current indentation depth
271    pub fn to_string_depth(&self, depth: usize) -> String {
272        match self {
273            IterableKind::Iterables(v) => {
274                let s = v
275                    .iter()
276                    .map(|e| e.to_string_depth(depth + 1))
277                    .collect::<Vec<_>>()
278                    .join(", ");
279                format!("{}[\n{}\n]", "    ".repeat(depth), s)
280            }
281            _ => format!("{}{}", "    ".repeat(depth), self),
282        }
283    }
284
285    /// Returns a LaTeX representation of the iterable.
286    ///
287    /// # Arguments
288    /// * `include_block` - Whether to wrap the output in a matrix block
289    pub fn latexify(&self, include_block: bool) -> String {
290        match self {
291            IterableKind::Numbers(v) => latexify_vec(v, include_block),
292            IterableKind::Integers(v) => latexify_vec(v, include_block),
293            IterableKind::PositiveIntegers(v) => latexify_vec(v, include_block),
294            IterableKind::Anys(v) => latexify_vec(v, include_block),
295            IterableKind::Strings(v) => latexify_vec(v, include_block),
296            IterableKind::Edges(v) => latexify_vec(v, include_block),
297            IterableKind::Nodes(v) => latexify_vec(v, include_block),
298            IterableKind::Tuples(v) => latexify_vec(v, include_block),
299            IterableKind::Booleans(v) => latexify_vec(v, include_block),
300            IterableKind::Graphs(v) => latexify_vec(v, include_block),
301            IterableKind::Iterables(v) => {
302                let s = v
303                    .iter()
304                    .map(|i| i.to_latex())
305                    .collect::<Vec<_>>()
306                    .join("\\\\");
307                if include_block {
308                    format!("\\begin{{bmatrix}} {} \\end{{bmatrix}}", s)
309                } else {
310                    s.to_string()
311                }
312            }
313        }
314    }
315}
316fn latexify_vec<T>(v: &[T], include_block: bool) -> String
317where
318    T: ToLatex,
319{
320    let values = v
321        .iter()
322        .map(|e| e.to_latex())
323        .collect::<Vec<_>>()
324        .join(" & ");
325    if include_block {
326        format!("\\begin{{bmatrix}} {} \\end{{bmatrix}}", values)
327    } else {
328        values.to_string()
329    }
330}
331
332impl ToLatex for IterableKind {
333    fn to_latex(&self) -> String {
334        match self {
335            IterableKind::Iterables(v) => {
336                let depth = self.depth();
337                if depth == 2 {
338                    //try to prettify for 2d matrices
339                    let items = v
340                        .iter()
341                        .map(|i| i.latexify(false))
342                        .collect::<Vec<_>>()
343                        .join(" \\\\ ");
344                    format!("\\begin{{bmatrix}} {} \\end{{bmatrix}}", items)
345                } else {
346                    self.latexify(true)
347                }
348            }
349            _ => self.latexify(true),
350        }
351    }
352}
353
354impl fmt::Display for IterableKind {
355    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
356        //TODO should i turn this into a self.to_primitive_set()  and then iterate and stringify?
357        let s = match self {
358            IterableKind::Numbers(v) => format!("{:?}", v),
359            IterableKind::Integers(v) => format!("{:?}", v),
360            IterableKind::Anys(v) => format!("{:?}", v),
361            IterableKind::PositiveIntegers(v) => format!("{:?}", v),
362            IterableKind::Strings(v) => format!("{:?}", v),
363            IterableKind::Edges(v) => format!("{:?}", v),
364            IterableKind::Nodes(v) => format!("{:?}", v),
365            IterableKind::Tuples(v) => format!("{:?}", v),
366            IterableKind::Booleans(v) => format!("{:?}", v),
367            IterableKind::Graphs(v) => format!("{:?}", v),
368            IterableKind::Iterables(v) => {
369                let result = v
370                    .iter()
371                    .map(|i| i.to_string_depth(1))
372                    .collect::<Vec<_>>()
373                    .join(",\n");
374                format!("[\n{}\n]", result)
375            }
376        };
377        f.write_str(&s)
378    }
379}
380
381impl ApplyOp for IterableKind {
382    type TargetType = PrimitiveKind;
383    type Target = Primitive;
384    type Error = OperatorError;
385    fn apply_binary_op(&self, op: BinOp, _to: &Primitive) -> Result<Primitive, OperatorError> {
386        Err(OperatorError::unsupported_bin_operation(op, _to.get_type()))
387    }
388    fn apply_unary_op(&self, op: UnOp) -> Result<Self::Target, Self::Error> {
389        Err(OperatorError::unsupported_un_operation(
390            op,
391            self.inner_type(),
392        ))
393    }
394    fn can_apply_binary_op(_: BinOp, _: Self::TargetType) -> bool {
395        false
396    }
397    fn can_apply_unary_op(_: UnOp) -> bool {
398        false
399    }
400}
401
402impl Spreadable for IterableKind {
403    fn to_primitive_set(self) -> Result<Vec<Primitive>, TransformError> {
404        Ok(self.to_primitives())
405    }
406}