use std::error::Error;
use std::fmt::{self, Display, Formatter};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Limits {
pub(crate) max_request_bytes: usize,
pub(crate) max_response_bytes: usize,
pub(crate) max_nesting: usize,
}
impl Limits {
pub fn new(
max_request_bytes: usize,
max_response_bytes: usize,
max_nesting: usize,
) -> Result<Self, LimitConfigurationError> {
if max_request_bytes == 0 {
return Err(LimitConfigurationError::ZeroRequestBytes);
}
if max_response_bytes == 0 {
return Err(LimitConfigurationError::ZeroResponseBytes);
}
if max_nesting == 0 {
return Err(LimitConfigurationError::ZeroNesting);
}
Ok(Self {
max_request_bytes,
max_response_bytes,
max_nesting,
})
}
#[must_use]
pub const fn max_request_bytes(self) -> usize {
self.max_request_bytes
}
#[must_use]
pub const fn max_response_bytes(self) -> usize {
self.max_response_bytes
}
#[must_use]
pub const fn max_nesting(self) -> usize {
self.max_nesting
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LimitConfigurationError {
ZeroRequestBytes,
ZeroResponseBytes,
ZeroNesting,
}
impl Display for LimitConfigurationError {
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
formatter.write_str(match self {
Self::ZeroRequestBytes => "request byte limit must be nonzero",
Self::ZeroResponseBytes => "response byte limit must be nonzero",
Self::ZeroNesting => "nesting limit must be nonzero",
})
}
}
impl Error for LimitConfigurationError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BodyKind {
Request,
Response,
}
#[derive(Debug)]
pub enum CodecError {
BodyTooLarge {
actual: usize,
maximum: usize,
},
InvalidJson(serde_json::Error),
NestingTooDeep {
maximum: usize,
},
MissingField {
field: String,
},
UnknownField {
field: String,
},
InvalidField {
field: String,
reason: String,
},
NullOptionalField {
field: String,
},
InvalidBase64 {
field: String,
},
ProtocolValidation(wip_protocol::ValidationError),
}
impl Display for CodecError {
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::BodyTooLarge { actual, maximum } => {
write!(formatter, "body has {actual} bytes; maximum is {maximum}")
}
Self::InvalidJson(error) => write!(formatter, "invalid JSON: {error}"),
Self::NestingTooDeep { maximum } => {
write!(formatter, "JSON nesting exceeds maximum {maximum}")
}
Self::MissingField { field } => write!(formatter, "missing field `{field}`"),
Self::UnknownField { field } => write!(formatter, "unknown field `{field}`"),
Self::InvalidField { field, reason } => {
write!(formatter, "invalid field `{field}`: {reason}")
}
Self::NullOptionalField { field } => {
write!(
formatter,
"optional field `{field}` must be omitted instead of null"
)
}
Self::InvalidBase64 { field } => {
write!(formatter, "field `{field}` is not canonical base64")
}
Self::ProtocolValidation(error) => error.fmt(formatter),
}
}
}
impl Error for CodecError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::InvalidJson(error) => Some(error),
Self::ProtocolValidation(error) => Some(error),
_ => None,
}
}
}
impl From<wip_protocol::ValidationError> for CodecError {
fn from(value: wip_protocol::ValidationError) -> Self {
Self::ProtocolValidation(value)
}
}