ozlrip-decode 0.2.0

OpenZL decoder for ozlrip
Documentation
use alloc::vec::Vec;

use ozlrip_core::{Error, ErrorKind, Limits, Result};

use super::{
    OwnedStream, StreamInput, numeric_element_count, partition::write_numeric_element_vec,
    read_usize_numeric_element,
};

#[inline(never)]
#[cold]
pub(super) fn decode_node(
    inputs: &[StreamInput<'_>],
    header: &[u8],
    limits: Limits,
) -> Result<OwnedStream> {
    let [distances, values] = inputs else {
        return Err(Error::new(ErrorKind::InvalidGraph)
            .with_detail("sparse_num input count does not match node shape"));
    };
    if !matches!(distances.element_width, 1 | 2 | 4) {
        return Err(Error::new(ErrorKind::InvalidType)
            .with_detail("sparse_num distance width is unsupported"));
    }
    if !matches!(values.element_width, 1 | 2 | 4 | 8) {
        return Err(
            Error::new(ErrorKind::InvalidType).with_detail("sparse_num value width is unsupported")
        );
    }
    if header.len() > values.element_width {
        return Err(
            Error::new(ErrorKind::Malformed).with_detail("sparse_num header exceeds value width")
        );
    }

    let distance_count = numeric_element_count(distances.bytes, distances.element_width)?;
    let value_count = numeric_element_count(values.bytes, values.element_width)?;
    if distance_count != value_count && distance_count != value_count.saturating_add(1) {
        return Err(Error::new(ErrorKind::Malformed)
            .with_detail("sparse_num distance count does not match literal count"));
    }

    let dominant = read_dominant(header);
    let mut output_elements = value_count;
    for index in 0..distance_count {
        output_elements = output_elements
            .checked_add(read_usize_numeric_element(
                distances.bytes,
                distances.element_width,
                index,
            )?)
            .ok_or_else(|| Error::new(ErrorKind::IntegerOverflow))?;
    }
    let output_len = output_elements
        .checked_mul(values.element_width)
        .ok_or_else(|| Error::new(ErrorKind::IntegerOverflow))?;
    if output_len > limits.max_decoded_bytes || output_len > limits.max_buffer_bytes {
        return Err(
            Error::new(ErrorKind::LimitExceeded).with_detail("decoded output limit exceeded")
        );
    }

    let mut output = Vec::new();
    output.try_reserve_exact(output_len).map_err(|_| {
        Error::new(ErrorKind::LimitExceeded).with_detail("sparse_num allocation failed")
    })?;
    for index in 0..value_count {
        let distance = read_usize_numeric_element(distances.bytes, distances.element_width, index)?;
        append_run(&mut output, dominant, distance, values.element_width)?;
        let start = index
            .checked_mul(values.element_width)
            .ok_or_else(|| Error::new(ErrorKind::IntegerOverflow))?;
        let end = start
            .checked_add(values.element_width)
            .ok_or_else(|| Error::new(ErrorKind::IntegerOverflow))?;
        let value = values.bytes.get(start..end).ok_or_else(|| {
            Error::new(ErrorKind::Malformed).with_detail("sparse_num value stream is truncated")
        })?;
        output.extend_from_slice(value);
    }
    if distance_count == value_count + 1 {
        let distance =
            read_usize_numeric_element(distances.bytes, distances.element_width, value_count)?;
        append_run(&mut output, dominant, distance, values.element_width)?;
    }
    debug_assert_eq!(output.len(), output_len);
    Ok(OwnedStream::typed(output, values.element_width))
}

#[inline(never)]
#[cold]
fn read_dominant(header: &[u8]) -> u64 {
    let mut bytes = [0u8; 8];
    bytes[..header.len()].copy_from_slice(header);
    u64::from_le_bytes(bytes)
}

#[inline(never)]
#[cold]
fn append_run(
    output: &mut Vec<u8>,
    dominant: u64,
    distance: usize,
    value_width: usize,
) -> Result<()> {
    let run_len = distance
        .checked_mul(value_width)
        .ok_or_else(|| Error::new(ErrorKind::IntegerOverflow))?;
    if dominant == 0 {
        output.resize(output.len() + run_len, 0);
        return Ok(());
    }
    for _ in 0..distance {
        write_numeric_element_vec(output, value_width, dominant);
    }
    Ok(())
}