1use crate::parser::scanner::{Range, ScanResult};
4use crate::{Error, Result};
5use smallvec::SmallVec;
6
7#[derive(Debug, Clone)]
9pub enum JsonValue<'a> {
10 Raw(&'a [u8]),
12 String(&'a str),
14 Number(&'a [u8]),
16 Bool(bool),
18 Null,
20 Array(LazyArray<'a>),
22 Object(LazyObject<'a>),
24}
25
26#[derive(Debug, Clone)]
28pub struct LazyArray<'a> {
29 raw: &'a [u8],
31 boundaries: SmallVec<[Range; 32]>,
33 cache: std::collections::HashMap<usize, JsonValue<'a>>,
35}
36
37#[derive(Debug, Clone)]
39pub struct LazyObject<'a> {
40 raw: &'a [u8],
42 fields: SmallVec<[FieldRange; 16]>,
44 cache: std::collections::HashMap<String, JsonValue<'a>>,
46}
47
48#[derive(Debug, Clone)]
50pub struct FieldRange {
51 key: Range,
53 value: Range,
55}
56
57impl<'a> JsonValue<'a> {
58 pub fn as_str(&self) -> Option<&str> {
60 match self {
61 JsonValue::String(s) => Some(s),
62 _ => None,
63 }
64 }
65
66 pub fn as_f64(&self) -> Option<f64> {
68 match self {
69 JsonValue::Number(bytes) => std::str::from_utf8(bytes).ok()?.parse().ok(),
70 _ => None,
71 }
72 }
73
74 pub fn as_i64(&self) -> Option<i64> {
76 match self {
77 JsonValue::Number(bytes) => std::str::from_utf8(bytes).ok()?.parse().ok(),
78 _ => None,
79 }
80 }
81
82 pub fn as_bool(&self) -> Option<bool> {
84 match self {
85 JsonValue::Bool(b) => Some(*b),
86 _ => None,
87 }
88 }
89
90 pub fn is_null(&self) -> bool {
92 matches!(self, JsonValue::Null)
93 }
94
95 pub fn as_array(&self) -> Option<&LazyArray<'a>> {
97 match self {
98 JsonValue::Array(arr) => Some(arr),
99 _ => None,
100 }
101 }
102
103 pub fn as_object(&self) -> Option<&LazyObject<'a>> {
105 match self {
106 JsonValue::Object(obj) => Some(obj),
107 _ => None,
108 }
109 }
110
111 pub fn parse_raw(&mut self) -> Result<()> {
113 match self {
114 JsonValue::Raw(_bytes) => {
115 *self = JsonValue::Null; Ok(())
119 }
120 _ => Ok(()),
121 }
122 }
123}
124
125impl<'a> LazyArray<'a> {
126 pub fn from_scan(raw: &'a [u8], scan_result: ScanResult) -> Self {
128 let boundaries = Self::extract_element_boundaries(raw, &scan_result);
130
131 Self {
132 raw,
133 boundaries,
134 cache: std::collections::HashMap::new(),
135 }
136 }
137
138 pub fn len(&self) -> usize {
140 self.boundaries.len()
141 }
142
143 pub fn is_empty(&self) -> bool {
145 self.boundaries.is_empty()
146 }
147
148 pub fn get(&self, index: usize) -> Option<&'a [u8]> {
150 if index >= self.boundaries.len() {
151 return None;
152 }
153
154 let range = self.boundaries[index];
155 Some(&self.raw[range.start..range.end])
156 }
157
158 pub fn get_parsed(&self, index: usize) -> Option<JsonValue<'a>> {
160 self.get(index).map(JsonValue::Raw)
161 }
162
163 pub fn iter(&'a self) -> LazyArrayIter<'a> {
165 LazyArrayIter {
166 array: self,
167 index: 0,
168 }
169 }
170
171 fn extract_element_boundaries(_raw: &[u8], _scan_result: &ScanResult) -> SmallVec<[Range; 32]> {
173 SmallVec::new()
176 }
177
178 pub fn is_numeric(&self) -> bool {
180 self.boundaries.len() > 4
182 && self.boundaries.iter().take(3).all(|range| {
183 let slice = &self.raw[range.start..range.end];
184 self.looks_like_number(slice)
185 })
186 }
187
188 fn looks_like_number(&self, bytes: &[u8]) -> bool {
189 if bytes.is_empty() {
190 return false;
191 }
192
193 bytes.iter().all(|&b| {
194 b.is_ascii_digit() || b == b'.' || b == b'-' || b == b'+' || b == b'e' || b == b'E'
195 })
196 }
197}
198
199impl<'a> LazyObject<'a> {
200 pub fn from_scan(raw: &'a [u8], scan_result: ScanResult) -> Self {
202 let fields = Self::extract_field_boundaries(raw, &scan_result);
203
204 Self {
205 raw,
206 fields,
207 cache: std::collections::HashMap::new(),
208 }
209 }
210
211 pub fn len(&self) -> usize {
213 self.fields.len()
214 }
215
216 pub fn is_empty(&self) -> bool {
218 self.fields.is_empty()
219 }
220
221 pub fn get(&self, key: &str) -> Option<&'a [u8]> {
223 let field_range = self.fields.iter().find(|field| {
225 let key_bytes = &self.raw[field.key.start..field.key.end];
226 std::str::from_utf8(key_bytes) == Ok(key)
227 })?;
228
229 Some(&self.raw[field_range.value.start..field_range.value.end])
231 }
232
233 pub fn keys(&self) -> Result<Vec<&str>> {
235 self.fields
236 .iter()
237 .map(|field| {
238 let key_bytes = &self.raw[field.key.start..field.key.end];
239 std::str::from_utf8(key_bytes).map_err(Error::from)
240 })
241 .collect()
242 }
243
244 fn extract_field_boundaries(
246 _raw: &[u8],
247 _scan_result: &ScanResult,
248 ) -> SmallVec<[FieldRange; 16]> {
249 SmallVec::new()
252 }
253}
254
255pub struct LazyArrayIter<'a> {
257 array: &'a LazyArray<'a>,
258 index: usize,
259}
260
261impl<'a> Iterator for LazyArrayIter<'a> {
262 type Item = &'a [u8]; fn next(&mut self) -> Option<Self::Item> {
265 if self.index >= self.array.boundaries.len() {
266 return None;
267 }
268
269 let range = self.array.boundaries[self.index];
270 self.index += 1;
271
272 Some(&self.array.raw[range.start..range.end])
273 }
274}
275
276impl FieldRange {
277 pub fn new(key: Range, value: Range) -> Self {
279 Self { key, value }
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use super::*;
286
287 #[test]
288 fn test_json_value_types() {
289 let val = JsonValue::String("hello");
290 assert_eq!(val.as_str(), Some("hello"));
291 assert!(val.as_f64().is_none());
292 }
293
294 #[test]
295 fn test_lazy_array_creation() {
296 let raw = b"[1, 2, 3]";
297 let scan_result = ScanResult::new();
298 let array = LazyArray::from_scan(raw, scan_result);
299
300 assert_eq!(array.len(), 0); }
302
303 #[test]
304 fn test_number_detection() {
305 let raw = b"[1.0, 2.5, 3.14]";
306 let scan_result = ScanResult::new();
307 let array = LazyArray::from_scan(raw, scan_result);
308
309 assert!(array.looks_like_number(b"123.45"));
310 assert!(!array.looks_like_number(b"\"string\""));
311 }
312}