1 //! Type representing a Liquid object, payload of the `Value::Object` variant
2 
3 pub mod map;
4 mod ser;
5 
6 use std::collections::BTreeMap;
7 use std::collections::HashMap;
8 use std::fmt;
9 
10 use kstring::KStringCow;
11 
12 use crate::model::value::DisplayCow;
13 use crate::model::State;
14 use crate::model::{Value, ValueView};
15 
16 pub use map::Object;
17 pub use ser::to_object;
18 
19 /// Accessor for objects.
20 pub trait ObjectView: ValueView {
21     /// Cast to ValueView
as_value(&self) -> &dyn ValueView22     fn as_value(&self) -> &dyn ValueView;
23 
24     /// Returns the number of elements.
size(&self) -> i6425     fn size(&self) -> i64;
26 
27     /// Keys available for lookup.
keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k>28     fn keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k>;
29     /// Keys available for lookup.
values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k>30     fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k>;
31     /// Returns an iterator .
iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k>32     fn iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k>;
33 
34     /// Access a contained `BoxedValue`.
contains_key(&self, index: &str) -> bool35     fn contains_key(&self, index: &str) -> bool;
36     /// Access a contained `Value`.
get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView>37     fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView>;
38 }
39 
40 impl ValueView for Object {
as_debug(&self) -> &dyn fmt::Debug41     fn as_debug(&self) -> &dyn fmt::Debug {
42         self
43     }
44 
render(&self) -> DisplayCow<'_>45     fn render(&self) -> DisplayCow<'_> {
46         DisplayCow::Owned(Box::new(ObjectRender { s: self }))
47     }
source(&self) -> DisplayCow<'_>48     fn source(&self) -> DisplayCow<'_> {
49         DisplayCow::Owned(Box::new(ObjectSource { s: self }))
50     }
type_name(&self) -> &'static str51     fn type_name(&self) -> &'static str {
52         "object"
53     }
query_state(&self, state: State) -> bool54     fn query_state(&self, state: State) -> bool {
55         match state {
56             State::Truthy => true,
57             State::DefaultValue | State::Empty | State::Blank => self.is_empty(),
58         }
59     }
60 
to_kstr(&self) -> KStringCow<'_>61     fn to_kstr(&self) -> KStringCow<'_> {
62         let s = ObjectRender { s: self }.to_string();
63         KStringCow::from_string(s)
64     }
to_value(&self) -> Value65     fn to_value(&self) -> Value {
66         Value::Object(self.clone())
67     }
68 
as_object(&self) -> Option<&dyn ObjectView>69     fn as_object(&self) -> Option<&dyn ObjectView> {
70         Some(self)
71     }
72 }
73 
74 impl ObjectView for Object {
as_value(&self) -> &dyn ValueView75     fn as_value(&self) -> &dyn ValueView {
76         self
77     }
78 
size(&self) -> i6479     fn size(&self) -> i64 {
80         self.len() as i64
81     }
82 
keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k>83     fn keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k> {
84         let keys = Object::keys(self).map(|s| s.as_ref().into());
85         Box::new(keys)
86     }
87 
values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k>88     fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k> {
89         let i = Object::values(self).map(|v| v.as_view());
90         Box::new(i)
91     }
92 
iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k>93     fn iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k> {
94         let i = Object::iter(self).map(|(k, v)| (k.as_str().into(), v.as_view()));
95         Box::new(i)
96     }
97 
contains_key(&self, index: &str) -> bool98     fn contains_key(&self, index: &str) -> bool {
99         Object::contains_key(self, index)
100     }
101 
get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView>102     fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView> {
103         Object::get(self, index).map(|v| v.as_view())
104     }
105 }
106 
107 impl<'o, O: ObjectView + ?Sized> ObjectView for &'o O {
as_value(&self) -> &dyn ValueView108     fn as_value(&self) -> &dyn ValueView {
109         <O as ObjectView>::as_value(self)
110     }
111 
size(&self) -> i64112     fn size(&self) -> i64 {
113         <O as ObjectView>::size(self)
114     }
115 
keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k>116     fn keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k> {
117         <O as ObjectView>::keys(self)
118     }
119 
values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k>120     fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k> {
121         <O as ObjectView>::values(self)
122     }
123 
iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k>124     fn iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k> {
125         <O as ObjectView>::iter(self)
126     }
127 
contains_key(&self, index: &str) -> bool128     fn contains_key(&self, index: &str) -> bool {
129         <O as ObjectView>::contains_key(self, index)
130     }
131 
get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView>132     fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView> {
133         <O as ObjectView>::get(self, index)
134     }
135 }
136 
137 /// Owned object index
138 pub trait ObjectIndex:
139     fmt::Debug + fmt::Display + Ord + std::hash::Hash + Eq + std::borrow::Borrow<str>
140 {
141     /// Borrow the index
as_index(&self) -> &str142     fn as_index(&self) -> &str;
143 }
144 
145 impl ObjectIndex for String {
as_index(&self) -> &str146     fn as_index(&self) -> &str {
147         self.as_str()
148     }
149 }
150 
151 impl ObjectIndex for kstring::KString {
as_index(&self) -> &str152     fn as_index(&self) -> &str {
153         self.as_str()
154     }
155 }
156 
157 impl<'s> ObjectIndex for kstring::KStringRef<'s> {
as_index(&self) -> &str158     fn as_index(&self) -> &str {
159         self.as_str()
160     }
161 }
162 
163 impl<'s> ObjectIndex for kstring::KStringCow<'s> {
as_index(&self) -> &str164     fn as_index(&self) -> &str {
165         self.as_str()
166     }
167 }
168 
169 impl<K: ObjectIndex, V: ValueView, S: ::std::hash::BuildHasher> ValueView for HashMap<K, V, S> {
as_debug(&self) -> &dyn fmt::Debug170     fn as_debug(&self) -> &dyn fmt::Debug {
171         self
172     }
173 
render(&self) -> DisplayCow<'_>174     fn render(&self) -> DisplayCow<'_> {
175         DisplayCow::Owned(Box::new(ObjectRender { s: self }))
176     }
source(&self) -> DisplayCow<'_>177     fn source(&self) -> DisplayCow<'_> {
178         DisplayCow::Owned(Box::new(ObjectSource { s: self }))
179     }
type_name(&self) -> &'static str180     fn type_name(&self) -> &'static str {
181         "object"
182     }
query_state(&self, state: State) -> bool183     fn query_state(&self, state: State) -> bool {
184         match state {
185             State::Truthy => true,
186             State::DefaultValue | State::Empty | State::Blank => self.is_empty(),
187         }
188     }
189 
to_kstr(&self) -> KStringCow<'_>190     fn to_kstr(&self) -> KStringCow<'_> {
191         let s = ObjectRender { s: self }.to_string();
192         KStringCow::from_string(s)
193     }
to_value(&self) -> Value194     fn to_value(&self) -> Value {
195         Value::Object(
196             self.iter()
197                 .map(|(k, v)| (kstring::KString::from_ref(k.as_index()), v.to_value()))
198                 .collect(),
199         )
200     }
201 
as_object(&self) -> Option<&dyn ObjectView>202     fn as_object(&self) -> Option<&dyn ObjectView> {
203         Some(self)
204     }
205 }
206 
207 impl<K: ObjectIndex, V: ValueView, S: ::std::hash::BuildHasher> ObjectView for HashMap<K, V, S> {
as_value(&self) -> &dyn ValueView208     fn as_value(&self) -> &dyn ValueView {
209         self
210     }
211 
size(&self) -> i64212     fn size(&self) -> i64 {
213         self.len() as i64
214     }
215 
keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k>216     fn keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k> {
217         let keys = HashMap::keys(self).map(|s| s.as_index().into());
218         Box::new(keys)
219     }
220 
values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k>221     fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k> {
222         let i = HashMap::values(self).map(as_view);
223         Box::new(i)
224     }
225 
iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k>226     fn iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k> {
227         let i = HashMap::iter(self).map(|(k, v)| (k.as_index().into(), as_view(v)));
228         Box::new(i)
229     }
230 
contains_key(&self, index: &str) -> bool231     fn contains_key(&self, index: &str) -> bool {
232         HashMap::contains_key(self, index)
233     }
234 
get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView>235     fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView> {
236         HashMap::get(self, index).map(as_view)
237     }
238 }
239 
240 impl<K: ObjectIndex, V: ValueView> ValueView for BTreeMap<K, V> {
as_debug(&self) -> &dyn fmt::Debug241     fn as_debug(&self) -> &dyn fmt::Debug {
242         self
243     }
244 
render(&self) -> DisplayCow<'_>245     fn render(&self) -> DisplayCow<'_> {
246         DisplayCow::Owned(Box::new(ObjectRender { s: self }))
247     }
source(&self) -> DisplayCow<'_>248     fn source(&self) -> DisplayCow<'_> {
249         DisplayCow::Owned(Box::new(ObjectSource { s: self }))
250     }
type_name(&self) -> &'static str251     fn type_name(&self) -> &'static str {
252         "object"
253     }
query_state(&self, state: State) -> bool254     fn query_state(&self, state: State) -> bool {
255         match state {
256             State::Truthy => true,
257             State::DefaultValue | State::Empty | State::Blank => self.is_empty(),
258         }
259     }
260 
to_kstr(&self) -> KStringCow<'_>261     fn to_kstr(&self) -> KStringCow<'_> {
262         let s = ObjectRender { s: self }.to_string();
263         KStringCow::from_string(s)
264     }
to_value(&self) -> Value265     fn to_value(&self) -> Value {
266         Value::Object(
267             self.iter()
268                 .map(|(k, v)| (kstring::KString::from_ref(k.as_index()), v.to_value()))
269                 .collect(),
270         )
271     }
272 
as_object(&self) -> Option<&dyn ObjectView>273     fn as_object(&self) -> Option<&dyn ObjectView> {
274         Some(self)
275     }
276 }
277 
278 impl<K: ObjectIndex, V: ValueView> ObjectView for BTreeMap<K, V> {
as_value(&self) -> &dyn ValueView279     fn as_value(&self) -> &dyn ValueView {
280         self
281     }
282 
size(&self) -> i64283     fn size(&self) -> i64 {
284         self.len() as i64
285     }
286 
keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k>287     fn keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k> {
288         let keys = BTreeMap::keys(self).map(|s| s.as_index().into());
289         Box::new(keys)
290     }
291 
values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k>292     fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k> {
293         let i = BTreeMap::values(self).map(as_view);
294         Box::new(i)
295     }
296 
iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k>297     fn iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k> {
298         let i = BTreeMap::iter(self).map(|(k, v)| (k.as_index().into(), as_view(v)));
299         Box::new(i)
300     }
301 
contains_key(&self, index: &str) -> bool302     fn contains_key(&self, index: &str) -> bool {
303         BTreeMap::contains_key(self, index)
304     }
305 
get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView>306     fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView> {
307         BTreeMap::get(self, index).map(as_view)
308     }
309 }
310 
as_view<T: ValueView>(value: &T) -> &dyn ValueView311 fn as_view<T: ValueView>(value: &T) -> &dyn ValueView {
312     value
313 }
314 
315 #[derive(Debug)]
316 /// Helper for `ObjectView::source`
317 pub struct ObjectSource<'s, O: ObjectView> {
318     s: &'s O,
319 }
320 
321 impl<'s, O: ObjectView> ObjectSource<'s, O> {
322     #[doc(hidden)]
new(other: &'s O) -> Self323     pub fn new(other: &'s O) -> Self {
324         Self { s: other }
325     }
326 }
327 
328 impl<'s, O: ObjectView> fmt::Display for ObjectSource<'s, O> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result329     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
330         write!(f, "{{")?;
331         for (k, v) in self.s.iter() {
332             write!(f, r#""{}": {}, "#, k, v.render())?;
333         }
334         write!(f, "}}")?;
335         Ok(())
336     }
337 }
338 
339 #[derive(Debug)]
340 /// Helper for `ObjectView::render`
341 pub struct ObjectRender<'s, O: ObjectView> {
342     s: &'s O,
343 }
344 
345 impl<'s, O: ObjectView> ObjectRender<'s, O> {
346     #[doc(hidden)]
new(other: &'s O) -> Self347     pub fn new(other: &'s O) -> Self {
348         Self { s: other }
349     }
350 }
351 
352 impl<'s, O: ObjectView> fmt::Display for ObjectRender<'s, O> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result353     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354         for (k, v) in self.s.iter() {
355             write!(f, "{}{}", k, v.render())?;
356         }
357         Ok(())
358     }
359 }
360 
361 #[cfg(test)]
362 mod test {
363     use super::*;
364 
365     #[test]
test_object()366     fn test_object() {
367         let obj = Object::new();
368         println!("{}", obj.source());
369         let object: &dyn ObjectView = &obj;
370         println!("{}", object.source());
371         let view: &dyn ValueView = object.as_value();
372         println!("{}", view.source());
373     }
374 }
375