bitvec_helpers-3.1.6/.cargo_vcs_info.json0000644000000001360000000000100140410ustar { "git": { "sha1": "c13fd9e673d007585250427affb11ce593dc3660" }, "path_in_vcs": "" }bitvec_helpers-3.1.6/.gitignore000064400000000000000000000005001046102023000146140ustar 00000000000000# Generated by Cargo # will have compiled files and executables /target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk bitvec_helpers-3.1.6/Cargo.toml0000644000000023370000000000100120440ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.79.0" name = "bitvec_helpers" version = "3.1.6" authors = ["quietvoid"] build = false autobins = false autoexamples = false autotests = false autobenches = false description = "BitVec based bitstream reader and writer" readme = "README.md" license = "MIT" repository = "https://github.com/quietvoid/bitvec_helpers" [lib] name = "bitvec_helpers" path = "src/lib.rs" [dependencies.anyhow] version = "1.0.88" optional = true [dependencies.bitstream-io] version = "2.5.3" optional = true [dependencies.bitvec] version = "1.0.1" optional = true [dependencies.funty] version = "2.0.0" optional = true [features] bitstream-io = ["dep:bitstream-io"] bitvec = [ "dep:bitvec", "dep:funty", "dep:anyhow", ] default = ["bitvec"] bitvec_helpers-3.1.6/Cargo.toml.orig000064400000000000000000000011101046102023000155110ustar 00000000000000[package] name = "bitvec_helpers" version = "3.1.6" authors = ["quietvoid"] edition = "2021" rust-version = "1.79.0" license = "MIT" description = "BitVec based bitstream reader and writer" repository = "https://github.com/quietvoid/bitvec_helpers" [dependencies] anyhow = { version = "1.0.88", optional = true } bitvec = { version = "1.0.1", optional = true } funty = { version = "2.0.0", optional = true } bitstream-io = { version = "2.5.3", optional = true } [features] default = ["bitvec"] bitvec = ["dep:bitvec", "dep:funty", "dep:anyhow"] bitstream-io = ["dep:bitstream-io"] bitvec_helpers-3.1.6/LICENSE000064400000000000000000000020521046102023000136350ustar 00000000000000MIT License Copyright (c) 2021 quietvoid Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. bitvec_helpers-3.1.6/README.md000064400000000000000000000003721046102023000141120ustar 00000000000000# bitvec_helpers Bitstream reader/writer helpers. ## Features - `bitvec`: Expose [bitvec](https://github.com/ferrilab/bitvec) based reader, writer. - `bitstream-io`: Expose [bitstream-io](https://github.com/tuffy/bitstream-io) based reader, writer. bitvec_helpers-3.1.6/src/bitstream_io_impl/bitstream_io_reader.rs000064400000000000000000000101101046102023000234640ustar 00000000000000use std::io; use bitstream_io::{BigEndian, BitRead, BitReader, Numeric}; pub struct BitstreamIoReader { bs: BitReader, len: u64, } /// Convenience type for Vec inner buffer pub type BsIoVecReader = BitstreamIoReader>>; /// Convenience type for &[u8] inner buffer pub type BsIoSliceReader<'a> = BitstreamIoReader>; impl BitstreamIoReader where R: io::Read + io::Seek, { pub fn new(read: R, len_bytes: u64) -> Self { Self { bs: BitReader::new(read), len: len_bytes * 8, } } #[inline(always)] pub fn get(&mut self) -> io::Result { self.bs.read_bit() } #[inline(always)] pub fn get_n(&mut self, n: u32) -> io::Result { self.available().and_then(|avail| { if n as u64 > avail { Err(io::Error::new( io::ErrorKind::UnexpectedEof, "get_n: out of bounds bits", )) } else { self.bs.read(n) } }) } #[inline(always)] pub fn get_ue(&mut self) -> io::Result { self.bs.read_unary1().and_then(|leading_zeroes| { if leading_zeroes > 0 { self.bs .read::(leading_zeroes) .map(|v| v + (1 << leading_zeroes) - 1) } else { Ok(0) } }) } #[inline(always)] pub fn get_se(&mut self) -> io::Result { self.get_ue().map(|code_num| { let m = ((code_num + 1) as f64 / 2.0).floor() as u64; if code_num % 2 == 0 { -(m as i64) } else { m as i64 } }) } #[inline(always)] pub fn is_aligned(&self) -> bool { self.bs.byte_aligned() } #[inline(always)] pub fn available(&mut self) -> io::Result { self.bs.position_in_bits().map(|pos| self.len - pos) } #[inline(always)] pub fn skip_n(&mut self, n: u32) -> io::Result<()> { self.available().and_then(|avail| { if n as u64 > avail { Err(io::Error::new( io::ErrorKind::UnexpectedEof, "skip_n: out of bounds bits", )) } else { self.bs.skip(n) } }) } #[inline(always)] pub fn position(&mut self) -> io::Result { self.bs.position_in_bits() } pub fn replace_inner(&mut self, read: R, len_bytes: u64) { self.len = len_bytes * 8; self.bs = BitReader::new(read); } } impl BsIoVecReader { pub fn from_vec(buf: Vec) -> Self { let len = buf.len() as u64; let read = io::Cursor::new(buf); Self::new(read, len) } pub fn replace_vec(&mut self, buf: Vec) { let len = buf.len() as u64; self.replace_inner(io::Cursor::new(buf), len); } } impl<'a> BsIoSliceReader<'a> { pub fn from_slice(buf: &'a [u8]) -> Self { let len = buf.len() as u64; let read = io::Cursor::new(buf); Self::new(read, len) } pub fn replace_slice(&mut self, buf: &'a [u8]) { let len = buf.len() as u64; self.replace_inner(io::Cursor::new(buf), len); } } impl Default for BsIoVecReader { fn default() -> Self { Self::from_vec(Vec::new()) } } impl<'a> Default for BsIoSliceReader<'a> { fn default() -> Self { Self::from_slice(&[]) } } #[test] fn get_n_validations() { let mut reader = BsIoSliceReader::from_slice(&[1]); assert!(reader.get_n::(9).is_err()); assert!(reader.get_n::(4).is_ok()); assert!(reader.get_n::(8).is_err()); assert!(reader.get_n::(4).is_ok()); assert!(reader.get().is_err()); } #[test] fn skip_n_validations() { let mut reader = BsIoSliceReader::from_slice(&[1]); assert!(reader.skip_n(9).is_err()); assert!(reader.skip_n(7).is_ok()); assert!(reader.get().is_ok()); assert!(reader.get().is_err()); } bitvec_helpers-3.1.6/src/bitstream_io_impl/bitstream_io_writer.rs000064400000000000000000000035331046102023000235510ustar 00000000000000use bitstream_io::{BigEndian, BitWrite, BitWriter, Numeric, SignedNumeric}; use std::io; use crate::signed_to_unsigned; pub struct BitstreamIoWriter(BitWriter, BigEndian>); impl BitstreamIoWriter { pub fn with_capacity(capacity: usize) -> Self { let write = Vec::with_capacity(capacity); Self(BitWriter::new(write)) } #[inline(always)] pub fn write(&mut self, v: bool) -> io::Result<()> { self.0.write_bit(v) } #[inline(always)] pub fn write_n(&mut self, v: &T, n: u32) -> io::Result<()> { self.0.write(n, *v) } #[inline(always)] pub fn write_signed_n(&mut self, v: &T, n: u32) -> io::Result<()> { self.0.write_signed(n, *v) } #[inline(always)] pub fn write_ue(&mut self, v: &u64) -> io::Result<()> { if *v == 0 { self.write(true) } else { let mut tmp = v + 1; let mut leading_zeroes: i64 = -1; while tmp > 0 { tmp >>= 1; leading_zeroes += 1; } let leading_zeroes = leading_zeroes as u32; self.0.write_unary1(leading_zeroes)?; let remaining = v + 1 - (1 << leading_zeroes); self.write_n(&remaining, leading_zeroes) } } #[inline(always)] pub fn write_se(&mut self, v: &i64) -> io::Result<()> { self.write_ue(&signed_to_unsigned(v)) } #[inline(always)] pub fn is_aligned(&self) -> bool { self.0.byte_aligned() } pub fn byte_align(&mut self) -> std::io::Result<()> { self.0.byte_align() } /// None if the writer is not byte aligned pub fn as_slice(&mut self) -> Option<&[u8]> { self.0.writer().map(|e| e.as_slice()) } pub fn into_inner(self) -> Vec { self.0.into_writer() } } bitvec_helpers-3.1.6/src/bitstream_io_impl/mod.rs000064400000000000000000000000721046102023000202460ustar 00000000000000pub mod bitstream_io_reader; pub mod bitstream_io_writer; bitvec_helpers-3.1.6/src/bitvec_impl/bitslice_reader.rs000064400000000000000000000047371046102023000214160ustar 00000000000000use anyhow::{bail, Result}; use bitvec::{prelude::Msb0, slice::BitSlice, view::BitView}; use funty::Integral; use std::fmt; use super::reads::BitSliceReadExt; #[derive(Default)] pub struct BitSliceReader<'a> { bytes: &'a [u8], offset: usize, } impl<'a> BitSliceReader<'a> { pub fn new(bytes: &'a [u8]) -> Self { Self { bytes, offset: 0 } } fn bits(&self) -> &BitSlice { self.bytes.view_bits::() } #[inline(always)] pub fn get(&mut self) -> Result { BitSliceReadExt::get(self.bytes.view_bits::(), &mut self.offset) } #[inline(always)] pub fn get_n(&mut self, n: usize) -> Result { BitSliceReadExt::get_n(self.bytes.view_bits::(), n, &mut self.offset) } #[inline(always)] pub fn get_ue(&mut self) -> Result { BitSliceReadExt::get_ue(self.bytes.view_bits::(), &mut self.offset) } #[inline(always)] pub fn get_se(&mut self) -> Result { BitSliceReadExt::get_se(self.bytes.view_bits::(), &mut self.offset) } #[inline(always)] pub fn is_aligned(&self) -> bool { self.offset % 8 == 0 } #[inline(always)] pub fn available(&self) -> usize { self.bits().len() - self.offset } #[inline(always)] pub fn skip_n(&mut self, n: usize) -> Result<()> { if n > self.available() { bail!("Cannot skip more bits than available"); } self.offset += n; Ok(()) } pub fn available_slice(&self) -> &BitSlice { &self.bits()[self.offset..] } #[inline(always)] pub fn position(&self) -> usize { self.offset } } impl fmt::Debug for BitSliceReader<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "BitSliceReader: {{offset: {}, len: {}}}", self.offset, self.bytes.len() ) } } #[test] fn get_n_validations() { let mut reader = BitSliceReader::new(&[1]); assert!(reader.get_n::(9).is_err()); assert!(reader.get_n::(4).is_ok()); assert!(reader.get_n::(8).is_err()); assert!(reader.get_n::(4).is_ok()); assert!(reader.get().is_err()); } #[test] fn skip_n_validations() { let mut reader = BitSliceReader::new(&[1]); assert!(reader.skip_n(9).is_err()); assert!(reader.skip_n(7).is_ok()); assert!(reader.get().is_ok()); assert!(reader.get().is_err()); } bitvec_helpers-3.1.6/src/bitvec_impl/bitvec_reader.rs000064400000000000000000000045671046102023000210750ustar 00000000000000use anyhow::{bail, Result}; use bitvec::{prelude::Msb0, slice::BitSlice, vec::BitVec}; use funty::Integral; use std::fmt; use super::reads::BitSliceReadExt; #[derive(Default)] pub struct BitVecReader { bs: BitVec, offset: usize, } impl BitVecReader { pub fn new(data: Vec) -> Self { Self { bs: BitVec::from_vec(data), offset: 0, } } #[inline(always)] pub fn get(&mut self) -> Result { BitSliceReadExt::get(self.bs.as_bitslice(), &mut self.offset) } #[inline(always)] pub fn get_n(&mut self, n: usize) -> Result { BitSliceReadExt::get_n(self.bs.as_bitslice(), n, &mut self.offset) } #[inline(always)] pub fn get_ue(&mut self) -> Result { BitSliceReadExt::get_ue(self.bs.as_bitslice(), &mut self.offset) } #[inline(always)] pub fn get_se(&mut self) -> Result { BitSliceReadExt::get_se(self.bs.as_bitslice(), &mut self.offset) } #[inline(always)] pub fn is_aligned(&self) -> bool { self.offset % 8 == 0 } #[inline(always)] pub fn available(&self) -> usize { self.bs.len() - self.offset } #[inline(always)] pub fn skip_n(&mut self, n: usize) -> Result<()> { if n > self.available() { bail!("Cannot skip more bits than available"); } self.offset += n; Ok(()) } pub fn available_slice(&self) -> &BitSlice { &self.bs[self.offset..] } #[inline(always)] pub fn position(&self) -> usize { self.offset } } impl fmt::Debug for BitVecReader { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "BitVecReader: {{offset: {}, len: {}}}", self.offset, self.bs.len() ) } } #[test] fn get_n_validations() { let mut reader = BitVecReader::new(vec![1]); assert!(reader.get_n::(9).is_err()); assert!(reader.get_n::(4).is_ok()); assert!(reader.get_n::(8).is_err()); assert!(reader.get_n::(4).is_ok()); assert!(reader.get().is_err()); } #[test] fn skip_n_validations() { let mut reader = BitVecReader::new(vec![1]); assert!(reader.skip_n(9).is_err()); assert!(reader.skip_n(7).is_ok()); assert!(reader.get().is_ok()); assert!(reader.get().is_err()); } bitvec_helpers-3.1.6/src/bitvec_impl/bitvec_writer.rs000064400000000000000000000045221046102023000211360ustar 00000000000000use bitvec::{prelude::Msb0, vec::BitVec, view::BitView}; use funty::Integral; use crate::signed_to_unsigned; #[derive(Debug, Default)] pub struct BitVecWriter { bs: BitVec, offset: usize, } impl BitVecWriter { pub fn new() -> Self { Self { bs: BitVec::new(), offset: 0, } } pub fn with_capacity(capacity: usize) -> Self { Self { bs: BitVec::with_capacity(capacity), offset: 0, } } #[inline(always)] pub fn write(&mut self, v: bool) { self.bs.push(v); self.offset += 1; } #[inline(always)] pub fn write_n(&mut self, v: &T, n: usize) where T::Bytes: BitView, { let bytes = v.to_be_bytes(); let slice = bytes.view_bits::(); let bits_diff = if n as u32 > T::BITS { (n as u32 - T::BITS) as usize } else { 0 }; if bits_diff > 0 { self.bs.extend(std::iter::repeat(false).take(bits_diff)); self.bs.extend_from_bitslice(slice); } else { self.bs.extend_from_bitslice(&slice[slice.len() - n..]); } self.offset += n; } #[inline(always)] pub fn write_ue(&mut self, v: &u64) { if *v == 0 { self.bs.push(true); self.offset += 1; } else { let mut tmp = v + 1; let mut leading_zeroes: i64 = -1; while tmp > 0 { tmp >>= 1; leading_zeroes += 1; } let leading_zeroes = leading_zeroes as usize; let bits_iter = std::iter::repeat(false) .take(leading_zeroes) .chain(std::iter::once(true)); self.bs.extend(bits_iter); self.offset += leading_zeroes + 1; let remaining = v + 1 - (1 << leading_zeroes); self.write_n(&remaining, leading_zeroes); } } #[inline(always)] pub fn write_se(&mut self, v: &i64) { self.write_ue(&signed_to_unsigned(v)); } #[inline(always)] pub fn is_aligned(&self) -> bool { self.offset % 8 == 0 } #[inline(always)] pub fn written_bits(&self) -> usize { self.offset } pub fn as_slice(&self) -> &[u8] { self.bs.as_raw_slice() } } bitvec_helpers-3.1.6/src/bitvec_impl/mod.rs000064400000000000000000000001231046102023000170360ustar 00000000000000pub mod bitslice_reader; pub mod bitvec_reader; pub mod bitvec_writer; mod reads; bitvec_helpers-3.1.6/src/bitvec_impl/reads.rs000064400000000000000000000045741046102023000173730ustar 00000000000000use anyhow::{anyhow, bail, ensure, Result}; use bitvec::{field::BitField, prelude::Msb0, slice::BitSlice}; use funty::Integral; pub(crate) struct BitSliceReadExt {} impl BitSliceReadExt { #[inline(always)] pub fn get(slice: &BitSlice, offset: &mut usize) -> Result { let val = { *slice .get(*offset) .ok_or_else(|| anyhow!("get: out of bounds"))? }; *offset += 1; Ok(val) } #[inline(always)] pub fn get_n( slice: &BitSlice, n: usize, offset: &mut usize, ) -> Result { let pos = *offset; let available = slice.len() - pos; ensure!(n <= available, "get_n: out of bounds bits"); let val = slice[pos..pos + n].load_be::(); *offset += n; Ok(val) } // bitstring.py implementation: https://github.com/scott-griffiths/bitstring/blob/master/bitstring.py#L1706 #[inline(always)] pub fn get_ue(slice: &BitSlice, offset: &mut usize) -> Result { let oldpos = *offset; let mut pos = oldpos; loop { match slice.get(pos) { Some(val) => { if !val { pos += 1; } else { break; } } None => bail!("get_ue: out of bounds index: {}", pos), } } let leading_zeroes = pos - oldpos; let endpos = pos + leading_zeroes + 1; let code_num = if leading_zeroes > 0 { if endpos > slice.len() { bail!("get_ue: out of bounds attempt"); } let code_num = (1 << leading_zeroes) - 1; code_num + slice[pos + 1..endpos].load_be::() } else { 0 }; *offset = endpos; Ok(code_num) } // bitstring.py implementation: https://github.com/scott-griffiths/bitstring/blob/master/bitstring.py#L1767 #[inline(always)] pub fn get_se(slice: &BitSlice, offset: &mut usize) -> Result { let code_num = Self::get_ue(slice, offset)?; let m = ((code_num + 1) as f64 / 2.0).floor() as u64; let val = if code_num % 2 == 0 { -(m as i64) } else { m as i64 }; Ok(val) } } bitvec_helpers-3.1.6/src/lib.rs000064400000000000000000000006641046102023000145420ustar 00000000000000#[cfg(feature = "bitvec")] mod bitvec_impl; #[cfg(feature = "bitvec")] pub use bitvec_impl::{bitslice_reader, bitvec_reader, bitvec_writer}; #[cfg(feature = "bitstream-io")] mod bitstream_io_impl; #[cfg(feature = "bitstream-io")] pub use bitstream_io_impl::{bitstream_io_reader, bitstream_io_writer}; pub(crate) fn signed_to_unsigned(v: &i64) -> u64 { let u = if v.is_positive() { (v * 2) - 1 } else { -2 * v }; u as u64 }