1 use super::HeaderError; 2 use crate::err::LenError; 3 4 /// Error when decoding IPv6 extension headers from a slice. 5 #[derive(Clone, Debug, Eq, PartialEq, Hash)] 6 pub enum HeaderSliceError { 7 /// Error when an length error is encountered (e.g. unexpected 8 /// end of slice). 9 Len(LenError), 10 11 /// Error caused by the contents of the header. 12 Content(HeaderError), 13 } 14 15 impl HeaderSliceError { 16 /// Adds an offset value to all slice length related fields. 17 #[inline] add_slice_offset(self, offset: usize) -> Self18 pub const fn add_slice_offset(self, offset: usize) -> Self { 19 use HeaderSliceError::*; 20 match self { 21 Len(err) => Len(err.add_offset(offset)), 22 Content(err) => Content(err), 23 } 24 } 25 26 /// Returns the [`crate::err::LenError`] if the error is an Len. len_error(&self) -> Option<&LenError>27 pub fn len_error(&self) -> Option<&LenError> { 28 use HeaderSliceError::*; 29 match self { 30 Len(err) => Some(err), 31 Content(_) => None, 32 } 33 } 34 35 /// Returns the [`crate::err::ipv6_exts::HeaderError`] if the error is an Len. content(&self) -> Option<&HeaderError>36 pub fn content(&self) -> Option<&HeaderError> { 37 use HeaderSliceError::*; 38 match self { 39 Len(_) => None, 40 Content(err) => Some(err), 41 } 42 } 43 } 44 45 impl core::fmt::Display for HeaderSliceError { fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result46 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 47 use HeaderSliceError::*; 48 match self { 49 Len(err) => err.fmt(f), 50 Content(err) => err.fmt(f), 51 } 52 } 53 } 54 55 #[cfg(feature = "std")] 56 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 57 impl std::error::Error for HeaderSliceError { source(&self) -> Option<&(dyn std::error::Error + 'static)>58 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 59 use HeaderSliceError::*; 60 match self { 61 Len(err) => Some(err), 62 Content(err) => Some(err), 63 } 64 } 65 } 66 67 #[cfg(test)] 68 mod tests { 69 use super::{HeaderSliceError::*, *}; 70 use crate::{err::Layer, LenSource}; 71 use alloc::format; 72 use std::{ 73 collections::hash_map::DefaultHasher, 74 error::Error, 75 hash::{Hash, Hasher}, 76 }; 77 78 #[test] add_slice_offset()79 fn add_slice_offset() { 80 assert_eq!( 81 Len(LenError { 82 required_len: 1, 83 layer: Layer::Icmpv4, 84 len: 2, 85 len_source: LenSource::Slice, 86 layer_start_offset: 3 87 }) 88 .add_slice_offset(200), 89 Len(LenError { 90 required_len: 1, 91 layer: Layer::Icmpv4, 92 len: 2, 93 len_source: LenSource::Slice, 94 layer_start_offset: 203 95 }) 96 ); 97 assert_eq!( 98 Content(HeaderError::HopByHopNotAtStart).add_slice_offset(200), 99 Content(HeaderError::HopByHopNotAtStart) 100 ); 101 } 102 103 #[test] len_error()104 fn len_error() { 105 assert_eq!( 106 Len(LenError { 107 required_len: 1, 108 layer: Layer::Icmpv4, 109 len: 2, 110 len_source: LenSource::Slice, 111 layer_start_offset: 3 112 }) 113 .len_error(), 114 Some(&LenError { 115 required_len: 1, 116 layer: Layer::Icmpv4, 117 len: 2, 118 len_source: LenSource::Slice, 119 layer_start_offset: 3 120 }) 121 ); 122 assert_eq!(Content(HeaderError::HopByHopNotAtStart).len_error(), None); 123 } 124 125 #[test] content()126 fn content() { 127 assert_eq!( 128 Len(LenError { 129 required_len: 1, 130 layer: Layer::Icmpv4, 131 len: 2, 132 len_source: LenSource::Slice, 133 layer_start_offset: 3 134 }) 135 .content(), 136 None 137 ); 138 assert_eq!( 139 Content(HeaderError::HopByHopNotAtStart).content(), 140 Some(&HeaderError::HopByHopNotAtStart) 141 ); 142 } 143 144 #[test] debug()145 fn debug() { 146 let err = HeaderError::HopByHopNotAtStart; 147 assert_eq!( 148 format!("Content({:?})", err.clone()), 149 format!("{:?}", Content(err)) 150 ); 151 } 152 153 #[test] clone_eq_hash()154 fn clone_eq_hash() { 155 let err = Content(HeaderError::HopByHopNotAtStart); 156 assert_eq!(err, err.clone()); 157 let hash_a = { 158 let mut hasher = DefaultHasher::new(); 159 err.hash(&mut hasher); 160 hasher.finish() 161 }; 162 let hash_b = { 163 let mut hasher = DefaultHasher::new(); 164 err.clone().hash(&mut hasher); 165 hasher.finish() 166 }; 167 assert_eq!(hash_a, hash_b); 168 } 169 170 #[test] fmt()171 fn fmt() { 172 { 173 let err = LenError { 174 required_len: 1, 175 layer: Layer::Icmpv4, 176 len: 2, 177 len_source: LenSource::Slice, 178 layer_start_offset: 3, 179 }; 180 assert_eq!(format!("{}", &err), format!("{}", Len(err))); 181 } 182 { 183 let err = HeaderError::HopByHopNotAtStart; 184 assert_eq!(format!("{}", &err), format!("{}", Content(err.clone()))); 185 } 186 } 187 188 #[cfg(feature = "std")] 189 #[test] source()190 fn source() { 191 assert!(Len(LenError { 192 required_len: 1, 193 layer: Layer::Icmpv4, 194 len: 2, 195 len_source: LenSource::Slice, 196 layer_start_offset: 3 197 }) 198 .source() 199 .is_some()); 200 assert!(Content(HeaderError::HopByHopNotAtStart).source().is_some()); 201 } 202 } 203