summaryrefslogtreecommitdiffstats
path: root/vendor/ruzstd/src/decoding/bit_reader.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/ruzstd/src/decoding/bit_reader.rs
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/ruzstd/src/decoding/bit_reader.rs')
-rw-r--r--vendor/ruzstd/src/decoding/bit_reader.rs107
1 files changed, 107 insertions, 0 deletions
diff --git a/vendor/ruzstd/src/decoding/bit_reader.rs b/vendor/ruzstd/src/decoding/bit_reader.rs
new file mode 100644
index 000000000..e07ac45c4
--- /dev/null
+++ b/vendor/ruzstd/src/decoding/bit_reader.rs
@@ -0,0 +1,107 @@
+pub struct BitReader<'s> {
+ idx: usize, //index counts bits already read
+ source: &'s [u8],
+}
+
+#[derive(Debug, thiserror::Error)]
+#[non_exhaustive]
+pub enum GetBitsError {
+ #[error("Cant serve this request. The reader is limited to {limit} bits, requested {num_requested_bits} bits")]
+ TooManyBits {
+ num_requested_bits: usize,
+ limit: u8,
+ },
+ #[error("Can't read {requested} bits, only have {remaining} bits left")]
+ NotEnoughRemainingBits { requested: usize, remaining: usize },
+}
+
+impl<'s> BitReader<'s> {
+ pub fn new(source: &'s [u8]) -> BitReader<'_> {
+ BitReader { idx: 0, source }
+ }
+
+ pub fn bits_left(&self) -> usize {
+ self.source.len() * 8 - self.idx
+ }
+
+ pub fn bits_read(&self) -> usize {
+ self.idx
+ }
+
+ pub fn return_bits(&mut self, n: usize) {
+ if n > self.idx {
+ panic!("Cant return this many bits");
+ }
+ self.idx -= n;
+ }
+
+ pub fn get_bits(&mut self, n: usize) -> Result<u64, GetBitsError> {
+ if n > 64 {
+ return Err(GetBitsError::TooManyBits {
+ num_requested_bits: n,
+ limit: 64,
+ });
+ }
+ if self.bits_left() < n {
+ return Err(GetBitsError::NotEnoughRemainingBits {
+ requested: n,
+ remaining: self.bits_left(),
+ });
+ }
+
+ let old_idx = self.idx;
+
+ let bits_left_in_current_byte = 8 - (self.idx % 8);
+ let bits_not_needed_in_current_byte = 8 - bits_left_in_current_byte;
+
+ //collect bits from the currently pointed to byte
+ let mut value = u64::from(self.source[self.idx / 8] >> bits_not_needed_in_current_byte);
+
+ if bits_left_in_current_byte >= n {
+ //no need for fancy stuff
+
+ //just mask all but the needed n bit
+ value &= (1 << n) - 1;
+ self.idx += n;
+ } else {
+ self.idx += bits_left_in_current_byte;
+
+ //n spans over multiple bytes
+ let full_bytes_needed = (n - bits_left_in_current_byte) / 8;
+ let bits_in_last_byte_needed = n - bits_left_in_current_byte - full_bytes_needed * 8;
+
+ assert!(
+ bits_left_in_current_byte + full_bytes_needed * 8 + bits_in_last_byte_needed == n
+ );
+
+ let mut bit_shift = bits_left_in_current_byte; //this many bits are already set in value
+
+ assert!(self.idx % 8 == 0);
+
+ //collect full bytes
+ for _ in 0..full_bytes_needed {
+ value |= u64::from(self.source[self.idx / 8]) << bit_shift;
+ self.idx += 8;
+ bit_shift += 8;
+ }
+
+ assert!(n - bit_shift == bits_in_last_byte_needed);
+
+ if bits_in_last_byte_needed > 0 {
+ let val_las_byte =
+ u64::from(self.source[self.idx / 8]) & ((1 << bits_in_last_byte_needed) - 1);
+ value |= val_las_byte << bit_shift;
+ self.idx += bits_in_last_byte_needed;
+ }
+ }
+
+ assert!(self.idx == old_idx + n);
+
+ Ok(value)
+ }
+
+ pub fn reset(&mut self, new_source: &'s [u8]) {
+ self.idx = 0;
+ self.source = new_source;
+ }
+}