use crate::{ConfigError, EncodeError};
use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum FramedEncodeError {
#[error("invalid framed encoder configuration: {0}")]
Config(#[from] ConfigError),
#[error("framing output is pending")]
OutputPending,
#[error("a framed session was abandoned; recover the owner")]
AbandonedSession,
#[error("a framed resource was abandoned")]
AbandonedResource,
#[error("invalid framed encoder state")]
InvalidState,
#[error("framed output destination is too small")]
OutputTooSmall,
#[error("framing allocation failed")]
AllocationFailed,
#[error("{scope} input size mismatch: expected {expected}, actual {actual}")]
InputSizeMismatch {
scope: &'static str,
expected: u64,
actual: u64,
},
#[error("invalid framing operation: {0}")]
Invalid(&'static str),
#[error("framing {kind} limit exceeded (limit {limit})")]
Limit {
kind: &'static str,
limit: u64,
},
#[error("framing size or offset overflow")]
Overflow,
#[error("resource encoding failed: {0}")]
Encode(#[from] EncodeError),
#[error("container output failed: {0}")]
#[cfg(not(feature = "no_std"))]
Io(#[from] std::io::Error),
}
#[cfg(not(feature = "no_std"))]
impl From<FramingError> for std::io::Error {
fn from(error: FramingError) -> Self {
match error {
FramingError::Io(error) => error,
other => Self::other(other),
}
}
}
#[derive(Debug)]
#[cfg(not(feature = "no_std"))]
pub struct FramingFinishError<T> {
pub writer: T,
pub error: FramingError,
}
pub type FramingError = FramedEncodeError;
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct FramedEncodeLocation {
pub resource_index: Option<u64>,
pub item_index: Option<usize>,
pub resource_input_offset: Option<u64>,
pub wire_offset: u64,
}
#[derive(Debug, Error)]
#[error("{error}")]
pub struct FramedEncodeFailure {
#[source]
pub error: FramedEncodeError,
pub consumed: usize,
pub produced: usize,
pub location: FramedEncodeLocation,
}
impl FramedEncodeFailure {
#[must_use]
pub fn into_error(self) -> FramedEncodeError {
self.error
}
}
impl From<FramedEncodeFailure> for FramedEncodeError {
fn from(failure: FramedEncodeFailure) -> Self {
failure.error
}
}
#[cfg(test)]
mod tests {
use super::*;
use ::core::error::Error as _;
use alloc::string::ToString;
#[test]
fn failures_keep_their_cause_as_the_source() {
let failure = FramedEncodeFailure {
error: FramedEncodeError::Encode(EncodeError::InvalidState),
consumed: 1,
produced: 2,
location: FramedEncodeLocation::default(),
};
assert_eq!(
failure.to_string(),
"resource encoding failed: the session cannot accept this operation in its current state"
);
assert!(failure.source().is_some());
assert!(matches!(
FramedEncodeError::from(failure),
FramedEncodeError::Encode(EncodeError::InvalidState)
));
}
#[cfg(not(feature = "no_std"))]
#[test]
fn io_conversion_preserves_transport_errors_and_wraps_the_rest() {
let io = std::io::Error::from(FramedEncodeError::Io(std::io::Error::from(
std::io::ErrorKind::WouldBlock,
)));
assert_eq!(io.kind(), std::io::ErrorKind::WouldBlock);
let other = std::io::Error::from(FramedEncodeError::OutputPending);
assert_eq!(other.kind(), std::io::ErrorKind::Other);
assert_eq!(other.to_string(), "framing output is pending");
}
}