sj/json/impls/object/inner.rs
1/*
2==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--
3
4SJ
5
6Copyright (C) 2019-2025 Anonymous
7
8There are several releases over multiple years,
9they are listed as ranges, such as: "2019-2025".
10
11This program is free software: you can redistribute it and/or modify
12it under the terms of the GNU Lesser General Public License as published by
13the Free Software Foundation, either version 3 of the License, or
14(at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19GNU Lesser General Public License for more details.
20
21You should have received a copy of the GNU Lesser General Public License
22along with this program. If not, see <https://www.gnu.org/licenses/>.
23
24::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
25*/
26
27//! # Inner
28
29use crate::{Error, Json, ObjectIndexes, Result};
30
31/// # Helper macro for Json::maybe_by()/maybe_mut_by()
32///
33/// Keys will be returned for logging purpose (from caller).
34macro_rules! maybe_by_or_mut_by { ($value: ident, $keys: ident, $code: tt) => {{
35 let keys = $keys.into();
36 if keys.len() == 0 {
37 return Err(err!("Keys must not be empty"));
38 }
39
40 let mut value = Some($value);
41 for (nth, key) in keys.iter().enumerate() {
42 match value {
43 Some(Json::Object(object)) => value = object.$code(key),
44 Some(_) => return Err(Error::from(match nth {
45 0 => e!("Json is not an Object"),
46 _ => err!("Json at {:?} is not an Object", keys.index_with_range_to(..nth)),
47 })),
48 None => return Err(err!("There is no value at {:?}", keys.index_with_range_to(..nth))),
49 };
50 }
51
52 Ok((value, keys))
53}}}
54
55/// # Helper function for macro maybe_by_or_mut_by!()
56///
57/// This provides one single place for calling macro `maybe_by_or_mut_by!()` with `get`
58pub (super) fn maybe_by<'a, K, const N: usize>(value: &Json, keys: K) -> Result<(Option<&Json>, ObjectIndexes<'a, N>)>
59where K: Into<ObjectIndexes<'a, N>> {
60 maybe_by_or_mut_by!(value, keys, get)
61}
62
63/// # Helper function for macro maybe_by_or_mut_by!()
64///
65/// This provides one single place for calling macro `maybe_by_or_mut_by!()` with `get_mut`
66pub (super) fn maybe_mut_by<'a, K, const N: usize>(value: &mut Json, keys: K) -> Result<(Option<&mut Json>, ObjectIndexes<'a, N>)>
67where K: Into<ObjectIndexes<'a, N>> {
68 maybe_by_or_mut_by!(value, keys, get_mut)
69}
70
71/// # Takes an optional item from an object and its sub objects
72///
73/// The function returns an error on one of these conditions:
74///
75/// - Keys are empty.
76/// - The value or any of its sub items is not an object.
77///
78/// Keys will be returned for logging purpose (from caller).
79pub (super) fn maybe_take_by<'a, K, const N: usize>(value: &mut Json, keys: K) -> Result<(Option<Json>, ObjectIndexes<'a, N>)>
80where K: Into<ObjectIndexes<'a, N>> {
81 let keys = keys.into();
82 if keys.len() == 0 {
83 return Err(e!("Keys must not be empty"));
84 }
85
86 let mut result = None;
87 let mut value = Some(value);
88 for (nth, key) in keys.iter().enumerate() {
89 match value {
90 Some(Json::Object(object)) => if nth + 1 == keys.len() {
91 result = object.remove(key);
92 break;
93 } else {
94 value = object.get_mut(key);
95 },
96 Some(_) => return Err(match nth {
97 0 => e!("Json is not an Object"),
98 _ => err!("Json at {:?} is not an Object", keys.index_with_range_to(..nth)),
99 }),
100 None => return Err(err!("There is no value at {:?}", keys.index_with_range_to(..nth))),
101 };
102 }
103
104 Ok((result, keys))
105}