rustapi_core/
json.rs

1//! JSON utilities with optional SIMD acceleration
2//!
3//! This module provides JSON parsing and serialization utilities that can use
4//! SIMD-accelerated parsing when the `simd-json` feature is enabled.
5//!
6//! # Performance
7//!
8//! When the `simd-json` feature is enabled, JSON parsing can be 2-4x faster
9//! for large payloads. This is particularly beneficial for API servers that
10//! handle large JSON request bodies.
11//!
12//! # Usage
13//!
14//! The module provides drop-in replacements for `serde_json` functions:
15//!
16//! ```rust,ignore
17//! use rustapi_core::json;
18//!
19//! // Deserialize from bytes (uses simd-json if available)
20//! let value: MyStruct = json::from_slice(&bytes)?;
21//!
22//! // Serialize to bytes
23//! let bytes = json::to_vec(&value)?;
24//! ```
25
26use serde::{de::DeserializeOwned, Serialize};
27
28/// Deserialize JSON from a byte slice.
29///
30/// When the `simd-json` feature is enabled, this uses SIMD-accelerated parsing.
31/// Otherwise, it falls back to standard `serde_json`.
32#[cfg(feature = "simd-json")]
33pub fn from_slice<T: DeserializeOwned>(slice: &[u8]) -> Result<T, JsonError> {
34    // simd-json requires mutable access for in-place parsing
35    let mut slice_copy = slice.to_vec();
36    simd_json::from_slice(&mut slice_copy).map_err(JsonError::SimdJson)
37}
38
39/// Deserialize JSON from a byte slice.
40///
41/// Standard `serde_json` implementation when `simd-json` feature is disabled.
42#[cfg(not(feature = "simd-json"))]
43pub fn from_slice<T: DeserializeOwned>(slice: &[u8]) -> Result<T, JsonError> {
44    serde_json::from_slice(slice).map_err(JsonError::SerdeJson)
45}
46
47/// Deserialize JSON from a mutable byte slice (zero-copy with simd-json).
48///
49/// This variant allows simd-json to parse in-place without copying,
50/// providing maximum performance.
51#[cfg(feature = "simd-json")]
52pub fn from_slice_mut<T: DeserializeOwned>(slice: &mut [u8]) -> Result<T, JsonError> {
53    simd_json::from_slice(slice).map_err(JsonError::SimdJson)
54}
55
56/// Deserialize JSON from a mutable byte slice.
57///
58/// Falls back to standard implementation when simd-json is disabled.
59#[cfg(not(feature = "simd-json"))]
60pub fn from_slice_mut<T: DeserializeOwned>(slice: &mut [u8]) -> Result<T, JsonError> {
61    serde_json::from_slice(slice).map_err(JsonError::SerdeJson)
62}
63
64/// Serialize a value to a JSON byte vector.
65///
66/// Uses pre-allocated buffer with estimated capacity for better performance.
67pub fn to_vec<T: Serialize>(value: &T) -> Result<Vec<u8>, JsonError> {
68    serde_json::to_vec(value).map_err(JsonError::SerdeJson)
69}
70
71/// Serialize a value to a JSON byte vector with pre-allocated capacity.
72///
73/// Use this when you have a good estimate of the output size to avoid
74/// reallocations.
75pub fn to_vec_with_capacity<T: Serialize>(
76    value: &T,
77    capacity: usize,
78) -> Result<Vec<u8>, JsonError> {
79    let mut buf = Vec::with_capacity(capacity);
80    serde_json::to_writer(&mut buf, value).map_err(JsonError::SerdeJson)?;
81    Ok(buf)
82}
83
84/// Serialize a value to a pretty-printed JSON byte vector.
85pub fn to_vec_pretty<T: Serialize>(value: &T) -> Result<Vec<u8>, JsonError> {
86    serde_json::to_vec_pretty(value).map_err(JsonError::SerdeJson)
87}
88
89/// JSON error type that wraps both serde_json and simd-json errors.
90#[derive(Debug)]
91pub enum JsonError {
92    SerdeJson(serde_json::Error),
93    #[cfg(feature = "simd-json")]
94    SimdJson(simd_json::Error),
95}
96
97impl std::fmt::Display for JsonError {
98    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99        match self {
100            JsonError::SerdeJson(e) => write!(f, "{}", e),
101            #[cfg(feature = "simd-json")]
102            JsonError::SimdJson(e) => write!(f, "{}", e),
103        }
104    }
105}
106
107impl std::error::Error for JsonError {
108    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
109        match self {
110            JsonError::SerdeJson(e) => Some(e),
111            #[cfg(feature = "simd-json")]
112            JsonError::SimdJson(e) => Some(e),
113        }
114    }
115}
116
117impl From<serde_json::Error> for JsonError {
118    fn from(e: serde_json::Error) -> Self {
119        JsonError::SerdeJson(e)
120    }
121}
122
123#[cfg(feature = "simd-json")]
124impl From<simd_json::Error> for JsonError {
125    fn from(e: simd_json::Error) -> Self {
126        JsonError::SimdJson(e)
127    }
128}