1use std::error::Error;
2use std::fmt::{self, Display, Formatter};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct Limits {
7 pub(crate) max_request_bytes: usize,
9 pub(crate) max_response_bytes: usize,
11 pub(crate) max_nesting: usize,
13}
14
15impl Limits {
16 pub fn new(
18 max_request_bytes: usize,
19 max_response_bytes: usize,
20 max_nesting: usize,
21 ) -> Result<Self, LimitConfigurationError> {
22 if max_request_bytes == 0 {
23 return Err(LimitConfigurationError::ZeroRequestBytes);
24 }
25 if max_response_bytes == 0 {
26 return Err(LimitConfigurationError::ZeroResponseBytes);
27 }
28 if max_nesting == 0 {
29 return Err(LimitConfigurationError::ZeroNesting);
30 }
31 Ok(Self {
32 max_request_bytes,
33 max_response_bytes,
34 max_nesting,
35 })
36 }
37
38 #[must_use]
40 pub const fn max_request_bytes(self) -> usize {
41 self.max_request_bytes
42 }
43
44 #[must_use]
46 pub const fn max_response_bytes(self) -> usize {
47 self.max_response_bytes
48 }
49
50 #[must_use]
52 pub const fn max_nesting(self) -> usize {
53 self.max_nesting
54 }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub enum LimitConfigurationError {
60 ZeroRequestBytes,
62 ZeroResponseBytes,
64 ZeroNesting,
66}
67
68impl Display for LimitConfigurationError {
69 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
70 formatter.write_str(match self {
71 Self::ZeroRequestBytes => "request byte limit must be nonzero",
72 Self::ZeroResponseBytes => "response byte limit must be nonzero",
73 Self::ZeroNesting => "nesting limit must be nonzero",
74 })
75 }
76}
77
78impl Error for LimitConfigurationError {}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum BodyKind {
83 Request,
85 Response,
87}
88
89#[derive(Debug)]
91pub enum CodecError {
92 BodyTooLarge {
94 actual: usize,
96 maximum: usize,
98 },
99 InvalidJson(serde_json::Error),
101 NestingTooDeep {
103 maximum: usize,
105 },
106 MissingField {
108 field: String,
110 },
111 UnknownField {
113 field: String,
115 },
116 InvalidField {
118 field: String,
120 reason: String,
122 },
123 NullOptionalField {
125 field: String,
127 },
128 InvalidBase64 {
130 field: String,
132 },
133 ProtocolValidation(wip_protocol::ValidationError),
135}
136
137impl Display for CodecError {
138 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
139 match self {
140 Self::BodyTooLarge { actual, maximum } => {
141 write!(formatter, "body has {actual} bytes; maximum is {maximum}")
142 }
143 Self::InvalidJson(error) => write!(formatter, "invalid JSON: {error}"),
144 Self::NestingTooDeep { maximum } => {
145 write!(formatter, "JSON nesting exceeds maximum {maximum}")
146 }
147 Self::MissingField { field } => write!(formatter, "missing field `{field}`"),
148 Self::UnknownField { field } => write!(formatter, "unknown field `{field}`"),
149 Self::InvalidField { field, reason } => {
150 write!(formatter, "invalid field `{field}`: {reason}")
151 }
152 Self::NullOptionalField { field } => {
153 write!(
154 formatter,
155 "optional field `{field}` must be omitted instead of null"
156 )
157 }
158 Self::InvalidBase64 { field } => {
159 write!(formatter, "field `{field}` is not canonical base64")
160 }
161 Self::ProtocolValidation(error) => error.fmt(formatter),
162 }
163 }
164}
165
166impl Error for CodecError {
167 fn source(&self) -> Option<&(dyn Error + 'static)> {
168 match self {
169 Self::InvalidJson(error) => Some(error),
170 Self::ProtocolValidation(error) => Some(error),
171 _ => None,
172 }
173 }
174}
175
176impl From<wip_protocol::ValidationError> for CodecError {
177 fn from(value: wip_protocol::ValidationError) -> Self {
178 Self::ProtocolValidation(value)
179 }
180}