1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//! # dyn_path
//!
//! dyn_path is a set of macros that permit you access objects
//! that have `.get()` methods that return `Option<T>` in a nested
//! way.
//!
//! It is as specific as it looks, but most libraries that parse
//! data interchange languages have a "Value" that contains other
//! "Value"s inside. And casually all the "Value"s have a `.get()`
//! method, a generic `.get()` method in fact.
//!
//! How does this work? Just like JavaScript.
//! ```rust
//! use serde_json::json;
//! use dyn_path::dyn_access;
//!
//! let object = json!({
//! "very": {
//! "nested": {
//! "value": [
//! "hello",
//! "world"
//! ]
//! }
//! }
//! });
//!
//! let hello = dyn_access!(object.very.nested.value[0]).unwrap();
//! let world = dyn_access!(object.very.nested.value[1]).unwrap();
//!
//! assert_eq!(hello, "hello");
//! assert_eq!(world, "world");
//! ```
//! This is also useful for nested `HashMap`s but the difference is
//! that you will actually get a compile time error if you are wrong
//! with the type.
//! ```rust
//! use std::collections::HashMap;
//! use dyn_path::dyn_access;
//!
//! let map: HashMap<String, HashMap<String, HashMap<i32, ()>>> = HashMap::new();
//!
//! dyn_access!(map.nested.value[&0]); // since we don't have any real value this will return None.
//! ```
//! Check the available macro documentation to learn more about how to use
//! the specific macros.
pub extern crate alloc;
/// # dyn_access
/// The `dyn_access` has a specific use-case, which is
/// accessing very deeply nested values in parsed structures.
///
/// For example, imagine you have an API, which you only need some
/// data for. Usually in JavaScript you simply fetch a value and
/// access it dinamically with a path like `value?.nested?.nested[0]`
/// then simply check for undefined.
///
/// This macro permits you access to very nested objects with javascript
/// like indexers, with the exception you don't need to use `?`, as you
/// get an `Option<T>` instead.
///
/// This macro is recursive and will stop working when the value
/// doesn't have a `.get` method that returns an Option<T>.
///
/// To invoke this macro you just use a path like
/// ```rust
/// use serde_json::json;
/// use dyn_path::dyn_access;
///
/// let object = json!({
/// "very": {
/// "nested": {
/// "value": [
/// "hello",
/// "world"
/// ]
/// }
/// }
/// });
///
/// let hello = dyn_access!(object.very.nested.value[0]).unwrap();
/// let world = dyn_access!(object.very.nested.value[1]).unwrap();
///
/// assert_eq!(hello, "hello");
/// assert_eq!(world, "world");
/// ```
/// You also have indices available to you, whether it is
/// for an array or an object.
///
/// Notice how the first element is the name of the variable,
/// you can have an expression in there with parenthesis like
/// `(value.parse::<serde_json::Value>()?).very.nested.value`,
/// the parenthesis are due to parsing system limitation since
/// this is a `macro_rules` and not a `proc_macro`.
};
=> ;
=> ;
=> ;
}
/// # dyn_path
/// The `dyn_path` macro just acts as a Display for the `dyn_access`
/// macro, meaning that this just generates a precomputed `String`
/// of the input path.
///
/// The syntax is essentially the same, with the only difference this
/// doesn't have a "head", meaning that you don't need to specify a source
/// from where to access something, the path is hypotetical.
///
/// An example invocation of this macro is
/// ```rust
/// use dyn_path::dyn_path;
///
/// let display_path = dyn_path!(nested.path.at[1 + 1].with["no"]["head"]);
///
/// assert_eq!(display_path, r#"nested.path.at[2].with["no"]["head"]"#);
/// ```
/// Notice how the macro pre-computes the indexes and generates the target string.