oasis_core_runtime/common/
bytes.rs

1//! Byte array type helpers.
2
3/// Define a byte array-like type.
4///
5/// # Examples
6///
7/// ```rust,ignore
8/// impl_bytes!(MyType, 32, "A 32-byte type.");
9/// ```
10#[macro_export]
11macro_rules! impl_bytes {
12    ($name:ident, $size:expr, $doc:expr) => {
13        #[doc=$doc]
14        #[derive(Clone, Copy, zeroize::Zeroize)]
15        pub struct $name(pub [u8; $size]);
16
17        impl $name {
18            /// Size of this object in bytes.
19            pub const fn len() -> usize {
20                $size
21            }
22        }
23
24        impl AsRef<[u8]> for $name {
25            fn as_ref(&self) -> &[u8] {
26                &self.0
27            }
28        }
29
30        impl Eq for $name {}
31
32        impl PartialOrd for $name {
33            fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
34                Some(self.cmp(other))
35            }
36        }
37
38        impl PartialEq for $name {
39            fn eq(&self, other: &Self) -> bool {
40                &self.0[..] == &other.0[..]
41            }
42        }
43
44        impl Ord for $name {
45            fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
46                self.0[..].cmp(&other.0[..])
47            }
48        }
49
50        impl ::core::hash::Hash for $name {
51            fn hash<H>(&self, state: &mut H)
52            where
53                H: ::core::hash::Hasher,
54            {
55                state.write(&self.0);
56            }
57        }
58
59        impl Default for $name {
60            fn default() -> Self {
61                $name([0; $size])
62            }
63        }
64
65        impl From<$name> for [u8; $size] {
66            fn from(b: $name) -> Self {
67                b.0
68            }
69        }
70
71        impl From<&[u8]> for $name {
72            fn from(b: &[u8]) -> $name {
73                let mut data = [0; $size];
74                data.copy_from_slice(b);
75                $name(data)
76            }
77        }
78
79        impl From<&'static str> for $name {
80            fn from(s: &'static str) -> $name {
81                let s = s.strip_prefix("0x").unwrap_or(s);
82
83                if s.len() % 2 == 1 {
84                    ("0".to_owned() + s).parse().unwrap()
85                } else {
86                    s.parse().unwrap()
87                }
88            }
89        }
90
91        impl From<Vec<u8>> for $name {
92            fn from(v: Vec<u8>) -> $name {
93                Self::from(&v[..])
94            }
95        }
96
97        impl ::std::str::FromStr for $name {
98            type Err = ::rustc_hex::FromHexError;
99
100            fn from_str(s: &str) -> Result<$name, ::rustc_hex::FromHexError> {
101                use ::rustc_hex::FromHex;
102
103                let a: Vec<u8> = s.from_hex()?;
104                if a.len() != $size {
105                    return Err(::rustc_hex::FromHexError::InvalidHexLength);
106                }
107
108                let mut ret = [0; $size];
109                ret.copy_from_slice(&a);
110                Ok($name(ret))
111            }
112        }
113
114        // Formatting.
115
116        impl ::core::fmt::LowerHex for $name {
117            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
118                for i in &self.0[..] {
119                    write!(f, "{:02x}", i)?;
120                }
121                Ok(())
122            }
123        }
124
125        impl ::core::fmt::Debug for $name {
126            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
127                ::core::fmt::LowerHex::fmt(self, f)
128            }
129        }
130
131        impl ::core::fmt::Display for $name {
132            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
133                for i in &self.0[0..2] {
134                    write!(f, "{:02x}", i)?;
135                }
136                write!(f, "…")?;
137                for i in &self.0[$size - 2..$size] {
138                    write!(f, "{:02x}", i)?;
139                }
140                Ok(())
141            }
142        }
143
144        // Serialization.
145
146        impl $crate::cbor::Encode for $name {
147            fn into_cbor_value(self) -> $crate::cbor::Value {
148                $crate::cbor::Value::ByteString(self.0.into())
149            }
150        }
151
152        // Deserialization.
153
154        impl $crate::cbor::Decode for $name {
155            fn try_default() -> Result<Self, $crate::cbor::DecodeError> {
156                Ok(Default::default())
157            }
158
159            fn try_from_cbor_value(
160                value: $crate::cbor::Value,
161            ) -> Result<Self, $crate::cbor::DecodeError> {
162                use ::std::convert::TryInto;
163
164                match value {
165                    $crate::cbor::Value::ByteString(data) => Ok(Self(
166                        data.try_into()
167                            .map_err(|_| $crate::cbor::DecodeError::UnexpectedType)?,
168                    )),
169                    _ => Err($crate::cbor::DecodeError::UnexpectedType),
170                }
171            }
172        }
173    };
174}
175
176#[cfg(test)]
177mod tests {
178    // Use hash of an empty string as a test key.
179    const TEST_KEY_BYTES: [u8; 32] = [
180        0xc6, 0x72, 0xb8, 0xd1, 0xef, 0x56, 0xed, 0x28, 0xab, 0x87, 0xc3, 0x62, 0x2c, 0x51, 0x14,
181        0x06, 0x9b, 0xdd, 0x3a, 0xd7, 0xb8, 0xf9, 0x73, 0x74, 0x98, 0xd0, 0xc0, 0x1e, 0xce, 0xf0,
182        0x96, 0x7a,
183    ];
184
185    impl_bytes!(TestKey, 32, "test key");
186
187    #[test]
188    fn test_length() {
189        assert_eq!(TestKey::len(), 32);
190    }
191
192    #[test]
193    fn test_cbor() {
194        // Serialize.
195        let test_key = TestKey(TEST_KEY_BYTES);
196        let test_key_vec = cbor::to_vec(test_key);
197
198        // CBOR prepends "X " to the binary value.
199        let mut expected_test_key_vec = vec![88, 32];
200        expected_test_key_vec.extend_from_slice(&TEST_KEY_BYTES);
201        assert_eq!(test_key_vec, expected_test_key_vec);
202
203        // Deserialize.
204        let new_test_key: TestKey = cbor::from_slice(&test_key_vec).unwrap();
205        assert_eq!(new_test_key, test_key);
206    }
207
208    #[test]
209    fn test_cbor_null() {
210        let test_key: TestKey = cbor::from_slice(&[0xF6]).unwrap();
211        assert_eq!(
212            test_key,
213            "0000000000000000000000000000000000000000000000000000000000000000".into()
214        );
215    }
216}