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#[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 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 write!(f, "HexBinary(")?;
76 for byte in self.0.iter() {
77 write!(f, "{byte:02x}")?;
78 }
79 write!(f, ")")?;
80 Ok(())
81 }
82}
83
84impl 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
103impl From<&[u8]> for HexBinary {
105 fn from(binary: &[u8]) -> Self {
106 Self(binary.to_vec())
107 }
108}
109
110impl<const LENGTH: usize> From<&[u8; LENGTH]> for HexBinary {
112 fn from(source: &[u8; LENGTH]) -> Self {
113 Self(source.to_vec())
114 }
115}
116
117impl<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
148impl PartialEq<Vec<u8>> for HexBinary {
150 fn eq(&self, rhs: &Vec<u8>) -> bool {
151 self.0 == *rhs
153 }
154}
155
156impl PartialEq<HexBinary> for Vec<u8> {
158 fn eq(&self, rhs: &HexBinary) -> bool {
159 *self == rhs.0
161 }
162}
163
164impl PartialEq<&[u8]> for HexBinary {
166 fn eq(&self, rhs: &&[u8]) -> bool {
167 self.as_slice() == *rhs
169 }
170}
171
172impl PartialEq<HexBinary> for &[u8] {
174 fn eq(&self, rhs: &HexBinary) -> bool {
175 *self == rhs.as_slice()
177 }
178}
179
180impl<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
187impl<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
194impl<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
201impl<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
208impl 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
222impl<'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 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 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 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 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 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 let binary = HexBinary::from(&[]);
359 let array: [u8; 0] = binary.to_array().unwrap();
360 assert_eq!(array, [] as [u8; 0]);
361
362 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 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 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 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 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 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 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 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 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 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 let data = HexBinary(vec![0x07, 0x35, 0xAA, 0xcb, 0x00, 0xff]);
600 assert_eq!(format!("{data:?}"), "HexBinary(0735aacb00ff)",);
601
602 let data = HexBinary(vec![]);
604 assert_eq!(format!("{data:?}"), "HexBinary()",);
605 }
606
607 #[test]
608 fn hex_binary_implements_deref() {
609 let data = HexBinary(vec![7u8, 35, 49, 101, 0, 255]);
611 assert_eq!(*data, [7u8, 35, 49, 101, 0, 255]);
612
613 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 #[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 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 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 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}