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