1use serde::Serialize;
2use serde_json::value::{to_value, Value as Json};
3
4pub(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)]
13pub 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
21impl<'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
53impl<'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)]
62pub struct PathAndJson<'reg, 'rc> {
63 relative_path: Option<String>,
64 value: ScopedJson<'reg, 'rc>,
65}
66
67impl<'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
105pub trait JsonRender {
106 fn render(&self) -> String;
107}
108
109pub trait JsonTruthy {
110 fn is_truthy(&self, include_zero: bool) -> bool;
111}
112
113impl 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
136pub fn to_json<T>(src: T) -> Json
137where
138 T: Serialize,
139{
140 to_value(src).unwrap_or_default()
141}
142
143pub fn as_string(src: &Json) -> Option<&str> {
144 src.as_str()
145}
146
147impl 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]
168fn 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]
176fn 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