byte_array_struct/
lib.rs

1/*
2Copyright 2020 ETCDEV GmbH
3Copyright 2020 EmeraldPay, Inc
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9    http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16*/
17
18///
19/// Produces byte-array based struct
20///```
21///# #[macro_use] extern crate byte_array_struct; use std::str::FromStr; fn main() {
22///byte_array_struct!(
23///    // 24 is the size of the struct in bytes
24///    pub struct Address(24);
25///);
26///
27///let foo = Address::default();
28///let foo = Address::from_str("0x00112233445566778899aabbccddeeff0123456789abcdef").unwrap();
29///# }
30///```
31//
32#[macro_export]
33macro_rules! byte_array_struct {
34    (
35        $visibility:vis struct $name:ident ($num:expr);
36    ) => {
37
38        #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
39        $visibility struct $name([u8; $num]);
40
41        impl ::std::ops::Deref for $name {
42            type Target = [u8];
43
44            fn deref(&self) -> &Self::Target {
45                &self.0
46            }
47        }
48
49        impl std::str::FromStr for $name {
50            type Err = ();
51
52            fn from_str(s: &str) -> Result<Self, Self::Err> {
53                let s_hex: &str = if s.len() == $num * 2 {
54                    s
55                } else if s.len() == $num * 2 + 2 && s.starts_with("0x") {
56                    &s[2..]
57                } else {
58                    return Err(());
59                };
60                let hex = hex::decode(s_hex).map_err(|_| ())?;
61                <$name as std::convert::TryFrom<Vec<u8>>>::try_from(hex)
62            }
63        }
64
65        impl ToString for $name {
66            fn to_string(&self) -> String {
67                hex::encode(&self.0)
68            }
69        }
70
71        impl From<[u8; $num]> for $name {
72            fn from(bytes: [u8; $num]) -> Self {
73                $name(bytes)
74            }
75        }
76
77        impl std::convert::TryFrom<&[u8]> for $name {
78            type Error = ();
79
80            fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
81                if value.len() != $num {
82                    return Err(());
83                }
84                let mut result: [u8; $num] = [0; $num];
85                result.copy_from_slice(value);
86                Ok(result.into())
87            }
88        }
89
90        impl std::convert::TryFrom<Vec<u8>> for $name {
91            type Error = ();
92
93            fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
94                if value.len() != $num {
95                    return Err(());
96                }
97                let mut result: [u8; $num] = [0; $num];
98                result.copy_from_slice(&value);
99                Ok(result.into())
100            }
101        }
102
103        impl Into<Vec<u8>> for $name {
104            fn into(self) -> Vec<u8> {
105                self.0.to_vec()
106            }
107        }
108
109        impl Into<[u8; $num]> for $name {
110            fn into(self) -> [u8; $num] {
111                self.0
112            }
113        }
114
115        // add implementation for Serde serialize/deserialize if with-serde feature is configured
116        __bas_with_serde!($name, $num);
117    };
118}
119
120// if with-serde is not enabled, generates nothing
121#[cfg(not(feature = "with-serde"))]
122#[macro_export]
123macro_rules! __bas_with_serde {
124    ($name:ident, $num:expr) => {
125
126    }
127}
128
129// if with-serde is enabled
130#[cfg(feature = "with-serde")]
131#[macro_export]
132macro_rules! __bas_with_serde {
133    ($name:ident, $num:expr) => {
134        impl<'de> ::serde::Deserialize<'de> for $name {
135            fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
136            where
137                D: ::serde::Deserializer<'de>,
138            {
139                use hex::FromHex;
140                let v = String::deserialize(deserializer)
141                    .and_then(|s| Vec::from_hex(s).map_err(::serde::de::Error::custom))?;
142
143                if v.len() != $num {
144                    return Err(::serde::de::Error::custom(&format!(
145                        "Byte array invalid length: {}",
146                        v.len()
147                    )));
148                }
149
150                let mut bytes = [0u8; $num];
151                bytes.copy_from_slice(&v);
152
153                Ok($name(bytes))
154            }
155        }
156
157        impl ::serde::Serialize for $name {
158            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
159            where
160                S: ::serde::Serializer,
161            {
162                use hex;
163                serializer.serialize_str(&hex::encode(&self.0))
164            }
165        }
166    }
167}
168
169#[cfg(test)]
170mod tests {
171    use std::str::FromStr;
172    use std::convert::TryFrom;
173
174    byte_array_struct!(
175        struct Bytes8(8);
176    );
177    byte_array_struct!(
178        pub struct Bytes20(20);
179    );
180    byte_array_struct!(
181        struct Bytes24 (24);
182    );
183    byte_array_struct!(
184        struct Bytes32(32);
185    );
186
187    #[test]
188    fn creates_8byte_struct() {
189        let act = Bytes8::default();
190        assert_eq!(act.0.len(), 8);
191    }
192
193    #[test]
194    fn creates_20byte_struct() {
195        let act = Bytes20::default();
196        assert_eq!(act.0.len(), 20);
197    }
198
199    #[test]
200    fn creates_24byte_struct() {
201        let act = Bytes24::default();
202        assert_eq!(act.0.len(), 24);
203    }
204
205    #[test]
206    fn creates_32byte_struct() {
207        let act = Bytes32::default();
208        assert_eq!(act.0.len(), 32);
209    }
210
211    #[test]
212    fn create_from_string() {
213        let act = Bytes20::from_str("00112233445566778899aabbccddeeff00112233").unwrap();
214        assert_eq!(act.to_string(), "00112233445566778899aabbccddeeff00112233");
215        assert_eq!(act.0.len(), 20);
216
217        let act = Bytes24::from_str("0x00112233445566778899aabbccddeeff0011223344556677").unwrap();
218        assert_eq!(act.to_string(), "00112233445566778899aabbccddeeff0011223344556677");
219        assert_eq!(act.0.len(), 24);
220    }
221
222    #[test]
223    fn fail_on_invalid_size_string() {
224        let act = Bytes20::from_str("00112233445566778899aabbccddeeff0011223344");
225        assert!(act.is_err());
226
227        let act = Bytes20::from_str("00112233445566778899aabbccddeeff001122");
228        assert!(act.is_err());
229    }
230
231    #[test]
232    fn fail_on_non_hex_string() {
233        let act = Bytes20::from_str("00112233445566778899aabbccddeeff1234qwer");
234        assert!(act.is_err());
235
236        let act = Bytes20::from_str("0_00112233445566778899aabbccddeeff00112233");
237        assert!(act.is_err());
238    }
239
240    #[test]
241    fn fail_on_empty_string() {
242        let act = Bytes20::from_str("");
243        assert!(act.is_err());
244    }
245
246    #[test]
247    fn create_from_bytes() {
248        let input = hex::decode("00112233445566778899aabbccddeeff00112233").unwrap();
249        let input = input.as_slice();
250        let act = Bytes20::try_from(input).unwrap();
251        assert_eq!(act.to_string(), "00112233445566778899aabbccddeeff00112233");
252        assert_eq!(act.0.len(), 20);
253    }
254
255    #[test]
256    fn create_from_vec() {
257        let input = hex::decode("00112233445566778899aabbccddeeff00112233").unwrap();
258        let act = Bytes20::try_from(input).unwrap();
259        assert_eq!(act.to_string(), "00112233445566778899aabbccddeeff00112233");
260        assert_eq!(act.0.len(), 20);
261    }
262
263    #[test]
264    fn fail_to_create_incorrect_arr() {
265        let input = hex::decode("00112233445566778899aabbccddeeff").unwrap();
266        let act = Bytes20::try_from(input.as_slice());
267        assert!(act.is_err());
268
269        let input = hex::decode("00112233445566778899aabbccddeeff00112233").unwrap();
270        let act = Bytes8::try_from(input.as_slice());
271        assert!(act.is_err());
272    }
273
274    #[test]
275    fn fail_to_create_incorrect_vec() {
276        let input = hex::decode("00112233445566778899aabbccddeeff").unwrap();
277        let act = Bytes20::try_from(input);
278        assert!(act.is_err());
279
280        let input = hex::decode("00112233445566778899aabbccddeeff00112233").unwrap();
281        let act = Bytes8::try_from(input);
282        assert!(act.is_err());
283    }
284
285    #[test]
286    fn convert_into_vec() {
287        let input = hex::decode("00112233445566778899aabbccddeeff00112233").unwrap();
288        let act = Bytes20::try_from(input.clone()).unwrap();
289        let output: Vec<u8> = act.into();
290        assert_eq!(output, input);
291    }
292
293    #[test]
294    fn convert_into_arr() {
295        let input = hex::decode("00112233445566778899aabbccddeeff00112233").unwrap();
296        let act = Bytes20::try_from(input.clone()).unwrap();
297        let output: [u8; 20] = act.into();
298        assert_eq!(output, input.as_slice());
299    }
300}
301
302#[cfg(all(test, feature = "with-serde"))]
303mod tests_serde {
304
305    byte_array_struct!(
306        struct Hex8(8);
307    );
308
309    #[test]
310    fn encode_default_byte_array() {
311        assert_eq!(
312            serde_json::to_string(&Hex8::default()).unwrap(),
313            "\"0000000000000000\""
314        );
315    }
316
317    #[test]
318    fn decode_zero_byte_array() {
319        assert_eq!(
320            serde_json::from_str::<Hex8>("\"0000000000000000\"").unwrap(),
321            Hex8::default()
322        );
323    }
324
325    #[test]
326    fn encode_byte_array() {
327        let hex = Hex8::from([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
328
329        assert_eq!(serde_json::to_string(&hex).unwrap(), "\"0123456789abcdef\"");
330    }
331
332    #[test]
333    fn decode_byte_array() {
334        let hex = Hex8::from([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
335
336        assert_eq!(
337            serde_json::from_str::<Hex8>("\"0123456789abcdef\"").unwrap(),
338            hex
339        );
340    }
341
342    #[test]
343    fn not_decode_invalid_byte_array() {
344        assert!(serde_json::from_str::<Hex8>("\"__23456789abcdef\"").is_err());
345    }
346
347    #[test]
348    fn not_decode_insufficient_byte_array() {
349        assert!(serde_json::from_str::<Hex8>("1234567890").is_err());
350    }
351
352    #[test]
353    fn not_decode_empty_text() {
354        assert!(serde_json::from_str::<Hex8>("\"\"").is_err());
355    }
356
357    #[test]
358    fn not_decode_absent_text() {
359        assert!(serde_json::from_str::<Hex8>("").is_err());
360    }
361}