1use std::borrow::Cow;
2use std::collections::BTreeMap;
3
4use serde::ser::Serialize;
5use serde_json::value::{to_value, Map, Value};
6
7#[derive(Debug, Clone, PartialEq)]
12pub struct Context {
13 data: BTreeMap<String, Value>,
14}
15
16impl Context {
17 pub fn new() -> Context {
19 Context { data: BTreeMap::new() }
20 }
21
22 pub fn insert<T: Serialize + ?Sized>(&mut self, key: &str, val: &T) {
30 self.data.insert(key.to_owned(), to_value(val).unwrap());
31 }
32
33 pub fn extend(&mut self, mut source: Context) {
46 self.data.append(&mut source.data);
47 }
48
49 pub fn into_json(self) -> Value {
51 let mut m = Map::new();
52 for (key, value) in self.data {
53 m.insert(key, value);
54 }
55 Value::Object(m)
56 }
57}
58
59impl Default for Context {
60 fn default() -> Context {
61 Context::new()
62 }
63}
64
65pub trait ValueRender {
66 fn render(&self) -> Cow<str>;
67}
68
69impl ValueRender for Value {
71 fn render(&self) -> Cow<str> {
72 match *self {
73 Value::String(ref s) => Cow::Borrowed(s),
74 Value::Number(ref i) => Cow::Owned(i.to_string()),
75 Value::Bool(i) => Cow::Owned(i.to_string()),
76 Value::Null => Cow::Owned(String::new()),
77 Value::Array(ref a) => {
78 let mut buf = String::new();
79 buf.push('[');
80 for i in a.iter() {
81 if buf.len() > 1 {
82 buf.push_str(", ");
83 }
84 buf.push_str(i.render().as_ref());
85 }
86 buf.push(']');
87 Cow::Owned(buf)
88 }
89 Value::Object(_) => Cow::Owned("[object]".to_owned()),
90 }
91 }
92}
93
94pub trait ValueNumber {
95 fn to_number(&self) -> Result<f64, ()>;
96}
97impl ValueNumber for Value {
100 fn to_number(&self) -> Result<f64, ()> {
101 match *self {
102 Value::Number(ref i) => Ok(i.as_f64().unwrap()),
103 _ => Err(()),
104 }
105 }
106}
107
108pub trait ValueTruthy {
110 fn is_truthy(&self) -> bool;
111}
112
113impl ValueTruthy for Value {
114 fn is_truthy(&self) -> bool {
115 match *self {
116 Value::Number(ref i) => {
117 if i.is_i64() {
118 return i.as_i64().unwrap() != 0;
119 }
120 if i.is_u64() {
121 return i.as_u64().unwrap() != 0;
122 }
123 let f = i.as_f64().unwrap();
124 f != 0.0 && !f.is_nan()
125 }
126 Value::Bool(ref i) => *i,
127 Value::Null => false,
128 Value::String(ref i) => !i.is_empty(),
129 Value::Array(ref i) => !i.is_empty(),
130 Value::Object(ref i) => !i.is_empty(),
131 }
132 }
133}
134
135#[inline]
137pub fn get_json_pointer(key: &str) -> String {
138 ["/", &key.replace(".", "/")].join("")
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn test_extend() {
147 let mut target = Context::new();
148 target.insert("a", &1);
149 target.insert("b", &2);
150 let mut source = Context::new();
151 source.insert("b", &3);
152 source.insert("c", &4);
153 target.extend(source);
154 assert_eq!(*target.data.get("a").unwrap(), to_value(1).unwrap());
155 assert_eq!(*target.data.get("b").unwrap(), to_value(3).unwrap());
156 assert_eq!(*target.data.get("c").unwrap(), to_value(4).unwrap());
157 }
158}