rusty_common/
json.rs

1//! JSON parsing utilities with performance optimizations
2//!
3//! This module provides a unified interface for JSON parsing using simd-json
4//! for maximum performance in HFT applications.
5
6use crate::SmartString;
7use crate::error::CommonError;
8use serde::{Deserialize, Serialize};
9
10/// Parse JSON from a string slice using simd-json
11///
12/// Use this for general-purpose JSON parsing
13#[inline]
14pub fn parse<T>(s: &str) -> Result<T, CommonError>
15where
16    T: for<'de> Deserialize<'de>,
17{
18    // Note: simd-json requires mutable input, so we need to create a mutable copy
19    let mut owned_str = s.to_owned();
20    // SAFETY: We own the string so it's safe to mutate it
21    unsafe {
22        simd_json::serde::from_str(&mut owned_str)
23            .map_err(|e| CommonError::Parse(format!("JSON parse error: {e}").into()))
24    }
25}
26
27/// Parse JSON from bytes using simd-json
28#[inline]
29pub fn parse_slice<T>(s: &[u8]) -> Result<T, CommonError>
30where
31    T: for<'de> Deserialize<'de>,
32{
33    // Note: simd-json requires mutable input, so we need to create a mutable copy
34    let mut owned_bytes = s.to_vec();
35    simd_json::serde::from_slice(&mut owned_bytes)
36        .map_err(|e| CommonError::Parse(format!("JSON parse error: {e}").into()))
37}
38
39/// Serialize to JSON SmartString using simd-json
40#[inline]
41pub fn to_smartstring<T>(value: &T) -> Result<SmartString, CommonError>
42where
43    T: Serialize,
44{
45    simd_json::serde::to_string(value)
46        .map(|s| s.into())
47        .map_err(|e| CommonError::Parse(format!("JSON serialize error: {e}").into()))
48}
49
50/// High-performance JSON parsing using simd-json
51///
52/// SAFETY: This function modifies the input string buffer for performance.
53/// Only use this when you own the string and don't need it afterwards.
54#[inline]
55pub fn parse_fast<T>(s: &mut str) -> Result<T, CommonError>
56where
57    T: for<'de> Deserialize<'de>,
58{
59    // SAFETY: simd_json requires mutable access to the string for in-place parsing
60    // The caller must ensure the string is not used after this call
61    unsafe {
62        simd_json::serde::from_str(s)
63            .map_err(|e| CommonError::Parse(format!("Fast JSON parse error: {e}").into()))
64    }
65}
66
67/// High-performance JSON parsing from owned SmartString
68///
69/// This is the preferred method for parsing market data messages
70#[inline]
71pub fn parse_fast_owned<T>(s: SmartString) -> Result<T, CommonError>
72where
73    T: for<'de> Deserialize<'de>,
74{
75    // Convert SmartString to String for simd_json parsing
76    // simd_json requires mutable access to the string buffer
77    let mut owned_string = s.to_string();
78    // SAFETY: We own the string so it's safe to mutate it
79    unsafe {
80        simd_json::serde::from_str(&mut owned_string)
81            .map_err(|e| CommonError::Parse(format!("Fast JSON parse error: {e}").into()))
82    }
83}
84
85/// High-performance JSON parsing from mutable byte slice
86///
87/// SAFETY: This function modifies the input byte buffer for performance.
88#[inline]
89pub fn parse_fast_slice<T>(s: &mut [u8]) -> Result<T, CommonError>
90where
91    T: for<'de> Deserialize<'de>,
92{
93    simd_json::serde::from_slice(s)
94        .map_err(|e| CommonError::Parse(format!("Fast JSON parse error: {e}").into()))
95}
96
97/// High-performance JSON parsing from owned Vec<u8>
98#[inline]
99pub fn parse_fast_vec<T>(mut v: Vec<u8>) -> Result<T, CommonError>
100where
101    T: for<'de> Deserialize<'de>,
102{
103    simd_json::serde::from_slice(&mut v)
104        .map_err(|e| CommonError::Parse(format!("Fast JSON parse error: {e}").into()))
105}
106
107/// Parse JSON from borrowed bytes with temporary allocation
108///
109/// Use this when you have borrowed bytes that need to be parsed but can't be mutated.
110/// This creates a temporary copy for parsing.
111#[inline]
112pub fn parse_bytes<T>(bytes: &[u8]) -> Result<T, CommonError>
113where
114    T: for<'de> Deserialize<'de>,
115{
116    let mut owned_bytes = bytes.to_vec();
117    simd_json::serde::from_slice(&mut owned_bytes)
118        .map_err(|e| CommonError::Parse(format!("JSON parse error: {e}").into()))
119}
120
121/// Deserialize from a JSON Value using simd-json
122#[inline]
123pub fn from_value<T>(value: Value) -> Result<T, CommonError>
124where
125    T: for<'de> Deserialize<'de>,
126{
127    simd_json::serde::from_owned_value(value)
128        .map_err(|e| CommonError::Parse(format!("JSON value deserialize error: {e}").into()))
129}
130
131// Re-export common JSON types for convenience
132pub use simd_json::{BorrowedValue, OwnedValue as Value, json};
133// For compatibility with simd_json API
134/// A type alias for `BTreeMap` for compatibility with `simd-json`.
135pub type Map<K, V> = std::collections::BTreeMap<K, V>;
136
137/// Zero-copy JSON parsing using borrowed data
138///
139/// This is the most efficient parsing method for hot paths when you can work with borrowed data.
140/// The lifetime 'a is tied to the input buffer.
141#[inline]
142pub fn parse_zerocopy<'a, T>(buffer: &'a mut [u8]) -> Result<T, CommonError>
143where
144    T: Deserialize<'a>,
145{
146    simd_json::serde::from_slice(buffer)
147        .map_err(|e| CommonError::Parse(format!("Zero-copy JSON parse error: {e}").into()))
148}
149
150/// Zero-copy JSON parsing to borrowed value
151///
152/// This returns a BorrowedValue that references the input buffer.
153/// Use this when you need to inspect JSON structure without deserializing to a concrete type.
154#[inline]
155pub fn parse_to_borrowed_value(buffer: &mut [u8]) -> Result<BorrowedValue<'_>, CommonError> {
156    simd_json::to_borrowed_value(buffer)
157        .map_err(|e| CommonError::Parse(format!("Zero-copy value parse error: {e}").into()))
158}
159
160/// High-performance JSON parsing with pooled buffers
161///
162/// This function is designed to work with the memory pool infrastructure.
163/// It parses JSON from the provided slice into the output buffer.
164#[inline]
165pub fn parse_with_buffer<'a, T>(input: &[u8], output_buffer: &'a mut [u8]) -> Result<T, CommonError>
166where
167    T: Deserialize<'a>,
168{
169    // Copy input to output buffer
170    let len = input.len().min(output_buffer.len());
171    output_buffer[..len].copy_from_slice(&input[..len]);
172
173    // Parse from the output buffer
174    simd_json::serde::from_slice(&mut output_buffer[..len])
175        .map_err(|e| CommonError::Parse(format!("Buffered JSON parse error: {e}").into()))
176}
177
178#[cfg(test)]
179mod tests {
180    use super::*;
181    use serde::{Deserialize, Serialize};
182
183    #[derive(Debug, PartialEq, Serialize, Deserialize)]
184    struct TestStruct {
185        name: SmartString,
186        value: i32,
187    }
188
189    #[test]
190    fn test_standard_parsing() {
191        let json = r#"{"name":"test","value":42}"#;
192        let result: TestStruct = parse(json).unwrap();
193        assert_eq!(result.name, "test");
194        assert_eq!(result.value, 42);
195    }
196
197    #[test]
198    fn test_fast_parsing() {
199        let json = SmartString::from(r#"{"name":"test","value":42}"#);
200        let result: TestStruct = parse_fast_owned(json).unwrap();
201        assert_eq!(result.name, "test");
202        assert_eq!(result.value, 42);
203    }
204
205    #[test]
206    fn test_serialization() {
207        let test = TestStruct {
208            name: "test".into(),
209            value: 42,
210        };
211        let json = to_smartstring(&test).unwrap();
212        assert!(json.contains("\"name\":\"test\""));
213        assert!(json.contains("\"value\":42"));
214    }
215
216    #[test]
217    fn test_parse_bytes() {
218        let json_bytes = br#"{"name":"test","value":42}"#;
219        let result: TestStruct = parse_bytes(json_bytes).unwrap();
220        assert_eq!(result.name, "test");
221        assert_eq!(result.value, 42);
222    }
223
224    #[test]
225    fn test_parse_fast_vec() {
226        let json_vec = br#"{"name":"test","value":42}"#.to_vec();
227        let result: TestStruct = parse_fast_vec(json_vec).unwrap();
228        assert_eq!(result.name, "test");
229        assert_eq!(result.value, 42);
230    }
231}