cosmwasm_std/
hex_binary.rs

1use alloc::{string::String, vec::Vec};
2use core::fmt;
3use core::ops::Deref;
4
5use serde::{de, ser, Deserialize, Deserializer, Serialize};
6
7use crate::{
8    encoding::{from_hex, to_hex},
9    Binary, StdError, StdResult,
10};
11
12/// This is a wrapper around Vec<u8> to add hex de/serialization
13/// with serde. It also adds some helper methods to help encode inline.
14///
15/// This is similar to `cosmwasm_std::Binary` but uses hex.
16/// See also <https://github.com/CosmWasm/cosmwasm/blob/main/docs/MESSAGE_TYPES.md>.
17#[derive(
18    Clone,
19    Default,
20    PartialEq,
21    Eq,
22    Hash,
23    PartialOrd,
24    Ord,
25    schemars::JsonSchema,
26    cw_schema::Schemaifier,
27)]
28#[schemaifier(type = cw_schema::NodeType::HexBinary)]
29pub struct HexBinary(#[schemars(with = "String")] Vec<u8>);
30
31impl HexBinary {
32    pub fn from_hex(input: &str) -> StdResult<Self> {
33        from_hex(input).map(Self)
34    }
35
36    pub fn to_hex(&self) -> String {
37        to_hex(&self.0)
38    }
39
40    pub fn as_slice(&self) -> &[u8] {
41        self.0.as_slice()
42    }
43
44    /// Copies content into fixed-sized array.
45    ///
46    /// # Examples
47    ///
48    /// Copy to array of explicit length
49    ///
50    /// ```
51    /// # use cosmwasm_std::HexBinary;
52    /// let data = HexBinary::from(&[0xfb, 0x1f, 0x37]);
53    /// let array: [u8; 3] = data.to_array().unwrap();
54    /// assert_eq!(array, [0xfb, 0x1f, 0x37]);
55    /// ```
56    ///
57    /// Copy to integer
58    ///
59    /// ```
60    /// # use cosmwasm_std::HexBinary;
61    /// let data = HexBinary::from(&[0x8b, 0x67, 0x64, 0x84, 0xb5, 0xfb, 0x1f, 0x37]);
62    /// let num = u64::from_be_bytes(data.to_array().unwrap());
63    /// assert_eq!(num, 10045108015024774967);
64    /// ```
65    pub fn to_array<const LENGTH: usize>(&self) -> StdResult<[u8; LENGTH]> {
66        if self.len() != LENGTH {
67            return Err(StdError::msg(format_args!(
68                "invalid length. expected {LENGTH}, got {}",
69                self.len()
70            )));
71        }
72
73        let mut out: [u8; LENGTH] = [0; LENGTH];
74        out.copy_from_slice(&self.0);
75        Ok(out)
76    }
77}
78
79impl fmt::Display for HexBinary {
80    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81        write!(f, "{}", self.to_hex())
82    }
83}
84
85impl fmt::Debug for HexBinary {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        // Use an output inspired by tuples (https://doc.rust-lang.org/std/fmt/struct.Formatter.html#method.debug_tuple)
88        // but with a custom implementation to avoid the need for an intermediate hex string.
89        write!(f, "HexBinary(")?;
90        for byte in self.0.iter() {
91            write!(f, "{byte:02x}")?;
92        }
93        write!(f, ")")?;
94        Ok(())
95    }
96}
97
98/// Just like Vec<u8>, HexBinary is a smart pointer to [u8].
99/// This implements `*data` for us and allows us to
100/// do `&*data`, returning a `&[u8]` from a `&HexBinary`.
101/// With [deref coercions](https://doc.rust-lang.org/1.22.1/book/first-edition/deref-coercions.html#deref-coercions),
102/// this allows us to use `&data` whenever a `&[u8]` is required.
103impl Deref for HexBinary {
104    type Target = [u8];
105
106    fn deref(&self) -> &Self::Target {
107        self.as_slice()
108    }
109}
110
111impl AsRef<[u8]> for HexBinary {
112    fn as_ref(&self) -> &[u8] {
113        self.as_slice()
114    }
115}
116
117// Slice
118impl From<&[u8]> for HexBinary {
119    fn from(binary: &[u8]) -> Self {
120        Self(binary.to_vec())
121    }
122}
123
124// Array reference
125impl<const LENGTH: usize> From<&[u8; LENGTH]> for HexBinary {
126    fn from(source: &[u8; LENGTH]) -> Self {
127        Self(source.to_vec())
128    }
129}
130
131// Owned array
132impl<const LENGTH: usize> From<[u8; LENGTH]> for HexBinary {
133    fn from(source: [u8; LENGTH]) -> Self {
134        Self(source.into())
135    }
136}
137
138impl From<Vec<u8>> for HexBinary {
139    fn from(vec: Vec<u8>) -> Self {
140        Self(vec)
141    }
142}
143
144impl From<HexBinary> for Vec<u8> {
145    fn from(original: HexBinary) -> Vec<u8> {
146        original.0
147    }
148}
149
150impl From<Binary> for HexBinary {
151    fn from(original: Binary) -> Self {
152        Self(original.into())
153    }
154}
155
156impl From<HexBinary> for Binary {
157    fn from(original: HexBinary) -> Binary {
158        Binary::from(original.0)
159    }
160}
161
162/// Implement `HexBinary == alloc::vec::Vec<u8>`
163impl PartialEq<Vec<u8>> for HexBinary {
164    fn eq(&self, rhs: &Vec<u8>) -> bool {
165        // Use Vec<u8> == Vec<u8>
166        self.0 == *rhs
167    }
168}
169
170/// Implement `alloc::vec::Vec<u8> == HexBinary`
171impl PartialEq<HexBinary> for Vec<u8> {
172    fn eq(&self, rhs: &HexBinary) -> bool {
173        // Use Vec<u8> == Vec<u8>
174        *self == rhs.0
175    }
176}
177
178/// Implement `HexBinary == &[u8]`
179impl PartialEq<&[u8]> for HexBinary {
180    fn eq(&self, rhs: &&[u8]) -> bool {
181        // Use &[u8] == &[u8]
182        self.as_slice() == *rhs
183    }
184}
185
186/// Implement `&[u8] == HexBinary`
187impl PartialEq<HexBinary> for &[u8] {
188    fn eq(&self, rhs: &HexBinary) -> bool {
189        // Use &[u8] == &[u8]
190        *self == rhs.as_slice()
191    }
192}
193
194/// Implement `HexBinary == [u8; LENGTH]`
195impl<const LENGTH: usize> PartialEq<[u8; LENGTH]> for HexBinary {
196    fn eq(&self, rhs: &[u8; LENGTH]) -> bool {
197        self.as_slice() == rhs.as_slice()
198    }
199}
200
201/// Implement `[u8; LENGTH] == HexBinary`
202impl<const LENGTH: usize> PartialEq<HexBinary> for [u8; LENGTH] {
203    fn eq(&self, rhs: &HexBinary) -> bool {
204        self.as_slice() == rhs.as_slice()
205    }
206}
207
208/// Implement `HexBinary == &[u8; LENGTH]`
209impl<const LENGTH: usize> PartialEq<&[u8; LENGTH]> for HexBinary {
210    fn eq(&self, rhs: &&[u8; LENGTH]) -> bool {
211        self.as_slice() == rhs.as_slice()
212    }
213}
214
215/// Implement `&[u8; LENGTH] == HexBinary`
216impl<const LENGTH: usize> PartialEq<HexBinary> for &[u8; LENGTH] {
217    fn eq(&self, rhs: &HexBinary) -> bool {
218        self.as_slice() == rhs.as_slice()
219    }
220}
221
222/// Serializes as a hex string
223impl Serialize for HexBinary {
224    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
225    where
226        S: ser::Serializer,
227    {
228        if serializer.is_human_readable() {
229            serializer.serialize_str(&self.to_hex())
230        } else {
231            serializer.serialize_bytes(&self.0)
232        }
233    }
234}
235
236/// Deserializes as a hex string
237impl<'de> Deserialize<'de> for HexBinary {
238    fn deserialize<D>(deserializer: D) -> Result<HexBinary, D::Error>
239    where
240        D: Deserializer<'de>,
241    {
242        if deserializer.is_human_readable() {
243            deserializer.deserialize_str(HexVisitor)
244        } else {
245            deserializer.deserialize_bytes(BytesVisitor)
246        }
247    }
248}
249
250struct HexVisitor;
251
252impl de::Visitor<'_> for HexVisitor {
253    type Value = HexBinary;
254
255    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
256        formatter.write_str("valid hex encoded string")
257    }
258
259    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
260    where
261        E: de::Error,
262    {
263        match HexBinary::from_hex(v) {
264            Ok(data) => Ok(data),
265            Err(_) => Err(E::custom(format!("invalid hex: {v}"))),
266        }
267    }
268}
269
270struct BytesVisitor;
271
272impl de::Visitor<'_> for BytesVisitor {
273    type Value = HexBinary;
274
275    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
276        formatter.write_str("byte array")
277    }
278
279    fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
280    where
281        E: de::Error,
282    {
283        Ok(HexBinary(v.to_vec()))
284    }
285}
286
287#[cfg(test)]
288mod tests {
289    use super::*;
290
291    use crate::{assert_hash_works, errors::ErrorKind};
292
293    #[test]
294    fn from_hex_works() {
295        let data = HexBinary::from_hex("").unwrap();
296        assert_eq!(data, b"");
297        let data = HexBinary::from_hex("61").unwrap();
298        assert_eq!(data, b"a");
299        let data = HexBinary::from_hex("00").unwrap();
300        assert_eq!(data, b"\0");
301
302        let data = HexBinary::from_hex("68656c6c6f").unwrap();
303        assert_eq!(data, b"hello");
304        let data = HexBinary::from_hex("68656C6C6F").unwrap();
305        assert_eq!(data, b"hello");
306        let data = HexBinary::from_hex("72616e646f6d695a").unwrap();
307        assert_eq!(data.as_slice(), b"randomiZ");
308
309        // odd
310        assert!(HexBinary::from_hex("123")
311            .unwrap_err()
312            .to_string()
313            .ends_with("Odd number of digits"));
314        // non-hex
315        assert!(HexBinary::from_hex("efgh")
316            .unwrap_err()
317            .to_string()
318            .ends_with("Invalid character 'g' at position 2"));
319        // 0x prefixed
320        assert!(HexBinary::from_hex("0xaa")
321            .unwrap_err()
322            .to_string()
323            .ends_with("Invalid character 'x' at position 1"));
324        // spaces
325        assert!(matches!(
326            HexBinary::from_hex("aa ").unwrap_err().kind(),
327            ErrorKind::Encoding,
328        ));
329        assert!(matches!(
330            HexBinary::from_hex(" aa").unwrap_err().kind(),
331            ErrorKind::Encoding,
332        ));
333        assert!(matches!(
334            HexBinary::from_hex("a a").unwrap_err().kind(),
335            ErrorKind::Encoding,
336        ));
337        assert!(matches!(
338            HexBinary::from_hex(" aa ").unwrap_err().kind(),
339            ErrorKind::Encoding,
340        ));
341    }
342
343    #[test]
344    fn to_hex_works() {
345        let binary: &[u8] = b"";
346        let encoded = HexBinary::from(binary).to_hex();
347        assert_eq!(encoded, "");
348
349        let binary: &[u8] = b"hello";
350        let encoded = HexBinary::from(binary).to_hex();
351        assert_eq!(encoded, "68656c6c6f");
352
353        let binary = vec![12u8, 187, 0, 17, 250, 1];
354        let encoded = HexBinary(binary).to_hex();
355        assert_eq!(encoded, "0cbb0011fa01");
356    }
357
358    #[test]
359    fn to_array_works() {
360        // simple
361        let binary = HexBinary::from(&[1, 2, 3]);
362        let array: [u8; 3] = binary.to_array().unwrap();
363        assert_eq!(array, [1, 2, 3]);
364
365        // empty
366        let binary = HexBinary::from(&[]);
367        let array: [u8; 0] = binary.to_array().unwrap();
368        assert_eq!(array, [] as [u8; 0]);
369
370        // invalid size
371        let binary = HexBinary::from(&[1, 2, 3]);
372        let error = binary.to_array::<8>().unwrap_err();
373        assert!(error
374            .to_string()
375            .ends_with("invalid length. expected 8, got 3"));
376
377        // long array (32 bytes)
378        let binary =
379            HexBinary::from_hex("b75d7d24e428c7859440498efe7caa3997cefb08c99bdd581b6b1f9f866096f0")
380                .unwrap();
381        let array: [u8; 32] = binary.to_array().unwrap();
382        assert_eq!(
383            array,
384            [
385                0xb7, 0x5d, 0x7d, 0x24, 0xe4, 0x28, 0xc7, 0x85, 0x94, 0x40, 0x49, 0x8e, 0xfe, 0x7c,
386                0xaa, 0x39, 0x97, 0xce, 0xfb, 0x08, 0xc9, 0x9b, 0xdd, 0x58, 0x1b, 0x6b, 0x1f, 0x9f,
387                0x86, 0x60, 0x96, 0xf0,
388            ]
389        );
390
391        // very long array > 32 bytes (requires Rust 1.47+)
392        let binary = HexBinary::from_hex(
393            "b75d7d24e428c7859440498efe7caa3997cefb08c99bdd581b6b1f9f866096f073c8c3b0316abe",
394        )
395        .unwrap();
396        let array: [u8; 39] = binary.to_array().unwrap();
397        assert_eq!(
398            array,
399            [
400                0xb7, 0x5d, 0x7d, 0x24, 0xe4, 0x28, 0xc7, 0x85, 0x94, 0x40, 0x49, 0x8e, 0xfe, 0x7c,
401                0xaa, 0x39, 0x97, 0xce, 0xfb, 0x08, 0xc9, 0x9b, 0xdd, 0x58, 0x1b, 0x6b, 0x1f, 0x9f,
402                0x86, 0x60, 0x96, 0xf0, 0x73, 0xc8, 0xc3, 0xb0, 0x31, 0x6a, 0xbe,
403            ]
404        );
405    }
406
407    #[test]
408    fn from_json_works() {
409        let original: &[u8] = &[0u8, 187, 61, 11, 250, 0];
410        let binary: HexBinary = original.into();
411        assert_eq!(binary.as_slice(), [0u8, 187, 61, 11, 250, 0]);
412    }
413
414    #[test]
415    fn from_fixed_length_array_works() {
416        let original = &[];
417        let binary: HexBinary = original.into();
418        assert_eq!(binary.len(), 0);
419
420        let original = &[0u8];
421        let binary: HexBinary = original.into();
422        assert_eq!(binary.as_slice(), [0u8]);
423
424        let original = &[0u8, 187, 61, 11, 250, 0];
425        let binary: HexBinary = original.into();
426        assert_eq!(binary.as_slice(), [0u8, 187, 61, 11, 250, 0]);
427
428        let original = &[
429            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
430            1, 1, 1,
431        ];
432        let binary: HexBinary = original.into();
433        assert_eq!(
434            binary.as_slice(),
435            [
436                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
437                1, 1, 1, 1,
438            ]
439        );
440    }
441
442    #[test]
443    fn from_owned_fixed_length_array_works() {
444        let original = [];
445        let binary: HexBinary = original.into();
446        assert_eq!(binary.len(), 0);
447
448        let original = [0u8];
449        let binary: HexBinary = original.into();
450        assert_eq!(binary.as_slice(), [0u8]);
451
452        let original = [0u8, 187, 61, 11, 250, 0];
453        let binary: HexBinary = original.into();
454        assert_eq!(binary.as_slice(), [0u8, 187, 61, 11, 250, 0]);
455
456        let original = [
457            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
458            1, 1, 1,
459        ];
460        let binary: HexBinary = original.into();
461        assert_eq!(
462            binary.as_slice(),
463            [
464                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
465                1, 1, 1, 1,
466            ]
467        );
468    }
469
470    #[test]
471    fn from_literal_works() {
472        let a: HexBinary = b"".into();
473        assert_eq!(a.len(), 0);
474
475        let a: HexBinary = b".".into();
476        assert_eq!(a.len(), 1);
477
478        let a: HexBinary = b"...".into();
479        assert_eq!(a.len(), 3);
480
481        let a: HexBinary = b"...............................".into();
482        assert_eq!(a.len(), 31);
483
484        let a: HexBinary = b"................................".into();
485        assert_eq!(a.len(), 32);
486
487        let a: HexBinary = (b".................................").into();
488        assert_eq!(a.len(), 33);
489    }
490
491    #[test]
492    fn from_vec_works() {
493        let original = vec![0u8, 187, 61, 11, 250, 0];
494        let original_ptr = original.as_ptr();
495        let binary: HexBinary = original.into();
496        assert_eq!(binary.as_slice(), [0u8, 187, 61, 11, 250, 0]);
497        assert_eq!(binary.0.as_ptr(), original_ptr, "vector must not be copied");
498    }
499
500    #[test]
501    fn into_vec_works() {
502        // Into<Vec<u8>> for HexBinary
503        let original = HexBinary(vec![0u8, 187, 61, 11, 250, 0]);
504        let original_ptr = original.0.as_ptr();
505        let vec: Vec<u8> = original.into();
506        assert_eq!(vec.as_slice(), [0u8, 187, 61, 11, 250, 0]);
507        assert_eq!(vec.as_ptr(), original_ptr, "vector must not be copied");
508
509        // From<HexBinary> for Vec<u8>
510        let original = HexBinary(vec![7u8, 35, 49, 101, 0, 255]);
511        let original_ptr = original.0.as_ptr();
512        let vec = Vec::<u8>::from(original);
513        assert_eq!(vec.as_slice(), [7u8, 35, 49, 101, 0, 255]);
514        assert_eq!(vec.as_ptr(), original_ptr, "vector must not be copied");
515    }
516
517    #[test]
518    fn from_binary_works() {
519        let original = Binary::from([0u8, 187, 61, 11, 250, 0]);
520        let original_ptr = original.as_ptr();
521        let binary: HexBinary = original.into();
522        assert_eq!(binary.as_slice(), [0u8, 187, 61, 11, 250, 0]);
523        assert_eq!(binary.0.as_ptr(), original_ptr, "vector must not be copied");
524    }
525
526    #[test]
527    fn into_binary_works() {
528        // Into<Binary> for HexBinary
529        let original = HexBinary(vec![0u8, 187, 61, 11, 250, 0]);
530        let original_ptr = original.0.as_ptr();
531        let bin: Binary = original.into();
532        assert_eq!(bin.as_slice(), [0u8, 187, 61, 11, 250, 0]);
533        assert_eq!(bin.as_ptr(), original_ptr, "vector must not be copied");
534
535        // From<HexBinary> for Binary
536        let original = HexBinary(vec![7u8, 35, 49, 101, 0, 255]);
537        let original_ptr = original.0.as_ptr();
538        let bin = Binary::from(original);
539        assert_eq!(bin.as_slice(), [7u8, 35, 49, 101, 0, 255]);
540        assert_eq!(bin.as_ptr(), original_ptr, "vector must not be copied");
541    }
542
543    #[test]
544    fn serialization_works() {
545        let binary = HexBinary(vec![0u8, 187, 61, 11, 250, 0]);
546
547        let json = serde_json::to_vec(&binary).unwrap();
548        let deserialized: HexBinary = serde_json::from_slice(&json).unwrap();
549
550        assert_eq!(binary, deserialized);
551    }
552
553    #[test]
554    fn deserialize_from_valid_string() {
555        let hex = "00bb3d0bfa00";
556        // this is the binary behind above string
557        let expected = vec![0u8, 187, 61, 11, 250, 0];
558
559        let serialized = serde_json::to_vec(&hex).unwrap();
560        let deserialized: HexBinary = serde_json::from_slice(&serialized).unwrap();
561        assert_eq!(expected, deserialized.as_slice());
562    }
563
564    #[test]
565    fn deserialize_from_invalid_string() {
566        let invalid_str = "**BAD!**";
567        let serialized = serde_json::to_vec(&invalid_str).unwrap();
568        let res = serde_json::from_slice::<HexBinary>(&serialized);
569        assert!(res.is_err());
570    }
571
572    #[test]
573    fn msgpack_serialization_works() {
574        let data = HexBinary(vec![0u8, 187, 61, 11, 250, 0]);
575        // see: https://github.com/msgpack/msgpack/blob/8aa09e2/spec.md#bin-format-family
576        let expected = [196, 6, 0, 187, 61, 11, 250, 0];
577
578        assert_eq!(rmp_serde::to_vec(&data).unwrap(), expected);
579    }
580
581    #[test]
582    fn msgpack_deserialize_from_valid_data() {
583        // see: https://github.com/msgpack/msgpack/blob/8aa09e2/spec.md#bin-format-family
584        let serialized = vec![196, 6, 0, 187, 61, 11, 250, 0];
585        let expected = vec![0u8, 187, 61, 11, 250, 0];
586
587        let deserialized: HexBinary = rmp_serde::from_slice(&serialized).unwrap();
588        assert_eq!(expected, deserialized.as_slice());
589    }
590
591    #[test]
592    fn msgpack_deserialize_from_invalid_data() {
593        let invalid_data = vec![0, 1, 2, 3, 4, 5];
594        let res = rmp_serde::from_slice::<HexBinary>(&invalid_data);
595        assert!(res.is_err());
596    }
597
598    #[test]
599    fn hex_binary_implements_debug() {
600        // Some data
601        let data = HexBinary(vec![0x07, 0x35, 0xAA, 0xcb, 0x00, 0xff]);
602        assert_eq!(format!("{data:?}"), "HexBinary(0735aacb00ff)",);
603
604        // Empty
605        let data = HexBinary(vec![]);
606        assert_eq!(format!("{data:?}"), "HexBinary()",);
607    }
608
609    #[test]
610    fn hex_binary_implements_deref() {
611        // Dereference to [u8]
612        let data = HexBinary(vec![7u8, 35, 49, 101, 0, 255]);
613        assert_eq!(*data, [7u8, 35, 49, 101, 0, 255]);
614
615        // This checks deref coercions from &Binary to &[u8] works
616        let data = HexBinary(vec![7u8, 35, 49, 101, 0, 255]);
617        assert_eq!(data.len(), 6);
618        let data_slice: &[u8] = &data;
619        assert_eq!(data_slice, &[7u8, 35, 49, 101, 0, 255]);
620    }
621
622    #[test]
623    fn hex_binary_implements_as_ref() {
624        let want = &[7u8, 35, 49, 101, 0, 255];
625        let data = HexBinary(want.to_vec());
626        assert_eq!(want, AsRef::<[u8]>::as_ref(&data));
627        assert_eq!(want, AsRef::<[u8]>::as_ref(&&data));
628    }
629
630    /// Tests that `HexBinary` implements `EQ` and `Hash` correctly and thus can
631    /// be used with hash maps and sets.
632    #[test]
633    fn hex_binary_implements_hash_eq() {
634        let a = HexBinary::from([0, 187, 61, 11, 250, 0]);
635        let b = HexBinary::from([16, 21, 33, 0, 255, 9]);
636        assert_hash_works!(a, b);
637    }
638
639    #[test]
640    fn hex_binary_implements_partial_eq_with_vector() {
641        let a = HexBinary(vec![5u8; 3]);
642        let b = vec![5u8; 3];
643        let c = vec![9u8; 3];
644        assert_eq!(a, b);
645        assert_eq!(b, a);
646        assert_ne!(a, c);
647        assert_ne!(c, a);
648    }
649
650    #[test]
651    fn hex_binary_implements_partial_eq_with_slice_and_array() {
652        let a = HexBinary(vec![0xAA, 0xBB]);
653
654        // Slice: &[u8]
655        assert_eq!(a, b"\xAA\xBB" as &[u8]);
656        assert_eq!(b"\xAA\xBB" as &[u8], a);
657        assert_ne!(a, b"\x11\x22" as &[u8]);
658        assert_ne!(b"\x11\x22" as &[u8], a);
659
660        // Array reference: &[u8; 2]
661        assert_eq!(a, b"\xAA\xBB");
662        assert_eq!(b"\xAA\xBB", a);
663        assert_ne!(a, b"\x11\x22");
664        assert_ne!(b"\x11\x22", a);
665
666        // Array: [u8; 2]
667        assert_eq!(a, [0xAA, 0xBB]);
668        assert_eq!([0xAA, 0xBB], a);
669        assert_ne!(a, [0x11, 0x22]);
670        assert_ne!([0x11, 0x22], a);
671    }
672}