sz_rust_core/json/
simd_safe.rs1use serde::de::DeserializeOwned;
13use thiserror::Error;
14
15#[derive(Debug, Error)]
17pub enum JsonError {
18 #[error("JSON parse error: {0}")]
20 Parse(String),
21 #[error("simd-json not available on this platform")]
23 Unsupported,
24}
25
26impl From<serde_json::Error> for JsonError {
27 fn from(e: serde_json::Error) -> Self {
28 JsonError::Parse(e.to_string())
29 }
30}
31
32pub fn from_str<T: DeserializeOwned>(s: &str) -> Result<T, JsonError> {
36 #[cfg(all(target_arch = "x86_64", feature = "simd-json"))]
37 {
38 simd_json_from_str(s)
39 }
40
41 #[cfg(not(all(target_arch = "x86_64", feature = "simd-json")))]
42 {
43 serde_json::from_str(s).map_err(JsonError::from)
44 }
45}
46
47#[cfg(all(target_arch = "x86_64", feature = "simd-json"))]
48fn simd_json_from_str<T: DeserializeOwned>(s: &str) -> Result<T, JsonError> {
49 let mut bytes = s.as_bytes().to_vec();
51 simd_json::from_slice(&mut bytes).map_err(|e| JsonError::Parse(e.to_string()))
52}
53
54pub fn from_slice<T: DeserializeOwned>(s: &[u8]) -> Result<T, JsonError> {
58 #[cfg(all(target_arch = "x86_64", feature = "simd-json"))]
59 {
60 let mut bytes = s.to_vec();
61 simd_json::from_slice(&mut bytes).map_err(|e| JsonError::Parse(e.to_string()))
62 }
63
64 #[cfg(not(all(target_arch = "x86_64", feature = "simd-json")))]
65 {
66 serde_json::from_slice(s).map_err(JsonError::from)
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73 use serde::Deserialize;
74
75 #[derive(Debug, Deserialize, PartialEq)]
76 struct MediumDto {
77 code: i64,
78 msg: String,
79 data: MediumData,
80 }
81
82 #[derive(Debug, Deserialize, PartialEq)]
83 struct MediumData {
84 id: i64,
85 name: String,
86 items: Vec<i64>,
87 }
88
89 #[test]
90 fn test_simd_safe_deserialize_medium() {
91 let json = r#"{"code":200,"msg":"ok","data":{"id":1,"name":"test","items":[1,2,3]}}"#;
92 let result: MediumDto = from_str(json).unwrap();
93 assert_eq!(result.code, 200);
94 assert_eq!(result.msg, "ok");
95 assert_eq!(result.data.id, 1);
96 assert_eq!(result.data.name, "test");
97 assert_eq!(result.data.items, vec![1, 2, 3]);
98 }
99
100 #[test]
101 fn test_simd_safe_deserialize_small() {
102 let json = r#"{"code":200,"msg":"ok"}"#;
103 #[derive(Debug, Deserialize, PartialEq)]
104 struct SmallDto {
105 code: i64,
106 msg: String,
107 }
108 let result: SmallDto = from_str(json).unwrap();
109 assert_eq!(result.code, 200);
110 assert_eq!(result.msg, "ok");
111 }
112
113 #[test]
114 fn test_simd_safe_skip_serializing() {
115 let json = r#"{"code":200,"msg":"ok"}"#;
117 #[derive(Debug, serde::Deserialize, serde::Serialize, PartialEq)]
118 struct DtoWithSensitive {
119 code: i64,
120 msg: String,
121 #[serde(skip_serializing)]
122 secret: Option<String>,
123 }
124 let result: DtoWithSensitive = from_str(json).unwrap();
125 assert_eq!(result.code, 200);
126 assert_eq!(result.msg, "ok");
127 assert_eq!(result.secret, None);
128
129 let serialized = serde_json::to_string(&result).unwrap();
131 assert!(!serialized.contains("secret"));
132 }
133
134 #[test]
135 fn test_simd_safe_error_mapping() {
136 let result: Result<i64, _> = from_str("invalid json");
137 assert!(result.is_err());
138 match result.unwrap_err() {
139 JsonError::Parse(_) => {}
140 JsonError::Unsupported => panic!("should be Parse error"),
141 }
142 }
143
144 #[test]
145 fn test_simd_safe_from_slice() {
146 let json = br#"{"code":200,"msg":"ok"}"#;
147 #[derive(Debug, Deserialize, PartialEq)]
148 struct SmallDto {
149 code: i64,
150 msg: String,
151 }
152 let result: SmallDto = from_slice(json).unwrap();
153 assert_eq!(result.code, 200);
154 assert_eq!(result.msg, "ok");
155 }
156}