1use crate::authoring::*;
3
4#[rustfmt::skip]
6pub const STACK_GAMUT: [OpParameter; 7] = [
7 OpParameter::Series { key: "push", default: Some("") },
8 OpParameter::Series { key: "pop", default: Some("") },
9 OpParameter::Series { key: "roll", default: Some("") },
10 OpParameter::Series { key: "unroll", default: Some("") },
11 OpParameter::Series { key: "flip", default: Some("") },
12 OpParameter::Flag { key: "swap" },
13 OpParameter::Flag { key: "drop" },
14];
15
16pub fn new(parameters: &RawParameters, _ctx: &dyn Context) -> Result<Op, Error> {
18 let def = ¶meters.definition;
19 let mut params = ParsedParameters::new(parameters, &STACK_GAMUT)?;
20
21 let mut subcommands_given: usize = 0;
24
25 let valid_indices = [1., 2., 3., 4.];
30
31 if let Ok(push_args) = params.series("push") {
34 subcommands_given += 1;
35 for i in push_args.iter() {
36 if !valid_indices.contains(i) {
37 return Err(Error::BadParam("push".to_string(), i.to_string()));
38 }
39 }
40 params.text.insert("action", "push".to_string());
41 }
42
43 if let Ok(flip_args) = params.series("flip") {
44 subcommands_given += 1;
45 for i in flip_args.iter() {
46 if !valid_indices.contains(i) {
47 return Err(Error::BadParam("flip".to_string(), i.to_string()));
48 }
49 }
50 params.text.insert("action", "flip".to_string());
51 }
52
53 if let Ok(pop_args) = params.series("pop") {
54 subcommands_given += 1;
55 for i in pop_args.iter() {
56 if !valid_indices.contains(i) {
57 return Err(Error::BadParam("pop".to_string(), i.to_string()));
58 }
59 }
60 params.text.insert("action", "pop".to_string());
61 }
62
63 if let Ok(roll_args) = params.series("roll") {
64 subcommands_given += 1;
65 if roll_args.len() != 2
66 || roll_args[0].fract() != 0.
67 || roll_args[1].fract() != 0.
68 || roll_args[0] <= roll_args[1].abs()
69 {
70 return Err(Error::MissingParam(
71 "roll takes exactly two integer parameters, ´(m,n): |n|<=m´".to_string(),
72 ));
73 }
74 params.text.insert("action", "roll".to_string());
75 }
76
77 if let Ok(roll_args) = params.series("unroll") {
78 subcommands_given += 1;
79 if roll_args.len() != 2
80 || roll_args[0].fract() != 0.
81 || roll_args[1].fract() != 0.
82 || roll_args[0] <= roll_args[1].abs()
83 {
84 return Err(Error::MissingParam(
85 "unroll takes exactly two integer parameters, ´(m,n): |n|<=m´".to_string(),
86 ));
87 }
88 params.text.insert("action", "unroll".to_string());
89 }
90
91 if params.boolean("swap") {
92 subcommands_given += 1;
93 params.text.insert("action", "swap".to_string());
94 }
95
96 if params.boolean("drop") {
97 subcommands_given += 1;
98 params.text.insert("action", "drop".to_string());
99 }
100
101 if subcommands_given != 1 {
102 return Err(Error::MissingParam(
103 "stack: must specify exactly one of push/pop/roll/swap/unroll/drop".to_string(),
104 ));
105 }
106
107 let descriptor = OpDescriptor::new(def, InnerOp::default(), Some(InnerOp::default()));
109 let steps = Vec::new();
110 let id = OpHandle::new();
111
112 Ok(Op {
113 descriptor,
114 params,
115 steps,
116 id,
117 })
118}
119
120pub(super) fn stack_fwd(
122 stack: &mut Vec<Vec<f64>>,
123 operands: &mut dyn CoordinateSet,
124 params: &ParsedParameters,
125) -> usize {
126 let Some(action) = params.text.get("action") else {
127 return 0;
128 };
129
130 let successes = match action.as_str() {
131 "push" => {
132 let args = params.series_as_usize("push").unwrap();
133 stack_push(stack, operands, &args)
134 }
135
136 "pop" => {
137 let args = params.series_as_usize("pop").unwrap();
138 stack_pop(stack, operands, &args)
139 }
140
141 "roll" => {
142 let args = params.series_as_i64("roll").unwrap();
143 stack_roll(stack, operands, &args)
144 }
145
146 "unroll" => {
147 let mut args = params.series_as_i64("unroll").unwrap();
148 args[1] = args[0] - args[1];
149 stack_roll(stack, operands, &args)
150 }
151
152 "flip" => {
153 let args = params.series_as_usize("flip").unwrap();
154 stack_flip(stack, operands, &args)
155 }
156
157 "swap" => {
158 let n = stack.len();
159 if n > 1 {
160 stack.swap(n - 1, n - 2)
161 }
162 if n == 0 {
163 0
164 } else {
165 stack[0].len()
166 }
167 }
168
169 _ => 0,
170 };
171
172 successes
173}
174
175pub(super) fn stack_inv(
179 stack: &mut Vec<Vec<f64>>,
180 operands: &mut dyn CoordinateSet,
181 params: &ParsedParameters,
182) -> usize {
183 let Some(action) = params.text.get("action") else {
184 return 0;
185 };
186
187 let successes = match action.as_str() {
188 "push" => {
190 let mut args = params.series_as_usize("push").unwrap();
191 args.reverse();
192 stack_pop(stack, operands, &args)
193 }
194
195 "pop" => {
197 let mut args = params.series_as_usize("pop").unwrap();
198 args.reverse();
199 stack_push(stack, operands, &args)
200 }
201
202 "roll" => {
203 let mut args = params.series_as_i64("roll").unwrap();
204 args[1] = args[0] - args[1];
205 stack_roll(stack, operands, &args)
206 }
207
208 "unroll" => {
209 let args = params.series_as_i64("roll").unwrap();
210 stack_roll(stack, operands, &args)
211 }
212
213 "flip" => {
214 let args = params.series_as_usize("flip").unwrap();
215 stack_flip(stack, operands, &args)
216 }
217
218 "swap" => {
220 let n = stack.len();
221 if n > 1 {
222 stack.swap(n - 1, n - 2)
223 }
224 if n == 0 {
225 0
226 } else {
227 stack[0].len()
228 }
229 }
230
231 _ => 0,
232 };
233
234 successes
235}
236
237fn stack_push(
239 stack: &mut Vec<Vec<f64>>,
240 operands: &mut dyn CoordinateSet,
241 args: &[usize],
242) -> usize {
243 let number_of_pushes = args.len();
244 let number_of_operands = operands.len();
245
246 let mut ext = vec![vec![0f64; number_of_operands]; number_of_pushes];
248
249 for i in 0..number_of_operands {
251 let coord = operands.get_coord(i);
252 for j in 0..number_of_pushes {
253 ext[j][i] = coord[args[j] - 1];
255 }
256 }
257
258 stack.extend(ext);
260 number_of_operands
261}
262
263fn stack_flip(stack: &mut [Vec<f64>], operands: &mut dyn CoordinateSet, args: &[usize]) -> usize {
265 let number_of_flips = args.len();
266 let number_of_operands = operands.len();
267 let stack_depth = stack.len();
268
269 if stack_depth < number_of_flips {
271 warn!("Stack flip underflow in pipeline");
272 operands.stomp();
273 return 0;
274 }
275
276 for i in 0..number_of_operands {
278 let mut coord = operands.get_coord(i);
279 for j in 0..number_of_flips {
280 let flip = coord[args[j] - 1];
282 let depth = stack_depth - 1 - j;
283 coord[args[j] - 1] = stack[depth][i];
284 stack[depth][i] = flip;
285 }
286 operands.set_coord(i, &coord);
287 }
288
289 number_of_operands
290}
291
292fn stack_roll(stack: &mut Vec<Vec<f64>>, operands: &mut dyn CoordinateSet, args: &[i64]) -> usize {
297 let m = args[0].abs();
298 let mut n = args[1];
299 let depth = stack.len();
300
301 n = if n < 0 { m + n } else { n };
304
305 let m = m as usize;
307 let n = n as usize;
308
309 if m > depth {
310 warn!("Roll too deep");
311 operands.stomp();
312 return 0;
313 }
314
315 for _ in 0..n {
316 let e = stack.pop().unwrap();
317 stack.insert(depth - m, e);
318 }
319
320 operands.len()
321}
322
323fn stack_pop(stack: &mut Vec<Vec<f64>>, operands: &mut dyn CoordinateSet, args: &[usize]) -> usize {
325 let number_of_pops = args.len();
326 let number_of_operands = operands.len();
327 let stack_depth = stack.len();
328
329 if stack_depth < number_of_pops {
331 warn!("Stack underflow in pipeline");
332 operands.stomp();
333 return 0;
334 }
335
336 let mut ext = Vec::with_capacity(number_of_pops);
338 for _ in args {
339 ext.push(stack.pop().unwrap());
340 }
341
342 for i in 0..number_of_operands {
345 let mut coord = operands.get_coord(i);
346 for j in 0..number_of_pops {
347 coord[args[j] - 1] = ext[j][i];
349 }
350 operands.set_coord(i, &coord);
351 }
352
353 number_of_operands
354}
355
356#[cfg(test)]
359mod tests {
360 use super::*;
361
362 #[test]
363 fn stack() -> Result<(), Error> {
364 let mut ctx = Minimal::default();
365 let master_data = vec![Coor4D([11., 12., 13., 14.]), Coor4D([21., 22., 23., 24.])];
366
367 assert!(ctx.op("stack push=2,2,1,1,3,3,4,4,4,4,4,4,4").is_ok());
375
376 assert!(ctx.op("stack push=2,2,1,1 pop=1,1,2").is_err());
379
380 assert!(ctx.op("stack push=2,2,1,1 | stack pop=1,1,2").is_ok());
384
385 let mut data = master_data.clone();
388
389 let op = ctx.op("stack push=1,2|stack pop=1,2")?;
403 ctx.apply(op, Fwd, &mut data)?;
404 assert_eq!(data[0][0], 12.);
405 assert_eq!(data[1][1], 21.);
406
407 ctx.apply(op, Inv, &mut data)?;
409 assert_eq!(data[0], master_data[0]);
410 assert_eq!(data[1], master_data[1]);
411
412 let op = ctx.op("stack push=2,1 | stack pop=2,1")?;
415 ctx.apply(op, Inv, &mut data)?;
417 assert_eq!(data[0][0], 12.);
418 assert_eq!(data[1][1], 21.);
419
420 ctx.apply(op, Fwd, &mut data)?;
422 assert_eq!(data[0], master_data[0]);
423 assert_eq!(data[1], master_data[1]);
424
425 let op = ctx.op("stack push=2,1 | stack swap | stack pop=1,2")?;
428 ctx.apply(op, Fwd, &mut data)?;
429 assert_eq!(data[0][0], 12.);
430 assert_eq!(data[1][1], 21.);
431
432 ctx.apply(op, Inv, &mut data)?;
434 assert_eq!(data[0], master_data[0]);
435 assert_eq!(data[1], master_data[1]);
436
437 let op = ctx.op("stack push=1,1,1,2,1,3,1,4 | stack roll=8,2 | stack pop=1,2")?;
439 ctx.apply(op, Fwd, &mut data)?;
440 assert_eq!(data[0][0], 13.);
441 assert_eq!(data[0][1], 11.);
442
443 assert_eq!(0, ctx.apply(op, Inv, &mut data)?);
448
449 let mut data = master_data.clone();
451 let op = ctx.op("stack push=1,2,3,4,1,2,3,4 | stack roll=8,6 | stack pop=1,2")?;
452 ctx.apply(op, Fwd, &mut data)?;
453 assert_eq!(data[0][0], 12.);
454 assert_eq!(data[0][1], 11.);
455
456 let mut data = master_data.clone();
457 let op = ctx.op("stack push=1,2,3,4,1,2,3,4 | stack roll=3,2 | stack pop=1,2")?;
458 ctx.apply(op, Fwd, &mut data)?;
459 assert_eq!(data[0][0], 12.);
460 assert_eq!(data[0][1], 14.);
461
462 let mut data = master_data.clone();
463 let op = ctx.op("stack push=1,2,3,4 | stack roll=3,-2 | stack pop=2,1")?;
464 ctx.apply(op, Fwd, &mut data)?;
465 assert_eq!(data[0][0], 12.);
466 assert_eq!(data[0][1], 13.);
467
468 let mut data = master_data.clone();
470 let op = ctx.op("stack push=1,2,3,4 | stack roll=3,2 | stack roll=3,1 | stack pop=1,2")?;
471 ctx.apply(op, Fwd, &mut data)?;
472 assert_eq!(data[0][0], 14.);
473 assert_eq!(data[0][1], 13.);
474
475 let mut data = master_data.clone();
477 let op =
478 ctx.op("stack push=1,2,3,4 | stack roll=3,2 | stack unroll=3,2 | stack pop=1,2")?;
479 ctx.apply(op, Fwd, &mut data)?;
480 assert_eq!(data[0][0], 14.);
481 assert_eq!(data[0][1], 13.);
482
483 Ok(())
484 }
485
486 #[test]
487 fn stack_examples_from_rumination_002() -> Result<(), Error> {
488 let mut ctx = Minimal::default();
489 let master_data = vec![Coor4D([1., 2., 3., 4.])];
490
491 let op = ctx.op("stack push=1,2,3,4 | stack roll=3,2 | stack pop=4,3,2,1")?;
493 let mut data = master_data.clone();
494 ctx.apply(op, Fwd, &mut data)?;
495 assert_eq!(data[0].0, [1., 3., 4., 2.]);
496
497 let op = ctx.op("stack push=1,2,3,4 | stack roll=3,-2 | stack pop=4,3,2,1")?;
498 let mut data = master_data.clone();
499 ctx.apply(op, Fwd, &mut data)?;
500 assert_eq!(data[0].0, [1., 4., 2., 3.]);
501
502 let op = ctx.op("stack push=1,2,3,4 | stack roll=3,2 | stack pop=4,3,2,1")?;
503 let mut data = master_data.clone();
504 ctx.apply(op, Fwd, &mut data)?;
505 assert_eq!(data[0].0, [1., 3., 4., 2.]);
506 let op = ctx.op("stack push=1,2,3,4 | stack roll=3,1 | stack pop=4,3,2,1")?;
507 ctx.apply(op, Fwd, &mut data)?;
508 assert_eq!(data[0].0, [1., 2., 3., 4.]);
509
510 let op = ctx.op("stack push=1,2,3,4 | stack unroll=3,2 | stack pop=4,3,2,1")?;
512 let mut data = master_data.clone();
513 ctx.apply(op, Fwd, &mut data)?;
514 assert_eq!(data[0].0, [1., 4., 2., 3.]);
515
516 let op = ctx.op("stack push=1,2,3,4 | stack unroll=3,-2 | stack pop=4,3,2,1")?;
517 let mut data = master_data.clone();
518 ctx.apply(op, Fwd, &mut data)?;
519 assert_eq!(data[0].0, [1., 3., 4., 2.]);
520
521 let op = ctx.op("stack push=1,2,3,4 | stack unroll=3,2 | stack pop=4,3,2,1")?;
522 ctx.apply(op, Fwd, &mut data)?;
523 assert_eq!(data[0].0, [1., 2., 3., 4.]);
524
525 let op = ctx.op("stack push=1,2,3,4 | stack roll=3,2 | stack pop=4,3,2,1")?;
526 ctx.apply(op, Fwd, &mut data)?;
527 assert_eq!(data[0].0, [1., 3., 4., 2.]);
528
529 let op = ctx.op("stack push=1,2,3,4 | stack unroll=3,2 | stack pop=4,3,2,1")?;
530 ctx.apply(op, Fwd, &mut data)?;
531 assert_eq!(data[0].0, [1., 2., 3., 4.]);
532
533 let op = ctx.op("stack push=1,2,3,4 | helmert x=4 y=4 z=4 | stack flip=1,2")?;
534 ctx.apply(op, Fwd, &mut data)?;
535 assert_eq!(data[0].0, [4., 3., 7., 4.]);
536
537 let mut data = master_data.clone();
538 let op = ctx.op(
539 "stack push=1,2,3,4 | helmert translation=4,4,4 | stack flip=1,2 | stack flip=1,2",
540 )?;
541 ctx.apply(op, Fwd, &mut data)?;
542 assert_eq!(data[0].0, [5., 6., 7., 4.]);
543
544 Ok(())
545 }
546}