nojson/
raw.rs

1use std::{borrow::Cow, fmt::Display, hash::Hash, ops::Range};
2
3use crate::{
4    DisplayJson, JsonFormatter, JsonValueKind,
5    parse::{JsonParser, Jsonc, Plain},
6};
7
8pub use crate::parse_error::JsonParseError;
9
10/// Owned version of [`RawJson`].
11#[derive(Debug, Clone)]
12pub struct RawJsonOwned {
13    text: String,
14    values: Vec<JsonValueIndexEntry>,
15}
16
17impl RawJsonOwned {
18    /// Parses a JSON string into a [`RawJsonOwned`] instance.
19    ///
20    /// This validates the JSON syntax without converting values to Rust types.
21    /// Unlike [`RawJson::parse`], this creates an owned version that doesn't
22    /// borrow from the input string.
23    ///
24    /// # Example
25    ///
26    /// ```
27    /// # use nojson::RawJsonOwned;
28    /// # fn main() -> Result<(), nojson::JsonParseError> {
29    /// let text = r#"{"name": "John", "age": 30}"#;
30    /// let json = RawJsonOwned::parse(text)?;
31    /// # Ok(())
32    /// # }
33    /// ```
34    pub fn parse<T>(text: T) -> Result<Self, JsonParseError>
35    where
36        T: Into<String>,
37    {
38        let text = text.into();
39        let (values, _) = JsonParser::<Plain>::new(&text).parse()?;
40        Ok(Self { text, values })
41    }
42
43    /// Parses a JSONC (JSON with Comments) string into a [`RawJsonOwned`] instance.
44    ///
45    /// This validates the JSONC syntax and strips out comments, returning both
46    /// the parsed JSON structure and the byte ranges where comments were found
47    /// in the original text. Comments can be either line comments (`//`) or
48    /// block comments (`/* */`). Additionally, this parser allows trailing commas
49    /// in objects and arrays.
50    ///
51    /// Unlike [`RawJson::parse_jsonc`], this creates an owned version that doesn't
52    /// borrow from the input string.
53    ///
54    /// # Example
55    ///
56    /// ```
57    /// # use nojson::RawJsonOwned;
58    /// # fn main() -> Result<(), nojson::JsonParseError> {
59    /// let text = r#"{
60    ///     "name": "John", // This is a comment
61    ///     "age": 30,
62    ///     /*
63    ///      * This is a multi-line
64    ///      * block comment
65    ///      */
66    ///     "city": "New York", // Trailing comma is allowed
67    /// }"#;
68    ///
69    /// let (json, comment_ranges) = RawJsonOwned::parse_jsonc(text)?;
70    ///
71    /// // The parsed JSON works normally
72    /// let name: String = json.value().to_member("name")?.required()?.try_into()?;
73    /// assert_eq!(name, "John");
74    ///
75    /// // Comment ranges indicate where comments were found in the original text
76    /// assert_eq!(comment_ranges.len(), 3); // Three comments found
77    ///
78    /// // You can extract the comment text if needed
79    /// let first_comment = &text[comment_ranges[0].clone()];
80    /// assert!(first_comment.contains("This is a comment"));
81    /// # Ok(())
82    /// # }
83    /// ```
84    pub fn parse_jsonc<T>(text: T) -> Result<(Self, Vec<Range<usize>>), JsonParseError>
85    where
86        T: Into<String>,
87    {
88        let text = text.into();
89        let (values, comments) = JsonParser::<Jsonc>::new(&text).parse()?;
90        Ok((Self { text, values }, comments))
91    }
92
93    /// Returns the original JSON text.
94    pub fn text(&self) -> &str {
95        &self.text
96    }
97
98    /// Returns the top-level value of the JSON.
99    ///
100    /// This value can be used as an entry point to traverse the entire JSON structure
101    /// and convert it to Rust types.
102    ///
103    /// # Example
104    ///
105    /// ```
106    /// # use nojson::RawJsonOwned;
107    /// # fn main() -> Result<(), nojson::JsonParseError> {
108    /// let text = r#"{"name": "John", "age": 30}"#;
109    /// let json = RawJsonOwned::parse(text).unwrap();
110    /// let value = json.value();
111    /// # Ok(())
112    /// # }
113    /// ```
114    pub fn value(&self) -> RawJsonValue<'_, '_> {
115        RawJsonValue {
116            json: self.as_raw_json_ref(),
117            index: 0,
118        }
119    }
120
121    /// Finds the JSON value at the specified byte position in the original text.
122    ///
123    /// This method traverses the JSON structure to find the most specific value
124    /// that contains the given position.
125    /// It returns `None` if the position is outside the bounds of the JSON text.
126    ///
127    /// This method is useful for retrieving the context
128    /// where a [`JsonParseError::InvalidValue`] error occurred.
129    ///
130    /// # Example
131    ///
132    /// ```
133    /// # use nojson::RawJsonOwned;
134    /// # fn main() -> Result<(), nojson::JsonParseError> {
135    /// let json = RawJsonOwned::parse(r#"{"name": "John", "age": 30}"#)?;
136    ///
137    /// // Position at "name" key
138    /// let name_value = json.get_value_by_position(2).expect("infallible");
139    /// assert_eq!(name_value.as_raw_str(), r#""name""#);
140    ///
141    /// // Position at number value
142    /// let age_value = json.get_value_by_position(25).expect("infallible");
143    /// assert_eq!(age_value.as_raw_str(), "30");
144    /// # Ok(())
145    /// # }
146    /// ```
147    pub fn get_value_by_position(&self, position: usize) -> Option<RawJsonValue<'_, '_>> {
148        self.as_raw_json_ref().get_value_by_position(position)
149    }
150
151    fn as_raw_json_ref(&self) -> RawJsonRef<'_, '_> {
152        RawJsonRef {
153            text: &self.text,
154            values: &self.values,
155        }
156    }
157}
158
159impl PartialEq for RawJsonOwned {
160    fn eq(&self, other: &Self) -> bool {
161        self.text == other.text
162    }
163}
164
165impl Eq for RawJsonOwned {}
166
167impl PartialOrd for RawJsonOwned {
168    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
169        Some(self.cmp(other))
170    }
171}
172
173impl Ord for RawJsonOwned {
174    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
175        self.text.cmp(&other.text)
176    }
177}
178
179impl Hash for RawJsonOwned {
180    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
181        self.text.hash(state);
182    }
183}
184
185impl Display for RawJsonOwned {
186    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187        write!(f, "{}", crate::Json(self))
188    }
189}
190
191impl DisplayJson for RawJsonOwned {
192    fn fmt(&self, f: &mut JsonFormatter<'_, '_>) -> std::fmt::Result {
193        DisplayJson::fmt(&self.value(), f)
194    }
195}
196
197impl std::str::FromStr for RawJsonOwned {
198    type Err = JsonParseError;
199
200    fn from_str(s: &str) -> Result<Self, Self::Err> {
201        Self::parse(s)
202    }
203}
204
205impl<'text, 'raw> TryFrom<RawJsonValue<'text, 'raw>> for RawJsonOwned {
206    type Error = JsonParseError;
207
208    fn try_from(value: RawJsonValue<'text, 'raw>) -> Result<Self, Self::Error> {
209        Ok(value.extract().into_owned())
210    }
211}
212
213/// Parsed JSON text (syntactically correct, but not yet converted to Rust types).
214///
215/// This struct holds a JSON text in its original form
216/// (i.e., JSON integers are not converted to Rust's integers),
217/// while ensuring the text is valid JSON syntax.
218///
219/// [`RawJson`] maintains index information about each JSON value in the text,
220/// including its type ([`JsonValueKind`]) and the start and end byte positions.
221/// You can traverse the JSON structure by accessing the top-level value
222/// via [`RawJson::value()`], which returns a [`RawJsonValue`]
223/// that provides methods to explore nested elements and convert them into Rust types.
224///
225/// Note that, for simple use cases,
226/// using [`Json`](crate::Json), which internally uses [`RawJson`], is a more convenient way to parse JSON text into Rust types.
227#[derive(Debug, Clone)]
228pub struct RawJson<'text> {
229    text: &'text str,
230    values: Vec<JsonValueIndexEntry>,
231}
232
233impl<'text> RawJson<'text> {
234    /// Parses a JSON string into a [`RawJson`] instance.
235    ///
236    /// This validates the JSON syntax without converting values to Rust types.
237    ///
238    /// # Example
239    ///
240    /// ```
241    /// # use nojson::RawJson;
242    /// # fn main() -> Result<(), nojson::JsonParseError> {
243    /// let text = r#"{"name": "John", "age": 30}"#;
244    /// let json = RawJson::parse(text)?;
245    /// # Ok(())
246    /// # }
247    /// ```
248    pub fn parse(text: &'text str) -> Result<Self, JsonParseError> {
249        let (values, _) = JsonParser::<Plain>::new(text).parse()?;
250        Ok(Self { text, values })
251    }
252
253    /// Parses a JSONC (JSON with Comments) string into a [`RawJson`] instance.
254    ///
255    /// This validates the JSONC syntax and strips out comments, returning both
256    /// the parsed JSON structure and the byte ranges where comments were found
257    /// in the original text. Comments can be either line comments (`//`) or
258    /// block comments (`/* */`). Additionally, this parser allows trailing commas
259    /// in objects and arrays.
260    ///
261    /// # Example
262    ///
263    /// ```
264    /// # use nojson::RawJson;
265    /// # fn main() -> Result<(), nojson::JsonParseError> {
266    /// let text = r#"{
267    ///     "name": "John", // This is a comment
268    ///     "age": 30,
269    ///     /* This is a block comment */
270    ///     "city": "New York", // Trailing comma is allowed
271    /// }"#;
272    ///
273    /// let (json, comment_ranges) = RawJson::parse_jsonc(text)?;
274    ///
275    /// // The parsed JSON works normally
276    /// let name: String = json.value().to_member("name")?.required()?.try_into()?;
277    /// assert_eq!(name, "John");
278    ///
279    /// // Comment ranges indicate where comments were found in the original text
280    /// assert_eq!(comment_ranges.len(), 3); // Three comments found
281    ///
282    /// // You can extract the comment text if needed
283    /// let first_comment = &text[comment_ranges[0].clone()];
284    /// assert!(first_comment.contains("This is a comment"));
285    /// # Ok(())
286    /// # }
287    /// ```
288    pub fn parse_jsonc(text: &'text str) -> Result<(Self, Vec<Range<usize>>), JsonParseError> {
289        let (values, comments) = JsonParser::<Jsonc>::new(text).parse()?;
290        Ok((Self { text, values }, comments))
291    }
292
293    /// Returns the original JSON text.
294    pub fn text(&self) -> &'text str {
295        self.text
296    }
297
298    /// Returns the top-level value of the JSON.
299    ///
300    /// This value can be used as an entry point to traverse the entire JSON structure
301    /// and convert it to Rust types.
302    ///
303    /// # Example
304    ///
305    /// ```
306    /// # use nojson::RawJson;
307    /// # fn main() -> Result<(), nojson::JsonParseError> {
308    /// let text = r#"{"name": "John", "age": 30}"#;
309    /// let json = RawJson::parse(text).unwrap();
310    /// let value = json.value();
311    /// # Ok(())
312    /// # }
313    /// ```
314    pub fn value(&self) -> RawJsonValue<'text, '_> {
315        RawJsonValue {
316            json: self.as_raw_json_ref(),
317            index: 0,
318        }
319    }
320
321    /// Finds the JSON value at the specified byte position in the original text.
322    ///
323    /// This method traverses the JSON structure to find the most specific value
324    /// that contains the given position.
325    /// It returns `None` if the position is outside the bounds of the JSON text.
326    ///
327    /// This method is useful for retrieving the context
328    /// where a [`JsonParseError::InvalidValue`] error occurred.
329    ///
330    /// # Example
331    ///
332    /// ```
333    /// # use nojson::RawJson;
334    /// # fn main() -> Result<(), nojson::JsonParseError> {
335    /// let json = RawJson::parse(r#"{"name": "John", "age": 30}"#)?;
336    ///
337    /// // Position at "name" key
338    /// let name_value = json.get_value_by_position(2).expect("infallible");
339    /// assert_eq!(name_value.as_raw_str(), r#""name""#);
340    ///
341    /// // Position at number value
342    /// let age_value = json.get_value_by_position(25).expect("infallible");
343    /// assert_eq!(age_value.as_raw_str(), "30");
344    /// # Ok(())
345    /// # }
346    /// ```
347    pub fn get_value_by_position(&self, position: usize) -> Option<RawJsonValue<'text, '_>> {
348        self.as_raw_json_ref().get_value_by_position(position)
349    }
350
351    /// Converts this borrowed [`RawJson`] into an owned [`RawJsonOwned`].
352    ///
353    /// This method creates an owned copy of the JSON data, allowing it to be used
354    /// beyond the lifetime of the original text. The resulting [`RawJsonOwned`]
355    /// contains its own copy of the JSON text and can be moved freely.
356    ///
357    /// # Example
358    ///
359    /// ```
360    /// # use nojson::RawJson;
361    /// # fn main() -> Result<(), nojson::JsonParseError> {
362    /// let text = r#"{"name": "John", "age": 30}"#;
363    /// let json = RawJson::parse(text)?;
364    /// let owned_json = json.into_owned();
365    ///
366    /// // The owned version can outlive the original text
367    /// drop(text);
368    /// assert_eq!(owned_json.text(), r#"{"name": "John", "age": 30}"#);
369    /// # Ok(())
370    /// # }
371    /// ```
372    pub fn into_owned(self) -> RawJsonOwned {
373        RawJsonOwned {
374            text: self.text.to_owned(),
375            values: self.values,
376        }
377    }
378
379    fn as_raw_json_ref(&self) -> RawJsonRef<'text, '_> {
380        RawJsonRef {
381            text: self.text,
382            values: &self.values,
383        }
384    }
385}
386
387impl PartialEq for RawJson<'_> {
388    fn eq(&self, other: &Self) -> bool {
389        self.text == other.text
390    }
391}
392
393impl Eq for RawJson<'_> {}
394
395impl PartialOrd for RawJson<'_> {
396    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
397        Some(self.cmp(other))
398    }
399}
400
401impl Ord for RawJson<'_> {
402    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
403        self.text.cmp(other.text)
404    }
405}
406
407impl Hash for RawJson<'_> {
408    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
409        self.text.hash(state);
410    }
411}
412
413impl Display for RawJson<'_> {
414    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
415        write!(f, "{}", crate::Json(self))
416    }
417}
418
419impl DisplayJson for RawJson<'_> {
420    fn fmt(&self, f: &mut JsonFormatter<'_, '_>) -> std::fmt::Result {
421        DisplayJson::fmt(&self.value(), f)
422    }
423}
424
425impl<'text, 'raw> TryFrom<RawJsonValue<'text, 'raw>> for RawJson<'text> {
426    type Error = JsonParseError;
427
428    fn try_from(value: RawJsonValue<'text, 'raw>) -> Result<Self, Self::Error> {
429        Ok(value.extract())
430    }
431}
432
433#[derive(Debug, Clone, PartialEq, Eq)]
434pub(crate) struct JsonValueIndexEntry {
435    pub kind: JsonValueKind,
436    pub escaped: bool,
437    pub text: Range<usize>,
438    pub end_index: usize,
439}
440
441#[derive(Debug, Clone, Copy)]
442struct RawJsonRef<'text, 'raw> {
443    text: &'text str,
444    values: &'raw [JsonValueIndexEntry],
445}
446
447impl<'text, 'raw> RawJsonRef<'text, 'raw> {
448    fn get_value_by_position(self, position: usize) -> Option<RawJsonValue<'text, 'raw>> {
449        let mut value = self.value();
450        if !value.entry().text.contains(&position) {
451            return None;
452        }
453        while let Some(child) = Children::new(value).find(|c| c.entry().text.contains(&position)) {
454            value = child;
455        }
456        Some(value)
457    }
458
459    fn value(self) -> RawJsonValue<'text, 'raw> {
460        RawJsonValue {
461            json: self,
462            index: 0,
463        }
464    }
465}
466
467impl PartialEq for RawJsonRef<'_, '_> {
468    fn eq(&self, other: &Self) -> bool {
469        self.text == other.text
470    }
471}
472
473impl Eq for RawJsonRef<'_, '_> {}
474
475impl PartialOrd for RawJsonRef<'_, '_> {
476    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
477        Some(self.cmp(other))
478    }
479}
480
481impl Ord for RawJsonRef<'_, '_> {
482    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
483        self.text.cmp(other.text)
484    }
485}
486
487impl Hash for RawJsonRef<'_, '_> {
488    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
489        self.text.hash(state);
490    }
491}
492
493impl Display for RawJsonRef<'_, '_> {
494    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
495        write!(f, "{}", crate::Json(self))
496    }
497}
498
499impl DisplayJson for RawJsonRef<'_, '_> {
500    fn fmt(&self, f: &mut JsonFormatter<'_, '_>) -> std::fmt::Result {
501        DisplayJson::fmt(&self.value(), f)
502    }
503}
504
505/// A JSON value in a [`RawJson`].
506///
507/// This struct provides the text and structural information (e.g., kind, parent, children) of a JSON value.
508/// Interpreting that text is the responsibility of the user.
509///
510/// To convert this JSON value to a Rust type, you can use the standard [`TryFrom`] and [`TryInto`] traits.
511/// For other parsing approaches, you can use the [`FromStr`](std::str::FromStr) trait or other parsing methods
512/// to parse the underlying JSON text of this value as shown below:
513///
514/// ```
515/// # use nojson::{RawJson, RawJsonValue, JsonParseError};
516/// # fn main() -> Result<(), JsonParseError> {
517/// let text = "1.23";
518/// let json = RawJson::parse(text)?;
519/// let raw: RawJsonValue = json.value();
520/// let parsed: f32 =
521///     raw.as_number_str()?.parse().map_err(|e| raw.invalid(e))?;
522/// assert_eq!(parsed, 1.23);
523/// # Ok(())
524/// # }
525/// ```
526///
527/// For types that implement `TryFrom<RawJsonValue<'_, '_>>`, you can use the [`TryInto`] trait:
528///
529/// ```
530/// # use nojson::{RawJson, JsonParseError};
531/// # fn main() -> Result<(), JsonParseError> {
532/// let json = RawJson::parse("[1, 2, 3]")?;
533/// let numbers: [u32; 3] = json.value().try_into()?;
534/// assert_eq!(numbers, [1, 2, 3]);
535/// # Ok(())
536/// # }
537/// ```
538#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
539pub struct RawJsonValue<'text, 'raw> {
540    index: usize,
541    json: RawJsonRef<'text, 'raw>,
542}
543
544impl<'text, 'raw> RawJsonValue<'text, 'raw> {
545    /// Returns the kind of this JSON value.
546    pub fn kind(self) -> JsonValueKind {
547        self.json.values[self.index].kind
548    }
549
550    /// Returns the byte position where this value begins in the JSON text (`self.json().text()`).
551    pub fn position(self) -> usize {
552        self.json.values[self.index].text.start
553    }
554
555    /// Returns the parent value (array or object) that contains this value.
556    pub fn parent(self) -> Option<Self> {
557        if self.index == 0 {
558            return None;
559        }
560        self.json.get_value_by_position(self.position() - 1)
561    }
562
563    /// Returns the root (top-level) value of the JSON data.
564    ///
565    /// This method navigates back to the root value of the entire JSON structure,
566    /// regardless of where this value is located in the JSON hierarchy. This is
567    /// useful when you want to access other parts of the JSON from a nested value.
568    ///
569    /// This operation is O(1) and more efficient than repeatedly calling [`parent()`](Self::parent)
570    /// to reach the root.
571    ///
572    /// # Examples
573    ///
574    /// ```
575    /// # fn main() -> Result<(), nojson::JsonParseError> {
576    /// let json = nojson::RawJson::parse(r#"{"user": {"name": "John", "age": 30}, "count": 42}"#)?;
577    /// let age_value = json.value()
578    ///     .to_member("user")?
579    ///     .required()?
580    ///     .to_member("age")?
581    ///     .required()?;
582    ///
583    /// // From the nested age value, navigate back to the root
584    /// let root = age_value.root();
585    ///
586    /// // Access any part of the original JSON structure
587    /// let count: i32 = root.to_member("count")?.required()?.try_into()?;
588    /// assert_eq!(count, 42);
589    ///
590    /// let user_name: String = root
591    ///     .to_member("user")?
592    ///     .required()?
593    ///     .to_member("name")?
594    ///     .required()?
595    ///     .try_into()?;
596    /// assert_eq!(user_name, "John");
597    /// # Ok(())
598    /// # }
599    /// ```
600    pub fn root(self) -> Self {
601        Self {
602            json: self.json,
603            index: 0,
604        }
605    }
606
607    /// Returns the raw JSON text of this value as-is.
608    pub fn as_raw_str(self) -> &'text str {
609        let text = &self.json.values[self.index].text;
610        &self.json.text[text.start..text.end]
611    }
612
613    /// Converts this value to a borrowed [`RawJson`] containing just this value and its children.
614    ///
615    /// This method creates a borrowed view of this specific JSON value and its text,
616    /// including all nested children if the value is an object or array. The resulting
617    /// [`RawJson`] contains only this value and its descendants as its root,
618    /// not the entire original JSON text.
619    ///
620    /// If you need an owned version, you can call `.into_owned()` on the result.
621    ///
622    /// # Example
623    ///
624    /// ```
625    /// # use nojson::RawJson;
626    /// # fn main() -> Result<(), nojson::JsonParseError> {
627    /// let text = r#"{"user": {"name": "John", "age": 30}, "count": 42}"#;
628    /// let json = RawJson::parse(text)?;
629    /// let user_value = json.value().to_member("user")?.required()?;
630    ///
631    /// // Extract the user object and its children to borrowed
632    /// let borrowed_user = user_value.extract();
633    ///
634    /// // The borrowed version references the original text
635    /// assert_eq!(borrowed_user.text(), r#"{"name": "John", "age": 30}"#);
636    /// let name: String = borrowed_user.value().to_member("name")?.required()?.try_into()?;
637    /// assert_eq!(name, "John");
638    ///
639    /// // Convert to owned if needed
640    /// let owned_user = borrowed_user.into_owned();
641    /// # Ok(())
642    /// # }
643    /// ```
644    pub fn extract(self) -> RawJson<'text> {
645        let start_index = self.index;
646        let end_index = self.entry().end_index;
647
648        // Extract the text range that covers this value and all its children
649        let start_pos = self.entry().text.start;
650        let end_pos = self.entry().text.end;
651        let value_text = &self.json.text[start_pos..end_pos];
652
653        // Extract all relevant value entries (this value and its children)
654        let relevant_entries = &self.json.values[start_index..end_index];
655
656        // Create new values vector with adjusted positions
657        let new_values = relevant_entries
658            .iter()
659            .map(|entry| JsonValueIndexEntry {
660                kind: entry.kind,
661                escaped: entry.escaped,
662                text: (entry.text.start - start_pos)..(entry.text.end - start_pos),
663                end_index: entry.end_index - start_index,
664            })
665            .collect();
666
667        RawJson {
668            text: value_text,
669            values: new_values,
670        }
671    }
672
673    /// Similar to [`RawJsonValue::as_raw_str()`],
674    /// but this method verifies whether the value is a JSON boolean.
675    ///
676    /// # Examples
677    ///
678    /// ```
679    /// # use nojson::RawJson;
680    /// # fn main() -> Result<(), nojson::JsonParseError> {
681    /// let json = RawJson::parse("false")?;
682    /// assert_eq!(json.value().as_boolean_str()?.parse(), Ok(false));
683    ///
684    /// let json = RawJson::parse("10")?;
685    /// assert!(json.value().as_boolean_str().is_err());
686    /// # Ok(())
687    /// # }
688    /// ```
689    pub fn as_boolean_str(self) -> Result<&'text str, JsonParseError> {
690        self.expect([JsonValueKind::Boolean])
691            .map(|v| v.as_raw_str())
692    }
693
694    /// Similar to [`RawJsonValue::as_raw_str()`],
695    /// but this method verifies whether the value is a JSON integer number.
696    ///
697    /// # Examples
698    ///
699    /// ```
700    /// # use nojson::RawJson;
701    /// # fn main() -> Result<(), nojson::JsonParseError> {
702    /// let json = RawJson::parse("123")?;
703    /// assert_eq!(json.value().as_integer_str()?.parse(), Ok(123));
704    ///
705    /// let json = RawJson::parse("12.3")?;
706    /// assert!(json.value().as_integer_str().is_err());
707    /// # Ok(())
708    /// # }
709    /// ```
710    pub fn as_integer_str(self) -> Result<&'text str, JsonParseError> {
711        self.expect([JsonValueKind::Integer])
712            .map(|v| v.as_raw_str())
713    }
714
715    /// Similar to [`RawJsonValue::as_raw_str()`],
716    /// but this method verifies whether the value is a JSON floating-point number.
717    ///
718    /// # Examples
719    ///
720    /// ```
721    /// # use nojson::RawJson;
722    /// # fn main() -> Result<(), nojson::JsonParseError> {
723    /// let json = RawJson::parse("12.3")?;
724    /// assert_eq!(json.value().as_float_str()?.parse(), Ok(12.3));
725    ///
726    /// let json = RawJson::parse("123")?;
727    /// assert!(json.value().as_float_str().is_err());
728    /// # Ok(())
729    /// # }
730    /// ```
731    pub fn as_float_str(self) -> Result<&'text str, JsonParseError> {
732        self.expect([JsonValueKind::Float]).map(|v| v.as_raw_str())
733    }
734
735    /// Similar to [`RawJsonValue::as_raw_str()`],
736    /// but this method verifies whether the value is a JSON number.
737    ///
738    /// # Examples
739    ///
740    /// ```
741    /// # use nojson::RawJson;
742    /// # fn main() -> Result<(), nojson::JsonParseError> {
743    /// let json = RawJson::parse("123")?;
744    /// assert_eq!(json.value().as_number_str()?.parse(), Ok(123));
745    ///
746    /// let json = RawJson::parse("12.3")?;
747    /// assert_eq!(json.value().as_number_str()?.parse(), Ok(12.3));
748    ///
749    /// let json = RawJson::parse("null")?;
750    /// assert!(json.value().as_number_str().is_err());
751    /// # Ok(())
752    /// # }
753    /// ```
754    pub fn as_number_str(self) -> Result<&'text str, JsonParseError> {
755        self.expect([JsonValueKind::Integer, JsonValueKind::Float])
756            .map(|v| v.as_raw_str())
757    }
758
759    /// Similar to [`RawJsonValue::as_raw_str()`],
760    /// but this method verifies whether the value is a JSON string and returns the unquoted content of the string.
761    ///
762    /// # Examples
763    ///
764    /// ```
765    /// # use nojson::RawJson;
766    /// # fn main() -> Result<(), nojson::JsonParseError> {
767    /// let json = RawJson::parse("\"123\"")?;
768    /// assert_eq!(json.value().to_unquoted_string_str()?, "123");
769    /// assert_eq!(json.value().to_unquoted_string_str()?.parse(), Ok(123));
770    ///
771    /// let json = RawJson::parse("123")?;
772    /// assert!(json.value().to_unquoted_string_str().is_err());
773    /// # Ok(())
774    /// # }
775    /// ```
776    pub fn to_unquoted_string_str(self) -> Result<Cow<'text, str>, JsonParseError> {
777        self.expect([JsonValueKind::String]).map(|v| v.unquote())
778    }
779
780    /// If the value is a JSON array,
781    /// this method returns an iterator that iterates over the array's elements.
782    ///
783    /// # Examples
784    ///
785    /// ```
786    /// # use nojson::RawJson;
787    /// # fn main() -> Result<(), nojson::JsonParseError> {
788    /// let json = RawJson::parse("[0, 1, 2]")?;
789    /// for (i, v) in json.value().to_array()?.enumerate() {
790    ///     assert_eq!(v.as_integer_str()?.parse(), Ok(i));
791    /// }
792    ///
793    /// let json = RawJson::parse("null")?;
794    /// assert!(json.value().to_array().is_err());
795    /// # Ok(())
796    /// # }
797    /// ```
798    ///
799    /// # Note
800    ///
801    /// For converting to a fixed-size array, you can use the `TryInto` trait instead:
802    /// ```
803    /// # use nojson::RawJson;
804    /// # fn main() -> Result<(), nojson::JsonParseError> {
805    /// let json = RawJson::parse("[0, 1, 2]")?;
806    /// let fixed_array: [usize; 3] = json.value().try_into()?;
807    /// # Ok(())
808    /// # }
809    /// ```
810    pub fn to_array(self) -> Result<impl Iterator<Item = Self>, JsonParseError> {
811        self.expect([JsonValueKind::Array]).map(Children::new)
812    }
813
814    /// If the value is a JSON object,
815    /// this method returns an iterator that iterates over
816    /// the name and value pairs of the object's members.
817    ///
818    /// # Examples
819    ///
820    /// ```
821    /// # use nojson::RawJson;
822    /// # fn main() -> Result<(), nojson::JsonParseError> {
823    /// let json = RawJson::parse(r#"{"a": 1, "b": 2, "c": 3}"#)?;
824    /// let mut members = json.value().to_object()?;
825    /// let (k, v) = members.next().expect("some");
826    /// assert_eq!(k.to_unquoted_string_str()?, "a");
827    /// assert_eq!(v.as_integer_str()?.parse(), Ok(1));
828    ///
829    /// let json = RawJson::parse("null")?;
830    /// assert!(json.value().to_object().is_err());
831    /// # Ok(())
832    /// # }
833    /// ```
834    pub fn to_object(self) -> Result<impl Iterator<Item = (Self, Self)>, JsonParseError> {
835        self.expect([JsonValueKind::Object])
836            .map(JsonKeyValuePairs::new)
837    }
838
839    /// Attempts to access a member of a JSON object by name.
840    ///
841    /// This method returns a [`RawJsonMember`] that represents the result of
842    /// looking up the specified member name. The member may or may not exist,
843    /// and you can use methods like [`RawJsonMember::required()`] or convert
844    /// it to an `Option<T>` to handle both cases.
845    ///
846    /// # Examples
847    ///
848    /// ```
849    /// # use nojson::RawJson;
850    /// # fn main() -> Result<(), nojson::JsonParseError> {
851    /// let json = RawJson::parse(r#"{"name": "Alice", "age": 30}"#)?;
852    /// let obj = json.value();
853    ///
854    /// // Access existing member
855    /// let name_value: String = obj.to_member("name")?.required()?.try_into()?;
856    /// assert_eq!(name_value, "Alice");
857    ///
858    /// // Handle optional member
859    /// let city_member = obj.to_member("city")?;
860    /// let city: Option<String> = city_member.try_into()?;
861    /// assert_eq!(city, None);
862    /// # Ok(())
863    /// # }
864    /// ```
865    ///
866    /// # Performance
867    ///
868    /// This method has O(n) complexity where n is the number of members in the object,
869    /// as it performs a linear search through all object members to find the requested name.
870    /// If you need to access multiple members from the same object, consider using
871    /// [`RawJsonValue::to_object()`] instead, which allows you to iterate through
872    /// all members once and extract the values you need more efficiently.
873    ///
874    /// ```
875    /// # use nojson::RawJson;
876    /// # fn main() -> Result<(), nojson::JsonParseError> {
877    /// let json = RawJson::parse(r#"{"name": "Alice", "age": 30, "city": "New York"}"#)?;
878    /// let obj = json.value();
879    ///
880    /// // Efficient: single iteration for multiple members
881    /// let mut name = None;
882    /// let mut age = None;
883    /// let mut city = None;
884    /// for (key, value) in obj.to_object()? {
885    ///     match key.to_unquoted_string_str()?.as_ref() {
886    ///         "name" => name = Some(value),
887    ///         "age" => age = Some(value),
888    ///         "city" => city = Some(value),
889    ///         _ => {}
890    ///     }
891    /// }
892    /// # Ok(())
893    /// # }
894    /// ```
895    pub fn to_member<'a>(
896        self,
897        name: &'a str,
898    ) -> Result<RawJsonMember<'text, 'raw, 'a>, JsonParseError> {
899        let member = self
900            .to_object()?
901            .find(|(key, _)| key.unquote() == name)
902            .map(|(_, value)| value);
903
904        Ok(RawJsonMember {
905            object: self,
906            name,
907            member,
908        })
909    }
910
911    /// Applies a transformation function to this JSON value.
912    ///
913    /// This method allows you to transform a `RawJsonValue` into any other type `T`
914    /// using a closure that can potentially fail with a `JsonParseError`. It's particularly
915    /// useful for chaining operations or applying custom parsing logic.
916    ///
917    /// # Examples
918    ///
919    /// ```
920    /// # use nojson::RawJson;
921    /// # fn main() -> Result<(), nojson::JsonParseError> {
922    /// let json = RawJson::parse("\"42\"")?;
923    ///
924    /// // Transform a string value to an integer
925    /// let number: i32 = json.value().map(|v| {
926    ///     v.to_unquoted_string_str()?.parse().map_err(|e| v.invalid(e))
927    /// })?;
928    /// assert_eq!(number, 42);
929    /// # Ok(())
930    /// # }
931    /// ```
932    ///
933    /// This method is equivalent to directly calling the function with the value,
934    /// but provides a more functional programming style for chaining operations.
935    pub fn map<F, T>(self, f: F) -> Result<T, JsonParseError>
936    where
937        F: FnOnce(RawJsonValue<'text, 'raw>) -> Result<T, JsonParseError>,
938    {
939        f(self)
940    }
941
942    /// Creates a [`JsonParseError::InvalidValue`] error for this value.
943    ///
944    /// This is a convenience method that's equivalent to calling
945    /// [`JsonParseError::invalid_value()`] with this value.
946    ///
947    /// # Examples
948    ///
949    /// ```
950    /// # use nojson::RawJson;
951    /// # fn main() -> Result<(), nojson::JsonParseError> {
952    /// let json = RawJson::parse("\"not_a_number\"")?;
953    /// let value = json.value();
954    ///
955    /// // These are equivalent:
956    /// let error1 = value.invalid("expected a number");
957    /// let error2 = nojson::JsonParseError::invalid_value(value, "expected a number");
958    /// # Ok(())
959    /// # }
960    /// ```
961    pub fn invalid<E>(self, error: E) -> JsonParseError
962    where
963        E: Into<Box<dyn Send + Sync + std::error::Error>>,
964    {
965        JsonParseError::invalid_value(self, error)
966    }
967
968    fn unquote(self) -> Cow<'text, str> {
969        debug_assert!(self.kind().is_string());
970
971        let content = &self.as_raw_str()[1..self.as_raw_str().len() - 1];
972        if !self.entry().escaped {
973            return Cow::Borrowed(content);
974        }
975
976        let mut unescaped = String::with_capacity(content.len());
977        let mut chars = content.chars();
978        while let Some(c) = chars.next() {
979            match c {
980                '\\' => {
981                    let c = chars.next().expect("infallible");
982                    match c {
983                        '\\' | '/' | '"' => unescaped.push(c),
984                        'n' => unescaped.push('\n'),
985                        't' => unescaped.push('\t'),
986                        'r' => unescaped.push('\r'),
987                        'b' => unescaped.push('\u{8}'),
988                        'f' => unescaped.push('\u{c}'),
989                        'u' => {
990                            let c = std::str::from_utf8(&[
991                                chars.next().expect("infallible") as u8,
992                                chars.next().expect("infallible") as u8,
993                                chars.next().expect("infallible") as u8,
994                                chars.next().expect("infallible") as u8,
995                            ])
996                            .ok()
997                            .and_then(|code| u32::from_str_radix(code, 16).ok())
998                            .and_then(char::from_u32)
999                            .expect("infallible");
1000                            unescaped.push(c);
1001                        }
1002                        _ => unreachable!(),
1003                    }
1004                }
1005                _ => unescaped.push(c),
1006            }
1007        }
1008        Cow::Owned(unescaped)
1009    }
1010
1011    fn expect<const N: usize>(self, kinds: [JsonValueKind; N]) -> Result<Self, JsonParseError> {
1012        if kinds.contains(&self.kind()) {
1013            Ok(self)
1014        } else {
1015            Err(self.invalid(format!(
1016                "expected {}, but found {:?}",
1017                if kinds.len() == 1 {
1018                    format!("{:?}", kinds[0])
1019                } else {
1020                    format!("one of {kinds:?}")
1021                },
1022                self.kind()
1023            )))
1024        }
1025    }
1026
1027    fn entry(&self) -> &JsonValueIndexEntry {
1028        &self.json.values[self.index]
1029    }
1030}
1031
1032impl Display for RawJsonValue<'_, '_> {
1033    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1034        write!(f, "{}", crate::Json(self))
1035    }
1036}
1037
1038impl DisplayJson for RawJsonValue<'_, '_> {
1039    fn fmt(&self, f: &mut JsonFormatter<'_, '_>) -> std::fmt::Result {
1040        match self.kind() {
1041            JsonValueKind::Null
1042            | JsonValueKind::Boolean
1043            | JsonValueKind::Integer
1044            | JsonValueKind::Float => write!(f.inner_mut(), "{}", self.as_raw_str()),
1045            JsonValueKind::String => f.string(self.unquote()),
1046            JsonValueKind::Array => f.array(|f| f.elements(self.to_array().expect("infallible"))),
1047            JsonValueKind::Object => f.object(|f| {
1048                f.members(
1049                    self.to_object()
1050                        .expect("infallible")
1051                        .map(|(k, v)| (k.unquote(), v)),
1052                )
1053            }),
1054        }
1055    }
1056}
1057
1058#[derive(Debug)]
1059struct Children<'text, 'raw> {
1060    value: RawJsonValue<'text, 'raw>,
1061    end_index: usize,
1062}
1063
1064impl<'text, 'raw> Children<'text, 'raw> {
1065    fn new(mut value: RawJsonValue<'text, 'raw>) -> Self {
1066        let end_index = value.entry().end_index;
1067        value.index += 1;
1068        Self { value, end_index }
1069    }
1070}
1071
1072impl<'text, 'raw> Iterator for Children<'text, 'raw> {
1073    type Item = RawJsonValue<'text, 'raw>;
1074
1075    fn next(&mut self) -> Option<Self::Item> {
1076        if self.value.index == self.end_index {
1077            return None;
1078        }
1079        let value = self.value;
1080        self.value.index = value.entry().end_index;
1081        Some(value)
1082    }
1083}
1084
1085#[derive(Debug)]
1086struct JsonKeyValuePairs<'text, 'raw> {
1087    inner: Children<'text, 'raw>,
1088}
1089
1090impl<'text, 'raw> JsonKeyValuePairs<'text, 'raw> {
1091    fn new(object: RawJsonValue<'text, 'raw>) -> Self {
1092        Self {
1093            inner: Children::new(object),
1094        }
1095    }
1096}
1097
1098impl<'text, 'raw> Iterator for JsonKeyValuePairs<'text, 'raw> {
1099    type Item = (RawJsonValue<'text, 'raw>, RawJsonValue<'text, 'raw>);
1100
1101    fn next(&mut self) -> Option<Self::Item> {
1102        let key = self.inner.next()?;
1103        let value = self.inner.next().expect("infallible");
1104        Some((key, value))
1105    }
1106}
1107
1108/// Represents a member access result for a JSON object.
1109///
1110/// This struct is returned by [`RawJsonValue::to_member()`] and allows you to handle
1111/// both present and missing object members. It wraps an optional value that is
1112/// `Some` if the member exists and `None` if it doesn't.
1113///
1114/// # Examples
1115///
1116/// ```
1117/// # use nojson::RawJson;
1118/// # fn main() -> Result<(), nojson::JsonParseError> {
1119/// let json = RawJson::parse(r#"{"name": "Alice", "age": 30}"#)?;
1120/// let obj = json.value();
1121///
1122/// // Access an existing member
1123/// let name_member = obj.to_member("name")?;
1124/// let name: String = name_member.required()?.try_into()?;
1125/// assert_eq!(name, "Alice");
1126///
1127/// // Access a missing member
1128/// let city_member = obj.to_member("city")?;
1129/// let city: Option<String> = city_member.try_into()?;
1130/// assert_eq!(city, None);
1131/// # Ok(())
1132/// # }
1133/// ```
1134#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1135pub struct RawJsonMember<'text, 'raw, 'a> {
1136    object: RawJsonValue<'text, 'raw>,
1137    name: &'a str,
1138    member: Option<RawJsonValue<'text, 'raw>>,
1139}
1140
1141impl<'text, 'raw, 'a> RawJsonMember<'text, 'raw, 'a> {
1142    /// Returns the member value if it exists, or an error if it's missing.
1143    ///
1144    /// This method is useful when you need to ensure that a required member
1145    /// is present in the JSON object.
1146    ///
1147    /// # Examples
1148    ///
1149    /// ```
1150    /// # use nojson::RawJson;
1151    /// # fn main() -> Result<(), nojson::JsonParseError> {
1152    /// let json = RawJson::parse(r#"{"name": "Alice"}"#)?;
1153    /// let obj = json.value();
1154    ///
1155    /// // Required member exists
1156    /// let name = obj.to_member("name")?.required()?;
1157    /// assert_eq!(name.to_unquoted_string_str()?, "Alice");
1158    ///
1159    /// // Required member missing - returns error
1160    /// let age_result = obj.to_member("age")?.required();
1161    /// assert!(age_result.is_err());
1162    /// # Ok(())
1163    /// # }
1164    /// ```
1165    pub fn required(self) -> Result<RawJsonValue<'text, 'raw>, JsonParseError> {
1166        self.member.ok_or_else(|| {
1167            self.object
1168                .invalid(format!("required member '{}' is missing", self.name))
1169        })
1170    }
1171
1172    /// Returns the inner raw JSON value as an `Option`.
1173    ///
1174    /// This method provides direct access to the underlying `Option<RawJsonValue>`,
1175    /// allowing you to handle the presence or absence of the member yourself.
1176    ///
1177    /// # Examples
1178    ///
1179    /// ```
1180    /// # use nojson::RawJson;
1181    /// # fn main() -> Result<(), nojson::JsonParseError> {
1182    /// let json = RawJson::parse(r#"{"name": "Alice", "age": 30}"#)?;
1183    /// let obj = json.value();
1184    ///
1185    /// // Existing member
1186    /// let name_member = obj.to_member("name")?;
1187    /// if let Some(name_value) = name_member.get() {
1188    ///     assert_eq!(name_value.to_unquoted_string_str()?, "Alice");
1189    /// }
1190    ///
1191    /// // Missing member
1192    /// let city_member = obj.to_member("city")?;
1193    /// assert!(city_member.get().is_none());
1194    ///
1195    /// // Using with pattern matching
1196    /// match obj.to_member("age")?.get() {
1197    ///     Some(age_value) => {
1198    ///         let age: i32 = age_value.as_integer_str()?.parse()
1199    ///             .map_err(|e| age_value.invalid(e))?;
1200    ///         assert_eq!(age, 30);
1201    ///     }
1202    ///     None => println!("Age not provided"),
1203    /// }
1204    /// # Ok(())
1205    /// # }
1206    /// ```
1207    pub fn get(self) -> Option<RawJsonValue<'text, 'raw>> {
1208        self.member
1209    }
1210
1211    /// Applies a transformation function to the member value if it exists.
1212    ///
1213    /// This method is similar to [`Option::map`], but designed for transformations
1214    /// that can fail with a [`JsonParseError`]. If the member exists, the function
1215    /// is applied to its value. If the member doesn't exist, `Ok(None)` is returned.
1216    ///
1217    /// # Examples
1218    ///
1219    /// ```
1220    /// # use nojson::RawJson;
1221    /// # fn main() -> Result<(), nojson::JsonParseError> {
1222    /// let json = RawJson::parse(r#"{"name": "Alice", "age": "30"}"#)?;
1223    /// let obj = json.value();
1224    ///
1225    /// // Transform existing member
1226    /// let age_member = obj.to_member("age")?;
1227    /// let age: Option<i32> = age_member.map(|v| {
1228    ///     v.to_unquoted_string_str()?.parse().map_err(|e| v.invalid(e))
1229    /// })?;
1230    /// assert_eq!(age, Some(30));
1231    ///
1232    /// // Transform missing member
1233    /// let city_member = obj.to_member("city")?;
1234    /// let city: Option<String> = city_member.map(|v| v.try_into())?;
1235    /// assert_eq!(city, None);
1236    /// # Ok(())
1237    /// # }
1238    /// ```
1239    ///
1240    /// This is particularly useful when you need to perform parsing or validation
1241    /// on optional members without having to handle the `Option` separately:
1242    ///
1243    /// ```
1244    /// # use nojson::RawJson;
1245    /// # fn main() -> Result<(), nojson::JsonParseError> {
1246    /// let json = RawJson::parse(r#"{"score": "95.5"}"#)?;
1247    /// let obj = json.value();
1248    ///
1249    /// // Parse optional numeric string
1250    /// let score: Option<f64> = obj.to_member("score")?.map(|v| {
1251    ///     v.to_unquoted_string_str()?.parse().map_err(|e| v.invalid(e))
1252    /// })?;
1253    /// assert_eq!(score, Some(95.5));
1254    /// # Ok(())
1255    /// # }
1256    /// ```
1257    pub fn map<F, T>(self, f: F) -> Result<Option<T>, JsonParseError>
1258    where
1259        F: FnOnce(RawJsonValue<'text, 'raw>) -> Result<T, JsonParseError>,
1260    {
1261        self.member.map(f).transpose()
1262    }
1263}
1264
1265impl<'text, 'raw, 'a, T> TryFrom<RawJsonMember<'text, 'raw, 'a>> for Option<T>
1266where
1267    T: TryFrom<RawJsonValue<'text, 'raw>, Error = JsonParseError>,
1268{
1269    type Error = JsonParseError;
1270
1271    fn try_from(value: RawJsonMember<'text, 'raw, 'a>) -> Result<Self, Self::Error> {
1272        value.member.map(T::try_from).transpose()
1273    }
1274}