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