conformal_component/parameters/utils/
either.rs

1use itertools::Either;
2
3use crate::parameters::{NumericBufferState, PiecewiseLinearCurve, PiecewiseLinearCurvePoint};
4
5/// Wraps a [`NumericBufferState<A>`] as a [`NumericBufferState<Either<A, B>>`]
6/// by placing the inner iterator on the `Left` side.
7///
8/// Useful when you need to return a single [`NumericBufferState`] type
9/// but the underlying buffer may come from one of two differently-typed sources.
10pub fn left_numeric_buffer<
11    A: Iterator<Item = PiecewiseLinearCurvePoint> + Clone,
12    B: Iterator<Item = PiecewiseLinearCurvePoint> + Clone,
13>(
14    state: NumericBufferState<A>,
15) -> NumericBufferState<Either<A, B>> {
16    match state {
17        NumericBufferState::Constant(value) => NumericBufferState::Constant(value),
18        NumericBufferState::PiecewiseLinear(curve) => {
19            let buffer_size = curve.buffer_size();
20            // Note we're sure that `curve` is valid, so so must be Either::Left(curve)
21            NumericBufferState::PiecewiseLinear(unsafe {
22                PiecewiseLinearCurve::from_parts_unchecked(
23                    Either::Left(curve.into_iter()),
24                    buffer_size,
25                )
26            })
27        }
28    }
29}
30
31/// Wraps a [`NumericBufferState<B>`] as a [`NumericBufferState<Either<A, B>>`]
32/// by placing the inner iterator on the `Right` side.
33///
34/// Useful when you need to return a single [`NumericBufferState`] type
35/// but the underlying buffer may come from one of two differently-typed sources.
36pub fn right_numeric_buffer<
37    A: Iterator<Item = PiecewiseLinearCurvePoint> + Clone,
38    B: Iterator<Item = PiecewiseLinearCurvePoint> + Clone,
39>(
40    state: NumericBufferState<B>,
41) -> NumericBufferState<Either<A, B>> {
42    match state {
43        NumericBufferState::Constant(value) => NumericBufferState::Constant(value),
44        NumericBufferState::PiecewiseLinear(curve) => {
45            let buffer_size = curve.buffer_size();
46            NumericBufferState::PiecewiseLinear(unsafe {
47                // Note we're sure that `curve` is valid, so so must be Either::Right(curve)
48                PiecewiseLinearCurve::from_parts_unchecked(
49                    Either::Right(curve.into_iter()),
50                    buffer_size,
51                )
52            })
53        }
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use crate::parameters::{PiecewiseLinearCurve, PiecewiseLinearCurvePoint};
61
62    type Iter = std::vec::IntoIter<PiecewiseLinearCurvePoint>;
63
64    fn make_curve() -> PiecewiseLinearCurve<Iter> {
65        let curve = PiecewiseLinearCurve::new(
66            vec![
67                PiecewiseLinearCurvePoint {
68                    sample_offset: 0,
69                    value: 0.0,
70                },
71                PiecewiseLinearCurvePoint {
72                    sample_offset: 50,
73                    value: 1.0,
74                },
75            ],
76            128,
77            0.0..=1.0,
78        )
79        .unwrap();
80        let buffer_size = curve.buffer_size();
81        unsafe { PiecewiseLinearCurve::from_parts_unchecked(curve.into_iter(), buffer_size) }
82    }
83
84    #[test]
85    fn left_constant_preserves_value() {
86        let state: NumericBufferState<Iter> = NumericBufferState::Constant(0.5);
87        let result = left_numeric_buffer::<_, Iter>(state);
88        assert_eq!(result.value_at_start_of_buffer(), 0.5);
89    }
90
91    #[test]
92    fn right_constant_preserves_value() {
93        let state: NumericBufferState<Iter> = NumericBufferState::Constant(0.75);
94        let result = right_numeric_buffer::<Iter, _>(state);
95        assert_eq!(result.value_at_start_of_buffer(), 0.75);
96    }
97
98    #[test]
99    fn left_piecewise_linear_preserves_points() {
100        let state = NumericBufferState::PiecewiseLinear(make_curve());
101        let result = left_numeric_buffer::<_, Iter>(state);
102        match result {
103            NumericBufferState::PiecewiseLinear(curve) => {
104                assert_eq!(curve.buffer_size(), 128);
105                let points: Vec<_> = curve.into_iter().collect();
106                assert_eq!(points.len(), 2);
107                assert_eq!(points[0].value, 0.0);
108                assert_eq!(points[1].value, 1.0);
109            }
110            _ => panic!("expected PiecewiseLinear"),
111        }
112    }
113
114    #[test]
115    fn right_piecewise_linear_preserves_points() {
116        let state = NumericBufferState::PiecewiseLinear(make_curve());
117        let result = right_numeric_buffer::<Iter, _>(state);
118        match result {
119            NumericBufferState::PiecewiseLinear(curve) => {
120                assert_eq!(curve.buffer_size(), 128);
121                let points: Vec<_> = curve.into_iter().collect();
122                assert_eq!(points.len(), 2);
123                assert_eq!(points[0].value, 0.0);
124                assert_eq!(points[1].value, 1.0);
125            }
126            _ => panic!("expected PiecewiseLinear"),
127        }
128    }
129}