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