1use serde::de::Visitor;
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3use std::convert::TryFrom;
4
5#[derive(Clone, Debug, PartialEq, Default)]
7pub struct Bytes(pub Vec<u8>);
8
9impl Bytes {
10 pub fn from_slice(slice: &[u8]) -> Self {
11 Bytes(slice.to_vec())
12 }
13}
14
15impl TryFrom<&str> for Bytes {
16 type Error = String;
17
18 fn try_from(value: &str) -> Result<Self, Self::Error> {
19 let trimmed = value.trim_start_matches("0x");
20 let length = trimmed.len();
21 let end = if length % 2 == 0 {
22 length / 2
23 } else {
24 length / 2 + 1
25 };
26 let mut data = Vec::<u8>::with_capacity(end);
27 let mut trimmed_chars = trimmed.chars();
28 for _ in 0..end {
29 let first = trimmed_chars
30 .next()
31 .unwrap()
32 .to_digit(16)
33 .ok_or_else(|| String::from("invalid digit found in string"))?;
34 let second = if let Some(sec) = trimmed_chars.next() {
35 sec.to_digit(16)
36 .ok_or_else(|| String::from("invalid digit found in string"))?
37 } else {
38 0
39 };
40 data.push((first * 16 + second) as u8)
41 }
42 Ok(Self(data))
43 }
44}
45
46impl std::fmt::Display for Bytes {
47 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 write!(
49 formatter,
50 "0x{}",
51 self.0
52 .iter()
53 .map(|b| format!("{:02x}", b))
54 .collect::<Vec<String>>()
55 .join("")
56 )
57 }
58}
59
60impl Serialize for Bytes {
61 fn serialize<T: Serializer>(&self, serializer: T) -> Result<T::Ok, T::Error> {
62 serializer.serialize_str(&self.to_string())
63 }
64}
65
66impl<'de> Deserialize<'de> for Bytes {
67 fn deserialize<T>(deserializer: T) -> Result<Bytes, T::Error>
68 where
69 T: Deserializer<'de>,
70 {
71 deserializer.deserialize_identifier(BytesVisitor)
72 }
73}
74
75struct BytesVisitor;
76
77impl<'de> Visitor<'de> for BytesVisitor {
78 type Value = Bytes;
79
80 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
81 write!(f, "a hex string")
82 }
83
84 fn visit_str<T: serde::de::Error>(self, value: &str) -> Result<Self::Value, T> {
85 let result = Self::Value::try_from(value)
86 .map_err(|err| serde::de::Error::custom(format!("Invalid hex string: {}", err)))?;
87 Ok(result)
88 }
89
90 fn visit_string<T: serde::de::Error>(self, value: String) -> Result<Self::Value, T> {
91 self.visit_str(&value)
92 }
93}
94
95#[test]
96fn test_bytes() {
97 let bytes_0 = Bytes::from_slice(&[]);
98 let bytes_1 = Bytes::from_slice(&[0, 0]);
99 let bytes_2 = Bytes::from_slice(&[17, 234]);
100 let bytes_3 = Bytes::try_from("0x").unwrap();
101 let bytes_4 = Bytes::try_from("0x00").unwrap();
102 let bytes_5 = Bytes::try_from("00421100").unwrap();
103
104 let expected_0 = "0x";
105 let expected_1 = "0x0000";
106 let expected_2 = "0x11ea";
107 let expected_3 = Bytes(vec![]);
108 let expected_4 = Bytes(vec![0]);
109 let expected_5 = Bytes(vec![0, 66, 17, 0]);
110
111 serde_test::assert_tokens(&bytes_0, &[serde_test::Token::BorrowedStr(expected_0)]);
112 serde_test::assert_tokens(&bytes_1, &[serde_test::Token::BorrowedStr(expected_1)]);
113 serde_test::assert_tokens(&bytes_2, &[serde_test::Token::BorrowedStr(expected_2)]);
114 assert_eq!(bytes_3, expected_3);
115 assert_eq!(bytes_4, expected_4);
116 assert_eq!(bytes_5, expected_5);
117}