1#[cfg(feature = "std")]
2use crate::err::{ipv4_exts, ipv6_exts, ValueTooBigError};
3
4#[cfg(feature = "std")]
6#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
7#[derive(Debug)]
8pub enum BuildWriteError {
9 Io(std::io::Error),
11
12 PayloadLen(ValueTooBigError<usize>),
15
16 Ipv4Exts(ipv4_exts::ExtsWalkError),
19
20 Ipv6Exts(ipv6_exts::ExtsWalkError),
23
24 Icmpv6InIpv4,
27
28 ArpHeaderNotMatch,
30}
31
32#[cfg(feature = "std")]
33#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
34impl BuildWriteError {
35 pub fn io(&self) -> Option<&std::io::Error> {
38 match self {
39 BuildWriteError::Io(err) => Some(err),
40 _ => None,
41 }
42 }
43
44 pub fn payload_len(&self) -> Option<&ValueTooBigError<usize>> {
47 match self {
48 BuildWriteError::PayloadLen(err) => Some(err),
49 _ => None,
50 }
51 }
52
53 pub fn ipv4_exts(&self) -> Option<&ipv4_exts::ExtsWalkError> {
56 match self {
57 BuildWriteError::Ipv4Exts(err) => Some(err),
58 _ => None,
59 }
60 }
61
62 pub fn ipv6_exts(&self) -> Option<&ipv6_exts::ExtsWalkError> {
65 match self {
66 BuildWriteError::Ipv6Exts(err) => Some(err),
67 _ => None,
68 }
69 }
70
71 pub fn is_icmpv6_in_ipv4(&self) -> bool {
73 matches!(self, BuildWriteError::Icmpv6InIpv4)
74 }
75}
76
77#[cfg(feature = "std")]
78#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
79impl core::fmt::Display for BuildWriteError {
80 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
81 use BuildWriteError::*;
82 match self {
83 Io(err) => err.fmt(f),
84 PayloadLen(err) => err.fmt(f),
85 Ipv4Exts(err) => err.fmt(f),
86 Ipv6Exts(err) => err.fmt(f),
87 ArpHeaderNotMatch => write!(f, "address size defined in the ARP header does not match the actual size"),
88 Icmpv6InIpv4 => write!(f, "Error: ICMPv6 can not be combined with an IPv4 headers (checksum can not be calculated)."),
89 }
90 }
91}
92
93impl core::error::Error for BuildWriteError {
94 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
95 use BuildWriteError::*;
96 match self {
97 Io(ref err) => Some(err),
98 PayloadLen(ref err) => Some(err),
99 Ipv4Exts(err) => Some(err),
100 Ipv6Exts(err) => Some(err),
101 Icmpv6InIpv4 => None,
102 ArpHeaderNotMatch => None,
103 }
104 }
105}
106
107#[cfg(feature = "std")]
108impl From<std::io::Error> for BuildWriteError {
109 fn from(value: std::io::Error) -> Self {
110 BuildWriteError::Io(value)
111 }
112}
113
114#[cfg(feature = "std")]
115impl From<ValueTooBigError<usize>> for BuildWriteError {
116 fn from(value: ValueTooBigError<usize>) -> Self {
117 BuildWriteError::PayloadLen(value)
118 }
119}
120
121#[cfg(feature = "std")]
122impl From<super::TransportChecksumError> for BuildWriteError {
123 fn from(value: super::TransportChecksumError) -> Self {
124 match value {
125 super::TransportChecksumError::PayloadLen(err) => BuildWriteError::PayloadLen(err),
126 super::TransportChecksumError::Icmpv6InIpv4 => BuildWriteError::Icmpv6InIpv4,
127 }
128 }
129}
130
131#[cfg(feature = "std")]
132impl From<crate::WriteError<std::io::Error, ipv4_exts::ExtsWalkError>> for BuildWriteError {
133 fn from(value: crate::WriteError<std::io::Error, ipv4_exts::ExtsWalkError>) -> Self {
134 match value {
135 crate::WriteError::Io(err) => BuildWriteError::Io(err),
136 crate::WriteError::Content(err) => BuildWriteError::Ipv4Exts(err),
137 }
138 }
139}
140
141#[cfg(feature = "std")]
142impl From<crate::WriteError<std::io::Error, ipv6_exts::ExtsWalkError>> for BuildWriteError {
143 fn from(value: crate::WriteError<std::io::Error, ipv6_exts::ExtsWalkError>) -> Self {
144 match value {
145 crate::WriteError::Io(err) => BuildWriteError::Io(err),
146 crate::WriteError::Content(err) => BuildWriteError::Ipv6Exts(err),
147 }
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::{BuildWriteError::*, *};
154 use crate::{err::ValueType, *};
155 use alloc::format;
156 use core::error::Error;
157
158 #[test]
159 fn io() {
160 assert!(Io(std::io::Error::new(
161 std::io::ErrorKind::UnexpectedEof,
162 "failed to fill whole buffer",
163 ))
164 .io()
165 .is_some());
166 assert!(Ipv4Exts(ipv4_exts::ExtsWalkError::ExtNotReferenced {
167 missing_ext: IpNumber::AUTHENTICATION_HEADER,
168 })
169 .io()
170 .is_none());
171 }
172
173 #[test]
174 fn payload_len() {
175 {
176 let err = ValueTooBigError {
177 actual: 3,
178 max_allowed: 2,
179 value_type: ValueType::Ipv4PayloadLength,
180 };
181 assert_eq!(Some(&err), PayloadLen(err.clone()).payload_len());
182 }
183 {
184 let err = ipv4_exts::ExtsWalkError::ExtNotReferenced {
185 missing_ext: IpNumber::AUTHENTICATION_HEADER,
186 };
187 assert_eq!(None, Ipv4Exts(err.clone()).payload_len());
188 }
189 }
190
191 #[test]
192 fn ipv4_exts() {
193 assert!(Io(std::io::Error::new(
194 std::io::ErrorKind::UnexpectedEof,
195 "failed to fill whole buffer",
196 ))
197 .ipv4_exts()
198 .is_none());
199 {
200 let err = ipv4_exts::ExtsWalkError::ExtNotReferenced {
201 missing_ext: IpNumber::AUTHENTICATION_HEADER,
202 };
203 assert_eq!(Some(&err), Ipv4Exts(err.clone()).ipv4_exts());
204 }
205 }
206
207 #[test]
208 fn ipv6_exts() {
209 assert!(Io(std::io::Error::new(
210 std::io::ErrorKind::UnexpectedEof,
211 "failed to fill whole buffer",
212 ))
213 .ipv6_exts()
214 .is_none());
215 {
216 let err = ipv6_exts::ExtsWalkError::ExtNotReferenced {
217 missing_ext: IpNumber::AUTHENTICATION_HEADER,
218 };
219 assert_eq!(Some(&err), Ipv6Exts(err.clone()).ipv6_exts());
220 }
221 }
222
223 #[test]
224 fn is_icmpv6_in_ipv4() {
225 assert_eq!(
226 false,
227 Io(std::io::Error::new(
228 std::io::ErrorKind::UnexpectedEof,
229 "failed to fill whole buffer",
230 ))
231 .is_icmpv6_in_ipv4()
232 );
233 assert!(Icmpv6InIpv4.is_icmpv6_in_ipv4());
234 }
235
236 #[test]
237 fn debug() {
238 let err = ipv4_exts::ExtsWalkError::ExtNotReferenced {
239 missing_ext: IpNumber::AUTHENTICATION_HEADER,
240 };
241 assert_eq!(
242 format!("Ipv4Exts({:?})", err.clone()),
243 format!("{:?}", Ipv4Exts(err))
244 );
245 }
246
247 #[test]
248 fn fmt() {
249 {
250 let err = std::io::Error::new(
251 std::io::ErrorKind::UnexpectedEof,
252 "failed to fill whole buffer",
253 );
254 assert_eq!(format!("{}", err), format!("{}", Io(err)));
255 }
256 {
257 let err = ValueTooBigError {
258 actual: 3,
259 max_allowed: 2,
260 value_type: ValueType::Ipv4PayloadLength,
261 };
262 assert_eq!(format!("{}", err), format!("{}", PayloadLen(err.clone())));
263 }
264 {
265 let err = ipv4_exts::ExtsWalkError::ExtNotReferenced {
266 missing_ext: IpNumber::AUTHENTICATION_HEADER,
267 };
268 assert_eq!(format!("{}", err), format!("{}", Ipv4Exts(err.clone())));
269 }
270 {
271 let err = ipv6_exts::ExtsWalkError::ExtNotReferenced {
272 missing_ext: IpNumber::AUTHENTICATION_HEADER,
273 };
274 assert_eq!(format!("{}", err), format!("{}", Ipv6Exts(err.clone())));
275 }
276 assert_eq!(
277 "Error: ICMPv6 can not be combined with an IPv4 headers (checksum can not be calculated).",
278 format!("{}", Icmpv6InIpv4)
279 );
280 }
281
282 #[cfg(feature = "std")]
283 #[test]
284 fn source() {
285 assert!(Io(std::io::Error::new(
286 std::io::ErrorKind::UnexpectedEof,
287 "failed to fill whole buffer",
288 ))
289 .source()
290 .is_some());
291 assert!(PayloadLen(ValueTooBigError {
292 actual: 3,
293 max_allowed: 2,
294 value_type: ValueType::Ipv4PayloadLength,
295 })
296 .source()
297 .is_some());
298 assert!(Ipv4Exts(ipv4_exts::ExtsWalkError::ExtNotReferenced {
299 missing_ext: IpNumber::AUTHENTICATION_HEADER,
300 })
301 .source()
302 .is_some());
303 assert!(Ipv6Exts(ipv6_exts::ExtsWalkError::ExtNotReferenced {
304 missing_ext: IpNumber::AUTHENTICATION_HEADER,
305 })
306 .source()
307 .is_some());
308 assert!(Icmpv6InIpv4.source().is_none());
309 }
310}