/// An error occurred while reading bytes. #[derive(Clone, Debug, thiserror::Error)] pubenum ByteReaderError { /// Provided relative offset would move the reader offset out of bounds. #[error( "Relative offset out of bounds: relative-offset={relative_offset}, offset={offset}, length={length}"
)]
InvalidRelativeOffset { /// Requested relative offset to move within the data buffer.
relative_offset: isize, /// Current offset in the underlying data buffer.
offset: usize, /// Total length of the underlying data buffer.
length: usize,
},
/// Insufficient remaining bytes left for the desired operation #[error("Insufficient bytes left: requested={requested}, remaining={remaining}, offset={offset}")]
InsufficientRemaining { /// Requested amount of bytes to be read.
requested: usize, /// Remaining amount of bytes available to read.
remaining: usize, /// Current offset in the underlying data buffer.
offset: usize,
},
/// The reader was expected to be consumed but has remaining bytes left #[error("Unexpected remaining bytes left: remaining={remaining}, length={length}")]
UnexpectedRemaining { /// Remaining amount of bytes left to read.
remaining: usize, /// Total length of the underlying data buffer.
length: usize,
},
}
/// Writer type used for [`ByteReader::run`]. type RunReader<'run>: ByteReader;
/// Writer type used for [`ByteReader::run_at`]. type RunAtReader<'run_at>: ByteReader;
/// Return the current offset of the reader. #[expect(dead_code, reason = "Will use later")] fn offset(&self) -> usize;
/// Return the amount of remaining bytes in the reader. fn remaining(&self) -> usize;
/// Skip over a specific amount of bytes. /// /// # Error /// /// Returns [`ByteReaderError::InsufficientRemaining`] if the reader is does not have sufficient /// remaining bytes left. fn skip(&mutself, length: usize) -> Result<(), ByteReaderError>;
/// Run an arbitrary operation on the reader. /// /// This is useful when chaining multiple read operations that can be mapped to a single error. /// /// # Error /// /// Returns any [`ByteReaderError`] returned by the operation. fn run<T, F: FnOnce(&mutSelf::RunReader<'_>) -> Result<T, ByteReaderError>>(
&mutself,
op: F,
) -> Result<T, ByteReaderError>;
/// Run an arbitrary operation on the reader and take it. /// /// Note: This does not call [`ByteReader::expect_consumed`] at the end of the function! /// /// This is useful when chaining multiple read operations that can be mapped to a single error. /// /// # Error /// /// Returns any [`ByteReaderError`] returned by the operation. fn run_owned<T, F: FnOnce(Self::RunReader<'_>) -> Result<T, ByteReaderError>>( self,
op: F,
) -> Result<T, ByteReaderError>;
/// Run an arbitrary operation on the reader at a relative offset to the current offset in a /// child reader instance. The parent reader will maintain the current offset. /// /// # Error /// /// Returns [`ByteReaderError::InsufficientRemaining`] if the reader offset would move of the /// underlying data boundary. /// /// Returns any [`ByteReaderError`] returned by the operation. fn run_at<T, F: FnOnce(Self::RunAtReader<'_>) -> Result<T, ByteReaderError>>(
&mutself,
relative_offset: isize,
op: F,
) -> Result<T, ByteReaderError>;
/// Expect the reader to have consumed all data (i.e. [`Self::remaining`] is `0`), returning the /// underlying buffer. /// /// # Error /// /// Returns [`ByteReaderError::UnexpectedRemaining`] if the reader is not yet consumed. fn expect_consumed(self) -> Result<Self::Buffer, ByteReaderError>;
/// Read a specific amount of bytes. /// /// # Error /// /// Returns [`ByteReaderError::InsufficientRemaining`] if the reader is does not have sufficient /// remaining bytes left. fn read(&mutself, length: usize) -> Result<&[u8], ByteReaderError>;
/// Read a specific amount of bytes, yielding the offset range of the slice. /// /// This can be used when wrapping a [`ByteReader`] around a [`Vec<u8>`] to get a mutable slice /// over the returned range at after consuming the [`ByteReader`]. /// /// # Error /// /// Returns [`ByteReaderError::InsufficientRemaining`] if the reader is does not have sufficient /// remaining bytes left. fn read_range(&mutself, length: usize) -> Result<Range<usize>, ByteReaderError>;
/// Read all remaining bytes in the reader. fn read_remaining(&mutself) -> &[u8];
/// Read a specific amount of bytes, yielding a fixed-size slice. /// /// # Error /// /// Returns [`ByteReaderError::InsufficientRemaining`] if the reader is does not have sufficient /// remaining bytes left. #[inline] fn read_fixed<const LENGTH: usize>(&mutself) -> Result<[u8; LENGTH], ByteReaderError> { let bytes = self.read(LENGTH)?; // Note: The `.read` call above ensures that the `expect` call does not fail
Ok(bytes
.try_into()
.expect("[offset..offset + LENGTH] must be LENGTH bytes"))
}
/// Read a u8. /// /// # Error /// /// Returns [`ByteReaderError::InsufficientRemaining`] if the reader is does not have sufficient /// remaining bytes left. #[inline] fn read_u8(&mutself) -> Result<u8, ByteReaderError> { self.read_fixed::<1>().map(|bytes| bytes[0])
}
/// Read a u16 (little endian). /// /// # Error /// /// Returns [`ByteReaderError::InsufficientRemaining`] if the reader is does not have sufficient /// remaining bytes left. #[inline] fn read_u16_le(&mutself) -> Result<u16, ByteReaderError> { let bytes = self.read_fixed::<2>()?;
Ok(u16::from_le_bytes(bytes))
}
/// Read a u32 (little endian). /// /// # Error /// /// Returns [`ByteReaderError::InsufficientRemaining`] if the reader is does not have sufficient /// remaining bytes left. #[inline] fn read_u32_le(&mutself) -> Result<u32, ByteReaderError> { let bytes = self.read_fixed::<4>()?;
Ok(u32::from_le_bytes(bytes))
}
/// Read a u64 (little endian). /// /// # Error /// /// Returns [`ByteReaderError::InsufficientRemaining`] if the reader is does not have sufficient /// remaining bytes left. #[inline] fn read_u64_le(&mutself) -> Result<u64, ByteReaderError> { let bytes = self.read_fixed::<8>()?;
Ok(u64::from_le_bytes(bytes))
}
}
/// Contains a range reference to an encrypted section of data. #[derive(Clone, Educe)] #[educe(Debug)] pub(crate) struct EncryptedDataRange<const TAG_LENGTH: usize> { /// Tag for the decryption process #[educe(Debug(method(debug_slice_length)))] pub(crate) tag: [u8; TAG_LENGTH],
/// Data range reference pub(crate) data: Range<usize>,
}
/// Extension to read a specific amount of encrypted bytes and its encryption tag. pub(crate) trait EncryptedDataRangeReader<const TAG_LENGTH: usize> { /// Read a specific amount of encrypted bytes and its encryption tag, yielding the offset range of the /// slice and the tag at once. /// /// Note: `length` should NOT include the length of the tag. /// /// IMPORTANT: This may only be used for encryption implementations with a **prefix tag** (e.g. /// Salsa20Poly1305). /// /// # Error /// /// Returns [`ByteReaderError::InsufficientRemaining`] if the reader is does not have sufficient remaining /// bytes left. fn read_encrypted_data_range_tag_ahead(
&mutself,
length: usize,
) -> Result<EncryptedDataRange<TAG_LENGTH>, ByteReaderError>;
} impl<TReader: ByteReader, const TAG_LENGTH: usize> EncryptedDataRangeReader<TAG_LENGTH> for TReader { fn read_encrypted_data_range_tag_ahead(
&mutself,
length: usize,
) -> Result<EncryptedDataRange<TAG_LENGTH>, ByteReaderError> {
Ok(EncryptedDataRange {
tag: self.read_fixed::<TAG_LENGTH>()?.to_owned(),
data: self.read_range(length)?,
})
}
}
#[duplicate_item(
buffer_type;
[ &'buffer [u8] ];
[ Vec<u8> ];
[ &'buffer Vec<u8> ];
)] #[expect(clippy::allow_attributes, reason = "duplicate shenanigans")] #[allow(clippy::extra_unused_lifetimes, reason = "Abstracted duplicate")] impl<'buffer> ByteReaderContainer<buffer_type> { /// Create a new [`ByteReader`] starting at the **beginning** of the `buffer`. #[inline] #[allow(dead_code, reason = "Will use later")] pub(crate) constfn new(buffer: buffer_type) -> Self { Self { buffer, offset: 0 }
}
/// Consume this reader, returning the underlying buffer. #[inline] #[allow(dead_code, reason = "Will use later")] pub(crate) fn into_inner(self) -> buffer_type { self.buffer
}
}
impl ByteReaderContainer<Vec<u8>> { /// Truncate the underlying buffer to the remaining bytes. The current offset will be updated accordingly. #[inline] pub(crate) fn truncate(&mutself) { let _ = self.buffer.drain(..self.offset); self.offset = 0;
}
/// Read all remaining bytes and consume the reader and its underlying buffer. #[inline] pub(crate) fn read_remaining_owned(mutself) -> Vec<u8> { self.buffer.drain(self.offset..).collect()
}
}
// Calculate new offset let updated_offset = self
.offset
.checked_add(length)
.ok_or_else(insufficient_remaining)?;
// Check if there are sufficient remaining bytes left if updated_offset > self.buffer.len() { return Err(insufficient_remaining());
}
// Update offset and return range let range = self.offset..updated_offset; self.offset = updated_offset;
Ok(range)
}
#[inline] fn read_remaining(&mutself) -> &[u8] { let bytes = self
.buffer
.get(self.offset..)
.expect("offset should be <= buffer length"); self.offset = self.buffer.len();
bytes
}
}
/// Wraps a [`&[u8]`] and allows to apply read operations safely within the constrained space. pub(crate) type SliceByteReader<'buffer> = ByteReaderContainer<&'buffer [u8]>;
/// Wraps or creates a [`Vec<u8>`] and allows to apply read operations safely within the constrained /// space. pub(crate) type OwnedVecByteReader = ByteReaderContainer<Vec<u8>>;
/// Wraps a [`&Vec<u8>`](Vec<u8>) and is otherwise identical to the [`OwnedVecByteReader`]. #[expect(dead_code, reason = "Will use later")] pub(crate) type BorrowedVecByteReader<'buffer> = ByteReaderContainer<&'buffer Vec<u8>>;
// Read range of length 2 let range_19_20 = reader.read_range(2).unwrap();
assert_eq!(range_19_20, validator.offset..(validator.offset + 2));
validator.assert_processed(&mut reader, 2);
// Check the last two bytes (i.e., [19, 20])
assert_eq!(
reader.run_at(-2, |mut reader| reader.read_u16_le()).unwrap(), 5139,
);
validator.assert_processed(&mut reader, 0);
// Skip the next byte (i.e., 21) and read u8 (i.e., 22)
assert_eq!(reader.run_at(1, |mut reader| reader.read_u8()).unwrap(), 22);
validator.assert_processed(&mut reader, 0);
// Try to read out of bound
assert!(
reader
.run_at(DATA.len().try_into().unwrap(), |mut reader| reader.read_u8())
.is_err(),
);
validator.assert_processed(&mut reader, 0);
// Get the remaining bytes let remaining_bytes = &DATA[validator.offset..];
assert_eq!(reader.read_remaining(), remaining_bytes);
validator.assert_processed(&mut reader, remaining_bytes.len());
// Try to read some more out of range...
assert!(reader.read_u8().is_err()); // .. but with changed offset it should work
assert_eq!(
reader.run_at(-1, |mut reader| reader.read_u8()).unwrap(),
DATA[DATA.len() - 1],
);
// Check that all data is read and compare underlying data let data = reader.expect_consumed().unwrap();
assert_eq!(inner(&data), DATA);
// Apply the range we read earlier against bytes [19, 20]
assert_eq!(&inner(&data)[range_19_20], &[19, 20]);
}
// Truncate after offset 18 and ensure only the remaining data is available
reader.skip(18).unwrap();
reader.truncate();
assert_eq!(reader.buffer, DATA[18..]);
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.28 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.