1use std::fmt;
2use std::ops::Deref;
3
4use schemars::JsonSchema;
5use serde::{de, ser, Deserialize, Deserializer, Serialize};
6
7use crate::errors::{StdError, StdResult};
8
9#[derive(Clone, Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, JsonSchema)]
14pub struct Binary(#[schemars(with = "String")] pub Vec<u8>);
15
16impl Binary {
17 pub fn from_base64(encoded: &str) -> StdResult<Self> {
20 let binary = base64::decode(&encoded).map_err(StdError::invalid_base64)?;
21 Ok(Binary(binary))
22 }
23
24 pub fn to_base64(&self) -> String {
27 base64::encode(&self.0)
28 }
29
30 pub fn as_slice(&self) -> &[u8] {
31 self.0.as_slice()
32 }
33
34 pub fn to_array<const LENGTH: usize>(&self) -> StdResult<[u8; LENGTH]> {
62 if self.len() != LENGTH {
63 return Err(StdError::invalid_data_size(LENGTH, self.len()));
64 }
65
66 let mut out: [u8; LENGTH] = [0; LENGTH];
67 out.copy_from_slice(&self.0);
68 Ok(out)
69 }
70}
71
72impl fmt::Display for Binary {
73 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74 write!(f, "{}", self.to_base64())
75 }
76}
77
78impl From<&[u8]> for Binary {
79 fn from(binary: &[u8]) -> Self {
80 Self(binary.to_vec())
81 }
82}
83
84impl Deref for Binary {
90 type Target = [u8];
91
92 fn deref(&self) -> &Self::Target {
93 self.as_slice()
94 }
95}
96
97impl<const LENGTH: usize> From<&[u8; LENGTH]> for Binary {
99 fn from(source: &[u8; LENGTH]) -> Self {
100 Self(source.to_vec())
101 }
102}
103
104impl<const LENGTH: usize> From<[u8; LENGTH]> for Binary {
106 fn from(source: [u8; LENGTH]) -> Self {
107 Self(source.into())
108 }
109}
110
111impl From<Vec<u8>> for Binary {
112 fn from(vec: Vec<u8>) -> Self {
113 Self(vec)
114 }
115}
116
117impl From<Binary> for Vec<u8> {
118 fn from(original: Binary) -> Vec<u8> {
119 original.0
120 }
121}
122
123impl PartialEq<Vec<u8>> for Binary {
125 fn eq(&self, rhs: &Vec<u8>) -> bool {
126 self.0 == *rhs
128 }
129}
130
131impl PartialEq<Binary> for Vec<u8> {
133 fn eq(&self, rhs: &Binary) -> bool {
134 *self == rhs.0
136 }
137}
138
139impl PartialEq<&[u8]> for Binary {
141 fn eq(&self, rhs: &&[u8]) -> bool {
142 self.as_slice() == *rhs
144 }
145}
146
147impl PartialEq<Binary> for &[u8] {
149 fn eq(&self, rhs: &Binary) -> bool {
150 *self == rhs.as_slice()
152 }
153}
154
155impl Serialize for Binary {
157 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
158 where
159 S: ser::Serializer,
160 {
161 serializer.serialize_str(&self.to_base64())
162 }
163}
164
165impl<'de> Deserialize<'de> for Binary {
167 fn deserialize<D>(deserializer: D) -> Result<Binary, D::Error>
168 where
169 D: Deserializer<'de>,
170 {
171 deserializer.deserialize_str(Base64Visitor)
172 }
173}
174
175struct Base64Visitor;
176
177impl<'de> de::Visitor<'de> for Base64Visitor {
178 type Value = Binary;
179
180 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
181 formatter.write_str("valid base64 encoded string")
182 }
183
184 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
185 where
186 E: de::Error,
187 {
188 match Binary::from_base64(v) {
189 Ok(binary) => Ok(binary),
190 Err(_) => Err(E::custom(format!("invalid base64: {}", v))),
191 }
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198 use crate::errors::StdError;
199 use crate::serde::{from_slice, to_vec};
200 use std::collections::hash_map::DefaultHasher;
201 use std::collections::HashSet;
202 use std::hash::{Hash, Hasher};
203 use std::iter::FromIterator;
204
205 #[test]
206 fn encode_decode() {
207 let binary: &[u8] = b"hello";
208 let encoded = Binary::from(binary).to_base64();
209 assert_eq!(8, encoded.len());
210 let decoded = Binary::from_base64(&encoded).unwrap();
211 assert_eq!(binary, decoded.as_slice());
212 }
213
214 #[test]
215 fn encode_decode_non_ascii() {
216 let binary = vec![12u8, 187, 0, 17, 250, 1];
217 let encoded = Binary(binary.clone()).to_base64();
218 assert_eq!(8, encoded.len());
219 let decoded = Binary::from_base64(&encoded).unwrap();
220 assert_eq!(binary.deref(), decoded.deref());
221 }
222
223 #[test]
224 fn to_array_works() {
225 let binary = Binary::from(&[1, 2, 3]);
227 let array: [u8; 3] = binary.to_array().unwrap();
228 assert_eq!(array, [1, 2, 3]);
229
230 let binary = Binary::from(&[]);
232 let array: [u8; 0] = binary.to_array().unwrap();
233 assert_eq!(array, [] as [u8; 0]);
234
235 let binary = Binary::from(&[1, 2, 3]);
237 let error = binary.to_array::<8>().unwrap_err();
238 match error {
239 StdError::InvalidDataSize {
240 expected, actual, ..
241 } => {
242 assert_eq!(expected, 8);
243 assert_eq!(actual, 3);
244 }
245 err => panic!("Unexpected error: {:?}", err),
246 }
247
248 let binary = Binary::from_base64("t119JOQox4WUQEmO/nyqOZfO+wjJm91YG2sfn4ZglvA=").unwrap();
250 let array: [u8; 32] = binary.to_array().unwrap();
251 assert_eq!(
252 array,
253 [
254 0xb7, 0x5d, 0x7d, 0x24, 0xe4, 0x28, 0xc7, 0x85, 0x94, 0x40, 0x49, 0x8e, 0xfe, 0x7c,
255 0xaa, 0x39, 0x97, 0xce, 0xfb, 0x08, 0xc9, 0x9b, 0xdd, 0x58, 0x1b, 0x6b, 0x1f, 0x9f,
256 0x86, 0x60, 0x96, 0xf0,
257 ]
258 );
259
260 let binary =
262 Binary::from_base64("t119JOQox4WUQEmO/nyqOZfO+wjJm91YG2sfn4ZglvBzyMOwMWq+").unwrap();
263 let array: [u8; 39] = binary.to_array().unwrap();
264 assert_eq!(
265 array,
266 [
267 0xb7, 0x5d, 0x7d, 0x24, 0xe4, 0x28, 0xc7, 0x85, 0x94, 0x40, 0x49, 0x8e, 0xfe, 0x7c,
268 0xaa, 0x39, 0x97, 0xce, 0xfb, 0x08, 0xc9, 0x9b, 0xdd, 0x58, 0x1b, 0x6b, 0x1f, 0x9f,
269 0x86, 0x60, 0x96, 0xf0, 0x73, 0xc8, 0xc3, 0xb0, 0x31, 0x6a, 0xbe,
270 ]
271 );
272 }
273
274 #[test]
275 fn from_valid_string() {
276 let valid_base64 = "cmFuZG9taVo=";
277 let binary = Binary::from_base64(valid_base64).unwrap();
278 assert_eq!(b"randomiZ", binary.as_slice());
279 }
280
281 #[test]
283 fn from_shortened_string() {
284 let short = "cmFuZG9taVo";
285 let long = "cmFuZG9taVo=";
286 let binary = Binary::from_base64(short).unwrap();
287 assert_eq!(b"randomiZ", binary.as_slice());
288 assert_eq!(long, binary.to_base64());
289 }
290
291 #[test]
292 fn from_invalid_string() {
293 let invalid_base64 = "cm%uZG9taVo";
294 let res = Binary::from_base64(invalid_base64);
295 match res.unwrap_err() {
296 StdError::InvalidBase64 { msg, .. } => assert_eq!(msg, "Invalid byte 37, offset 2."),
297 _ => panic!("Unexpected error type"),
298 }
299 }
300
301 #[test]
302 fn from_slice_works() {
303 let original: &[u8] = &[0u8, 187, 61, 11, 250, 0];
304 let binary: Binary = original.into();
305 assert_eq!(binary.as_slice(), [0u8, 187, 61, 11, 250, 0]);
306 }
307
308 #[test]
309 fn from_fixed_length_array_works() {
310 let original = &[];
311 let binary: Binary = original.into();
312 assert_eq!(binary.len(), 0);
313
314 let original = &[0u8];
315 let binary: Binary = original.into();
316 assert_eq!(binary.as_slice(), [0u8]);
317
318 let original = &[0u8, 187, 61, 11, 250, 0];
319 let binary: Binary = original.into();
320 assert_eq!(binary.as_slice(), [0u8, 187, 61, 11, 250, 0]);
321
322 let original = &[
323 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,
324 1, 1, 1,
325 ];
326 let binary: Binary = original.into();
327 assert_eq!(
328 binary.as_slice(),
329 [
330 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,
331 1, 1, 1, 1,
332 ]
333 );
334 }
335
336 #[test]
337 fn from_owned_fixed_length_array_works() {
338 let original = [];
339 let binary: Binary = original.into();
340 assert_eq!(binary.len(), 0);
341
342 let original = [0u8];
343 let binary: Binary = original.into();
344 assert_eq!(binary.as_slice(), [0u8]);
345
346 let original = [0u8, 187, 61, 11, 250, 0];
347 let binary: Binary = original.into();
348 assert_eq!(binary.as_slice(), [0u8, 187, 61, 11, 250, 0]);
349
350 let original = [
351 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,
352 1, 1, 1,
353 ];
354 let binary: Binary = original.into();
355 assert_eq!(
356 binary.as_slice(),
357 [
358 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,
359 1, 1, 1, 1,
360 ]
361 );
362 }
363
364 #[test]
365 fn from_literal_works() {
366 let a: Binary = b"".into();
367 assert_eq!(a.len(), 0);
368
369 let a: Binary = b".".into();
370 assert_eq!(a.len(), 1);
371
372 let a: Binary = b"...".into();
373 assert_eq!(a.len(), 3);
374
375 let a: Binary = b"...............................".into();
376 assert_eq!(a.len(), 31);
377
378 let a: Binary = b"................................".into();
379 assert_eq!(a.len(), 32);
380
381 let a: Binary = (b"................................." as &[u8]).into();
383 assert_eq!(a.len(), 33);
384 }
385
386 #[test]
387 fn from_vec_works() {
388 let original = vec![0u8, 187, 61, 11, 250, 0];
389 let original_ptr = original.as_ptr();
390 let binary: Binary = original.into();
391 assert_eq!(binary.as_slice(), [0u8, 187, 61, 11, 250, 0]);
392 assert_eq!(binary.0.as_ptr(), original_ptr, "vector must not be copied");
393 }
394
395 #[test]
396 fn into_vec_works() {
397 let original = Binary(vec![0u8, 187, 61, 11, 250, 0]);
399 let original_ptr = original.0.as_ptr();
400 let vec: Vec<u8> = original.into();
401 assert_eq!(vec.as_slice(), [0u8, 187, 61, 11, 250, 0]);
402 assert_eq!(vec.as_ptr(), original_ptr, "vector must not be copied");
403
404 let original = Binary(vec![7u8, 35, 49, 101, 0, 255]);
406 let original_ptr = original.0.as_ptr();
407 let vec = Vec::<u8>::from(original);
408 assert_eq!(vec.as_slice(), [7u8, 35, 49, 101, 0, 255]);
409 assert_eq!(vec.as_ptr(), original_ptr, "vector must not be copied");
410 }
411
412 #[test]
413 fn serialization_works() {
414 let binary = Binary(vec![0u8, 187, 61, 11, 250, 0]);
415
416 let json = to_vec(&binary).unwrap();
417 let deserialized: Binary = from_slice(&json).unwrap();
418
419 assert_eq!(binary, deserialized);
420 }
421
422 #[test]
423 fn deserialize_from_valid_string() {
424 let b64_str = "ALs9C/oA";
425 let expected = vec![0u8, 187, 61, 11, 250, 0];
427
428 let serialized = to_vec(&b64_str).unwrap();
429 let deserialized: Binary = from_slice(&serialized).unwrap();
430 assert_eq!(expected, deserialized.as_slice());
431 }
432
433 #[test]
434 fn deserialize_from_invalid_string() {
435 let invalid_str = "**BAD!**";
436 let serialized = to_vec(&invalid_str).unwrap();
437 let res = from_slice::<Binary>(&serialized);
438 assert!(res.is_err());
439 }
440
441 #[test]
442 fn binary_implements_deref() {
443 let binary = Binary(vec![7u8, 35, 49, 101, 0, 255]);
445 assert_eq!(*binary, [7u8, 35, 49, 101, 0, 255]);
446
447 let binary = Binary(vec![7u8, 35, 49, 101, 0, 255]);
449 assert_eq!(binary.len(), 6);
450 let binary_slice: &[u8] = &binary;
451 assert_eq!(binary_slice, &[7u8, 35, 49, 101, 0, 255]);
452 }
453
454 #[test]
455 fn binary_implements_hash() {
456 let a1 = Binary::from([0, 187, 61, 11, 250, 0]);
457 let mut hasher = DefaultHasher::new();
458 a1.hash(&mut hasher);
459 let a1_hash = hasher.finish();
460
461 let a2 = Binary::from([0, 187, 61, 11, 250, 0]);
462 let mut hasher = DefaultHasher::new();
463 a2.hash(&mut hasher);
464 let a2_hash = hasher.finish();
465
466 let b = Binary::from([16, 21, 33, 0, 255, 9]);
467 let mut hasher = DefaultHasher::new();
468 b.hash(&mut hasher);
469 let b_hash = hasher.finish();
470
471 assert_eq!(a1_hash, a2_hash);
472 assert_ne!(a1_hash, b_hash);
473 }
474
475 #[test]
477 fn binary_can_be_used_in_hash_set() {
478 let a1 = Binary::from([0, 187, 61, 11, 250, 0]);
479 let a2 = Binary::from([0, 187, 61, 11, 250, 0]);
480 let b = Binary::from([16, 21, 33, 0, 255, 9]);
481
482 let mut set = HashSet::new();
483 set.insert(a1.clone());
484 set.insert(a2.clone());
485 set.insert(b.clone());
486 assert_eq!(set.len(), 2);
487
488 let set1 = HashSet::<Binary>::from_iter(vec![b.clone(), a1.clone()]);
489 let set2 = HashSet::from_iter(vec![a1, a2, b]);
490 assert_eq!(set1, set2);
491 }
492
493 #[test]
494 fn binary_implements_partial_eq_with_vector() {
495 let a = Binary(vec![5u8; 3]);
496 let b = vec![5u8; 3];
497 let c = vec![9u8; 3];
498 assert_eq!(a, b);
499 assert_eq!(b, a);
500 assert_ne!(a, c);
501 assert_ne!(c, a);
502 }
503
504 #[test]
505 fn binary_implements_partial_eq_with_slice() {
506 let a = Binary(vec![0xAA, 0xBB]);
507 assert_eq!(a, b"\xAA\xBB" as &[u8]);
508 assert_eq!(b"\xAA\xBB" as &[u8], a);
509 assert_ne!(a, b"\x11\x22" as &[u8]);
510 assert_ne!(b"\x11\x22" as &[u8], a);
511 }
512}