Trait bitstream_io::read::FromBitStreamWith

source ·
pub trait FromBitStreamWith<'a> {
    type Context: 'a;
    type Error;

    // Required method
    fn from_reader<R: BitRead + ?Sized>(
        r: &mut R,
        context: &Self::Context
    ) -> Result<Self, Self::Error>
       where Self: Sized;
}
Expand description

Implemented by complex types that require some immutable context to parse themselves from a reader.

§Example

use std::io::{Cursor, Read};
use bitstream_io::{BigEndian, BitRead, BitReader, FromBitStreamWith};

#[derive(Default)]
struct Streaminfo {
    minimum_block_size: u16,
    maximum_block_size: u16,
    minimum_frame_size: u32,
    maximum_frame_size: u32,
    sample_rate: u32,
    channels: u8,
    bits_per_sample: u8,
    total_samples: u64,
    md5: [u8; 16],
}

#[derive(Debug, PartialEq, Eq)]
struct FrameHeader {
    variable_block_size: bool,
    block_size: u32,
    sample_rate: u32,
    channel_assignment: u8,
    sample_size: u8,
    frame_number: u64,
    crc8: u8,
}

impl FromBitStreamWith<'_> for FrameHeader {
    type Context = Streaminfo;

    type Error = FrameHeaderError;

    fn from_reader<R: BitRead + ?Sized>(
        r: &mut R,
        streaminfo: &Streaminfo,
    ) -> Result<Self, Self::Error> {
        if r.read::<u16>(14)? != 0b11111111111110 {
            return Err(FrameHeaderError::InvalidSync);
        }

        if r.read_bit()? != false {
            return Err(FrameHeaderError::InvalidReservedBit);
        }

        let variable_block_size = r.read_bit()?;

        let block_size_bits = r.read::<u8>(4)?;

        let sample_rate_bits = r.read::<u8>(4)?;

        let channel_assignment = r.read::<u8>(4)?;

        let sample_size = match r.read::<u8>(3)? {
            0b000 => streaminfo.bits_per_sample,
            0b001 => 8,
            0b010 => 12,
            0b011 => return Err(FrameHeaderError::InvalidSampleSize),
            0b100 => 16,
            0b101 => 20,
            0b110 => 24,
            0b111 => 32,
            _ => unreachable!(),
        };

        if r.read_bit()? != false {
            return Err(FrameHeaderError::InvalidReservedBit);
        }

        let frame_number = read_utf8(r)?;

        Ok(FrameHeader {
            variable_block_size,
            block_size: match block_size_bits {
                0b0000 => return Err(FrameHeaderError::InvalidBlockSize),
                0b0001 => 192,
                n @ 0b010..=0b0101 => 576 * (1 << (n - 2)),
                0b0110 => r.read::<u32>(8)? + 1,
                0b0111 => r.read::<u32>(16)? + 1,
                n @ 0b1000..=0b1111 => 256 * (1 << (n - 8)),
                _ => unreachable!(),
            },
            sample_rate: match sample_rate_bits {
                0b0000 => streaminfo.sample_rate,
                0b0001 => 88200,
                0b0010 => 176400,
                0b0011 => 192000,
                0b0100 => 8000,
                0b0101 => 16000,
                0b0110 => 22050,
                0b0111 => 24000,
                0b1000 => 32000,
                0b1001 => 44100,
                0b1010 => 48000,
                0b1011 => 96000,
                0b1100 => r.read::<u32>(8)? * 1000,
                0b1101 => r.read::<u32>(16)?,
                0b1110 => r.read::<u32>(16)? * 10,
                0b1111 => return Err(FrameHeaderError::InvalidSampleRate),
                _ => unreachable!(),
            },
            channel_assignment,
            sample_size,
            frame_number,
            crc8: r.read(8)?
        })
    }
}

#[derive(Debug)]
enum FrameHeaderError {
    Io(std::io::Error),
    InvalidSync,
    InvalidReservedBit,
    InvalidSampleSize,
    InvalidBlockSize,
    InvalidSampleRate,
}

impl From<std::io::Error> for FrameHeaderError {
    fn from(err: std::io::Error) -> Self {
        Self::Io(err)
    }
}

fn read_utf8<R: BitRead + ?Sized>(r: &mut R) -> Result<u64, std::io::Error> {
    r.read(8)  // left unimplimented in this example
}

let mut reader = BitReader::endian(Cursor::new(b"\xFF\xF8\xC9\x18\x00\xC2"), BigEndian);
assert_eq!(
    reader.parse_with::<FrameHeader>(&Streaminfo::default()).unwrap(),
    FrameHeader {
        variable_block_size: false,
        block_size: 4096,
        sample_rate: 44100,
        channel_assignment: 1,
        sample_size: 16,
        frame_number: 0,
        crc8: 0xC2,
    }
);

§Example with lifetime-contrained Context

In some cases, the Context can depend on a reference to another struct.

use std::io::{Cursor, Read};
use bitstream_io::{BigEndian, BitRead, BitReader, FromBitStreamWith};

#[derive(Default)]
struct ModeParameters {
    size_len: u8,
    index_len: u8,
    index_delta_len: u8,
    // ...
}

struct AuHeaderParseContext<'a> {
    params: &'a ModeParameters,
    base_index: Option<u32>,
}

#[derive(Debug, PartialEq, Eq)]
struct AuHeader {
    size: u32,
    index: u32,
    // ...
}

impl<'a> FromBitStreamWith<'a> for AuHeader {
    type Context = AuHeaderParseContext<'a>;

    type Error = AuHeaderError;

    fn from_reader<R: BitRead + ?Sized>(
        r: &mut R,
        ctx: &AuHeaderParseContext<'a>,
    ) -> Result<Self, Self::Error> {
        let size = r.read::<u32>(ctx.params.size_len as u32)?;
        let index = match ctx.base_index {
            None => r.read::<u32>(ctx.params.index_len as u32)?,
            Some(base_index) => {
                base_index
                + 1
                + r.read::<u32>(ctx.params.index_delta_len as u32)?
            }
        };

        Ok(AuHeader {
            size,
            index,
            // ...
        })
    }
}

#[derive(Debug)]
enum AuHeaderError {
    Io(std::io::Error),
}

impl From<std::io::Error> for AuHeaderError {
    fn from(err: std::io::Error) -> Self {
        Self::Io(err)
    }
}

let mut reader = BitReader::endian(Cursor::new(b"\xFF\xEA\xFF\x10"), BigEndian);

let mode_params = ModeParameters {
    size_len: 10,
    index_len: 6,
    index_delta_len: 2,
    // ...
};

let mut ctx = AuHeaderParseContext {
    params: &mode_params,
    base_index: None,
};

let header1 = reader.parse_with::<AuHeader>(&ctx).unwrap();
assert_eq!(
    header1,
    AuHeader {
        size: 1023,
        index: 42,
    }
);

ctx.base_index = Some(header1.index);

assert_eq!(
    reader.parse_with::<AuHeader>(&ctx).unwrap(),
    AuHeader {
        size: 1020,
        index: 44,
    }
);

Required Associated Types§

source

type Context: 'a

Some context to use when parsing

source

type Error

Error generated during parsing, such as io::Error

Required Methods§

source

fn from_reader<R: BitRead + ?Sized>( r: &mut R, context: &Self::Context ) -> Result<Self, Self::Error>
where Self: Sized,

Parse Self from reader with the given context

Implementors§