use crate::authoring::*;
use std::collections::BTreeSet;
#[rustfmt::skip]
pub const PUSH_POP_GAMUT: [OpParameter; 4] = [
OpParameter::Flag { key: "v_1" },
OpParameter::Flag { key: "v_2" },
OpParameter::Flag { key: "v_3" },
OpParameter::Flag { key: "v_4" },
];
pub fn push(parameters: &RawParameters, _ctx: &dyn Context) -> Result<Op, Error> {
let def = ¶meters.instantiated_as;
let params = ParsedParameters::new(parameters, &PUSH_POP_GAMUT)?;
let descriptor = OpDescriptor::new(def, InnerOp::default(), Some(InnerOp::default()));
Ok(Op {
descriptor,
params,
steps: None,
})
}
pub fn pop(parameters: &RawParameters, _ctx: &dyn Context) -> Result<Op, Error> {
let def = ¶meters.instantiated_as;
let params = ParsedParameters::new(parameters, &PUSH_POP_GAMUT)?;
let descriptor = OpDescriptor::new(def, InnerOp::default(), Some(InnerOp::default()));
Ok(Op {
descriptor,
params,
steps: None,
})
}
pub(super) fn do_the_push(
stack: &mut Vec<Vec<f64>>,
operands: &mut dyn CoordinateSet,
flags: &BTreeSet<&'static str>,
) -> usize {
let n = operands.len();
const ELEMENTS: [&str; 4] = ["v_1", "v_2", "v_3", "v_4"];
for j in [0, 1, 2, 3] {
if !flags.contains(ELEMENTS[j]) {
continue;
}
let mut all = Vec::with_capacity(n);
for i in 0..n {
all.push(operands.get_coord(i)[j]);
}
stack.push(all);
}
operands.len()
}
pub(super) fn do_the_pop(
stack: &mut Vec<Vec<f64>>,
operands: &mut dyn CoordinateSet,
flags: &BTreeSet<&'static str>,
) -> usize {
let n = operands.len();
const ELEMENTS: [&str; 4] = ["v_4", "v_3", "v_2", "v_1"];
for j in [0, 1, 2, 3] {
if !flags.contains(ELEMENTS[j]) {
continue;
}
if stack.is_empty() {
for i in 0..n {
let mut op = operands.get_coord(i);
op[3 - j] = f64::NAN;
operands.set_coord(i, &op);
}
warn!("Stack underflow in pipeline");
return 0;
}
let v = stack.pop().unwrap();
for (i, value) in v.iter().enumerate() {
let mut op = operands.get_coord(i);
op[3 - j] = *value;
operands.set_coord(i, &op);
}
}
operands.len()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn push_pop() -> Result<(), Error> {
let mut ctx = Minimal::default();
let mut data = crate::test_data::coor3d();
let op = ctx.op("push v_2 v_1|addone|pop v_1|pop v_2")?;
ctx.apply(op, Fwd, &mut data)?;
assert_eq!(data[0][0], 12.);
assert_eq!(data[0][1], 55.);
let op = ctx.op("push v_1 v_2|pop v_1 v_2")?;
ctx.apply(op, Fwd, &mut data)?;
assert_eq!(data[0][0], 12.);
assert_eq!(data[0][1], 55.);
let op = ctx.op("push v_1 v_2|pop v_2 v_1 v_3")?;
assert_eq!(0, ctx.apply(op, Fwd, &mut data)?);
assert!(data[0][0].is_nan());
assert_eq!(data[0][2], 55.);
let op = ctx.op("push v_1 v_2|pop v_2 v_1 v_3")?;
let mut data = crate::test_data::coor3d();
assert_eq!(2, ctx.apply(op, Inv, &mut data)?);
assert_eq!(data[0][0], 12.);
assert_eq!(data[0][1], 0.);
let op = ctx.op("push v_1 v_2|pop v_2 v_1 v_3 omit_fwd")?;
let mut data = crate::test_data::coor3d();
assert_eq!(2, ctx.apply(op, Fwd, &mut data)?);
assert_eq!(data[0][0], 55.);
assert_eq!(data[0][1], 12.);
assert_eq!(2, ctx.apply(op, Inv, &mut data)?);
assert_eq!(data[0][0], 12.);
assert_eq!(data[0][1], 0.);
let op = ctx.op("push v_1 v_2 v_3 omit_inv|pop v_1 v_2")?;
let mut data = crate::test_data::coor3d();
assert_eq!(2, ctx.apply(op, Inv, &mut data)?);
assert_eq!(data[0][0], 55.);
assert_eq!(data[0][1], 12.);
Ok(())
}
}