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