1 | use serde::Serialize; |
2 | use serde_json::value::{to_value, Value as Json}; |
3 | |
4 | pub(crate) static DEFAULT_VALUE: Json = Json::Null; |
5 | |
6 | /// A JSON wrapper designed for handlebars internal use case |
7 | /// |
8 | /// * Constant: the JSON value hardcoded into template |
9 | /// * Context: the JSON value referenced in your provided data context |
10 | /// * Derived: the owned JSON value computed during rendering process |
11 | /// |
12 | #[derive (Debug)] |
13 | pub enum ScopedJson<'reg: 'rc, 'rc> { |
14 | Constant(&'reg Json), |
15 | Derived(Json), |
16 | // represents a json reference to context value, its full path |
17 | Context(&'rc Json, Vec<String>), |
18 | Missing, |
19 | } |
20 | |
21 | impl<'reg: 'rc, 'rc> ScopedJson<'reg, 'rc> { |
22 | /// get the JSON reference |
23 | pub fn as_json(&self) -> &Json { |
24 | match self { |
25 | ScopedJson::Constant(j) => j, |
26 | ScopedJson::Derived(ref j) => j, |
27 | ScopedJson::Context(j, _) => j, |
28 | _ => &DEFAULT_VALUE, |
29 | } |
30 | } |
31 | |
32 | pub fn render(&self) -> String { |
33 | self.as_json().render() |
34 | } |
35 | |
36 | pub fn is_missing(&self) -> bool { |
37 | matches!(self, ScopedJson::Missing) |
38 | } |
39 | |
40 | pub fn into_derived(self) -> ScopedJson<'reg, 'rc> { |
41 | let v = self.as_json(); |
42 | ScopedJson::Derived(v.clone()) |
43 | } |
44 | |
45 | pub fn context_path(&self) -> Option<&Vec<String>> { |
46 | match self { |
47 | ScopedJson::Context(_, ref p) => Some(p), |
48 | _ => None, |
49 | } |
50 | } |
51 | } |
52 | |
53 | impl<'reg: 'rc, 'rc> From<Json> for ScopedJson<'reg, 'rc> { |
54 | fn from(v: Json) -> ScopedJson<'reg, 'rc> { |
55 | ScopedJson::Derived(v) |
56 | } |
57 | } |
58 | |
59 | /// Json wrapper that holds the Json value and reference path information |
60 | /// |
61 | #[derive (Debug)] |
62 | pub struct PathAndJson<'reg, 'rc> { |
63 | relative_path: Option<String>, |
64 | value: ScopedJson<'reg, 'rc>, |
65 | } |
66 | |
67 | impl<'reg: 'rc, 'rc> PathAndJson<'reg, 'rc> { |
68 | pub fn new( |
69 | relative_path: Option<String>, |
70 | value: ScopedJson<'reg, 'rc>, |
71 | ) -> PathAndJson<'reg, 'rc> { |
72 | PathAndJson { |
73 | relative_path, |
74 | value, |
75 | } |
76 | } |
77 | |
78 | /// Returns relative path when the value is referenced |
79 | /// If the value is from a literal, the path is `None` |
80 | pub fn relative_path(&self) -> Option<&String> { |
81 | self.relative_path.as_ref() |
82 | } |
83 | |
84 | /// Returns full path to this value if any |
85 | pub fn context_path(&self) -> Option<&Vec<String>> { |
86 | self.value.context_path() |
87 | } |
88 | |
89 | /// Returns the value |
90 | pub fn value(&self) -> &Json { |
91 | self.value.as_json() |
92 | } |
93 | |
94 | /// Test if value is missing |
95 | pub fn is_value_missing(&self) -> bool { |
96 | self.value.is_missing() |
97 | } |
98 | |
99 | pub fn render(&self) -> String { |
100 | self.value.render() |
101 | } |
102 | } |
103 | |
104 | /// Render Json data with default format |
105 | pub trait JsonRender { |
106 | fn render(&self) -> String; |
107 | } |
108 | |
109 | pub trait JsonTruthy { |
110 | fn is_truthy(&self, include_zero: bool) -> bool; |
111 | } |
112 | |
113 | impl JsonRender for Json { |
114 | fn render(&self) -> String { |
115 | match *self { |
116 | Json::String(ref s: &String) => s.to_string(), |
117 | Json::Bool(i: bool) => i.to_string(), |
118 | Json::Number(ref n: &Number) => n.to_string(), |
119 | Json::Null => "" .to_owned(), |
120 | Json::Array(ref a: &Vec) => { |
121 | let mut buf: String = String::new(); |
122 | buf.push(ch:'[' ); |
123 | for i: &Value in a.iter() { |
124 | buf.push_str(string:i.render().as_ref()); |
125 | buf.push_str(string:", " ); |
126 | } |
127 | buf.push(ch:']' ); |
128 | buf |
129 | } |
130 | Json::Object(_) => "[object]" .to_owned(), |
131 | } |
132 | } |
133 | } |
134 | |
135 | /// Convert any serializable data into Serde Json type |
136 | pub fn to_json<T>(src: T) -> Json |
137 | where |
138 | T: Serialize, |
139 | { |
140 | to_value(src).unwrap_or_default() |
141 | } |
142 | |
143 | pub fn as_string(src: &Json) -> Option<&str> { |
144 | src.as_str() |
145 | } |
146 | |
147 | impl JsonTruthy for Json { |
148 | fn is_truthy(&self, include_zero: bool) -> bool { |
149 | match *self { |
150 | Json::Bool(ref i: &bool) => *i, |
151 | Json::Number(ref n: &Number) => { |
152 | if include_zero { |
153 | n.as_f64().map(|f| !f.is_nan()).unwrap_or(default:false) |
154 | } else { |
155 | // there is no inifity in json/serde_json |
156 | n.as_f64().map(|f| f.is_normal()).unwrap_or(default:false) |
157 | } |
158 | } |
159 | Json::Null => false, |
160 | Json::String(ref i: &String) => !i.is_empty(), |
161 | Json::Array(ref i: &Vec) => !i.is_empty(), |
162 | Json::Object(ref i: &Map) => !i.is_empty(), |
163 | } |
164 | } |
165 | } |
166 | |
167 | #[test ] |
168 | fn test_json_render() { |
169 | let raw: &str = "<p>Hello world</p> \n<p thing= \"hello \"</p>" ; |
170 | let thing: Value = Json::String(raw.to_string()); |
171 | |
172 | assert_eq!(raw, thing.render()); |
173 | } |
174 | |
175 | #[test ] |
176 | fn test_json_number_truthy() { |
177 | use std::f64; |
178 | assert!(json!(16i16).is_truthy(false)); |
179 | assert!(json!(16i16).is_truthy(true)); |
180 | |
181 | assert!(json!(0i16).is_truthy(true)); |
182 | assert!(!json!(0i16).is_truthy(false)); |
183 | |
184 | assert!(json!(1.0f64).is_truthy(false)); |
185 | assert!(json!(1.0f64).is_truthy(true)); |
186 | |
187 | assert!(json!(Some(16i16)).is_truthy(false)); |
188 | assert!(json!(Some(16i16)).is_truthy(true)); |
189 | |
190 | assert!(!json!(None as Option<i16>).is_truthy(false)); |
191 | assert!(!json!(None as Option<i16>).is_truthy(true)); |
192 | |
193 | assert!(!json!(f64::NAN).is_truthy(false)); |
194 | assert!(!json!(f64::NAN).is_truthy(true)); |
195 | |
196 | // there is no infinity in json/serde_json |
197 | // assert!(json!(f64::INFINITY).is_truthy(false)); |
198 | // assert!(json!(f64::INFINITY).is_truthy(true)); |
199 | |
200 | // assert!(json!(f64::NEG_INFINITY).is_truthy(false)); |
201 | // assert!(json!(f64::NEG_INFINITY).is_truthy(true)); |
202 | } |
203 | |