dsi-bitstream 0.9.2

A Rust implementation of read/write bit streams supporting several types of instantaneous codes
Documentation
/*
 * SPDX-FileCopyrightText: 2023 Tommaso Fontana
 * SPDX-FileCopyrightText: 2023 Inria
 * SPDX-FileCopyrightText: 2023 Sebastiano Vigna
 *
 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
 */

use crate::prelude::*;
use core::convert::Infallible;
#[cfg(feature = "mem_dbg")]
use mem_dbg::{MemDbg, MemSize};

/// An implementation of [`WordRead`] and [`WordSeek`] for a slice.
///
/// The implementation depends on the `INF` parameter: if true, the reader will
/// behave as if the slice is infinitely extended with zeros.
/// If false (default), the reader will return an error when reading
/// beyond the end of the slice. You can create a strict
/// reader with [`MemWordReader::new`] and a zero-extended
/// reader with [`MemWordReader::new_inf`].
///
/// The zero-extended reader might loop infinitely when reading beyond the end
/// of the slice. It is mainly of historical value.
///
/// # Examples
///
/// ```rust
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
/// use dsi_bitstream::prelude::*;
///
/// let words: [u32; 2] = [1, 2];
///
/// let mut word_reader = MemWordReader::new(&words);
/// assert_eq!(word_reader.read_word()?, 1);
/// assert_eq!(word_reader.read_word()?, 2);
/// assert!(word_reader.read_word().is_err());
///
/// let mut word_reader = MemWordReader::new_inf(&words);
/// assert_eq!(word_reader.read_word()?, 1);
/// assert_eq!(word_reader.read_word()?, 2);
/// assert_eq!(word_reader.read_word()?, 0);
/// assert_eq!(word_reader.read_word()?, 0);
/// # Ok(())
/// # }
/// ```
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
pub struct MemWordReader<W: Word, B, const INF: bool = false> {
    data: B,
    word_index: usize,
    _marker: core::marker::PhantomData<W>,
}

impl<W: Word, B, const INF: bool> MemWordReader<W, B, INF> {
    /// Consumes this reader and returns the underlying data.
    #[must_use]
    pub fn into_inner(self) -> B {
        self.data
    }
}

impl<W: Word, B: AsRef<[W]>> MemWordReader<W, B> {
    /// Creates a new [`MemWordReader`] from a slice of data.
    #[must_use]
    pub const fn new(data: B) -> Self {
        Self {
            data,
            word_index: 0,
            _marker: core::marker::PhantomData,
        }
    }
}

impl<W: Word, B: AsRef<[W]>> MemWordReader<W, B, true> {
    /// Creates a new [`MemWordReader`] from a slice of data.
    ///
    /// The resulting reader behaves as if the slice is infinitely
    /// extended with zeros.
    #[must_use]
    pub const fn new_inf(data: B) -> Self {
        Self {
            data,
            word_index: 0,
            _marker: core::marker::PhantomData,
        }
    }
}

impl<W: Word, B: AsRef<[W]>> WordRead for MemWordReader<W, B, true> {
    type Error = Infallible;
    type Word = W;

    #[inline(always)]
    fn read_word(&mut self) -> Result<W, Infallible> {
        let res = self
            .data
            .as_ref()
            .get(self.word_index)
            .copied()
            .unwrap_or(Self::Word::ZERO);

        self.word_index += 1;
        Ok(res)
    }
}

impl<W: Word, B: AsRef<[W]>> WordRead for MemWordReader<W, B, false> {
    type Error = WordError;
    type Word = W;

    #[inline(always)]
    fn read_word(&mut self) -> Result<W, WordError> {
        let res = self
            .data
            .as_ref()
            .get(self.word_index)
            .ok_or(WordError::UnexpectedEof {
                word_pos: self.word_index,
            })?;

        self.word_index += 1;
        Ok(*res)
    }
}

impl<W: Word, B: AsRef<[W]>> WordSeek for MemWordReader<W, B, true> {
    type Error = Infallible;

    #[inline(always)]
    fn word_pos(&mut self) -> Result<u64, Infallible> {
        Ok(self.word_index as u64)
    }

    #[inline(always)]
    fn set_word_pos(&mut self, word_index: u64) -> Result<(), Infallible> {
        // This is dirty but it's infallible
        self.word_index = word_index.min(usize::MAX as u64) as usize;
        Ok(())
    }
}

impl<W: Word, B: AsRef<[W]>> WordSeek for MemWordReader<W, B, false> {
    type Error = WordError;

    #[inline(always)]
    fn word_pos(&mut self) -> Result<u64, WordError> {
        Ok(self.word_index as u64)
    }
    #[inline(always)]
    fn set_word_pos(&mut self, word_index: u64) -> Result<(), WordError> {
        if word_index > self.data.as_ref().len() as u64 {
            Err(WordError::UnexpectedEof {
                word_pos: self.word_index,
            })
        } else {
            self.word_index = word_index as usize;
            Ok(())
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::codes::{DeltaWrite, delta::DeltaReadParam};

    #[test]
    fn test_eof_table_read() {
        let mut words: [u64; 1] = [0];
        let mut writer = crate::prelude::BufBitWriter::<crate::prelude::LE, _>::new(
            MemWordWriterSlice::new(&mut words),
        );
        for _ in 0..16 {
            writer.write_delta(1).unwrap();
        }
        writer.flush().unwrap();
        drop(writer);

        let mut reader = crate::prelude::BufBitReader::<crate::prelude::LE, _>::new(
            MemWordReader::new_inf(&words),
        );
        for _ in 0..16 {
            // Here the last table read returns zero-extended data
            assert_eq!(reader.read_delta_param::<true, true>().unwrap(), 1);
        }
    }
}