Skip to main content

pictorus_blocks/core_blocks/
passthrough_block.rs

1// TODO: Currently we require alloc in this crate to support OldBlockData,
2// but eventually this crate should be no_std and no_alloc. When we remove
3// OldBlockData, we should also update this block to function without alloc
4extern crate alloc;
5
6use crate::traits::DefaultStorage;
7use pictorus_block_data::{BlockData as OldBlockData, FromPass};
8use pictorus_traits::{PassBy, ProcessBlock};
9
10// A block that passes through the input data, storing it in a buffer.
11//
12// Eventually it would be better to remove this block and just use the input value directly,
13// but we need to maintain it for now to keep the old block data system working.
14#[doc(hidden)]
15pub struct PassthroughBlock<T: DefaultStorage>
16where
17    OldBlockData: FromPass<T>,
18{
19    pub data: OldBlockData,
20    buffer: T::Storage,
21}
22
23impl<T: DefaultStorage> Default for PassthroughBlock<T>
24where
25    OldBlockData: FromPass<T>,
26{
27    fn default() -> Self {
28        Self {
29            data: <OldBlockData as FromPass<T>>::from_pass(<T as DefaultStorage>::from_storage(
30                &T::default_storage(),
31            )),
32            buffer: T::default_storage(),
33        }
34    }
35}
36
37#[doc(hidden)]
38#[derive(Default)]
39pub struct Parameters;
40
41impl Parameters {
42    pub fn new() -> Parameters {
43        Parameters {}
44    }
45}
46
47impl<T: DefaultStorage> ProcessBlock for PassthroughBlock<T>
48where
49    OldBlockData: FromPass<T>,
50{
51    type Parameters = Parameters;
52    type Inputs = T;
53    type Output = T;
54
55    fn process<'b>(
56        &'b mut self,
57        _parameters: &Self::Parameters,
58        _context: &dyn pictorus_traits::Context,
59        input: PassBy<'_, Self::Inputs>,
60    ) -> pictorus_traits::PassBy<'b, Self::Output> {
61        T::copy_into(input, &mut self.buffer);
62        let res = <T as DefaultStorage>::from_storage(&self.buffer);
63        self.data = <OldBlockData as FromPass<T>>::from_pass(res);
64        res
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use crate::testing::StubContext;
71    use pictorus_traits::{ByteSliceSignal, Matrix, Pass};
72
73    use super::*;
74
75    #[test]
76    fn test_passthrough_block_scalar() {
77        let ctxt = StubContext::default();
78        let params = Parameters;
79        let mut block = PassthroughBlock::<f64>::default();
80
81        let input = 99.999;
82        let output = block.process(&params, &ctxt, input.as_by());
83        assert_eq!(output, input);
84        assert_eq!(block.data.scalar(), input);
85    }
86
87    #[test]
88    fn test_passthrough_block_bytes() {
89        let ctxt = StubContext::default();
90        let params = Parameters;
91        let mut block = PassthroughBlock::<ByteSliceSignal>::default();
92
93        let input = b"hello world";
94        let output = block.process(&params, &ctxt, input.as_slice());
95        assert_eq!(output, input);
96        assert_eq!(block.data.to_raw_bytes(), input);
97
98        let input = b"";
99        let output = block.process(&params, &ctxt, input.as_slice());
100        assert_eq!(output, input);
101        assert_eq!(block.data.to_raw_bytes(), input);
102    }
103
104    #[test]
105    fn test_passthrough_block_matrix() {
106        let ctxt = StubContext::default();
107        let params = Parameters;
108        let mut block = PassthroughBlock::<Matrix<2, 2, f64>>::default();
109
110        let input = Matrix {
111            data: [[1.0, 2.0], [3.0, 4.0]],
112        };
113        let output = block.process(&params, &ctxt, input.as_by());
114        assert_eq!(output, &input);
115        assert_eq!(block.data.get_data().as_slice(), input.data.as_flattened());
116    }
117}