Skip to main content

sim_lib_music_serial/
nesting.rs

1//! Finite rotation and bounded nesting helpers for serial techniques.
2
3use thiserror::Error;
4
5/// One recursively nestable serial value.
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub enum NestedSerialValue<T> {
8    /// One terminal value.
9    Value(T),
10    /// One nested serial group.
11    Group(Vec<NestedSerialValue<T>>),
12}
13
14/// Explicit safety limits for recursive serial expansion.
15#[derive(Copy, Clone, Debug, PartialEq, Eq)]
16pub struct NestingLimits {
17    /// Maximum recursive group depth, counting the outermost sequence as depth 1.
18    pub max_depth: usize,
19    /// Maximum number of terminal values emitted by expansion.
20    pub max_output: usize,
21}
22
23/// Result of one bounded nesting expansion.
24#[derive(Clone, Debug, PartialEq, Eq)]
25pub struct NestingExpansion<T> {
26    /// Maximum depth encountered while traversing the source.
27    pub depth_reached: usize,
28    /// Expanded terminal values in left-to-right order.
29    pub values: Vec<T>,
30}
31
32/// Failure while expanding a finite nested serial pattern.
33#[derive(Copy, Clone, Debug, PartialEq, Eq, Error)]
34pub enum NestingError {
35    /// The requested limit admitted no nesting depth.
36    #[error("nesting depth limit must be at least 1")]
37    ZeroDepthLimit,
38    /// The requested limit admitted no output.
39    #[error("nesting output limit must be at least 1")]
40    ZeroOutputLimit,
41    /// Expansion encountered a deeper group than permitted.
42    #[error("nesting depth {depth} exceeds limit {max_depth}")]
43    DepthExceeded {
44        /// Observed depth at the failing group.
45        depth: usize,
46        /// Maximum permitted depth.
47        max_depth: usize,
48    },
49    /// Expansion would emit more terminal values than permitted.
50    #[error("nesting output would exceed limit {max_output}")]
51    OutputExceeded {
52        /// Maximum permitted output cardinality.
53        max_output: usize,
54    },
55}
56
57/// Returns a left-rotated copy of `values`, reduced modulo `values.len()`.
58pub fn rotate_sequence_left<T: Clone>(values: &[T], steps: usize) -> Vec<T> {
59    if values.is_empty() {
60        return Vec::new();
61    }
62    let mut rotated = values.to_vec();
63    let len = rotated.len();
64    rotated.rotate_left(steps % len);
65    rotated
66}
67
68/// Expands one finite nested serial pattern under explicit depth and output limits.
69pub fn expand_nested<T: Clone>(
70    source: &[NestedSerialValue<T>],
71    limits: NestingLimits,
72) -> Result<NestingExpansion<T>, NestingError> {
73    if limits.max_depth == 0 {
74        return Err(NestingError::ZeroDepthLimit);
75    }
76    if limits.max_output == 0 {
77        return Err(NestingError::ZeroOutputLimit);
78    }
79    let mut values = Vec::new();
80    let mut depth_reached = 1;
81    expand_level(source, 1, limits, &mut depth_reached, &mut values)?;
82    Ok(NestingExpansion {
83        depth_reached,
84        values,
85    })
86}
87
88fn expand_level<T: Clone>(
89    source: &[NestedSerialValue<T>],
90    depth: usize,
91    limits: NestingLimits,
92    depth_reached: &mut usize,
93    values: &mut Vec<T>,
94) -> Result<(), NestingError> {
95    if depth > limits.max_depth {
96        return Err(NestingError::DepthExceeded {
97            depth,
98            max_depth: limits.max_depth,
99        });
100    }
101    *depth_reached = (*depth_reached).max(depth);
102    for item in source {
103        match item {
104            NestedSerialValue::Value(value) => {
105                if values.len() == limits.max_output {
106                    return Err(NestingError::OutputExceeded {
107                        max_output: limits.max_output,
108                    });
109                }
110                values.push(value.clone());
111            }
112            NestedSerialValue::Group(group) => {
113                expand_level(group, depth + 1, limits, depth_reached, values)?;
114            }
115        }
116    }
117    Ok(())
118}