sim_lib_music_serial/
nesting.rs1use thiserror::Error;
4
5#[derive(Clone, Debug, PartialEq, Eq)]
7pub enum NestedSerialValue<T> {
8 Value(T),
10 Group(Vec<NestedSerialValue<T>>),
12}
13
14#[derive(Copy, Clone, Debug, PartialEq, Eq)]
16pub struct NestingLimits {
17 pub max_depth: usize,
19 pub max_output: usize,
21}
22
23#[derive(Clone, Debug, PartialEq, Eq)]
25pub struct NestingExpansion<T> {
26 pub depth_reached: usize,
28 pub values: Vec<T>,
30}
31
32#[derive(Copy, Clone, Debug, PartialEq, Eq, Error)]
34pub enum NestingError {
35 #[error("nesting depth limit must be at least 1")]
37 ZeroDepthLimit,
38 #[error("nesting output limit must be at least 1")]
40 ZeroOutputLimit,
41 #[error("nesting depth {depth} exceeds limit {max_depth}")]
43 DepthExceeded {
44 depth: usize,
46 max_depth: usize,
48 },
49 #[error("nesting output would exceed limit {max_output}")]
51 OutputExceeded {
52 max_output: usize,
54 },
55}
56
57pub 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
68pub 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}