Skip to main content

mlt_core/frames/v01/stream/
physical.rs

1use integer_encoding::VarInt as _;
2
3use crate::MltError::ParsingStreamType;
4use crate::codecs::bytes::{encode_u32s_to_bytes, encode_u64s_to_bytes};
5use crate::codecs::fastpfor::encode_fastpfor;
6use crate::utils::parse_u8;
7use crate::v01::{
8    DictionaryType, EncodedStreamData, LengthType, OffsetType, PhysicalEncoding, StreamType,
9};
10use crate::{MltError, MltRefResult, MltResult};
11
12impl StreamType {
13    pub fn from_bytes(input: &'_ [u8]) -> MltRefResult<'_, Self> {
14        let (input, value) = parse_u8(input)?;
15        let pt = Self::from_u8(value).ok_or(ParsingStreamType(value))?;
16        Ok((input, pt))
17    }
18
19    fn from_u8(value: u8) -> Option<Self> {
20        let high4 = value >> 4;
21        let low4 = value & 0x0F;
22        Some(match high4 {
23            #[cfg(fuzzing)]
24            // when fuzzing, we cannot have ignored bits, to preserve roundtrip-ability
25            0 if low4 == 0 => StreamType::Present,
26            #[cfg(not(fuzzing))]
27            0 => StreamType::Present,
28            1 => StreamType::Data(DictionaryType::try_from(low4).ok()?),
29            2 => StreamType::Offset(OffsetType::try_from(low4).ok()?),
30            3 => StreamType::Length(LengthType::try_from(low4).ok()?),
31            _ => return None,
32        })
33    }
34    #[must_use]
35    pub fn as_u8(self) -> u8 {
36        let proto_high4 = match self {
37            StreamType::Present => 0,
38            StreamType::Data(_) => 1,
39            StreamType::Offset(_) => 2,
40            StreamType::Length(_) => 3,
41        };
42        let high4 = proto_high4 << 4;
43        let low4 = match self {
44            StreamType::Present => 0,
45            StreamType::Data(i) => i as u8,
46            StreamType::Offset(i) => i as u8,
47            StreamType::Length(i) => i as u8,
48        };
49        debug_assert!(low4 <= 0x0F, "secondary types should not exceed 4 bit");
50        high4 | low4
51    }
52}
53
54impl PhysicalEncoding {
55    pub fn parse(value: u8) -> MltResult<Self> {
56        Self::try_from(value).or(Err(MltError::ParsingPhysicalEncoding(value)))
57    }
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::EnumIter)]
61#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
62#[cfg_attr(all(not(test), feature = "arbitrary"), derive(arbitrary::Arbitrary))]
63pub enum PhysicalEncoder {
64    None,
65    /// Can produce better results in combination with a heavyweight compression scheme like `Gzip`.
66    /// Simple compression scheme where the encoding is easier to implement compared to `FastPFOR`.
67    VarInt,
68    /// Preferred, tends to produce the best compression ratio and decoding performance.
69    ///
70    /// Does not support u64/i64 integers
71    FastPFOR,
72}
73
74impl PhysicalEncoder {
75    /// Physically encode a `u32` sequence into the appropriate `EncodedStreamData` variant.
76    pub fn encode_u32s(
77        self,
78        values: Vec<u32>,
79    ) -> Result<(EncodedStreamData, PhysicalEncoding), MltError> {
80        match self {
81            Self::None => {
82                let data = encode_u32s_to_bytes(&values);
83                let stream = EncodedStreamData::Encoded(data);
84                Ok((stream, PhysicalEncoding::None))
85            }
86            Self::VarInt => {
87                let mut data = Vec::new();
88                for v in values {
89                    data.extend_from_slice(&u64::from(v).encode_var_vec());
90                }
91                let stream = EncodedStreamData::VarInt(data);
92                Ok((stream, PhysicalEncoding::VarInt))
93            }
94            Self::FastPFOR => {
95                let data = encode_fastpfor(&values)?;
96                let stream = EncodedStreamData::Encoded(data);
97                Ok((stream, PhysicalEncoding::FastPFOR))
98            }
99        }
100    }
101
102    /// Physically encode a `u64` sequence into the appropriate `EncodedStreamData` variant.
103    pub fn encode_u64s(
104        self,
105        values: Vec<u64>,
106    ) -> Result<(EncodedStreamData, PhysicalEncoding), MltError> {
107        match self {
108            Self::None => {
109                let data = encode_u64s_to_bytes(&values);
110                let stream = EncodedStreamData::Encoded(data);
111                Ok((stream, PhysicalEncoding::None))
112            }
113            Self::VarInt => {
114                let mut data = Vec::new();
115                for v in values {
116                    data.extend_from_slice(&v.encode_var_vec());
117                }
118                let stream = EncodedStreamData::VarInt(data);
119                Ok((stream, PhysicalEncoding::VarInt))
120            }
121            Self::FastPFOR => Err(MltError::UnsupportedPhysicalEncoding("FastPFOR on u64")),
122        }
123    }
124}