1use crate::error::FieldError;
5use crate::node::Node;
6use crate::value::Value;
7use std::any::Any;
8use std::collections::HashMap;
9use std::sync::Arc;
10
11#[derive(Clone, Debug, PartialEq)]
13pub enum PathPart {
14 Key(Arc<str>),
16 Index(usize),
17}
18
19impl PathPart {
20 pub fn as_key(&self) -> String {
21 match self {
22 PathPart::Key(k) => k.to_string(),
23 PathPart::Index(i) => i.to_string(),
24 }
25 }
26
27 fn write_to(&self, out: &mut String) {
28 match self {
29 PathPart::Key(k) => out.push_str(k),
30 PathPart::Index(i) => out.push_str(&i.to_string()),
31 }
32 }
33}
34
35#[derive(Default)]
38pub struct Context {
39 pub custom: HashMap<String, Box<dyn Any + Send + Sync>>,
43 pub refs: HashMap<String, Arc<Node>>,
45 pub(crate) defs: Arc<HashMap<String, Arc<Node>>>,
47 pub err: Vec<FieldError>,
49 pub(crate) terse: bool,
52}
53
54impl Context {
55 pub fn new() -> Context {
56 Context::default()
57 }
58
59 pub fn get<T: 'static>(&self, key: &str) -> Option<&T> {
61 self.custom.get(key).and_then(|b| b.downcast_ref::<T>())
62 }
63
64 pub fn set<T: Any + Send + Sync>(&mut self, key: &str, value: T) {
66 self.custom.insert(key.to_string(), Box::new(value));
67 }
68}
69
70pub struct State<'a> {
72 pub path_arr: &'a [PathPart],
75 pub key: &'a str,
77 pub value: &'a Value,
79 pub node: &'a Node,
81 pub parent_is_array: bool,
83 pub is_match: bool,
85 pub ctx: &'a mut Context,
86 pub absent: bool,
88 pub check_name: &'a str,
90}
91
92impl<'a> State<'a> {
93 pub fn path_str(&self) -> String {
95 join_path(self.path_arr)
96 }
97
98 pub fn path_keys(&self) -> Vec<String> {
100 self.path_arr.iter().map(|p| p.as_key()).collect()
101 }
102}
103
104pub fn join_path(path: &[PathPart]) -> String {
106 let mut out = String::new();
107 for p in path {
108 if matches!(p, PathPart::Key(k) if k.is_empty()) {
109 continue;
110 }
111 if !out.is_empty() {
112 out.push('.');
113 }
114 p.write_to(&mut out);
115 }
116 out
117}
118
119#[derive(Clone, Debug)]
121pub enum UpdateErr {
122 Text(String),
124 Field(Box<FieldError>),
126 Fields(Vec<FieldError>),
128}
129
130#[derive(Default)]
132pub struct Update {
133 pub done: bool,
135 pub why: Option<String>,
137 pub mark: i64,
139 pub err: Option<UpdateErr>,
140 pub val: Option<Value>,
142 pub node: Option<Arc<Node>>,
144 pub fatal: bool,
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 fn context_custom_is_typed() {
154 let mut c = Context::new();
155 c.set("n", 3u32);
156 assert_eq!(c.get::<u32>("n"), Some(&3));
157 assert_eq!(c.get::<String>("n"), None);
158 assert_eq!(c.get::<u32>("m"), None);
159 }
160
161 #[test]
162 fn paths_join_and_render() {
163 let k = |s: &str| PathPart::Key(s.into());
164 assert_eq!(
165 join_path(&[k("a"), k(""), k("b"), PathPart::Index(1)]),
166 "a.b.1"
167 );
168 assert_eq!(join_path(&[]), "");
169 assert_eq!(PathPart::Key("k".into()).as_key(), "k");
170 assert_eq!(PathPart::Index(2).as_key(), "2");
171 let mut ctx = Context::new();
172 let node = Node::default();
173 let path = [k("a")];
174 let s = State {
175 path_arr: &path,
176 key: "a",
177 value: &Value::Null,
178 node: &node,
179 parent_is_array: false,
180 is_match: false,
181 ctx: &mut ctx,
182 absent: false,
183 check_name: "",
184 };
185 assert_eq!(s.path_str(), "a");
186 assert_eq!(s.path_keys(), vec!["a".to_string()]);
187 let u = Update::default();
188 assert!(!u.done && u.val.is_none());
189 }
190}