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