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}