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_base64, to_base64},
9 errors::{ErrorKind, StdError, StdResult},
10};
11
12#[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::Binary)]
29pub struct Binary(#[schemars(with = "String")] Vec<u8>);
30
31impl Binary {
32 pub const fn new(data: Vec<u8>) -> Self {
34 Self(data)
35 }
36
37 pub fn from_base64(encoded: &str) -> StdResult<Self> {
40 from_base64(encoded).map(Self::new)
41 }
42
43 pub fn to_base64(&self) -> String {
46 to_base64(&self.0)
47 }
48
49 pub fn as_slice(&self) -> &[u8] {
50 self.0.as_slice()
51 }
52
53 pub fn to_array<const LENGTH: usize>(&self) -> StdResult<[u8; LENGTH]> {
75 if self.len() != LENGTH {
76 return Err(StdError::msg(format_args!(
77 "invalid length. expected {LENGTH}, got {}",
78 self.len()
79 )));
80 }
81
82 let mut out: [u8; LENGTH] = [0; LENGTH];
83 out.copy_from_slice(&self.0);
84 Ok(out)
85 }
86
87 pub fn from_hex(input: &str) -> StdResult<Self> {
88 let binary = hex::decode(input)
89 .map_err(|err| StdError::from(err).with_kind(ErrorKind::InvalidData))?;
90 Ok(Self(binary))
91 }
92
93 pub fn to_hex(&self) -> String {
94 hex::encode(&self.0)
95 }
96}
97
98impl fmt::Display for Binary {
99 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
100 write!(f, "{}", self.to_base64())
101 }
102}
103
104impl fmt::Debug for Binary {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 write!(f, "Binary(")?;
109 for byte in self.0.iter() {
110 write!(f, "{byte:02x}")?;
111 }
112 write!(f, ")")?;
113 Ok(())
114 }
115}
116
117impl Deref for Binary {
123 type Target = [u8];
124
125 fn deref(&self) -> &Self::Target {
126 self.as_slice()
127 }
128}
129
130impl AsRef<[u8]> for Binary {
131 fn as_ref(&self) -> &[u8] {
132 self.as_slice()
133 }
134}
135
136impl From<&[u8]> for Binary {
138 fn from(binary: &[u8]) -> Self {
139 Self(binary.to_vec())
140 }
141}
142
143impl<const LENGTH: usize> From<&[u8; LENGTH]> for Binary {
145 fn from(source: &[u8; LENGTH]) -> Self {
146 Self(source.to_vec())
147 }
148}
149
150impl<const LENGTH: usize> From<[u8; LENGTH]> for Binary {
152 fn from(source: [u8; LENGTH]) -> Self {
153 Self(source.into())
154 }
155}
156
157impl From<Vec<u8>> for Binary {
158 fn from(vec: Vec<u8>) -> Self {
159 Self(vec)
160 }
161}
162
163impl From<Binary> for Vec<u8> {
164 fn from(original: Binary) -> Vec<u8> {
165 original.0
166 }
167}
168
169impl PartialEq<Vec<u8>> for Binary {
171 fn eq(&self, rhs: &Vec<u8>) -> bool {
172 self.0 == *rhs
174 }
175}
176
177impl PartialEq<Binary> for Vec<u8> {
179 fn eq(&self, rhs: &Binary) -> bool {
180 *self == rhs.0
182 }
183}
184
185impl PartialEq<&[u8]> for Binary {
187 fn eq(&self, rhs: &&[u8]) -> bool {
188 self.as_slice() == *rhs
190 }
191}
192
193impl PartialEq<Binary> for &[u8] {
195 fn eq(&self, rhs: &Binary) -> bool {
196 *self == rhs.as_slice()
198 }
199}
200
201impl<const LENGTH: usize> PartialEq<&[u8; LENGTH]> for Binary {
203 fn eq(&self, rhs: &&[u8; LENGTH]) -> bool {
204 self.as_slice() == rhs.as_slice()
205 }
206}
207
208impl<const LENGTH: usize> PartialEq<Binary> for &[u8; LENGTH] {
210 fn eq(&self, rhs: &Binary) -> bool {
211 self.as_slice() == rhs.as_slice()
212 }
213}
214
215impl<const LENGTH: usize> PartialEq<[u8; LENGTH]> for Binary {
217 fn eq(&self, rhs: &[u8; LENGTH]) -> bool {
218 self.as_slice() == rhs.as_slice()
219 }
220}
221
222impl<const LENGTH: usize> PartialEq<Binary> for [u8; LENGTH] {
224 fn eq(&self, rhs: &Binary) -> bool {
225 self.as_slice() == rhs.as_slice()
226 }
227}
228
229impl Serialize for Binary {
231 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
232 where
233 S: ser::Serializer,
234 {
235 if serializer.is_human_readable() {
236 serializer.serialize_str(&self.to_base64())
237 } else {
238 serializer.serialize_bytes(&self.0)
239 }
240 }
241}
242
243impl<'de> Deserialize<'de> for Binary {
245 fn deserialize<D>(deserializer: D) -> Result<Binary, D::Error>
246 where
247 D: Deserializer<'de>,
248 {
249 if deserializer.is_human_readable() {
250 deserializer.deserialize_str(Base64Visitor)
251 } else {
252 deserializer.deserialize_bytes(BytesVisitor)
253 }
254 }
255}
256
257struct Base64Visitor;
258
259impl de::Visitor<'_> for Base64Visitor {
260 type Value = Binary;
261
262 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
263 formatter.write_str("valid base64 encoded string")
264 }
265
266 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
267 where
268 E: de::Error,
269 {
270 match Binary::from_base64(v) {
271 Ok(binary) => Ok(binary),
272 Err(_) => Err(E::custom(format_args!("invalid base64: {v}"))),
273 }
274 }
275}
276
277struct BytesVisitor;
278
279impl de::Visitor<'_> for BytesVisitor {
280 type Value = Binary;
281
282 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
283 formatter.write_str("byte array")
284 }
285
286 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
287 where
288 E: de::Error,
289 {
290 Ok(Binary(v.to_vec()))
291 }
292}
293
294#[cfg(test)]
295mod tests {
296 use super::*;
297 use crate::assert_hash_works;
298
299 #[test]
300 fn to_array_works() {
301 let binary = Binary::from(&[1, 2, 3]);
303 let array: [u8; 3] = binary.to_array().unwrap();
304 assert_eq!(array, [1, 2, 3]);
305
306 let binary = Binary::from(&[]);
308 let array: [u8; 0] = binary.to_array().unwrap();
309 assert_eq!(array, [] as [u8; 0]);
310
311 let binary = Binary::from(&[1, 2, 3]);
313 let error = binary.to_array::<8>().unwrap_err();
314 assert!(error
315 .to_string()
316 .ends_with("invalid length. expected 8, got 3"));
317
318 let binary = Binary::from_base64("t119JOQox4WUQEmO/nyqOZfO+wjJm91YG2sfn4ZglvA=").unwrap();
320 let array: [u8; 32] = binary.to_array().unwrap();
321 assert_eq!(
322 array,
323 [
324 0xb7, 0x5d, 0x7d, 0x24, 0xe4, 0x28, 0xc7, 0x85, 0x94, 0x40, 0x49, 0x8e, 0xfe, 0x7c,
325 0xaa, 0x39, 0x97, 0xce, 0xfb, 0x08, 0xc9, 0x9b, 0xdd, 0x58, 0x1b, 0x6b, 0x1f, 0x9f,
326 0x86, 0x60, 0x96, 0xf0,
327 ]
328 );
329
330 let binary =
332 Binary::from_base64("t119JOQox4WUQEmO/nyqOZfO+wjJm91YG2sfn4ZglvBzyMOwMWq+").unwrap();
333 let array: [u8; 39] = binary.to_array().unwrap();
334 assert_eq!(
335 array,
336 [
337 0xb7, 0x5d, 0x7d, 0x24, 0xe4, 0x28, 0xc7, 0x85, 0x94, 0x40, 0x49, 0x8e, 0xfe, 0x7c,
338 0xaa, 0x39, 0x97, 0xce, 0xfb, 0x08, 0xc9, 0x9b, 0xdd, 0x58, 0x1b, 0x6b, 0x1f, 0x9f,
339 0x86, 0x60, 0x96, 0xf0, 0x73, 0xc8, 0xc3, 0xb0, 0x31, 0x6a, 0xbe,
340 ]
341 );
342 }
343
344 #[test]
345 fn test_base64_encoding_success() {
346 for (value, encoded, encoded_no_pad) in [
347 (&b""[..], "", ""),
348 (&b"hello"[..], "aGVsbG8=", "aGVsbG8"),
349 (&b"\x0C\xBB\x00\x11\xFA\x01"[..], "DLsAEfoB", "DLsAEfoB"),
350 (&b"rand"[..], "cmFuZA==", "cmFuZA"),
351 (&b"rand"[..], "cmFuZA==", "cmFuZA="),
352 (&b"randomiZ"[..], "cmFuZG9taVo=", "cmFuZG9taVo"),
353 ] {
354 let value = Binary::from(value);
355 assert_eq!(encoded, value.to_base64());
356 assert_eq!(value.clone(), Binary::from_base64(encoded).unwrap());
357 assert_eq!(value.clone(), Binary::from_base64(encoded_no_pad).unwrap());
358 }
359 }
360
361 #[test]
362 fn test_base64_encoding_error() {
363 for (invalid_base64, want) in [
364 ("cm%uZG9taVo", "Invalid symbol 37, offset 2."),
365 ("cmFuZ", "Invalid input length: 5"),
366 ] {
367 assert!(Binary::from_base64(invalid_base64)
368 .unwrap_err()
369 .to_string()
370 .ends_with(want));
371 }
372 }
373
374 #[test]
375 fn from_slice_works() {
376 let original: &[u8] = &[0u8, 187, 61, 11, 250, 0];
377 let binary: Binary = original.into();
378 assert_eq!(binary.as_slice(), [0u8, 187, 61, 11, 250, 0]);
379 }
380
381 #[test]
382 fn from_fixed_length_array_works() {
383 let original = &[];
384 let binary: Binary = original.into();
385 assert_eq!(binary.len(), 0);
386
387 let original = &[0u8];
388 let binary: Binary = original.into();
389 assert_eq!(binary.as_slice(), [0u8]);
390
391 let original = &[0u8, 187, 61, 11, 250, 0];
392 let binary: Binary = original.into();
393 assert_eq!(binary.as_slice(), [0u8, 187, 61, 11, 250, 0]);
394
395 let original = &[
396 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,
397 1, 1, 1,
398 ];
399 let binary: Binary = original.into();
400 assert_eq!(
401 binary.as_slice(),
402 [
403 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,
404 1, 1, 1, 1,
405 ]
406 );
407 }
408
409 #[test]
410 fn from_owned_fixed_length_array_works() {
411 let original = [];
412 let binary: Binary = original.into();
413 assert_eq!(binary.len(), 0);
414
415 let original = [0u8];
416 let binary: Binary = original.into();
417 assert_eq!(binary.as_slice(), [0u8]);
418
419 let original = [0u8, 187, 61, 11, 250, 0];
420 let binary: Binary = original.into();
421 assert_eq!(binary.as_slice(), [0u8, 187, 61, 11, 250, 0]);
422
423 let original = [
424 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,
425 1, 1, 1,
426 ];
427 let binary: Binary = original.into();
428 assert_eq!(
429 binary.as_slice(),
430 [
431 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,
432 1, 1, 1, 1,
433 ]
434 );
435 }
436
437 #[test]
438 fn from_literal_works() {
439 let a: Binary = b"".into();
440 assert_eq!(a.len(), 0);
441
442 let a: Binary = b".".into();
443 assert_eq!(a.len(), 1);
444
445 let a: Binary = b"...".into();
446 assert_eq!(a.len(), 3);
447
448 let a: Binary = b"...............................".into();
449 assert_eq!(a.len(), 31);
450
451 let a: Binary = b"................................".into();
452 assert_eq!(a.len(), 32);
453
454 let a: Binary = b".................................".into();
455 assert_eq!(a.len(), 33);
456 }
457
458 #[test]
459 fn from_vec_works() {
460 let original = vec![0u8, 187, 61, 11, 250, 0];
461 let original_ptr = original.as_ptr();
462 let binary: Binary = original.into();
463 assert_eq!(binary.as_slice(), [0u8, 187, 61, 11, 250, 0]);
464 assert_eq!(binary.0.as_ptr(), original_ptr, "vector must not be copied");
465 }
466
467 #[test]
468 fn into_vec_works() {
469 let original = Binary(vec![0u8, 187, 61, 11, 250, 0]);
471 let original_ptr = original.0.as_ptr();
472 let vec: Vec<u8> = original.into();
473 assert_eq!(vec.as_slice(), [0u8, 187, 61, 11, 250, 0]);
474 assert_eq!(vec.as_ptr(), original_ptr, "vector must not be copied");
475
476 let original = Binary(vec![7u8, 35, 49, 101, 0, 255]);
478 let original_ptr = original.0.as_ptr();
479 let vec = Vec::<u8>::from(original);
480 assert_eq!(vec.as_slice(), [7u8, 35, 49, 101, 0, 255]);
481 assert_eq!(vec.as_ptr(), original_ptr, "vector must not be copied");
482 }
483
484 #[test]
485 fn json_serialization_works() {
486 let binary = Binary(vec![0u8, 187, 61, 11, 250, 0]);
487
488 let json = serde_json::to_vec(&binary).unwrap();
489 let deserialized: Binary = serde_json::from_slice(&json).unwrap();
490
491 assert_eq!(binary, deserialized);
492 }
493
494 #[test]
495 fn json_deserialize_from_valid_string() {
496 let b64_str = "ALs9C/oA";
497 let expected = vec![0u8, 187, 61, 11, 250, 0];
499
500 let serialized = serde_json::to_vec(&b64_str).unwrap();
501 let deserialized: Binary = serde_json::from_slice(&serialized).unwrap();
502 assert_eq!(expected, deserialized.as_slice());
503 }
504
505 #[test]
506 fn json_deserialize_from_invalid_string() {
507 let invalid_str = "**BAD!**";
508 let serialized = serde_json::to_vec(&invalid_str).unwrap();
509 let res = serde_json::from_slice::<Binary>(&serialized);
510 assert!(res.is_err());
511 }
512
513 #[test]
514 fn msgpack_serialization_works() {
515 let data = Binary(vec![0u8, 187, 61, 11, 250, 0]);
516 let expected = [196, 6, 0, 187, 61, 11, 250, 0];
518
519 assert_eq!(rmp_serde::to_vec(&data).unwrap(), expected);
520 }
521
522 #[test]
523 fn msgpack_deserialize_from_valid_data() {
524 let serialized = vec![196, 6, 0, 187, 61, 11, 250, 0];
526 let expected = vec![0u8, 187, 61, 11, 250, 0];
527
528 let deserialized: Binary = rmp_serde::from_slice(&serialized).unwrap();
529 assert_eq!(expected, deserialized.as_slice());
530 }
531
532 #[test]
533 fn msgpack_deserialize_from_invalid_data() {
534 let invalid_data = vec![0, 1, 2, 3, 4, 5];
535 let res = rmp_serde::from_slice::<Binary>(&invalid_data);
536 assert!(res.is_err());
537 }
538
539 #[test]
540 fn binary_implements_debug() {
541 let binary = Binary(vec![0x07, 0x35, 0xAA, 0xcb, 0x00, 0xff]);
543 assert_eq!(format!("{binary:?}"), "Binary(0735aacb00ff)",);
544
545 let binary = Binary(vec![]);
547 assert_eq!(format!("{binary:?}"), "Binary()",);
548 }
549
550 #[test]
551 fn binary_implements_deref() {
552 let binary = Binary(vec![7u8, 35, 49, 101, 0, 255]);
554 assert_eq!(*binary, [7u8, 35, 49, 101, 0, 255]);
555
556 let binary = Binary(vec![7u8, 35, 49, 101, 0, 255]);
558 assert_eq!(binary.len(), 6);
559 let binary_slice: &[u8] = &binary;
560 assert_eq!(binary_slice, &[7u8, 35, 49, 101, 0, 255]);
561 }
562
563 #[test]
564 fn binary_implements_as_ref() {
565 let want = &[7u8, 35, 49, 101, 0, 255];
566 let data = Binary(want.to_vec());
567 assert_eq!(want, AsRef::<[u8]>::as_ref(&data));
568 assert_eq!(want, AsRef::<[u8]>::as_ref(&&data));
569 }
570
571 #[test]
574 fn binary_implements_hash_eq() {
575 let a = Binary::from([0, 187, 61, 11, 250, 0]);
576 let b = Binary::from([16, 21, 33, 0, 255, 9]);
577 assert_hash_works!(a, b);
578 }
579
580 #[test]
581 fn binary_implements_partial_eq_with_vector() {
582 let a = Binary(vec![5u8; 3]);
583 let b = vec![5u8; 3];
584 let c = vec![9u8; 3];
585 assert_eq!(a, b);
586 assert_eq!(b, a);
587 assert_ne!(a, c);
588 assert_ne!(c, a);
589 }
590
591 #[test]
592 fn binary_implements_partial_eq_with_slice_and_array() {
593 let a = Binary(vec![0xAA, 0xBB]);
594
595 assert_eq!(a, b"\xAA\xBB" as &[u8]);
597 assert_eq!(b"\xAA\xBB" as &[u8], a);
598 assert_ne!(a, b"\x11\x22" as &[u8]);
599 assert_ne!(b"\x11\x22" as &[u8], a);
600
601 assert_eq!(a, b"\xAA\xBB");
603 assert_eq!(b"\xAA\xBB", a);
604 assert_ne!(a, b"\x11\x22");
605 assert_ne!(b"\x11\x22", a);
606
607 assert_eq!(a, [0xAA, 0xBB]);
609 assert_eq!([0xAA, 0xBB], a);
610 assert_ne!(a, [0x11, 0x22]);
611 assert_ne!([0x11, 0x22], a);
612 }
613
614 #[test]
615 fn hex_encoding_works() {
616 let hash = "722c8c993fd75a7627d69ed941344fe2a1423a3e75efd3e6778a142884227104";
617 let parsed = Binary::from_hex(hash).unwrap();
618 assert_eq!(parsed.to_hex(), hash);
619
620 let odd_num_of_digits = "722c8c993fd75a7627d69ed941344fe2a1423a3e75efd3e6778a142884227";
622 assert!(Binary::from_hex(odd_num_of_digits).is_err());
623 let invalid_char = "722c8c993fd75a7627d69ed941344fe2a1423a3e75efd3e6778a1428842271g4";
624 assert!(Binary::from_hex(invalid_char).is_err());
625 let hex_prefix_unexpected =
626 "0x722c8c993fd75a7627d69ed941344fe2a1423a3e75efd3e6778a142884227104";
627 assert!(Binary::from_hex(hex_prefix_unexpected).is_err());
628 }
629}