Skip to main content

sz_rust_core/json/
simd_safe.rs

1//! simd-json 安全封装层
2//!
3//! 在 x86_64 平台使用 `simd_json::from_str` 加速 JSON 反序列化(2-3x),
4//! 其他平台自动回退到 `serde_json::from_str`。
5//!
6//! # 安全保证
7//!
8//! - 不暴露 simd-json 内部 unsafe 到公开 API
9//! - 脱敏语义保持:`#[serde(skip_serializing)]` 不受影响(序列化仍用 serde_json)
10//! - 错误类型统一映射为 `JsonError`
11
12use serde::de::DeserializeOwned;
13use thiserror::Error;
14
15/// JSON 解析错误
16#[derive(Debug, Error)]
17pub enum JsonError {
18    /// 解析错误
19    #[error("JSON parse error: {0}")]
20    Parse(String),
21    /// SIMD JSON 不支持此平台
22    #[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
32/// 从字符串反序列化 JSON
33///
34/// x86_64 平台使用 simd-json 加速,其他平台回退到 serde_json。
35pub 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    // simd_json 需要 mutable 的输入,所以先复制到 Vec<u8>
50    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
54/// 从字节切片反序列化 JSON
55///
56/// x86_64 平台使用 simd-json 加速,其他平台回退到 serde_json。
57pub 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        // 脱敏字段在序列化时跳过(serde_json 控制),反序列化时不影响
116        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        // 序列化时 secret 不出现
130        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}