defuse_serde_utils/
hex.rs1pub use serde_with::formats::{Format, Lowercase, Uppercase};
2
3use derive_more::From;
4use near_sdk::serde::{Deserialize, Serialize};
5use serde_with::serde_as;
6
7#[cfg_attr(
10 all(feature = "abi", not(target_arch = "wasm32")),
11 serde_as(schemars = true),
12 derive(::near_sdk::schemars::JsonSchema),
13 schemars(crate = "::near_sdk::schemars", transparent)
14)]
15#[cfg_attr(
16 not(all(feature = "abi", not(target_arch = "wasm32"))),
17 serde_as(schemars = false)
18)]
19#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, From)]
20#[serde(
21 crate = "::near_sdk::serde",
22 bound(serialize = "T: AsRef<[u8]>", deserialize = "T: TryFrom<Vec<u8>>")
23)]
24pub struct AsHex<T>(#[serde_as(as = "::serde_with::hex::Hex")] pub T);
25
26impl<T> AsHex<T> {
27 #[inline]
28 pub fn into_inner(self) -> T {
29 self.0
30 }
31}
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36 use near_sdk::serde_json;
37
38 #[test]
39 fn serialize_vec() {
40 let val = AsHex(vec![0xde, 0xad, 0xbe, 0xef]);
41 let json = serde_json::to_string(&val).unwrap();
42 assert_eq!(json, r#""deadbeef""#);
43 }
44
45 #[test]
46 fn deserialize_vec() {
47 let val: AsHex<Vec<u8>> = serde_json::from_str(r#""deadbeef""#).unwrap();
48 assert_eq!(val.0, vec![0xde, 0xad, 0xbe, 0xef]);
49 }
50
51 #[test]
52 fn roundtrip_vec() {
53 let original = vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
54 let wrapped = AsHex(original.clone());
55 let json = serde_json::to_string(&wrapped).unwrap();
56 let recovered: AsHex<Vec<u8>> = serde_json::from_str(&json).unwrap();
57 assert_eq!(recovered.0, original);
58 }
59
60 #[test]
61 fn serialize_fixed_array() {
62 let val = AsHex([0xff, 0x00, 0xab]);
63 let json = serde_json::to_string(&val).unwrap();
64 assert_eq!(json, r#""ff00ab""#);
65 }
66
67 #[test]
68 fn deserialize_fixed_array() {
69 let val: AsHex<[u8; 3]> = serde_json::from_str(r#""ff00ab""#).unwrap();
70 assert_eq!(val.0, [0xff, 0x00, 0xab]);
71 }
72
73 #[test]
74 fn empty_bytes() {
75 let val = AsHex(Vec::<u8>::new());
76 let json = serde_json::to_string(&val).unwrap();
77 assert_eq!(json, r#""""#);
78
79 let recovered: AsHex<Vec<u8>> = serde_json::from_str(&json).unwrap();
80 assert!(recovered.0.is_empty());
81 }
82
83 #[test]
84 fn into_inner() {
85 let data = vec![1, 2, 3];
86 let wrapped = AsHex(data.clone());
87 assert_eq!(wrapped.into_inner(), data);
88 }
89
90 #[test]
91 fn from_impl() {
92 let data = vec![1, 2, 3];
93 let wrapped: AsHex<Vec<u8>> = data.clone().into();
94 assert_eq!(wrapped.0, data);
95 }
96
97 #[test]
98 fn deserialize_uppercase_input() {
99 let val: AsHex<Vec<u8>> = serde_json::from_str(r#""DEADBEEF""#).unwrap();
100 assert_eq!(val.0, vec![0xde, 0xad, 0xbe, 0xef]);
101 }
102
103 #[test]
104 fn deserialize_mixed_case_input() {
105 let val: AsHex<Vec<u8>> = serde_json::from_str(r#""DeAdBeEf""#).unwrap();
106 assert_eq!(val.0, vec![0xde, 0xad, 0xbe, 0xef]);
107 }
108
109 #[test]
110 fn deserialize_invalid_hex() {
111 let result = serde_json::from_str::<AsHex<Vec<u8>>>(r#""xyz""#);
112 assert!(result.is_err());
113 }
114
115 #[test]
116 fn deserialize_odd_length() {
117 let result = serde_json::from_str::<AsHex<Vec<u8>>>(r#""abc""#);
118 assert!(result.is_err());
119 }
120
121 #[test]
122 fn deserialize_wrong_length_for_fixed_array() {
123 let result = serde_json::from_str::<AsHex<[u8; 4]>>(r#""deadbeefaa""#);
124 assert!(result.is_err());
125 }
126}