nojson/
raw.rs

1use std::{borrow::Cow, fmt::Display, hash::Hash, ops::Range};
2
3use crate::{DisplayJson, JsonFormatter, JsonValueKind, parse::JsonParser};
4
5pub use crate::parse_error::JsonParseError;
6
7/// Parsed JSON text (syntactically correct, but not yet converted to Rust types).
8///
9/// This struct holds a JSON text in its original form
10/// (i.e., JSON integers are not converted to Rust's integers),
11/// while ensuring the text is valid JSON syntax.
12///
13/// [`RawJson`] maintains index information about each JSON value in the text,
14/// including its type ([`JsonValueKind`]) and the start and end byte positions.
15/// You can traverse the JSON structure by accessing the top-level value
16/// via [`RawJson::value()`], which returns a [`RawJsonValue`]
17/// that provides methods to explore nested elements and convert them into Rust types.
18///
19/// Note that, for simple use cases,
20/// using [`Json`](crate::Json), which internally uses [`RawJson`], is a more convenient way to parse JSON text into Rust types.
21#[derive(Debug, Clone)]
22pub struct RawJson<'text> {
23    text: &'text str,
24    values: Vec<JsonValueIndexEntry>,
25}
26
27impl<'text> RawJson<'text> {
28    /// Parses a JSON string into a [`RawJson`] instance.
29    ///
30    /// This validates the JSON syntax without converting values to Rust types.
31    ///
32    /// # Example
33    ///
34    /// ```
35    /// # use nojson::RawJson;
36    /// # fn main() -> Result<(), nojson::JsonParseError> {
37    /// let text = r#"{"name": "John", "age": 30}"#;
38    /// let json = RawJson::parse(text)?;
39    /// # Ok(())
40    /// # }
41    /// ```
42    pub fn parse(text: &'text str) -> Result<Self, JsonParseError> {
43        let values = JsonParser::new(text).parse()?;
44        Ok(Self { text, values })
45    }
46
47    /// Returns the original JSON text.
48    pub fn text(&self) -> &'text str {
49        self.text
50    }
51
52    /// Returns the top-level value of the JSON.
53    ///
54    /// This value can be used as an entry point to traverse the entire JSON structure
55    /// and convert it to Rust types.
56    ///
57    /// # Example
58    ///
59    /// ```
60    /// # use nojson::RawJson;
61    /// # fn main() -> Result<(), nojson::JsonParseError> {
62    /// let text = r#"{"name": "John", "age": 30}"#;
63    /// let json = RawJson::parse(text).unwrap();
64    /// let value = json.value();
65    /// # Ok(())
66    /// # }
67    /// ```
68    pub fn value(&self) -> RawJsonValue<'text, '_> {
69        RawJsonValue {
70            json: self,
71            index: 0,
72        }
73    }
74
75    /// Finds the JSON value at the specified byte position in the original text.
76    ///
77    /// This method traverses the JSON structure to find the most specific value
78    /// that contains the given position.
79    /// It returns `None` if the position is outside the bounds of the JSON text.
80    ///
81    /// This method is useful for retrieving the context
82    /// where a [`JsonParseError::InvalidValue`] error occurred.
83    ///
84    /// # Example
85    ///
86    /// ```
87    /// # use nojson::RawJson;
88    /// # fn main() -> Result<(), nojson::JsonParseError> {
89    /// let json = RawJson::parse(r#"{"name": "John", "age": 30}"#)?;
90    ///
91    /// // Position at "name" key
92    /// let name_value = json.get_value_by_position(2).expect("infallible");
93    /// assert_eq!(name_value.as_raw_str(), r#""name""#);
94    ///
95    /// // Position at number value
96    /// let age_value = json.get_value_by_position(25).expect("infallible");
97    /// assert_eq!(age_value.as_raw_str(), "30");
98    /// # Ok(())
99    /// # }
100    /// ```
101    pub fn get_value_by_position(&self, position: usize) -> Option<RawJsonValue<'text, '_>> {
102        let mut value = self.value();
103        if !value.entry().text.contains(&position) {
104            return None;
105        }
106        while let Some(child) = Children::new(value).find(|c| c.entry().text.contains(&position)) {
107            value = child;
108        }
109        Some(value)
110    }
111}
112
113impl PartialEq for RawJson<'_> {
114    fn eq(&self, other: &Self) -> bool {
115        self.text == other.text
116    }
117}
118
119impl Eq for RawJson<'_> {}
120
121impl PartialOrd for RawJson<'_> {
122    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
123        Some(self.cmp(other))
124    }
125}
126
127impl Ord for RawJson<'_> {
128    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
129        self.text.cmp(other.text)
130    }
131}
132
133impl Hash for RawJson<'_> {
134    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
135        self.text.hash(state);
136    }
137}
138
139impl Display for RawJson<'_> {
140    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141        write!(f, "{}", self.text)
142    }
143}
144
145impl DisplayJson for RawJson<'_> {
146    fn fmt(&self, f: &mut JsonFormatter<'_, '_>) -> std::fmt::Result {
147        DisplayJson::fmt(&self.value(), f)
148    }
149}
150
151#[derive(Debug, Clone, PartialEq, Eq)]
152pub(crate) struct JsonValueIndexEntry {
153    pub kind: JsonValueKind,
154    pub escaped: bool,
155    pub text: Range<usize>,
156    pub end_index: usize,
157}
158
159/// A JSON value in a [`RawJson`].
160///
161/// This struct provides the text and structural information (e.g., kind, parent, children) of a JSON value.
162/// Interpreting that text is the responsibility of the user.
163///
164/// To convert this JSON value to a Rust type, you can use the standard [`TryFrom`] and [`TryInto`] traits.
165/// For other parsing approaches, you can use the [`FromStr`](std::str::FromStr) trait or other parsing methods
166/// to parse the underlying JSON text of this value as shown below:
167///
168/// ```
169/// # use nojson::{RawJson, RawJsonValue, JsonParseError};
170/// # fn main() -> Result<(), JsonParseError> {
171/// let text = "1.23";
172/// let json = RawJson::parse(text)?;
173/// let raw: RawJsonValue = json.value();
174/// let parsed: f32 =
175///     raw.as_number_str()?.parse().map_err(|e| raw.invalid(e))?;
176/// assert_eq!(parsed, 1.23);
177/// # Ok(())
178/// # }
179/// ```
180///
181/// For types that implement `TryFrom<RawJsonValue<'_, '_>>`, you can use the [`TryInto`] trait:
182///
183/// ```
184/// # use nojson::{RawJson, JsonParseError};
185/// # fn main() -> Result<(), JsonParseError> {
186/// let json = RawJson::parse("[1, 2, 3]")?;
187/// let numbers: [u32; 3] = json.value().try_into()?;
188/// assert_eq!(numbers, [1, 2, 3]);
189/// # Ok(())
190/// # }
191/// ```
192#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
193pub struct RawJsonValue<'text, 'raw> {
194    index: usize,
195    json: &'raw RawJson<'text>,
196}
197
198impl<'text, 'raw> RawJsonValue<'text, 'raw> {
199    /// Returns the kind of this JSON value.
200    pub fn kind(self) -> JsonValueKind {
201        self.json.values[self.index].kind
202    }
203
204    /// Returns the byte position where this value begins in the JSON text (`self.json().text()`).
205    pub fn position(self) -> usize {
206        self.json.values[self.index].text.start
207    }
208
209    /// Returns a reference to the [`RawJson`] instance that contains this value.
210    pub fn json(self) -> &'raw RawJson<'text> {
211        self.json
212    }
213
214    /// Returns the parent value (array or object) that contains this value.
215    pub fn parent(self) -> Option<Self> {
216        if self.index == 0 {
217            return None;
218        }
219        self.json.get_value_by_position(self.position() - 1)
220    }
221
222    /// Returns the raw JSON text of this value as-is.
223    pub fn as_raw_str(self) -> &'text str {
224        let text = &self.json.values[self.index].text;
225        &self.json.text[text.start..text.end]
226    }
227
228    /// Similar to [`RawJsonValue::as_raw_str()`],
229    /// but this method verifies whether the value is a JSON boolean.
230    ///
231    /// # Examples
232    ///
233    /// ```
234    /// # use nojson::RawJson;
235    /// # fn main() -> Result<(), nojson::JsonParseError> {
236    /// let json = RawJson::parse("false")?;
237    /// assert_eq!(json.value().as_boolean_str()?.parse(), Ok(false));
238    ///
239    /// let json = RawJson::parse("10")?;
240    /// assert!(json.value().as_boolean_str().is_err());
241    /// # Ok(())
242    /// # }
243    /// ```
244    pub fn as_boolean_str(self) -> Result<&'text str, JsonParseError> {
245        self.expect([JsonValueKind::Boolean])
246            .map(|v| v.as_raw_str())
247    }
248
249    /// Similar to [`RawJsonValue::as_raw_str()`],
250    /// but this method verifies whether the value is a JSON integer number.
251    ///
252    /// # Examples
253    ///
254    /// ```
255    /// # use nojson::RawJson;
256    /// # fn main() -> Result<(), nojson::JsonParseError> {
257    /// let json = RawJson::parse("123")?;
258    /// assert_eq!(json.value().as_integer_str()?.parse(), Ok(123));
259    ///
260    /// let json = RawJson::parse("12.3")?;
261    /// assert!(json.value().as_integer_str().is_err());
262    /// # Ok(())
263    /// # }
264    /// ```
265    pub fn as_integer_str(self) -> Result<&'text str, JsonParseError> {
266        self.expect([JsonValueKind::Integer])
267            .map(|v| v.as_raw_str())
268    }
269
270    /// Similar to [`RawJsonValue::as_raw_str()`],
271    /// but this method verifies whether the value is a JSON floating-point number.
272    ///
273    /// # Examples
274    ///
275    /// ```
276    /// # use nojson::RawJson;
277    /// # fn main() -> Result<(), nojson::JsonParseError> {
278    /// let json = RawJson::parse("12.3")?;
279    /// assert_eq!(json.value().as_float_str()?.parse(), Ok(12.3));
280    ///
281    /// let json = RawJson::parse("123")?;
282    /// assert!(json.value().as_float_str().is_err());
283    /// # Ok(())
284    /// # }
285    /// ```
286    pub fn as_float_str(self) -> Result<&'text str, JsonParseError> {
287        self.expect([JsonValueKind::Float]).map(|v| v.as_raw_str())
288    }
289
290    /// Similar to [`RawJsonValue::as_raw_str()`],
291    /// but this method verifies whether the value is a JSON number.
292    ///
293    /// # Examples
294    ///
295    /// ```
296    /// # use nojson::RawJson;
297    /// # fn main() -> Result<(), nojson::JsonParseError> {
298    /// let json = RawJson::parse("123")?;
299    /// assert_eq!(json.value().as_number_str()?.parse(), Ok(123));
300    ///
301    /// let json = RawJson::parse("12.3")?;
302    /// assert_eq!(json.value().as_number_str()?.parse(), Ok(12.3));
303    ///
304    /// let json = RawJson::parse("null")?;
305    /// assert!(json.value().as_number_str().is_err());
306    /// # Ok(())
307    /// # }
308    /// ```
309    pub fn as_number_str(self) -> Result<&'text str, JsonParseError> {
310        self.expect([JsonValueKind::Integer, JsonValueKind::Float])
311            .map(|v| v.as_raw_str())
312    }
313
314    /// Similar to [`RawJsonValue::as_raw_str()`],
315    /// but this method verifies whether the value is a JSON string and returns the unquoted content of the string.
316    ///
317    /// # Examples
318    ///
319    /// ```
320    /// # use nojson::RawJson;
321    /// # fn main() -> Result<(), nojson::JsonParseError> {
322    /// let json = RawJson::parse("\"123\"")?;
323    /// assert_eq!(json.value().to_unquoted_string_str()?, "123");
324    /// assert_eq!(json.value().to_unquoted_string_str()?.parse(), Ok(123));
325    ///
326    /// let json = RawJson::parse("123")?;
327    /// assert!(json.value().to_unquoted_string_str().is_err());
328    /// # Ok(())
329    /// # }
330    /// ```
331    pub fn to_unquoted_string_str(self) -> Result<Cow<'text, str>, JsonParseError> {
332        self.expect([JsonValueKind::String]).map(|v| v.unquote())
333    }
334
335    /// If the value is a JSON array,
336    /// this method returns an iterator that iterates over the array's elements.
337    ///
338    /// # Examples
339    ///
340    /// ```
341    /// # use nojson::RawJson;
342    /// # fn main() -> Result<(), nojson::JsonParseError> {
343    /// let json = RawJson::parse("[0, 1, 2]")?;
344    /// for (i, v) in json.value().to_array()?.enumerate() {
345    ///     assert_eq!(v.as_integer_str()?.parse(), Ok(i));
346    /// }
347    ///
348    /// let json = RawJson::parse("null")?;
349    /// assert!(json.value().to_array().is_err());
350    /// # Ok(())
351    /// # }
352    /// ```
353    ///
354    /// # Note
355    ///
356    /// For converting to a fixed-size array, you can use the `TryInto` trait instead:
357    /// ```
358    /// # use nojson::RawJson;
359    /// # fn main() -> Result<(), nojson::JsonParseError> {
360    /// let json = RawJson::parse("[0, 1, 2]")?;
361    /// let fixed_array: [usize; 3] = json.value().try_into()?;
362    /// # Ok(())
363    /// # }
364    /// ```
365    pub fn to_array(self) -> Result<impl Iterator<Item = Self>, JsonParseError> {
366        self.expect([JsonValueKind::Array]).map(Children::new)
367    }
368
369    /// If the value is a JSON object,
370    /// this method returns an iterator that iterates over
371    /// the name and value pairs of the object's members.
372    ///
373    /// # Examples
374    ///
375    /// ```
376    /// # use nojson::RawJson;
377    /// # fn main() -> Result<(), nojson::JsonParseError> {
378    /// let json = RawJson::parse(r#"{"a": 1, "b": 2, "c": 3}"#)?;
379    /// let mut members = json.value().to_object()?;
380    /// let (k, v) = members.next().expect("some");
381    /// assert_eq!(k.to_unquoted_string_str()?, "a");
382    /// assert_eq!(v.as_integer_str()?.parse(), Ok(1));
383    ///
384    /// let json = RawJson::parse("null")?;
385    /// assert!(json.value().to_object().is_err());
386    /// # Ok(())
387    /// # }
388    /// ```
389    pub fn to_object(self) -> Result<impl Iterator<Item = (Self, Self)>, JsonParseError> {
390        self.expect([JsonValueKind::Object])
391            .map(JsonKeyValuePairs::new)
392    }
393
394    /// Attempts to access a member of a JSON object by name.
395    ///
396    /// This method returns a [`RawJsonMember`] that represents the result of
397    /// looking up the specified member name. The member may or may not exist,
398    /// and you can use methods like [`RawJsonMember::required()`] or convert
399    /// it to an `Option<T>` to handle both cases.
400    ///
401    /// # Examples
402    ///
403    /// ```
404    /// # use nojson::RawJson;
405    /// # fn main() -> Result<(), nojson::JsonParseError> {
406    /// let json = RawJson::parse(r#"{"name": "Alice", "age": 30}"#)?;
407    /// let obj = json.value();
408    ///
409    /// // Access existing member
410    /// let name_value: String = obj.to_member("name")?.required()?.try_into()?;
411    /// assert_eq!(name_value, "Alice");
412    ///
413    /// // Handle optional member
414    /// let city_member = obj.to_member("city")?;
415    /// let city: Option<String> = city_member.try_into()?;
416    /// assert_eq!(city, None);
417    /// # Ok(())
418    /// # }
419    /// ```
420    ///
421    /// # Performance
422    ///
423    /// This method has O(n) complexity where n is the number of members in the object,
424    /// as it performs a linear search through all object members to find the requested name.
425    /// If you need to access multiple members from the same object, consider using
426    /// [`RawJsonValue::to_object()`] instead, which allows you to iterate through
427    /// all members once and extract the values you need more efficiently.
428    ///
429    /// ```
430    /// # use nojson::RawJson;
431    /// # fn main() -> Result<(), nojson::JsonParseError> {
432    /// let json = RawJson::parse(r#"{"name": "Alice", "age": 30, "city": "New York"}"#)?;
433    /// let obj = json.value();
434    ///
435    /// // Efficient: single iteration for multiple members
436    /// let mut name = None;
437    /// let mut age = None;
438    /// let mut city = None;
439    /// for (key, value) in obj.to_object()? {
440    ///     match key.to_unquoted_string_str()?.as_ref() {
441    ///         "name" => name = Some(value),
442    ///         "age" => age = Some(value),
443    ///         "city" => city = Some(value),
444    ///         _ => {}
445    ///     }
446    /// }
447    /// # Ok(())
448    /// # }
449    /// ```
450    pub fn to_member<'a>(
451        self,
452        name: &'a str,
453    ) -> Result<RawJsonMember<'text, 'raw, 'a>, JsonParseError> {
454        let member = self
455            .to_object()?
456            .find(|(key, _)| key.unquote() == name)
457            .map(|(_, value)| value);
458
459        Ok(RawJsonMember {
460            object: self,
461            name,
462            member,
463        })
464    }
465
466    /// Creates a [`JsonParseError::InvalidValue`] error for this value.
467    ///
468    /// This is a convenience method that's equivalent to calling
469    /// [`JsonParseError::invalid_value()`] with this value.
470    ///
471    /// # Examples
472    ///
473    /// ```
474    /// # use nojson::RawJson;
475    /// # fn main() -> Result<(), nojson::JsonParseError> {
476    /// let json = RawJson::parse("\"not_a_number\"")?;
477    /// let value = json.value();
478    ///
479    /// // These are equivalent:
480    /// let error1 = value.invalid("expected a number");
481    /// let error2 = nojson::JsonParseError::invalid_value(value, "expected a number");
482    /// # Ok(())
483    /// # }
484    /// ```
485    pub fn invalid<E>(self, error: E) -> JsonParseError
486    where
487        E: Into<Box<dyn Send + Sync + std::error::Error>>,
488    {
489        JsonParseError::invalid_value(self, error)
490    }
491
492    fn unquote(self) -> Cow<'text, str> {
493        debug_assert!(self.kind().is_string());
494
495        let content = &self.as_raw_str()[1..self.as_raw_str().len() - 1];
496        if !self.entry().escaped {
497            return Cow::Borrowed(content);
498        }
499
500        let mut unescaped = String::with_capacity(content.len());
501        let mut chars = content.chars();
502        while let Some(c) = chars.next() {
503            match c {
504                '\\' => {
505                    let c = chars.next().expect("infallible");
506                    match c {
507                        '\\' | '/' | '"' => unescaped.push(c),
508                        'n' => unescaped.push('\n'),
509                        't' => unescaped.push('\t'),
510                        'r' => unescaped.push('\r'),
511                        'b' => unescaped.push('\u{8}'),
512                        'f' => unescaped.push('\u{c}'),
513                        'u' => {
514                            let c = std::str::from_utf8(&[
515                                chars.next().expect("infallible") as u8,
516                                chars.next().expect("infallible") as u8,
517                                chars.next().expect("infallible") as u8,
518                                chars.next().expect("infallible") as u8,
519                            ])
520                            .ok()
521                            .and_then(|code| u32::from_str_radix(code, 16).ok())
522                            .and_then(char::from_u32)
523                            .expect("infallible");
524                            unescaped.push(c);
525                        }
526                        _ => unreachable!(),
527                    }
528                }
529                _ => unescaped.push(c),
530            }
531        }
532        Cow::Owned(unescaped)
533    }
534
535    fn expect<const N: usize>(self, kinds: [JsonValueKind; N]) -> Result<Self, JsonParseError> {
536        if kinds.contains(&self.kind()) {
537            Ok(self)
538        } else {
539            Err(self.invalid(format!(
540                "expected {}, but found {:?}",
541                if kinds.len() == 1 {
542                    format!("{:?}", kinds[0])
543                } else {
544                    format!("one of {kinds:?}")
545                },
546                self.kind()
547            )))
548        }
549    }
550
551    fn entry(&self) -> &JsonValueIndexEntry {
552        &self.json.values[self.index]
553    }
554}
555
556impl Display for RawJsonValue<'_, '_> {
557    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
558        write!(f, "{}", self.as_raw_str())
559    }
560}
561
562impl DisplayJson for RawJsonValue<'_, '_> {
563    fn fmt(&self, f: &mut JsonFormatter<'_, '_>) -> std::fmt::Result {
564        match self.kind() {
565            JsonValueKind::Null
566            | JsonValueKind::Boolean
567            | JsonValueKind::Integer
568            | JsonValueKind::Float => write!(f.inner_mut(), "{}", self.as_raw_str()),
569            JsonValueKind::String => f.string(self.unquote()),
570            JsonValueKind::Array => f.array(|f| f.elements(self.to_array().expect("infallible"))),
571            JsonValueKind::Object => f.object(|f| f.members(self.to_object().expect("infallible"))),
572        }
573    }
574}
575
576#[derive(Debug)]
577struct Children<'text, 'raw> {
578    value: RawJsonValue<'text, 'raw>,
579    end_index: usize,
580}
581
582impl<'text, 'raw> Children<'text, 'raw> {
583    fn new(mut value: RawJsonValue<'text, 'raw>) -> Self {
584        let end_index = value.entry().end_index;
585        value.index += 1;
586        Self { value, end_index }
587    }
588}
589
590impl<'text, 'raw> Iterator for Children<'text, 'raw> {
591    type Item = RawJsonValue<'text, 'raw>;
592
593    fn next(&mut self) -> Option<Self::Item> {
594        if self.value.index == self.end_index {
595            return None;
596        }
597        let value = self.value;
598        self.value.index = value.entry().end_index;
599        Some(value)
600    }
601}
602
603#[derive(Debug)]
604struct JsonKeyValuePairs<'text, 'raw> {
605    inner: Children<'text, 'raw>,
606}
607
608impl<'text, 'raw> JsonKeyValuePairs<'text, 'raw> {
609    fn new(object: RawJsonValue<'text, 'raw>) -> Self {
610        Self {
611            inner: Children::new(object),
612        }
613    }
614}
615
616impl<'text, 'raw> Iterator for JsonKeyValuePairs<'text, 'raw> {
617    type Item = (RawJsonValue<'text, 'raw>, RawJsonValue<'text, 'raw>);
618
619    fn next(&mut self) -> Option<Self::Item> {
620        let key = self.inner.next()?;
621        let value = self.inner.next().expect("infallible");
622        Some((key, value))
623    }
624}
625
626/// Represents a member access result for a JSON object.
627///
628/// This struct is returned by [`RawJsonValue::to_member()`] and allows you to handle
629/// both present and missing object members. It wraps an optional value that is
630/// `Some` if the member exists and `None` if it doesn't.
631///
632/// # Examples
633///
634/// ```
635/// # use nojson::RawJson;
636/// # fn main() -> Result<(), nojson::JsonParseError> {
637/// let json = RawJson::parse(r#"{"name": "Alice", "age": 30}"#)?;
638/// let obj = json.value();
639///
640/// // Access an existing member
641/// let name_member = obj.to_member("name")?;
642/// let name: String = name_member.required()?.try_into()?;
643/// assert_eq!(name, "Alice");
644///
645/// // Access a missing member
646/// let city_member = obj.to_member("city")?;
647/// let city: Option<String> = city_member.try_into()?;
648/// assert_eq!(city, None);
649/// # Ok(())
650/// # }
651/// ```
652#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
653pub struct RawJsonMember<'text, 'raw, 'a> {
654    object: RawJsonValue<'text, 'raw>,
655    name: &'a str,
656    member: Option<RawJsonValue<'text, 'raw>>,
657}
658
659impl<'text, 'raw, 'a> RawJsonMember<'text, 'raw, 'a> {
660    /// Returns the member value if it exists, or an error if it's missing.
661    ///
662    /// This method is useful when you need to ensure that a required member
663    /// is present in the JSON object.
664    ///
665    /// # Examples
666    ///
667    /// ```
668    /// # use nojson::RawJson;
669    /// # fn main() -> Result<(), nojson::JsonParseError> {
670    /// let json = RawJson::parse(r#"{"name": "Alice"}"#)?;
671    /// let obj = json.value();
672    ///
673    /// // Required member exists
674    /// let name = obj.to_member("name")?.required()?;
675    /// assert_eq!(name.to_unquoted_string_str()?, "Alice");
676    ///
677    /// // Required member missing - returns error
678    /// let age_result = obj.to_member("age")?.required();
679    /// assert!(age_result.is_err());
680    /// # Ok(())
681    /// # }
682    /// ```
683    pub fn required(self) -> Result<RawJsonValue<'text, 'raw>, JsonParseError> {
684        self.member.ok_or_else(|| {
685            self.object
686                .invalid(format!("required member '{}' is missing", self.name))
687        })
688    }
689}
690
691impl<'text, 'raw, 'a, T> TryFrom<RawJsonMember<'text, 'raw, 'a>> for Option<T>
692where
693    T: TryFrom<RawJsonValue<'text, 'raw>>,
694    JsonParseError: From<T::Error>,
695{
696    type Error = JsonParseError;
697
698    fn try_from(value: RawJsonMember<'text, 'raw, 'a>) -> Result<Self, Self::Error> {
699        value
700            .member
701            .map(T::try_from)
702            .transpose()
703            .map_err(JsonParseError::from)
704    }
705}