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}