use std::fmt::Debug;
use std::iter::repeat_n;
use num_traits::{PrimInt, ToPrimitive as _};
use usize_cast::IntoUsize as _;
use crate::MltError::{ParsingLogicalTechnique, RleRunLenInvalid, UnsupportedLogicalEncoding};
#[cfg(feature = "unstable-v2")]
use crate::codecs::zigzag::decode_componentwise_delta_vec3s;
use crate::codecs::zigzag::{
decode_componentwise_delta_vec2s, decode_componentwise_delta2_vec2s, decode_zigzag,
decode_zigzag_delta, decode_zigzag_delta2,
};
#[cfg(feature = "unstable-v2")]
use crate::decoder::XyzLogical;
use crate::decoder::{
FloatLogical, IntLogical, LogicalEncoding, LogicalTechnique, LogicalValue, RleMeta, StreamMeta,
VertexLogical,
};
use crate::errors::{AsMltError as _, fail_if_invalid_stream_size};
use crate::{Decoder, MltResult};
impl RleMeta {
pub fn decode<T: PrimInt + Debug>(self, data: &[T], dec: &mut Decoder) -> MltResult<Vec<T>> {
match self {
Self::Split {
runs,
num_rle_values,
} => Self::decode_split(runs, num_rle_values, data, dec),
#[cfg(feature = "unstable-v2")]
Self::Interleaved { num_rle_values } => {
Self::decode_interleaved(num_rle_values, data, dec)
}
}
}
fn decode_split<T: PrimInt + Debug>(
runs: u32,
num_rle_values: u32,
data: &[T],
dec: &mut Decoder,
) -> MltResult<Vec<T>> {
let expected_len = runs.into_usize().checked_mul(2).or_overflow()?;
fail_if_invalid_stream_size(data.len(), expected_len)?;
let (run_lens, values) = data.split_at(runs.into_usize());
fail_if_invalid_stream_size(
num_rle_values.into_usize(),
Self::calc_size(run_lens)?.into_usize(),
)?;
let alloc_size = num_rle_values.into_usize();
let mut result = dec.alloc(alloc_size)?;
for (&run_len, &val) in run_lens.iter().zip(values.iter()) {
let run = run_len
.to_usize()
.ok_or_else(|| RleRunLenInvalid(run_len.to_i128().unwrap_or_default()))?;
result.extend(repeat_n(val, run));
}
dec.adjust_alloc(&result, alloc_size)?;
Ok(result)
}
#[cfg(feature = "unstable-v2")]
fn decode_interleaved<T: PrimInt + Debug>(
num_rle_values: u32,
data: &[T],
dec: &mut Decoder,
) -> MltResult<Vec<T>> {
if !data.len().is_multiple_of(2) {
return Err(RleRunLenInvalid(data.len().to_i128().unwrap_or_default()));
}
let alloc_size = num_rle_values.into_usize();
let mut result = dec.alloc(alloc_size)?;
for [cnt, val] in data.as_chunks::<2>().0 {
let run = cnt
.to_usize()
.filter(|&run| run <= alloc_size - result.len())
.ok_or_else(|| RleRunLenInvalid(cnt.to_i128().unwrap_or_default()))?;
result.extend(repeat_n(val, run));
}
fail_if_invalid_stream_size(result.len(), alloc_size)?;
dec.adjust_alloc(&result, alloc_size)?;
Ok(result)
}
fn calc_size<T: PrimInt + Debug>(run_lens: &[T]) -> MltResult<u32> {
run_lens
.iter()
.try_fold(T::zero(), |a, v| a.checked_add(v))
.and_then(|v| v.to_u32())
.ok_or_else(|| RleRunLenInvalid(run_lens.len().to_i128().unwrap_or_default()))
}
}
impl LogicalTechnique {
pub fn parse(value: u8) -> MltResult<Self> {
Self::try_from(value).or(Err(ParsingLogicalTechnique(value)))
}
}
impl LogicalValue {
#[must_use]
pub fn new(meta: StreamMeta) -> Self {
Self { meta }
}
pub fn decode_i32(self, data: &[u32], dec: &mut Decoder) -> MltResult<Vec<i32>> {
use IntLogical as IL;
use LogicalEncoding as LE;
use VertexLogical as VL;
match self.meta.encoding.logical {
LE::Int(IL::None) | LE::Vertex(VL::None) => decode_zigzag(data, dec),
LE::Int(IL::Rle(v)) => decode_zigzag(&v.decode(data, dec)?, dec),
LE::Vertex(VL::ComponentwiseDelta) => decode_componentwise_delta_vec2s(data, dec),
LE::Int(IL::Delta) | LE::Vertex(VL::Delta) => decode_zigzag_delta::<i32, _>(data, dec),
LE::Int(IL::DeltaRle(v)) => {
let expanded = v.decode(data, dec)?;
decode_zigzag_delta::<i32, _>(&expanded, dec)
}
LE::Int(IL::Delta2) => decode_zigzag_delta2::<i32, _>(data, dec),
LE::Vertex(VL::ComponentwiseDelta2) => decode_componentwise_delta2_vec2s(data, dec),
LE::Vertex(VL::MortonDelta(v)) => v.decode_delta(data, dec),
LE::Vertex(VL::Rans) => Err(UnsupportedLogicalEncoding(
self.meta.encoding.logical,
"a stream decoded without the layer's topology",
)),
#[cfg(feature = "unstable-v2")]
LE::Vertex(VL::Xyz(_, xyz)) => {
if !data.len().is_multiple_of(3) {
return Err(crate::MltError::InvalidTripleStreamSize(data.len()));
}
match xyz {
XyzLogical::None => decode_zigzag(data, dec),
XyzLogical::Delta => decode_zigzag_delta::<i32, _>(data, dec),
XyzLogical::ComponentwiseDelta => decode_componentwise_delta_vec3s(data, dec),
}
}
LE::Bool(_) | LE::Float(_) => Err(UnsupportedLogicalEncoding(
self.meta.encoding.logical,
"i32",
)),
}
}
pub fn decode_u32(self, data: &[u32], dec: &mut Decoder) -> MltResult<Vec<u32>> {
let num = self.meta.num_values.into_usize();
match self.meta.encoding.logical {
LogicalEncoding::Int(IntLogical::None) | LogicalEncoding::Float(FloatLogical::Dict) => {
dec.consume_items::<u32>(num)?;
Ok(data.to_vec())
}
LogicalEncoding::Int(IntLogical::Rle(rle)) => rle.decode(data, dec),
LogicalEncoding::Int(IntLogical::Delta) => decode_zigzag_delta::<i32, _>(data, dec),
LogicalEncoding::Int(IntLogical::DeltaRle(rle)) => {
decode_zigzag_delta::<i32, _>(&rle.decode(data, dec)?, dec)
}
LogicalEncoding::Int(IntLogical::Delta2) => decode_zigzag_delta2::<i32, _>(data, dec),
LogicalEncoding::Bool(_) | LogicalEncoding::Float(_) | LogicalEncoding::Vertex(_) => {
Err(UnsupportedLogicalEncoding(
self.meta.encoding.logical,
"u32",
))
}
}
}
pub fn decode_i64(self, data: &[u64], dec: &mut Decoder) -> MltResult<Vec<i64>> {
match self.meta.encoding.logical {
LogicalEncoding::Int(IntLogical::None) => decode_zigzag(data, dec),
LogicalEncoding::Int(IntLogical::Delta) => decode_zigzag_delta::<i64, _>(data, dec),
LogicalEncoding::Int(IntLogical::DeltaRle(rle)) => {
let expanded = rle.decode(data, dec)?;
decode_zigzag_delta::<i64, _>(&expanded, dec)
}
LogicalEncoding::Int(IntLogical::Rle(rle)) => {
let expanded = rle.decode(data, dec)?;
decode_zigzag(&expanded, dec)
}
LogicalEncoding::Int(IntLogical::Delta2) => decode_zigzag_delta2::<i64, _>(data, dec),
LogicalEncoding::Bool(_) | LogicalEncoding::Float(_) | LogicalEncoding::Vertex(_) => {
Err(UnsupportedLogicalEncoding(
self.meta.encoding.logical,
"i64",
))
}
}
}
pub fn decode_u64(self, data: &[u64], dec: &mut Decoder) -> MltResult<Vec<u64>> {
let num = self.meta.num_values.into_usize();
match self.meta.encoding.logical {
LogicalEncoding::Int(IntLogical::None) | LogicalEncoding::Float(FloatLogical::Dict) => {
dec.consume_items::<u64>(num)?;
Ok(data.to_vec())
}
LogicalEncoding::Int(IntLogical::Rle(rle)) => rle.decode(data, dec),
LogicalEncoding::Int(IntLogical::Delta) => decode_zigzag_delta::<i64, _>(data, dec),
LogicalEncoding::Int(IntLogical::DeltaRle(rle)) => {
let expanded = rle.decode(data, dec)?;
decode_zigzag_delta::<i64, _>(&expanded, dec)
}
LogicalEncoding::Int(IntLogical::Delta2) => decode_zigzag_delta2::<i64, _>(data, dec),
LogicalEncoding::Bool(_) | LogicalEncoding::Float(_) | LogicalEncoding::Vertex(_) => {
Err(UnsupportedLogicalEncoding(
self.meta.encoding.logical,
"u64",
))
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::MltError::InvalidDecodingStreamSize;
use crate::test_helpers::dec;
#[test]
fn test_decode_rle_empty() {
let rle = RleMeta::Split {
runs: 0,
num_rle_values: 0,
};
assert_eq!(rle.decode::<u32>(&[], &mut dec()).unwrap(), [] as [u32; 0]);
}
#[test]
fn test_decode_rle_invalid_stream_size() {
let rle = RleMeta::Split {
runs: 2,
num_rle_values: 3,
};
let data = [1u32, 2, 3];
let err = rle.decode::<u32>(&data, &mut dec()).unwrap_err();
assert!(matches!(err, InvalidDecodingStreamSize(3, 4)));
}
fn value(logical: LogicalEncoding) -> LogicalValue {
use crate::decoder::{DictionaryType, IntEncoding, PhysicalEncoding, StreamType};
let encoding = IntEncoding::new(logical, PhysicalEncoding::VarInt);
LogicalValue::new(StreamMeta::new(
StreamType::Data(DictionaryType::None),
encoding,
2,
))
}
#[test]
fn a_raw_u64_stream_passes_through() {
let decoded = value(LogicalEncoding::Int(IntLogical::None))
.decode_u64(&[7, 9], &mut dec())
.unwrap();
assert_eq!(decoded, [7, 9]);
}
#[rstest::rstest]
#[case::i32_bool(LogicalEncoding::Bool(crate::decoder::BoolLogical::None), "i32")]
#[case::i32_float(LogicalEncoding::Float(FloatLogical::None), "i32")]
#[case::u32_vertex(LogicalEncoding::Vertex(VertexLogical::None), "u32")]
#[case::i64_bool(LogicalEncoding::Bool(crate::decoder::BoolLogical::None), "i64")]
#[case::u64_float(LogicalEncoding::Float(FloatLogical::None), "u64")]
fn a_decoder_rejects_an_encoding_of_another_kind(
#[case] logical: LogicalEncoding,
#[case] target: &str,
) {
let v = value(logical);
let err = match target {
"u32" => v.decode_u32(&[], &mut dec()).map(drop),
"i64" => v.decode_i64(&[], &mut dec()).map(drop),
"u64" => v.decode_u64(&[], &mut dec()).map(drop),
_ => v.decode_i32(&[], &mut dec()).map(drop),
}
.unwrap_err();
assert!(matches!(err, UnsupportedLogicalEncoding(l, t) if l == logical && t == target));
}
#[cfg(feature = "unstable-v2")]
#[test]
fn test_decode_rle_interleaved() {
let rle = RleMeta::Interleaved { num_rle_values: 6 };
let data = [3u32, 7, 1, 9, 2, 7];
let decoded = rle.decode(&data, &mut dec()).unwrap();
assert_eq!(decoded, vec![7, 7, 7, 9, 7, 7]);
}
#[cfg(feature = "unstable-v2")]
#[test]
fn test_decode_rle_interleaved_empty() {
let rle = RleMeta::Interleaved { num_rle_values: 0 };
assert_eq!(
rle.decode::<u32>(&[], &mut dec()).unwrap(),
Vec::<u32>::new()
);
}
#[cfg(feature = "unstable-v2")]
#[test]
fn test_decode_rle_interleaved_count_mismatch() {
let rle = RleMeta::Interleaved { num_rle_values: 5 };
let data = [3u32, 7, 1, 9];
assert!(rle.decode(&data, &mut dec()).is_err());
}
#[cfg(feature = "unstable-v2")]
#[test]
fn test_decode_rle_interleaved_odd_length() {
let rle = RleMeta::Interleaved { num_rle_values: 3 };
let data = [3u32, 7, 1];
assert!(rle.decode(&data, &mut dec()).is_err());
}
#[cfg(feature = "unstable-v2")]
#[test]
fn test_decode_rle_interleaved_overflowing_run() {
let rle = RleMeta::Interleaved { num_rle_values: 2 };
let data = [u32::MAX, 7];
assert!(rle.decode(&data, &mut dec()).is_err());
}
#[cfg(feature = "unstable-v2")]
fn xyz(logical: XyzLogical) -> LogicalValue {
use crate::decoder::{DictionaryType, IntEncoding, PhysicalEncoding, StreamType};
use crate::tile::ZStep;
let encoding = IntEncoding::new(
LogicalEncoding::Vertex(VertexLogical::Xyz(ZStep::new(0).unwrap(), logical)),
PhysicalEncoding::VarInt,
);
LogicalValue::new(StreamMeta::new(
StreamType::Data(DictionaryType::Vertex),
encoding,
2,
))
}
#[cfg(feature = "unstable-v2")]
#[rstest::rstest]
#[case::none(XyzLogical::None, [1, 2, -1, 3, 4, -2])]
#[case::delta(XyzLogical::Delta, [1, 3, 2, 5, 9, 7])]
#[case::componentwise_delta(XyzLogical::ComponentwiseDelta, [1, 2, -1, 4, 6, -3])]
fn an_xyz_stream_decodes_its_triples(#[case] logical: XyzLogical, #[case] expected: [i32; 6]) {
let zigzag = [2, 4, 1, 6, 8, 3];
assert_eq!(
xyz(logical).decode_i32(&zigzag, &mut dec()).unwrap(),
expected
);
}
#[cfg(feature = "unstable-v2")]
#[test]
fn an_xyz_stream_of_partial_triples_is_rejected() {
let err = xyz(XyzLogical::None)
.decode_i32(&[2, 4, 1, 6], &mut dec())
.unwrap_err();
assert!(matches!(err, crate::MltError::InvalidTripleStreamSize(4)));
}
}