draco-core 1.0.1

Pure Rust core encoder and decoder for Draco geometry compression
Documentation
//! Uncompressed (direct) bit decoder.
//!
//! [`DirectBitDecoder`] reads raw, non-entropy-coded bits packed into 32-bit
//! words. Used where Draco stores values verbatim rather than rANS-coded. Port
//! of Draco's `direct_bit_decoder.h`.

use crate::decoder_buffer::DecoderBuffer;

#[derive(Default)]
pub struct DirectBitDecoder {
    bits: Vec<u32>,
    pos: usize,
    num_used_bits: u32,
}

impl DirectBitDecoder {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn clear(&mut self) {
        self.bits.clear();
        self.pos = 0;
        self.num_used_bits = 0;
    }

    pub fn start_decoding<'a>(&mut self, source_buffer: &mut DecoderBuffer<'a>) -> bool {
        self.clear();
        let size_in_bytes = match source_buffer.decode_u32() {
            Ok(v) => v,
            Err(_) => return false,
        };

        if size_in_bytes == 0 || (size_in_bytes & 0x3) != 0 {
            return false;
        }
        let num_words = (size_in_bytes / 4) as usize;
        if source_buffer.remaining_size() < size_in_bytes as usize {
            return false;
        }
        self.bits.reserve(num_words);
        for _ in 0..num_words {
            let w = match source_buffer.decode_u32() {
                Ok(v) => v,
                Err(_) => return false,
            };
            self.bits.push(w);
        }
        self.pos = 0;
        self.num_used_bits = 0;
        true
    }

    pub fn decode_next_bit(&mut self) -> bool {
        if self.pos >= self.bits.len() {
            return false;
        }
        let selector = 1u32 << (31 - self.num_used_bits);
        let bit = (self.bits[self.pos] & selector) != 0;
        self.num_used_bits += 1;
        if self.num_used_bits == 32 {
            self.pos += 1;
            self.num_used_bits = 0;
        }
        bit
    }

    pub fn decode_least_significant_bits32(&mut self, nbits: u32, value: &mut u32) -> bool {
        if nbits == 0 || nbits > 32 {
            return false;
        }
        let remaining = 32 - self.num_used_bits;
        if nbits <= remaining {
            let Some(&word) = self.bits.get(self.pos) else {
                return false;
            };
            *value = (word << self.num_used_bits) >> (32 - nbits);
            self.num_used_bits += nbits;
            if self.num_used_bits == 32 {
                self.pos += 1;
                self.num_used_bits = 0;
            }
        } else {
            let Some(next_pos) = self.pos.checked_add(1) else {
                return false;
            };
            let (Some(&word_l), Some(&word_r)) = (self.bits.get(self.pos), self.bits.get(next_pos))
            else {
                return false;
            };
            let value_l = word_l << self.num_used_bits;
            self.num_used_bits = nbits - remaining;
            self.pos = next_pos;
            let value_r = word_r >> (32 - self.num_used_bits);
            *value = (value_l >> (32 - self.num_used_bits - remaining)) | value_r;
        }
        true
    }

    pub fn end_decoding(&mut self) {}
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn decode_least_significant_bits32_rejects_invalid_bit_counts() {
        let mut decoder = DirectBitDecoder::new();
        decoder.bits.push(0xffff_ffff);
        let mut value = 123;

        assert!(!decoder.decode_least_significant_bits32(0, &mut value));
        assert!(!decoder.decode_least_significant_bits32(33, &mut value));
        assert_eq!(value, 123);
    }

    #[test]
    fn decode_least_significant_bits32_rejects_missing_second_word() {
        let mut decoder = DirectBitDecoder::new();
        decoder.bits.push(0xffff_ffff);
        decoder.num_used_bits = 31;
        let mut value = 0;

        assert!(!decoder.decode_least_significant_bits32(2, &mut value));
    }
}