1#[macro_export]
5macro_rules! impl_serhex_seq {
6 ($type: ty, $bytes: expr) => {
7 impl $crate::SerHexSeq<$crate::Strict> for $type {
8 fn size() -> usize {
9 $bytes
10 }
11 }
12
13 impl $crate::SerHexSeq<$crate::StrictPfx> for $type {
14 fn size() -> usize {
15 $bytes
16 }
17 }
18
19 impl $crate::SerHexSeq<$crate::StrictCap> for $type {
20 fn size() -> usize {
21 $bytes
22 }
23 }
24
25 impl $crate::SerHexSeq<$crate::StrictCapPfx> for $type {
26 fn size() -> usize {
27 $bytes
28 }
29 }
30 };
31}
32
33#[doc(hidden)]
36#[macro_export]
37macro_rules! into_hex_bytearray {
38 ($src: ident, $dst: ident, $len: expr) => {{
39 let src: &[u8] = $src.as_ref();
40 debug_assert!(src.len() == $len);
41 if <C as $crate::HexConf>::withpfx() {
43 $dst.write_all("0x".as_bytes())?;
44 }
45 if <C as $crate::HexConf>::compact() {
47 if let Some((idx, val)) = src.iter().enumerate().find(|&(_, v)| *v > 0u8) {
49 if *val < 0x10 {
51 if <C as $crate::HexConf>::withcap() {
52 $dst.write_all(&[$crate::utils::fromvalcaps(*val)])?;
53 $crate::utils::writehexcaps(&src[(idx + 1)..], $dst)
54 } else {
55 $dst.write_all(&[$crate::utils::fromval(*val)])?;
56 $crate::utils::writehex(&src[(idx + 1)..], $dst)
57 }
58 } else {
59 if <C as $crate::HexConf>::withcap() {
60 $crate::utils::writehexcaps(&src[idx..], $dst)
61 } else {
62 $crate::utils::writehex(&src[idx..], $dst)
63 }
64 }
65 } else {
67 $dst.write_all(&[b'0'])?;
68 Ok(())
69 }
70 } else {
71 if <C as $crate::HexConf>::withcap() {
72 $crate::utils::writehexcaps(src, $dst)
73 } else {
74 $crate::utils::writehex(src, $dst)
75 }
76 }
77 }};
78}
79
80#[doc(hidden)]
83#[macro_export]
84macro_rules! from_hex_bytearray {
85 ($src: ident, $len: expr) => {{
86 let raw: &[u8] = $src.as_ref();
87 let hex = if <C as $crate::HexConf>::withpfx() {
88 let pfx = "0x".as_bytes();
89 if raw.starts_with(pfx) {
90 &raw[2..]
91 } else {
92 raw
93 }
94 } else {
95 raw
96 };
97 let mut buf = [0u8; $len];
98 if <C as $crate::HexConf>::compact() {
99 let min = 1;
100 let max = $len * 2;
101 let got = hex.len();
102 if got < min || got > max {
103 let inner = $crate::types::ParseHexError::Range { min, max, got };
104 let error = $crate::types::Error::from(inner);
105 return Err(error.into());
106 }
107 let body = $len - (got / 2);
108 let head = got % 2;
109 if head > 0 {
110 buf[body - head] = $crate::utils::intobyte(b'0', hex[0])?;
111 }
112 $crate::utils::fromhex(&mut buf[body..], &hex[head..])?;
113 } else {
114 $crate::utils::fromhex(&mut buf[..], hex)?;
115 }
116 Ok(buf)
117 }};
118}
119
120#[macro_export]
123macro_rules! impl_serhex_bytearray {
124 ($type: ty, $len: expr) => {
125 impl_serhex_seq!($type, $len);
126 impl<C> $crate::SerHex<C> for $type
127 where
128 C: $crate::HexConf,
129 {
130 type Error = $crate::types::Error;
131 fn into_hex_raw<D>(&self, mut dst: D) -> ::std::result::Result<(), Self::Error>
132 where
133 D: ::std::io::Write,
134 {
135 into_hex_bytearray!(self, dst, $len)?;
136 Ok(())
137 }
138 fn from_hex_raw<S>(src: S) -> ::std::result::Result<Self, Self::Error>
139 where
140 S: AsRef<[u8]>,
141 {
142 let rslt: ::std::result::Result<[u8; $len], Self::Error> =
143 from_hex_bytearray!(src, $len);
144 match rslt {
145 Ok(buf) => Ok(buf.into()),
146 Err(e) => Err(e),
147 }
148 }
149 }
150 };
151}
152
153#[cfg(test)]
154mod tests {
155 use {
156 Compact, CompactCap, CompactCapPfx, CompactPfx, SerHex, Strict, StrictCap, StrictCapPfx,
157 StrictPfx,
158 };
159
160 #[derive(Debug, PartialEq, Eq)]
161 struct Foo([u8; 4]);
162 impl_newtype_bytearray!(Foo, 4);
163 impl_serhex_bytearray!(Foo, 4);
164
165 #[test]
166 fn hex_strict_ok() {
167 let f1 = Foo([0, 1, 2, 3]);
168 let hs = <Foo as SerHex<Strict>>::into_hex(&f1).unwrap();
169 let f2 = <Foo as SerHex<Strict>>::from_hex(&hs).unwrap();
170 assert_eq!(f1, f2);
171 }
172
173 #[test]
174 #[should_panic]
175 fn hex_strict_err() {
176 let _ = <Foo as SerHex<Strict>>::from_hex("faaffaa").unwrap();
177 }
178
179 #[test]
180 fn hex_compact() {
181 let f1 = Foo([0, 0, 0x0a, 0xff]);
182 let hs = <Foo as SerHex<Compact>>::into_hex(&f1).unwrap();
183 assert_eq!(&hs, "aff");
184 let f2 = <Foo as SerHex<Compact>>::from_hex(&hs).unwrap();
185 assert_eq!(f1, f2);
186 }
187
188 #[test]
189 fn hex_variants() {
190 let f = Foo([0x00, 0x0f, 0xff, 0x11]);
191 assert_eq!(
192 "0x000fff11",
193 <Foo as SerHex<StrictPfx>>::into_hex(&f).unwrap()
194 );
195 assert_eq!(
196 "000FFF11",
197 <Foo as SerHex<StrictCap>>::into_hex(&f).unwrap()
198 );
199 assert_eq!(
200 "0x000FFF11",
201 <Foo as SerHex<StrictCapPfx>>::into_hex(&f).unwrap()
202 );
203 assert_eq!(
204 "0xfff11",
205 <Foo as SerHex<CompactPfx>>::into_hex(&f).unwrap()
206 );
207 assert_eq!("FFF11", <Foo as SerHex<CompactCap>>::into_hex(&f).unwrap());
208 assert_eq!(
209 "0xFFF11",
210 <Foo as SerHex<CompactCapPfx>>::into_hex(&f).unwrap()
211 );
212 }
213
214 #[test]
215 fn blanket_array() {
216 let v: [Foo; 2] = <[Foo; 2] as SerHex<StrictPfx>>::from_hex("0xffaaffaa11221122").unwrap();
217 assert_eq!(v[0], Foo([0xff, 0xaa, 0xff, 0xaa]));
218 assert_eq!(v[1], Foo([0x11, 0x22, 0x11, 0x22]));
219 let hs = <[Foo; 2] as SerHex<StrictPfx>>::into_hex(&v).unwrap();
220 assert_eq!(hs, "0xffaaffaa11221122");
221 }
222}