Skip to main content

mlt_core/decoder/stream/
logical.rs

1use std::fmt::Debug;
2use std::iter::repeat_n;
3
4use num_traits::{PrimInt, ToPrimitive as _};
5use usize_cast::IntoUsize as _;
6
7use crate::MltError::{ParsingLogicalTechnique, RleRunLenInvalid, UnsupportedLogicalEncoding};
8use crate::codecs::zigzag::{decode_componentwise_delta_vec2s, decode_zigzag, decode_zigzag_delta};
9use crate::decoder::{LogicalEncoding, LogicalTechnique, LogicalValue, RleMeta, StreamMeta};
10use crate::errors::{AsMltError as _, fail_if_invalid_stream_size};
11use crate::{Decoder, MltResult};
12
13impl RleMeta {
14    /// Decode RLE (Run-Length Encoding) data.
15    /// Charges the decoder for the expanded output allocation.
16    pub fn decode<T: PrimInt + Debug>(self, data: &[T], dec: &mut Decoder) -> MltResult<Vec<T>> {
17        let expected_len = self.runs.into_usize().checked_mul(2).or_overflow()?;
18        fail_if_invalid_stream_size(data.len(), expected_len)?;
19
20        let (run_lens, values) = data.split_at(self.runs.into_usize());
21        fail_if_invalid_stream_size(
22            self.num_rle_values.into_usize(),
23            Self::calc_size(run_lens)?.into_usize(),
24        )?;
25
26        let alloc_size = self.num_rle_values.into_usize();
27        let mut result = dec.alloc(alloc_size)?;
28        for (&run_len, &val) in run_lens.iter().zip(values.iter()) {
29            let run = run_len
30                .to_usize()
31                .ok_or_else(|| RleRunLenInvalid(run_len.to_i128().unwrap_or_default()))?;
32            result.extend(repeat_n(val, run));
33        }
34        dec.adjust_alloc(&result, alloc_size)?;
35        Ok(result)
36    }
37
38    fn calc_size<T: PrimInt + Debug>(run_lens: &[T]) -> MltResult<u32> {
39        run_lens
40            .iter()
41            .try_fold(T::zero(), |a, v| a.checked_add(v))
42            .and_then(|v| v.to_u32())
43            .ok_or_else(|| RleRunLenInvalid(run_lens.len().to_i128().unwrap_or_default()))
44    }
45}
46
47impl LogicalTechnique {
48    pub fn parse(value: u8) -> MltResult<Self> {
49        Self::try_from(value).or(Err(ParsingLogicalTechnique(value)))
50    }
51}
52
53impl LogicalValue {
54    #[must_use]
55    pub fn new(meta: StreamMeta) -> Self {
56        Self { meta }
57    }
58
59    /// Logically decode `data` (physically decoded u32 words) into `Vec<i32>`.
60    ///
61    /// Never called for `LogicalEncoding::None` - that case is handled directly
62    /// in the bridge (physical buffer decoded into a fresh output Vec).
63    pub fn decode_i32(self, data: &[u32], dec: &mut Decoder) -> MltResult<Vec<i32>> {
64        match self.meta.encoding.logical {
65            LogicalEncoding::None => decode_zigzag(data, dec),
66            LogicalEncoding::Rle(v) => decode_zigzag(&v.decode(data, dec)?, dec),
67            LogicalEncoding::ComponentwiseDelta => decode_componentwise_delta_vec2s(data, dec),
68            LogicalEncoding::Delta => decode_zigzag_delta::<i32, _>(data, dec),
69            LogicalEncoding::DeltaRle(v) => {
70                let expanded = v.decode(data, dec)?;
71                decode_zigzag_delta::<i32, _>(&expanded, dec)
72            }
73            LogicalEncoding::Morton(v) => v.decode_codes(data, dec),
74            LogicalEncoding::MortonDelta(v) => v.decode_delta(data, dec),
75            LogicalEncoding::MortonRle(_) => Err(UnsupportedLogicalEncoding(
76                self.meta.encoding.logical,
77                "i32 (MortonRle)",
78            )),
79            LogicalEncoding::PseudoDecimal => Err(UnsupportedLogicalEncoding(
80                self.meta.encoding.logical,
81                "i32",
82            )),
83        }
84    }
85
86    /// Logically decode `data` (physically decoded u32 words) into `Vec<u32>`.
87    ///
88    /// Not called for `LogicalEncoding::None` - that case is handled entirely
89    /// in the bridge (physical buffer decoded directly into the output Vec).
90    pub fn decode_u32(self, data: &[u32], dec: &mut Decoder) -> MltResult<Vec<u32>> {
91        let num = self.meta.num_values.into_usize();
92        match self.meta.encoding.logical {
93            LogicalEncoding::None => {
94                // Caller should have used the direct-output path; this is a fallback.
95                dec.consume_items::<u32>(num)?;
96                Ok(data.to_vec())
97            }
98            LogicalEncoding::Rle(rle) => rle.decode(data, dec),
99            LogicalEncoding::Delta => decode_zigzag_delta::<i32, _>(data, dec),
100            LogicalEncoding::DeltaRle(rle) => {
101                decode_zigzag_delta::<i32, _>(&rle.decode(data, dec)?, dec)
102            }
103            _ => Err(UnsupportedLogicalEncoding(
104                self.meta.encoding.logical,
105                "u32",
106            )),
107        }
108    }
109
110    /// Logically decode `data` (physically decoded u64 words) into `Vec<i64>`.
111    ///
112    /// Never called for `LogicalEncoding::None` - that case is handled directly
113    /// in the bridge (physical buffer decoded into a fresh output Vec).
114    pub fn decode_i64(self, data: &[u64], dec: &mut Decoder) -> MltResult<Vec<i64>> {
115        match self.meta.encoding.logical {
116            LogicalEncoding::None => decode_zigzag(data, dec),
117            LogicalEncoding::Delta => decode_zigzag_delta::<i64, _>(data, dec),
118            LogicalEncoding::DeltaRle(rle) => {
119                let expanded = rle.decode(data, dec)?;
120                decode_zigzag_delta::<i64, _>(&expanded, dec)
121            }
122            LogicalEncoding::Rle(rle) => {
123                // rle.decode() charges for expanded u64 vec; decode_zigzag charges for i64 vec
124                let expanded = rle.decode(data, dec)?;
125                decode_zigzag(&expanded, dec)
126            }
127            _ => Err(UnsupportedLogicalEncoding(
128                self.meta.encoding.logical,
129                "i64",
130            )),
131        }
132    }
133
134    /// Logically decode `data` (physically decoded u64 words) into `Vec<u64>`.
135    ///
136    /// Not called for `LogicalEncoding::None` - that case is handled entirely
137    /// in the bridge (physical buffer decoded directly into the output Vec).
138    pub fn decode_u64(self, data: &[u64], dec: &mut Decoder) -> MltResult<Vec<u64>> {
139        let num = self.meta.num_values.into_usize();
140        match self.meta.encoding.logical {
141            LogicalEncoding::None => {
142                // Caller should have used the direct-output path; this is a fallback.
143                dec.consume_items::<u64>(num)?;
144                Ok(data.to_vec())
145            }
146            LogicalEncoding::Rle(rle) => rle.decode(data, dec),
147            LogicalEncoding::Delta => decode_zigzag_delta::<i64, _>(data, dec),
148            LogicalEncoding::DeltaRle(rle) => {
149                let expanded = rle.decode(data, dec)?;
150                decode_zigzag_delta::<i64, _>(&expanded, dec)
151            }
152            _ => Err(UnsupportedLogicalEncoding(
153                self.meta.encoding.logical,
154                "u64",
155            )),
156        }
157    }
158}
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163    use crate::MltError::InvalidDecodingStreamSize;
164    use crate::test_helpers::dec;
165
166    #[test]
167    fn test_decode_rle_empty() {
168        let rle = RleMeta {
169            runs: 0,
170            num_rle_values: 0,
171        };
172        assert_eq!(rle.decode::<u32>(&[], &mut dec()).unwrap(), [] as [u32; 0]);
173    }
174
175    #[test]
176    fn test_decode_rle_invalid_stream_size() {
177        // Valid RLE for runs=2 needs 4 elements (2 run lengths + 2 values). Only 3 provided.
178        let rle = RleMeta {
179            runs: 2,
180            num_rle_values: 3,
181        };
182        let data = [1u32, 2, 3];
183        let err = rle.decode::<u32>(&data, &mut dec()).unwrap_err();
184        assert!(matches!(err, InvalidDecodingStreamSize(3, 4)));
185    }
186}