1use std::collections::{HashMap, VecDeque};
2
3use serde::Serialize;
4use serde_json::value::{to_value, Map, Value as Json};
5
6use crate::block::{BlockContext, BlockParamHolder};
7use crate::error::{RenderError, RenderErrorReason};
8use crate::grammar::Rule;
9use crate::json::path::*;
10use crate::json::value::ScopedJson;
11use crate::util::extend;
12
13pub type Object = HashMap<String, Json>;
14
15#[derive(Debug, Clone)]
18pub struct Context {
19 data: Json,
20}
21
22#[derive(Debug)]
23enum ResolvedPath<'a> {
24 AbsolutePath(Vec<String>),
27 RelativePath(Vec<String>),
29 BlockParamValue(Vec<String>, &'a Json),
31 LocalValue(Vec<String>, &'a Json),
33}
34
35fn parse_json_visitor<'a>(
36 relative_path: &[PathSeg],
37 block_contexts: &'a VecDeque<BlockContext<'_>>,
38 always_for_absolute_path: bool,
39) -> ResolvedPath<'a> {
40 let mut path_context_depth: i64 = 0;
41 let mut with_block_param = None;
42 let mut from_root = false;
43
44 for path_seg in relative_path {
46 match path_seg {
47 PathSeg::Named(the_path) => {
48 if let Some((holder, base_path)) = get_in_block_params(block_contexts, the_path) {
49 with_block_param = Some((holder, base_path));
50 }
51 break;
52 }
53 PathSeg::Ruled(the_rule) => match the_rule {
54 Rule::path_root => {
55 from_root = true;
56 break;
57 }
58 Rule::path_up => path_context_depth += 1,
59 _ => break,
60 },
61 }
62 }
63
64 let mut path_stack = Vec::with_capacity(relative_path.len() + 5);
65 match with_block_param {
66 Some((BlockParamHolder::Value(ref value), _)) => {
67 merge_json_path(&mut path_stack, &relative_path[1..]);
68 ResolvedPath::BlockParamValue(path_stack, value)
69 }
70 Some((BlockParamHolder::Path(ref paths), base_path)) => {
71 extend(&mut path_stack, base_path);
72 if !paths.is_empty() {
73 extend(&mut path_stack, paths);
74 }
75 merge_json_path(&mut path_stack, &relative_path[1..]);
76
77 ResolvedPath::AbsolutePath(path_stack)
78 }
79 None => {
80 if path_context_depth > 0 {
81 let blk = block_contexts
82 .get(path_context_depth as usize)
83 .or_else(|| block_contexts.front());
84
85 if let Some(base_value) = blk.and_then(|blk| blk.base_value()) {
86 merge_json_path(&mut path_stack, relative_path);
87 ResolvedPath::LocalValue(path_stack, base_value)
88 } else {
89 if let Some(base_path) = blk.map(|blk| blk.base_path()) {
90 extend(&mut path_stack, base_path);
91 }
92 merge_json_path(&mut path_stack, relative_path);
93 ResolvedPath::AbsolutePath(path_stack)
94 }
95 } else if from_root {
96 merge_json_path(&mut path_stack, relative_path);
97 ResolvedPath::AbsolutePath(path_stack)
98 } else if always_for_absolute_path {
99 if let Some(base_value) = block_contexts.front().and_then(|blk| blk.base_value()) {
100 merge_json_path(&mut path_stack, relative_path);
101 ResolvedPath::LocalValue(path_stack, base_value)
102 } else {
103 if let Some(base_path) = block_contexts.front().map(|blk| blk.base_path()) {
104 extend(&mut path_stack, base_path);
105 }
106 merge_json_path(&mut path_stack, relative_path);
107 ResolvedPath::AbsolutePath(path_stack)
108 }
109 } else {
110 merge_json_path(&mut path_stack, relative_path);
111 ResolvedPath::RelativePath(path_stack)
112 }
113 }
114 }
115}
116
117fn get_data<'a>(d: Option<&'a Json>, p: &str) -> Result<Option<&'a Json>, RenderError> {
118 let result = match d {
119 Some(Json::Array(l)) => p
120 .parse::<usize>()
121 .map(|idx_u| l.get(idx_u))
122 .map_err(|_| RenderErrorReason::InvalidJsonIndex(p.to_owned()))?,
123 Some(Json::Object(m)) => m.get(p),
124 Some(_) => None,
125 None => None,
126 };
127 Ok(result)
128}
129
130fn get_in_block_params<'a>(
131 block_contexts: &'a VecDeque<BlockContext<'_>>,
132 p: &str,
133) -> Option<(&'a BlockParamHolder, &'a Vec<String>)> {
134 for bc in block_contexts {
135 let v = bc.get_block_param(p);
136 if v.is_some() {
137 return v.map(|v| (v, bc.base_path()));
138 }
139 }
140
141 None
142}
143
144pub(crate) fn merge_json(base: &Json, addition: &HashMap<&str, &Json>) -> Json {
145 let mut base_map = match base {
146 Json::Object(ref m) => m.clone(),
147 _ => Map::new(),
148 };
149
150 for (k, v) in addition.iter() {
151 base_map.insert(k.to_string(), (*v).clone());
152 }
153
154 Json::Object(base_map)
155}
156
157impl Context {
158 pub fn null() -> Context {
160 Context { data: Json::Null }
161 }
162
163 pub fn wraps<T: Serialize>(e: T) -> Result<Context, RenderError> {
165 to_value(e)
166 .map_err(|e| RenderErrorReason::SerdeError(e).into())
167 .map(|d| Context { data: d })
168 }
169
170 pub(crate) fn navigate<'rc>(
172 &'rc self,
173 relative_path: &[PathSeg],
174 block_contexts: &VecDeque<BlockContext<'_>>,
175 ) -> Result<ScopedJson<'rc>, RenderError> {
176 let resolved_visitor = parse_json_visitor(relative_path, block_contexts, true);
178
179 match resolved_visitor {
180 ResolvedPath::AbsolutePath(paths) => {
181 let mut ptr = Some(self.data());
182 for p in paths.iter() {
183 ptr = get_data(ptr, p)?;
184 }
185
186 Ok(ptr
187 .map(|v| ScopedJson::Context(v, paths))
188 .unwrap_or_else(|| ScopedJson::Missing))
189 }
190 ResolvedPath::RelativePath(_paths) => {
191 unreachable!()
193 }
202 ResolvedPath::BlockParamValue(paths, value)
203 | ResolvedPath::LocalValue(paths, value) => {
204 let mut ptr = Some(value);
205 for p in paths.iter() {
206 ptr = get_data(ptr, p)?;
207 }
208 Ok(ptr
209 .map(|v| ScopedJson::Derived(v.clone()))
210 .unwrap_or_else(|| ScopedJson::Missing))
211 }
212 }
213 }
214
215 pub fn data(&self) -> &Json {
217 &self.data
218 }
219
220 pub fn data_mut(&mut self) -> &mut Json {
222 &mut self.data
223 }
224}
225
226impl From<Json> for Context {
227 fn from(data: Json) -> Context {
228 Context { data }
229 }
230}
231
232#[cfg(test)]
233mod test {
234 use crate::block::{BlockContext, BlockParams};
235 use crate::context::{self, Context};
236 use crate::error::RenderError;
237 use crate::json::path::Path;
238 use crate::json::value::{self, ScopedJson};
239 use serde_json::value::Map;
240 use std::collections::{HashMap, VecDeque};
241
242 fn navigate_from_root<'reg, 'rc>(
243 ctx: &'rc Context,
244 path: &str,
245 ) -> Result<ScopedJson<'rc>, RenderError> {
246 let relative_path = Path::parse(path).unwrap();
247 ctx.navigate(relative_path.segs().unwrap(), &VecDeque::new())
248 }
249
250 #[derive(Serialize)]
251 struct Address {
252 city: String,
253 country: String,
254 }
255
256 #[derive(Serialize)]
257 struct Person {
258 name: String,
259 age: i16,
260 addr: Address,
261 titles: Vec<String>,
262 }
263
264 #[test]
265 fn test_render() {
266 let v = "hello";
267 let ctx = Context::wraps(&v.to_string()).unwrap();
268 assert_eq!(
269 navigate_from_root(&ctx, "this").unwrap().render(),
270 v.to_string()
271 );
272 }
273
274 #[test]
275 fn test_navigation() {
276 let addr = Address {
277 city: "Beijing".to_string(),
278 country: "China".to_string(),
279 };
280
281 let person = Person {
282 name: "Ning Sun".to_string(),
283 age: 27,
284 addr,
285 titles: vec!["programmer".to_string(), "cartographer".to_string()],
286 };
287
288 let ctx = Context::wraps(&person).unwrap();
289 assert_eq!(
290 navigate_from_root(&ctx, "./addr/country").unwrap().render(),
291 "China".to_string()
292 );
293 assert_eq!(
294 navigate_from_root(&ctx, "addr.[country]").unwrap().render(),
295 "China".to_string()
296 );
297
298 let v = true;
299 let ctx2 = Context::wraps(&v).unwrap();
300 assert_eq!(
301 navigate_from_root(&ctx2, "this").unwrap().render(),
302 "true".to_string()
303 );
304
305 assert_eq!(
306 navigate_from_root(&ctx, "titles.[0]").unwrap().render(),
307 "programmer".to_string()
308 );
309
310 assert_eq!(
311 navigate_from_root(&ctx, "age").unwrap().render(),
312 "27".to_string()
313 );
314 }
315
316 #[test]
317 fn test_this() {
318 let mut map_with_this = Map::new();
319 map_with_this.insert("this".to_string(), value::to_json("hello"));
320 map_with_this.insert("age".to_string(), value::to_json(5usize));
321 let ctx1 = Context::wraps(&map_with_this).unwrap();
322
323 let mut map_without_this = Map::new();
324 map_without_this.insert("age".to_string(), value::to_json(4usize));
325 let ctx2 = Context::wraps(&map_without_this).unwrap();
326
327 assert_eq!(
328 navigate_from_root(&ctx1, "this").unwrap().render(),
329 "[object]".to_owned()
330 );
331 assert_eq!(
332 navigate_from_root(&ctx2, "age").unwrap().render(),
333 "4".to_owned()
334 );
335 }
336
337 #[test]
338 fn test_merge_json() {
339 let map = json!({ "age": 4 });
340 let s = "hello".to_owned();
341 let mut hash = HashMap::new();
342 let v = value::to_json("h1");
343 hash.insert("tag", &v);
344
345 let ctx_a1 = Context::wraps(&context::merge_json(&map, &hash)).unwrap();
346 assert_eq!(
347 navigate_from_root(&ctx_a1, "age").unwrap().render(),
348 "4".to_owned()
349 );
350 assert_eq!(
351 navigate_from_root(&ctx_a1, "tag").unwrap().render(),
352 "h1".to_owned()
353 );
354
355 let ctx_a2 = Context::wraps(&context::merge_json(&value::to_json(s), &hash)).unwrap();
356 assert_eq!(
357 navigate_from_root(&ctx_a2, "this").unwrap().render(),
358 "[object]".to_owned()
359 );
360 assert_eq!(
361 navigate_from_root(&ctx_a2, "tag").unwrap().render(),
362 "h1".to_owned()
363 );
364 }
365
366 #[test]
367 fn test_key_name_with_this() {
368 let m = json!({
369 "this_name": "the_value"
370 });
371 let ctx = Context::wraps(&m).unwrap();
372 assert_eq!(
373 navigate_from_root(&ctx, "this_name").unwrap().render(),
374 "the_value".to_string()
375 );
376 }
377
378 use serde::ser::Error as SerdeError;
379 use serde::{Serialize, Serializer};
380
381 struct UnserializableType {}
382
383 impl Serialize for UnserializableType {
384 fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
385 where
386 S: Serializer,
387 {
388 Err(SerdeError::custom("test"))
389 }
390 }
391
392 #[test]
393 fn test_serialize_error() {
394 let d = UnserializableType {};
395 assert!(Context::wraps(&d).is_err());
396 }
397
398 #[test]
399 fn test_root() {
400 let m = json!({
401 "a" : {
402 "b" : {
403 "c" : {
404 "d" : 1
405 }
406 }
407 },
408 "b": 2
409 });
410 let ctx = Context::wraps(&m).unwrap();
411 let mut block = BlockContext::new();
412 *block.base_path_mut() = ["a".to_owned(), "b".to_owned()].to_vec();
413
414 let mut blocks = VecDeque::new();
415 blocks.push_front(block);
416
417 assert_eq!(
418 ctx.navigate(&Path::parse("@root/b").unwrap().segs().unwrap(), &blocks)
419 .unwrap()
420 .render(),
421 "2".to_string()
422 );
423 }
424
425 #[test]
426 fn test_block_params() {
427 let m = json!([{
428 "a": [1, 2]
429 }, {
430 "b": [2, 3]
431 }]);
432
433 let ctx = Context::wraps(&m).unwrap();
434 let mut block_params = BlockParams::new();
435 block_params
436 .add_path("z", ["0".to_owned(), "a".to_owned()].to_vec())
437 .unwrap();
438 block_params.add_value("t", json!("good")).unwrap();
439
440 let mut block = BlockContext::new();
441 block.set_block_params(block_params);
442
443 let mut blocks = VecDeque::new();
444 blocks.push_front(block);
445
446 assert_eq!(
447 ctx.navigate(&Path::parse("z.[1]").unwrap().segs().unwrap(), &blocks)
448 .unwrap()
449 .render(),
450 "2".to_string()
451 );
452 assert_eq!(
453 ctx.navigate(&Path::parse("t").unwrap().segs().unwrap(), &blocks)
454 .unwrap()
455 .render(),
456 "good".to_string()
457 );
458 }
459}