1#[cfg(feature = "partial-parse")]
7pub mod partial;
8
9#[cfg(feature = "partial-parse")]
10pub use partial::{
11 JiterConfig, JiterPartialParser, ParseDiagnostic, PartialJsonParser, PartialParseResult,
12 StreamingHint,
13};
14
15pub mod aligned_alloc;
16pub mod buffer_pool;
17pub mod scanner;
18pub mod simd;
19pub mod simd_zero_copy;
20pub mod simple;
21pub mod sonic;
22pub mod value;
23pub mod zero_copy;
24
25pub use aligned_alloc::{AlignedAllocator, aligned_allocator};
26pub use buffer_pool::{
27 BufferPool, BufferSize, PoolConfig, PooledBuffer, SimdType, global_buffer_pool,
28};
29pub use scanner::{JsonScanner, ScanResult, StringLocation};
30pub use simd_zero_copy::{
31 SimdParseResult, SimdParsingStats, SimdZeroCopyConfig, SimdZeroCopyParser,
32};
33pub use simple::{ParseConfig, ParseStats, SimpleParser};
34pub use sonic::{SonicConfig, SonicParser};
35pub use value::{JsonValue, LazyArray, LazyObject};
36pub use zero_copy::{IncrementalParser, LazyJsonValue, LazyParser, MemoryUsage, ZeroCopyParser};
37
38use crate::{Result, SemanticMeta};
39
40pub struct Parser {
42 sonic: SonicParser,
43 simple: SimpleParser,
44 use_sonic: bool,
45}
46
47impl Parser {
48 pub fn new() -> Self {
54 Self {
55 sonic: SonicParser::new(),
56 simple: SimpleParser::new(),
57 use_sonic: cfg!(pjs_simd),
58 }
59 }
60
61 pub fn with_config(config: ParseConfig) -> Self {
63 let sonic_config = SonicConfig {
64 detect_semantics: config.detect_semantics,
65 max_input_size: config.max_size_mb * 1024 * 1024,
66 };
67
68 Self {
69 sonic: SonicParser::with_config(sonic_config),
70 simple: SimpleParser::with_config(config),
71 use_sonic: cfg!(pjs_simd),
72 }
73 }
74
75 pub fn with_serde_fallback() -> Self {
77 Self {
78 sonic: SonicParser::new(),
79 simple: SimpleParser::new(),
80 use_sonic: false,
81 }
82 }
83
84 pub fn zero_copy_optimized() -> Self {
86 Self {
87 sonic: SonicParser::new(),
88 simple: SimpleParser::new(),
89 use_sonic: false,
90 }
91 }
92
93 pub fn parse(&self, input: &[u8]) -> Result<crate::Frame> {
95 if self.use_sonic {
96 match self.sonic.parse(input) {
98 Ok(frame) => Ok(frame),
99 Err(_) => {
100 self.simple.parse(input)
102 }
103 }
104 } else {
105 self.simple.parse(input)
106 }
107 }
108
109 pub fn parse_with_semantics(
111 &self,
112 input: &[u8],
113 semantics: &SemanticMeta,
114 ) -> Result<crate::Frame> {
115 if self.use_sonic {
116 self.simple.parse_with_semantics(input, semantics)
119 } else {
120 self.simple.parse_with_semantics(input, semantics)
121 }
122 }
123
124 #[cfg(feature = "partial-parse")]
148 pub fn parse_partial(&self, input: &[u8]) -> crate::Result<Option<PartialParseResult>> {
149 use partial::PartialJsonParser as _;
150 let result = JiterPartialParser::default().parse_partial(input)?;
151 if result.consumed == 0 {
152 Ok(None)
153 } else {
154 Ok(Some(result))
155 }
156 }
157
158 pub fn stats(&self) -> ParseStats {
160 if self.use_sonic {
161 let sonic_stats = self.sonic.get_stats();
162 ParseStats {
163 total_parses: sonic_stats.total_parses,
164 semantic_detections: sonic_stats.sonic_successes,
165 avg_parse_time_ms: sonic_stats.avg_parse_time_ns as f64 / 1_000_000.0,
166 }
167 } else {
168 self.simple.stats()
169 }
170 }
171}
172
173impl Default for Parser {
174 fn default() -> Self {
175 Self::new()
176 }
177}
178
179#[derive(Debug, Clone, Copy, PartialEq)]
181pub enum ValueType {
182 Object,
183 Array,
184 String,
185 Number,
186 Boolean,
187 Null,
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193
194 #[test]
195 fn test_parser_creation() {
196 let parser = Parser::new();
197 assert_eq!(parser.stats().total_parses, 0);
198 }
199
200 #[test]
201 fn test_simple_parsing() {
202 let parser = Parser::new();
203 let input = br#"{"hello": "world"}"#;
204 let result = parser.parse(input);
205 assert!(result.is_ok());
206
207 let frame = result.unwrap();
208 assert_eq!(frame.payload.len(), input.len());
210 }
211
212 #[test]
213 fn test_numeric_array_parsing() {
214 let parser = Parser::new();
215 let input = b"[1.0, 2.0, 3.0, 4.0]";
216 let result = parser.parse(input);
217 assert!(result.is_ok());
218 }
219
220 #[test]
221 fn test_semantic_parsing() {
222 let parser = Parser::new();
223 let input = b"[1, 2, 3, 4]";
224
225 let semantics = crate::SemanticMeta::new(crate::semantic::SemanticType::NumericArray {
226 dtype: crate::semantic::NumericDType::I32,
227 length: Some(4),
228 });
229
230 let result = parser.parse_with_semantics(input, &semantics);
231 assert!(result.is_ok());
232 }
233
234 #[test]
235 fn test_custom_config() {
236 let config = ParseConfig {
237 detect_semantics: false,
238 max_size_mb: 50,
239 stream_large_arrays: false,
240 stream_threshold: 500,
241 };
242
243 let parser = Parser::with_config(config);
244 let input = br#"{"test": "data"}"#;
245 let result = parser.parse(input);
246 assert!(result.is_ok());
247 }
248}