starknet_api/
serde_utils.rs1#[cfg(test)]
3#[path = "serde_utils_test.rs"]
4mod serde_utils_test;
5
6use serde::de::{Deserialize, Visitor};
7use serde::ser::{Serialize, SerializeTuple};
8use serde::Deserializer;
9
10use crate::deprecated_contract_class::ContractClassAbiEntry;
11
12pub type PrefixedBytesAsHex<const N: usize> = BytesAsHex<N, true>;
14
15#[derive(Debug, Eq, PartialEq)]
20pub struct BytesAsHex<const N: usize, const PREFIXED: bool>(pub(crate) [u8; N]);
21
22impl<'de, const N: usize, const PREFIXED: bool> Deserialize<'de> for BytesAsHex<N, PREFIXED> {
23 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
24 where
25 D: serde::Deserializer<'de>,
26 {
27 struct ByteArrayVisitor<const N: usize, const PREFIXED: bool>;
28 impl<'de, const N: usize, const PREFIXED: bool> Visitor<'de> for ByteArrayVisitor<N, PREFIXED> {
29 type Value = BytesAsHex<N, PREFIXED>;
30
31 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 formatter.write_str("a byte array")
33 }
34
35 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
36 where
37 A: serde::de::SeqAccess<'de>,
38 {
39 let mut res = [0u8; N];
40 let mut i = 0;
41 while let Some(value) = seq.next_element()? {
42 res[i] = value;
43 i += 1;
44 }
45 Ok(BytesAsHex(res))
46 }
47 }
48
49 if deserializer.is_human_readable() {
50 let s = String::deserialize(deserializer)?;
51 bytes_from_hex_str::<N, PREFIXED>(s.as_str())
52 .map_err(serde::de::Error::custom)
53 .map(BytesAsHex)
54 } else {
55 deserializer.deserialize_tuple(N, ByteArrayVisitor)
56 }
57 }
58}
59
60impl<const N: usize, const PREFIXED: bool> Serialize for BytesAsHex<N, PREFIXED> {
61 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
62 where
63 S: serde::Serializer,
64 {
65 if serializer.is_human_readable() {
66 let hex_str = hex_str_from_bytes::<N, PREFIXED>(self.0);
67 serializer.serialize_str(&hex_str)
68 } else {
69 let mut seq = serializer.serialize_tuple(N)?;
70 for element in &self.0[..] {
71 seq.serialize_element(element)?;
72 }
73 seq.end()
74 }
75 }
76}
77
78#[derive(thiserror::Error, Clone, Debug, PartialEq)]
88pub enum InnerDeserializationError {
89 #[error(transparent)]
91 FromHex(#[from] hex::FromHexError),
92 #[error("Missing prefix 0x in {hex_str}")]
94 MissingPrefix { hex_str: String },
95 #[error("Bad input - expected #bytes: {expected_byte_count}, string found: {string_found}.")]
97 BadInput { expected_byte_count: usize, string_found: String },
98}
99
100pub fn bytes_from_hex_str<const N: usize, const PREFIXED: bool>(
102 hex_str: &str,
103) -> Result<[u8; N], InnerDeserializationError> {
104 let hex_str = if PREFIXED {
105 hex_str
106 .strip_prefix("0x")
107 .ok_or(InnerDeserializationError::MissingPrefix { hex_str: hex_str.into() })?
108 } else {
109 hex_str
110 };
111
112 if hex_str.len() > 2 * N {
114 let mut err_str = "0x".to_owned();
115 err_str.push_str(hex_str);
116 return Err(InnerDeserializationError::BadInput {
117 expected_byte_count: N,
118 string_found: err_str,
119 });
120 }
121
122 let to_add = 2 * N - hex_str.len();
124 let padded_str = vec!["0"; to_add].join("") + hex_str;
125
126 Ok(hex::decode(padded_str)?.try_into().expect("Unexpected length of deserialized hex bytes."))
127}
128
129pub fn hex_str_from_bytes<const N: usize, const PREFIXED: bool>(bytes: [u8; N]) -> String {
131 let hex_str = hex::encode(bytes);
132 let mut hex_str = hex_str.trim_start_matches('0');
133 hex_str = if hex_str.is_empty() { "0" } else { hex_str };
134 if PREFIXED { format!("0x{hex_str}") } else { hex_str.to_string() }
135}
136
137pub fn deserialize_optional_contract_class_abi_entry_vector<'de, D>(
138 deserializer: D,
139) -> Result<Option<Vec<ContractClassAbiEntry>>, D::Error>
140where
141 D: Deserializer<'de>,
142{
143 let result: Result<Option<Vec<ContractClassAbiEntry>>, _> = Option::deserialize(deserializer);
145
146 match result {
148 Ok(value) => Ok(value),
149 Err(_) => Ok(None),
150 }
151}