loose_liquid_core/model/object/
mod.rs1pub mod map;
4mod ser;
5
6use std::collections::BTreeMap;
7use std::collections::HashMap;
8use std::fmt;
9
10use crate::model::KStringCow;
11
12use crate::model::value::DisplayCow;
13use crate::model::State;
14use crate::model::{Value, ValueView};
15
16pub use map::Object;
17pub use ser::to_object;
18
19pub trait ObjectView: ValueView {
21 fn as_value(&self) -> &dyn ValueView;
23
24 fn size(&self) -> i64;
26
27 fn keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k>;
29 fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k>;
31 fn iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k>;
33
34 fn contains_key(&self, index: &str) -> bool;
36 fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView>;
38}
39
40impl ValueView for Object {
41 fn as_debug(&self) -> &dyn fmt::Debug {
42 self
43 }
44
45 fn render(&self) -> DisplayCow<'_> {
46 DisplayCow::Owned(Box::new(ObjectRender { s: self }))
47 }
48 fn source(&self) -> DisplayCow<'_> {
49 DisplayCow::Owned(Box::new(ObjectSource { s: self }))
50 }
51 fn type_name(&self) -> &'static str {
52 "object"
53 }
54 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
61 fn to_kstr(&self) -> KStringCow<'_> {
62 let s = ObjectRender { s: self }.to_string();
63 KStringCow::from_string(s)
64 }
65 fn to_value(&self) -> Value {
66 Value::Object(self.clone())
67 }
68
69 fn as_object(&self) -> Option<&dyn ObjectView> {
70 Some(self)
71 }
72}
73
74impl ObjectView for Object {
75 fn as_value(&self) -> &dyn ValueView {
76 self
77 }
78
79 fn size(&self) -> i64 {
80 self.len() as i64
81 }
82
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
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
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
98 fn contains_key(&self, index: &str) -> bool {
99 Object::contains_key(self, index)
100 }
101
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
107impl<'o, O: ObjectView + ?Sized> ObjectView for &'o O {
108 fn as_value(&self) -> &dyn ValueView {
109 <O as ObjectView>::as_value(self)
110 }
111
112 fn size(&self) -> i64 {
113 <O as ObjectView>::size(self)
114 }
115
116 fn keys<'k>(&'k self) -> Box<dyn Iterator<Item = KStringCow<'k>> + 'k> {
117 <O as ObjectView>::keys(self)
118 }
119
120 fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k> {
121 <O as ObjectView>::values(self)
122 }
123
124 fn iter<'k>(&'k self) -> Box<dyn Iterator<Item = (KStringCow<'k>, &'k dyn ValueView)> + 'k> {
125 <O as ObjectView>::iter(self)
126 }
127
128 fn contains_key(&self, index: &str) -> bool {
129 <O as ObjectView>::contains_key(self, index)
130 }
131
132 fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView> {
133 <O as ObjectView>::get(self, index)
134 }
135}
136
137pub trait ObjectIndex:
139 fmt::Debug + fmt::Display + Ord + std::hash::Hash + Eq + std::borrow::Borrow<str>
140{
141 fn as_index(&self) -> &str;
143}
144
145impl ObjectIndex for String {
146 fn as_index(&self) -> &str {
147 self.as_str()
148 }
149}
150
151impl ObjectIndex for crate::model::KString {
152 fn as_index(&self) -> &str {
153 self.as_str()
154 }
155}
156
157impl<'s> ObjectIndex for crate::model::KStringRef<'s> {
158 fn as_index(&self) -> &str {
159 self.as_str()
160 }
161}
162
163impl<'s> ObjectIndex for crate::model::KStringCow<'s> {
164 fn as_index(&self) -> &str {
165 self.as_str()
166 }
167}
168
169impl<K: ObjectIndex, V: ValueView, S: ::std::hash::BuildHasher> ValueView for HashMap<K, V, S> {
170 fn as_debug(&self) -> &dyn fmt::Debug {
171 self
172 }
173
174 fn render(&self) -> DisplayCow<'_> {
175 DisplayCow::Owned(Box::new(ObjectRender { s: self }))
176 }
177 fn source(&self) -> DisplayCow<'_> {
178 DisplayCow::Owned(Box::new(ObjectSource { s: self }))
179 }
180 fn type_name(&self) -> &'static str {
181 "object"
182 }
183 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
190 fn to_kstr(&self) -> KStringCow<'_> {
191 let s = ObjectRender { s: self }.to_string();
192 KStringCow::from_string(s)
193 }
194 fn to_value(&self) -> Value {
195 Value::Object(
196 self.iter()
197 .map(|(k, v)| (crate::model::KString::from_ref(k.as_index()), v.to_value()))
198 .collect(),
199 )
200 }
201
202 fn as_object(&self) -> Option<&dyn ObjectView> {
203 Some(self)
204 }
205}
206
207impl<K: ObjectIndex, V: ValueView, S: ::std::hash::BuildHasher> ObjectView for HashMap<K, V, S> {
208 fn as_value(&self) -> &dyn ValueView {
209 self
210 }
211
212 fn size(&self) -> i64 {
213 self.len() as i64
214 }
215
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
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
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
231 fn contains_key(&self, index: &str) -> bool {
232 HashMap::contains_key(self, index)
233 }
234
235 fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView> {
236 HashMap::get(self, index).map(as_view)
237 }
238}
239
240impl<K: ObjectIndex, V: ValueView> ValueView for BTreeMap<K, V> {
241 fn as_debug(&self) -> &dyn fmt::Debug {
242 self
243 }
244
245 fn render(&self) -> DisplayCow<'_> {
246 DisplayCow::Owned(Box::new(ObjectRender { s: self }))
247 }
248 fn source(&self) -> DisplayCow<'_> {
249 DisplayCow::Owned(Box::new(ObjectSource { s: self }))
250 }
251 fn type_name(&self) -> &'static str {
252 "object"
253 }
254 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
261 fn to_kstr(&self) -> KStringCow<'_> {
262 let s = ObjectRender { s: self }.to_string();
263 KStringCow::from_string(s)
264 }
265 fn to_value(&self) -> Value {
266 Value::Object(
267 self.iter()
268 .map(|(k, v)| (crate::model::KString::from_ref(k.as_index()), v.to_value()))
269 .collect(),
270 )
271 }
272
273 fn as_object(&self) -> Option<&dyn ObjectView> {
274 Some(self)
275 }
276}
277
278impl<K: ObjectIndex, V: ValueView> ObjectView for BTreeMap<K, V> {
279 fn as_value(&self) -> &dyn ValueView {
280 self
281 }
282
283 fn size(&self) -> i64 {
284 self.len() as i64
285 }
286
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
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
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
302 fn contains_key(&self, index: &str) -> bool {
303 BTreeMap::contains_key(self, index)
304 }
305
306 fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView> {
307 BTreeMap::get(self, index).map(as_view)
308 }
309}
310
311fn as_view<T: ValueView>(value: &T) -> &dyn ValueView {
312 value
313}
314
315#[derive(Debug)]
316pub struct ObjectSource<'s, O: ObjectView> {
318 s: &'s O,
319}
320
321impl<'s, O: ObjectView> ObjectSource<'s, O> {
322 #[doc(hidden)]
323 pub fn new(other: &'s O) -> Self {
324 Self { s: other }
325 }
326}
327
328impl<'s, O: ObjectView> fmt::Display for ObjectSource<'s, O> {
329 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)]
340pub struct ObjectRender<'s, O: ObjectView> {
342 s: &'s O,
343}
344
345impl<'s, O: ObjectView> ObjectRender<'s, O> {
346 #[doc(hidden)]
347 pub fn new(other: &'s O) -> Self {
348 Self { s: other }
349 }
350}
351
352impl<'s, O: ObjectView> fmt::Display for ObjectRender<'s, O> {
353 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)]
362mod test {
363 use super::*;
364
365 #[test]
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}