pub use varing::{
ConstDecodeError as ConstDecodeVarintError, ConstEncodeError as ConstEncodeVarintError,
DecodeError as DecodeVarintError, EncodeError as EncodeVarintError, InsufficientData,
InsufficientSpace,
};
use core::num::NonZeroUsize;
macro_rules! try_op_error {
(
#[doc = $doc:literal]
#[error($msg:literal)]
$op:ident
) => {
paste::paste! {
#[doc = $doc]
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
#[error($msg)]
pub struct [< Try $op:camel Error >] {
requested: NonZeroUsize,
available: usize,
}
impl [< Try $op:camel Error >] {
#[doc = "Creates a new `Try" $op:camel "Error` with the requested and available bytes."]
#[inline]
pub const fn new(requested: NonZeroUsize, available: usize) -> Self {
assert!(requested.get() > available, concat!(stringify!([< Try $op:camel Error >]), ": requested must be greater than available"));
Self {
requested,
available,
}
}
#[inline]
pub const fn requested(&self) -> NonZeroUsize {
self.requested
}
#[inline]
pub const fn available(&self) -> usize {
self.available
}
}
}
};
}
try_op_error!(
#[doc = "An error that occurs when trying to advance the buffer cursor beyond available data.
This error indicates that an attempt was made to move the buffer's read position forward
by more bytes than are currently available. This is a recoverable error - the buffer
position remains unchanged and the operation can be retried with a smaller advance amount."]
#[error(
"not enough bytes available to advance (requested {requested} but only {available} available)"
)]
advance
);
#[cfg(feature = "std")]
impl From<TryAdvanceError> for std::io::Error {
fn from(e: TryAdvanceError) -> Self {
std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e)
}
}
try_op_error!(
#[doc = "An error that occurs when trying to read data from a buffer with insufficient bytes.
This error indicates that a read operation failed because the buffer does not contain
enough bytes to satisfy the request. Failed read operations do not consume any bytes - the buffer position remains unchanged."]
#[error(
"not enough bytes available to read value (requested {requested} but only {available} available)"
)]
read
);
#[cfg(feature = "std")]
impl From<TryReadError> for std::io::Error {
fn from(e: TryReadError) -> Self {
std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e)
}
}
try_op_error!(
#[doc = "An error that occurs when trying to peek at data beyond the buffer's available bytes.
This error indicates that a peek operation failed because the buffer does not contain
enough bytes at the current position. Peek operations never modify the buffer position,
so this error leaves the buffer in its original state."]
#[error(
"not enough bytes available to peek value (requested {requested} but only {available} available)"
)]
peek
);
#[cfg(feature = "std")]
impl From<TryPeekError> for std::io::Error {
fn from(e: TryPeekError) -> Self {
std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e)
}
}
impl From<TryPeekError> for TryReadError {
#[inline]
fn from(e: TryPeekError) -> Self {
TryReadError {
requested: e.requested,
available: e.available,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
#[error("invalid segment range {start}..{end} for buffer with {available} bytes")]
pub struct TrySegmentError {
start: usize,
end: usize,
available: usize,
}
impl TrySegmentError {
#[inline]
pub const fn new(start: usize, end: usize, available: usize) -> Self {
debug_assert!(
start > end || end > available,
"TrySegmentError: invalid error - range is valid"
);
Self {
start,
end,
available,
}
}
#[inline]
pub const fn start(&self) -> usize {
self.start
}
#[inline]
pub const fn end(&self) -> usize {
self.end
}
#[inline]
pub const fn available(&self) -> usize {
self.available
}
#[inline]
pub const fn requested(&self) -> usize {
self.end.saturating_sub(self.start)
}
#[inline]
pub const fn is_inverted(&self) -> bool {
self.start > self.end
}
#[inline]
pub const fn overflow(&self) -> usize {
self.end.saturating_sub(self.available)
}
}
#[cfg(feature = "std")]
impl From<TrySegmentError> for std::io::Error {
fn from(e: TrySegmentError) -> Self {
std::io::Error::new(std::io::ErrorKind::InvalidInput, e)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
#[error("offset {offset} is out of bounds for buffer length {length}")]
pub struct OutOfBounds {
offset: usize,
length: usize,
}
impl OutOfBounds {
#[inline]
pub const fn new(offset: usize, length: usize) -> Self {
debug_assert!(offset >= length, "OutOfBounds: offset must be >= length");
Self { offset, length }
}
#[inline]
pub const fn offset(&self) -> usize {
self.offset
}
#[inline]
pub const fn length(&self) -> usize {
self.length
}
#[inline]
pub const fn excess(&self) -> usize {
self.offset() - self.length() + 1
}
}
#[cfg(feature = "std")]
impl From<OutOfBounds> for std::io::Error {
fn from(e: OutOfBounds) -> Self {
std::io::Error::new(std::io::ErrorKind::InvalidInput, e)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
#[error(
"not enough bytes available at {offset} (requested {} but only {} available)",
self.info.requested(), self.info.available()
)]
pub struct InsufficientSpaceAt {
info: InsufficientSpace,
offset: usize,
}
impl InsufficientSpaceAt {
#[inline]
pub const fn new(requested: NonZeroUsize, available: usize, offset: usize) -> Self {
assert!(
requested.get() > available,
"InsufficientSpaceAt: requested must be greater than available"
);
Self {
info: InsufficientSpace::new(requested, available),
offset,
}
}
#[inline]
pub const fn requested(&self) -> NonZeroUsize {
self.info.requested()
}
#[inline]
pub const fn available(&self) -> usize {
self.info.available()
}
#[inline]
pub const fn offset(&self) -> usize {
self.offset
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InsufficientDataAt {
info: InsufficientData,
offset: usize,
}
impl core::fmt::Display for InsufficientDataAt {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self.requested() {
Some(requested) => write!(
f,
"not enough bytes available at {}: available {}, requested {}",
self.offset,
self.info.available(),
requested
),
None => write!(
f,
"not enough bytes available at {}: available {}",
self.offset,
self.info.available()
),
}
}
}
impl core::error::Error for InsufficientDataAt {}
impl InsufficientDataAt {
#[inline]
pub const fn new(available: usize, offset: usize) -> Self {
Self {
info: InsufficientData::new(available),
offset,
}
}
#[inline]
pub const fn with_requested(available: usize, offset: usize, requested: NonZeroUsize) -> Self {
assert!(
requested.get() > available,
"InsufficientDataAt: requested must be greater than available"
);
Self {
info: InsufficientData::with_required(requested, available),
offset,
}
}
#[inline]
pub const fn requested(&self) -> Option<NonZeroUsize> {
self.info.required()
}
#[inline]
pub const fn available(&self) -> usize {
self.info.available()
}
#[inline]
pub const fn offset(&self) -> usize {
self.offset
}
}
#[cfg(feature = "std")]
impl From<InsufficientDataAt> for std::io::Error {
fn from(e: InsufficientDataAt) -> Self {
std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e)
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum TryPeekAtError {
#[error(transparent)]
OutOfBounds(#[from] OutOfBounds),
#[error(transparent)]
InsufficientData(#[from] InsufficientDataAt),
}
impl TryPeekAtError {
#[inline]
pub const fn out_of_bounds(offset: usize, length: usize) -> Self {
Self::OutOfBounds(OutOfBounds::new(offset, length))
}
#[inline]
pub const fn insufficient_data(available: usize, offset: usize) -> Self {
Self::InsufficientData(InsufficientDataAt::new(available, offset))
}
#[inline]
pub const fn insufficient_data_with_requested(
available: usize,
offset: usize,
requested: NonZeroUsize,
) -> Self {
Self::InsufficientData(InsufficientDataAt::with_requested(
available, offset, requested,
))
}
}
#[cfg(feature = "std")]
impl From<TryPeekAtError> for std::io::Error {
fn from(e: TryPeekAtError) -> Self {
std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e)
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum TryPutAtError {
#[error(transparent)]
OutOfBounds(#[from] OutOfBounds),
#[error(transparent)]
InsufficientSpace(#[from] InsufficientSpaceAt),
}
impl TryPutAtError {
#[inline]
pub const fn out_of_bounds(offset: usize, length: usize) -> Self {
Self::OutOfBounds(OutOfBounds::new(offset, length))
}
#[inline]
pub const fn insufficient_space(
requested: NonZeroUsize,
available: usize,
offset: usize,
) -> Self {
Self::InsufficientSpace(InsufficientSpaceAt::new(requested, available, offset))
}
}
#[cfg(feature = "std")]
impl From<TryPutAtError> for std::io::Error {
fn from(e: TryPutAtError) -> Self {
match e {
TryPutAtError::OutOfBounds(e) => std::io::Error::new(std::io::ErrorKind::InvalidInput, e),
TryPutAtError::InsufficientSpace(e) => {
if e.offset() >= e.available() {
std::io::Error::new(std::io::ErrorKind::InvalidInput, e)
} else {
std::io::Error::new(std::io::ErrorKind::WriteZero, e)
}
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum EncodeVarintAtError {
#[error(transparent)]
OutOfBounds(#[from] OutOfBounds),
#[error(transparent)]
InsufficientSpace(#[from] InsufficientSpaceAt),
#[error("{0}")]
#[cfg(not(any(feature = "std", feature = "alloc")))]
Other(&'static str),
#[error("{0}")]
#[cfg(any(feature = "std", feature = "alloc"))]
Other(std::borrow::Cow<'static, str>),
}
impl EncodeVarintAtError {
#[inline]
pub const fn out_of_bounds(offset: usize, length: usize) -> Self {
Self::OutOfBounds(OutOfBounds::new(offset, length))
}
#[inline]
pub const fn insufficient_space(
requested: NonZeroUsize,
available: usize,
offset: usize,
) -> Self {
Self::InsufficientSpace(InsufficientSpaceAt::new(requested, available, offset))
}
#[inline]
pub fn from_varint_error(err: EncodeVarintError, offset: usize) -> Self {
match err {
EncodeVarintError::InsufficientSpace(e) => {
Self::insufficient_space(e.requested(), e.available(), offset)
}
EncodeVarintError::Other(msg) => Self::Other(msg),
_ => Self::other("unknown error"),
}
}
#[inline]
pub const fn from_const_varint_error(err: ConstEncodeVarintError, offset: usize) -> Self {
match err {
ConstEncodeVarintError::InsufficientSpace(e) => {
Self::insufficient_space(e.requested(), e.available(), offset)
}
#[cfg(not(any(feature = "std", feature = "alloc")))]
ConstEncodeVarintError::Other(msg) => Self::Other(msg),
#[cfg(any(feature = "std", feature = "alloc"))]
ConstEncodeVarintError::Other(msg) => Self::Other(std::borrow::Cow::Borrowed(msg)),
#[cfg(not(any(feature = "std", feature = "alloc")))]
_ => Self::other("unknown error"),
#[cfg(any(feature = "std", feature = "alloc"))]
_ => Self::Other(std::borrow::Cow::Borrowed("unknown error")),
}
}
#[cfg(not(any(feature = "std", feature = "alloc")))]
#[inline]
pub const fn other(msg: &'static str) -> Self {
Self::Other(msg)
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[inline]
pub fn other(msg: impl Into<std::borrow::Cow<'static, str>>) -> Self {
Self::Other(msg.into())
}
}
#[cfg(feature = "std")]
impl From<EncodeVarintAtError> for std::io::Error {
fn from(e: EncodeVarintAtError) -> Self {
match e {
EncodeVarintAtError::OutOfBounds(e) => {
std::io::Error::new(std::io::ErrorKind::InvalidInput, e)
}
EncodeVarintAtError::InsufficientSpace(e) => {
if e.offset() >= e.available() {
std::io::Error::new(std::io::ErrorKind::InvalidInput, e)
} else {
std::io::Error::new(std::io::ErrorKind::WriteZero, e)
}
}
EncodeVarintAtError::Other(msg) => std::io::Error::other(msg),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum DecodeVarintAtError {
#[error(transparent)]
OutOfBounds(#[from] OutOfBounds),
#[error(transparent)]
InsufficientData(#[from] InsufficientDataAt),
#[error("{0}")]
#[cfg(not(any(feature = "std", feature = "alloc")))]
Other(&'static str),
#[error("{0}")]
#[cfg(any(feature = "std", feature = "alloc"))]
Other(std::borrow::Cow<'static, str>),
}
impl DecodeVarintAtError {
#[inline]
pub const fn out_of_bounds(offset: usize, length: usize) -> Self {
Self::OutOfBounds(OutOfBounds::new(offset, length))
}
#[inline]
pub const fn insufficient_data(available: usize, offset: usize) -> Self {
Self::InsufficientData(InsufficientDataAt::new(available, offset))
}
#[inline]
pub fn from_varint_error(err: DecodeVarintError, offset: usize) -> Self {
match err {
DecodeVarintError::InsufficientData(e) => Self::insufficient_data(e.available(), offset),
DecodeVarintError::Other(msg) => Self::other(msg),
_ => Self::other("unknown error"),
}
}
#[inline]
pub const fn from_const_varint_error(err: ConstDecodeVarintError, offset: usize) -> Self {
match err {
ConstDecodeVarintError::InsufficientData(e) => Self::insufficient_data(e.available(), offset),
#[cfg(not(any(feature = "std", feature = "alloc")))]
ConstDecodeVarintError::Other(msg) => Self::Other(msg),
#[cfg(any(feature = "std", feature = "alloc"))]
ConstDecodeVarintError::Other(msg) => Self::Other(std::borrow::Cow::Borrowed(msg)),
#[cfg(not(any(feature = "std", feature = "alloc")))]
_ => Self::other("unknown error"),
#[cfg(any(feature = "std", feature = "alloc"))]
_ => Self::Other(std::borrow::Cow::Borrowed("unknown error")),
}
}
#[cfg(not(any(feature = "std", feature = "alloc")))]
#[inline]
pub const fn other(msg: &'static str) -> Self {
Self::Other(msg)
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[inline]
pub fn other(msg: impl Into<std::borrow::Cow<'static, str>>) -> Self {
Self::Other(msg.into())
}
}
#[cfg(feature = "std")]
impl From<DecodeVarintAtError> for std::io::Error {
fn from(e: DecodeVarintAtError) -> Self {
match e {
DecodeVarintAtError::Other(msg) => std::io::Error::other(msg),
_ => std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e),
}
}
}
#[cfg(feature = "bytes_1")]
const _: () = {
use bytes_1::TryGetError;
impl From<TryGetError> for TryAdvanceError {
fn from(e: TryGetError) -> Self {
TryAdvanceError::new(
NonZeroUsize::new(e.requested).expect("requested must be non-zero"),
e.available,
)
}
}
impl From<TryGetError> for TryReadError {
fn from(e: TryGetError) -> Self {
TryReadError::new(
NonZeroUsize::new(e.requested).expect("requested must be non-zero"),
e.available,
)
}
}
};