minijinja/value/object.rs
1use std::any::Any;
2use std::borrow::Cow;
3use std::cmp::Ordering;
4use std::collections::BTreeMap;
5use std::fmt;
6use std::hash::Hash;
7use std::sync::Arc;
8
9use crate::error::{Error, ErrorKind};
10use crate::value::{mapped_enumerator, Value};
11use crate::vm::State;
12
13/// A trait that represents a dynamic object.
14///
15/// There is a type erased wrapper of this trait available called
16/// [`DynObject`] which is what the engine actually holds internally.
17///
18/// # Basic Struct
19///
20/// The following example shows how to implement a dynamic object which
21/// represents a struct. All that's needed is to implement
22/// [`get_value`](Self::get_value) to look up a field by name as well as
23/// [`enumerate`](Self::enumerate) to return an enumerator over the known keys.
24/// The [`repr`](Self::repr) defaults to `Map` so nothing needs to be done here.
25///
26/// ```
27/// use std::sync::Arc;
28/// use minijinja::value::{Value, Object, Enumerator};
29///
30/// #[derive(Debug)]
31/// struct Point(f32, f32, f32);
32///
33/// impl Object for Point {
34/// fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
35/// match key.as_str()? {
36/// "x" => Some(Value::from(self.0)),
37/// "y" => Some(Value::from(self.1)),
38/// "z" => Some(Value::from(self.2)),
39/// _ => None,
40/// }
41/// }
42///
43/// fn enumerate(self: &Arc<Self>) -> Enumerator {
44/// Enumerator::Str(&["x", "y", "z"])
45/// }
46/// }
47///
48/// let value = Value::from_object(Point(1.0, 2.5, 3.0));
49/// ```
50///
51/// # Basic Sequence
52///
53/// The following example shows how to implement a dynamic object which
54/// represents a sequence. All that's needed is to implement
55/// [`repr`](Self::repr) to indicate that this is a sequence,
56/// [`get_value`](Self::get_value) to look up a field by index, and
57/// [`enumerate`](Self::enumerate) to return a sequential enumerator.
58/// This enumerator will automatically call `get_value` from `0..length`.
59///
60/// ```
61/// use std::sync::Arc;
62/// use minijinja::value::{Value, Object, ObjectRepr, Enumerator};
63///
64/// #[derive(Debug)]
65/// struct Point(f32, f32, f32);
66///
67/// impl Object for Point {
68/// fn repr(self: &Arc<Self>) -> ObjectRepr {
69/// ObjectRepr::Seq
70/// }
71///
72/// fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
73/// match key.as_usize()? {
74/// 0 => Some(Value::from(self.0)),
75/// 1 => Some(Value::from(self.1)),
76/// 2 => Some(Value::from(self.2)),
77/// _ => None,
78/// }
79/// }
80///
81/// fn enumerate(self: &Arc<Self>) -> Enumerator {
82/// Enumerator::Seq(3)
83/// }
84/// }
85///
86/// let value = Value::from_object(Point(1.0, 2.5, 3.0));
87/// ```
88///
89/// # Iterables
90///
91/// If you have something that is not quite a sequence but is capable of yielding
92/// values over time, you can directly implement an iterable. This is somewhat
93/// uncommon as you can normally directly use [`Value::make_iterable`]. Here
94/// is how this can be done though:
95///
96/// ```
97/// use std::sync::Arc;
98/// use minijinja::value::{Value, Object, ObjectRepr, Enumerator};
99///
100/// #[derive(Debug)]
101/// struct Range10;
102///
103/// impl Object for Range10 {
104/// fn repr(self: &Arc<Self>) -> ObjectRepr {
105/// ObjectRepr::Iterable
106/// }
107///
108/// fn enumerate(self: &Arc<Self>) -> Enumerator {
109/// Enumerator::Iter(Box::new((1..10).map(Value::from)))
110/// }
111/// }
112///
113/// let value = Value::from_object(Range10);
114/// ```
115///
116/// Iteration is encouraged to fail immediately (object is not iterable) or not at
117/// all. However this is not always possible, but the iteration interface itself
118/// does not support fallible iteration. It is however possible to accomplish the
119/// same thing by creating an [invalid value](index.html#invalid-values).
120///
121/// # Map As Context
122///
123/// Map can also be used as template rendering context. This has a lot of
124/// benefits as it means that the serialization overhead can be largely to
125/// completely avoided. This means that even if templates take hundreds of
126/// values, MiniJinja does not spend time eagerly converting them into values.
127///
128/// Here is a very basic example of how a template can be rendered with a dynamic
129/// context. Note that the implementation of [`enumerate`](Self::enumerate)
130/// is optional for this to work. It's in fact not used by the engine during
131/// rendering but it is necessary for the [`debug()`](crate::functions::debug)
132/// function to be able to show which values exist in the context.
133///
134/// ```
135/// # fn main() -> Result<(), minijinja::Error> {
136/// # use minijinja::Environment;
137/// use std::sync::Arc;
138/// use minijinja::value::{Value, Object};
139///
140/// #[derive(Debug)]
141/// pub struct DynamicContext {
142/// magic: i32,
143/// }
144///
145/// impl Object for DynamicContext {
146/// fn get_value(self: &Arc<Self>, field: &Value) -> Option<Value> {
147/// match field.as_str()? {
148/// #[cfg(not(target_os = "wasi"))]
149/// "pid" => Some(Value::from(std::process::id())),
150/// #[cfg(target_os = "wasi")]
151/// "pid" => Some(Value::from(1234_u32)), // Mock PID for WASI
152/// #[cfg(not(target_os = "wasi"))]
153/// "env" => Some(Value::from_iter(std::env::vars())),
154/// #[cfg(target_os = "wasi")]
155/// "env" => Some(Value::from_iter([("HOME".to_string(), "/home/user".to_string())])), // Mock env for WASI
156/// "magic" => Some(Value::from(self.magic)),
157/// _ => None,
158/// }
159/// }
160/// }
161///
162/// # let env = Environment::new();
163/// let tmpl = env.template_from_str("HOME={{ env.HOME }}; PID={{ pid }}; MAGIC={{ magic }}")?;
164/// let ctx = Value::from_object(DynamicContext { magic: 42 });
165/// let rv = tmpl.render(ctx)?;
166/// # Ok(()) }
167/// ```
168///
169/// One thing of note here is that in the above example `env` would be re-created every
170/// time the template needs it. A better implementation would cache the value after it
171/// was created first.
172pub trait Object: fmt::Debug + Send + Sync {
173 /// Indicates the natural representation of an object.
174 ///
175 /// The default implementation returns [`ObjectRepr::Map`].
176 fn repr(self: &Arc<Self>) -> ObjectRepr {
177 ObjectRepr::Map
178 }
179
180 /// Given a key, looks up the associated value.
181 fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
182 let _ = key;
183 None
184 }
185
186 /// Enumerates the object.
187 ///
188 /// The engine uses the returned enumerator to implement iteration and
189 /// the size information of an object. For more information see
190 /// [`Enumerator`]. The default implementation returns `Empty` for
191 /// all object representations other than [`ObjectRepr::Plain`] which
192 /// default to `NonEnumerable`.
193 ///
194 /// When wrapping other objects you might want to consider using
195 /// [`ObjectExt::mapped_enumerator`] and [`ObjectExt::mapped_rev_enumerator`].
196 fn enumerate(self: &Arc<Self>) -> Enumerator {
197 match self.repr() {
198 ObjectRepr::Plain => Enumerator::NonEnumerable,
199 ObjectRepr::Iterable | ObjectRepr::Map | ObjectRepr::Seq => Enumerator::Empty,
200 }
201 }
202
203 /// Returns the length of the enumerator.
204 ///
205 /// By default the length is taken by calling [`enumerate`](Self::enumerate) and
206 /// inspecting the [`Enumerator`]. This means that in order to determine
207 /// the length, an iteration is started. If you think this is a problem for your
208 /// uses, you can manually implement this. This might for instance be
209 /// needed if your type can only be iterated over once.
210 fn enumerator_len(self: &Arc<Self>) -> Option<usize> {
211 self.enumerate().query_len()
212 }
213
214 /// Returns `true` if this object is considered true for if conditions.
215 ///
216 /// The default implementation checks if the [`enumerator_len`](Self::enumerator_len)
217 /// is not `Some(0)` which is the recommended behavior for objects.
218 fn is_true(self: &Arc<Self>) -> bool {
219 self.enumerator_len() != Some(0)
220 }
221
222 /// The engine calls this to invoke the object itself.
223 ///
224 /// The default implementation returns an
225 /// [`InvalidOperation`](crate::ErrorKind::InvalidOperation) error.
226 fn call(self: &Arc<Self>, state: &State<'_, '_>, args: &[Value]) -> Result<Value, Error> {
227 let (_, _) = (state, args);
228 Err(Error::new(
229 ErrorKind::InvalidOperation,
230 "object is not callable",
231 ))
232 }
233
234 /// The engine calls this to invoke a method on the object.
235 ///
236 /// The default implementation returns an
237 /// [`UnknownMethod`](crate::ErrorKind::UnknownMethod) error. When this error
238 /// is returned the engine will invoke the
239 /// [`unknown_method_callback`](crate::Environment::set_unknown_method_callback) of
240 /// the environment.
241 fn call_method(
242 self: &Arc<Self>,
243 state: &State<'_, '_>,
244 method: &str,
245 args: &[Value],
246 ) -> Result<Value, Error> {
247 if let Some(value) = self.get_value(&Value::from(method)) {
248 return value.call(state, args);
249 }
250
251 Err(Error::from(ErrorKind::UnknownMethod))
252 }
253
254 /// Custom comparison of this object against another object of the same type.
255 ///
256 /// This must return either `None` or `Some(Ordering)`. When implemented this
257 /// must guarantee a total ordering as otherwise sort functions will crash.
258 /// This will only compare against other objects of the same type, not
259 /// anything else. Objects of different types are given an absolute
260 /// ordering outside the scope of this method.
261 ///
262 /// The requirement is that an implementer downcasts the other [`DynObject`]
263 /// to itself, and it that cannot be accomplished `None` must be returned.
264 ///
265 /// ```rust
266 /// # use std::sync::Arc;
267 /// # use std::cmp::Ordering;
268 /// # use minijinja::value::{DynObject, Object};
269 /// # #[derive(Debug)]
270 /// # struct Thing { num: u32 };
271 /// impl Object for Thing {
272 /// fn custom_cmp(self: &Arc<Self>, other: &DynObject) -> Option<Ordering> {
273 /// let other = other.downcast_ref::<Self>()?;
274 /// Some(self.num.cmp(&other.num))
275 /// }
276 /// }
277 /// ```
278 fn custom_cmp(self: &Arc<Self>, other: &DynObject) -> Option<Ordering> {
279 let _ = other;
280 None
281 }
282
283 /// Formats the object for stringification.
284 ///
285 /// The default implementation is specific to the behavior of
286 /// [`repr`](Self::repr) and usually does not need modification.
287 fn render(self: &Arc<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result
288 where
289 Self: Sized + 'static,
290 {
291 match self.repr() {
292 ObjectRepr::Map => {
293 let mut dbg = f.debug_map();
294 for (key, value) in self.try_iter_pairs().into_iter().flatten() {
295 dbg.entry(&key, &value);
296 }
297 dbg.finish()
298 }
299 // for either sequences or iterables, a length is needed, otherwise we
300 // don't want to risk iteration during printing and fall back to the
301 // debug print.
302 ObjectRepr::Seq | ObjectRepr::Iterable if self.enumerator_len().is_some() => {
303 let mut dbg = f.debug_list();
304 for value in self.try_iter().into_iter().flatten() {
305 dbg.entry(&value);
306 }
307 dbg.finish()
308 }
309 _ => {
310 write!(f, "{self:?}")
311 }
312 }
313 }
314}
315
316macro_rules! impl_object_helpers {
317 ($vis:vis $self_ty: ty) => {
318 /// Iterates over this object.
319 ///
320 /// If this returns `None` then the default object iteration as defined by
321 /// the object's `enumeration` is used.
322 $vis fn try_iter(self: $self_ty) -> Option<Box<dyn Iterator<Item = Value> + Send + Sync>>
323 where
324 Self: 'static,
325 {
326 match self.enumerate() {
327 Enumerator::NonEnumerable => None,
328 Enumerator::Empty => Some(Box::new(None::<Value>.into_iter())),
329 Enumerator::Seq(l) => {
330 let self_clone = self.clone();
331 Some(Box::new((0..l).map(move |idx| {
332 self_clone.get_value(&Value::from(idx)).unwrap_or_default()
333 })))
334 }
335 Enumerator::Iter(iter) => Some(iter),
336 Enumerator::RevIter(iter) => Some(Box::new(iter)),
337 Enumerator::Str(s) => Some(Box::new(s.iter().copied().map(Value::from))),
338 Enumerator::Values(v) => Some(Box::new(v.into_iter())),
339 }
340 }
341
342 /// Iterate over key and value at once.
343 $vis fn try_iter_pairs(
344 self: $self_ty,
345 ) -> Option<Box<dyn Iterator<Item = (Value, Value)> + Send + Sync>> {
346 let iter = some!(self.try_iter());
347 let repr = self.repr();
348 let self_clone = self.clone();
349 Some(Box::new(iter.enumerate().map(move |(idx, item)| {
350 match repr {
351 ObjectRepr::Map => {
352 let value = self_clone.get_value(&item);
353 (item, value.unwrap_or_default())
354 }
355 _ => (Value::from(idx), item)
356 }
357 })))
358 }
359 };
360}
361
362/// Provides utility methods for working with objects.
363pub trait ObjectExt: Object + Send + Sync + 'static {
364 /// Creates a new iterator enumeration that projects into the given object.
365 ///
366 /// It takes a method that is passed a reference to `self` and is expected
367 /// to return an [`Iterator`]. This iterator is then wrapped in an
368 /// [`Enumerator::Iter`]. This allows one to create an iterator that borrows
369 /// out of the object.
370 ///
371 /// # Example
372 ///
373 /// ```
374 /// # use std::collections::HashMap;
375 /// use std::sync::Arc;
376 /// use minijinja::value::{Value, Object, ObjectExt, Enumerator};
377 ///
378 /// #[derive(Debug)]
379 /// struct CustomMap(HashMap<usize, i64>);
380 ///
381 /// impl Object for CustomMap {
382 /// fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
383 /// self.0.get(&key.as_usize()?).copied().map(Value::from)
384 /// }
385 ///
386 /// fn enumerate(self: &Arc<Self>) -> Enumerator {
387 /// self.mapped_enumerator(|this| {
388 /// Box::new(this.0.keys().copied().map(Value::from))
389 /// })
390 /// }
391 /// }
392 /// ```
393 fn mapped_enumerator<F>(self: &Arc<Self>, maker: F) -> Enumerator
394 where
395 F: for<'a> FnOnce(&'a Self) -> Box<dyn Iterator<Item = Value> + Send + Sync + 'a>
396 + Send
397 + Sync
398 + 'static,
399 Self: Sized,
400 {
401 mapped_enumerator(self, maker)
402 }
403
404 /// Creates a new reversible iterator enumeration that projects into the given object.
405 ///
406 /// It takes a method that is passed a reference to `self` and is expected
407 /// to return a [`DoubleEndedIterator`]. This iterator is then wrapped in an
408 /// [`Enumerator::RevIter`]. This allows one to create an iterator that borrows
409 /// out of the object and is reversible.
410 ///
411 /// # Example
412 ///
413 /// ```
414 /// # use std::collections::HashMap;
415 /// use std::sync::Arc;
416 /// use std::ops::Range;
417 /// use minijinja::value::{Value, Object, ObjectExt, ObjectRepr, Enumerator};
418 ///
419 /// #[derive(Debug)]
420 /// struct VecView(Vec<usize>);
421 ///
422 /// impl Object for VecView {
423 /// fn repr(self: &Arc<Self>) -> ObjectRepr {
424 /// ObjectRepr::Iterable
425 /// }
426 ///
427 /// fn enumerate(self: &Arc<Self>) -> Enumerator {
428 /// self.mapped_enumerator(|this| {
429 /// Box::new(this.0.iter().cloned().map(Value::from))
430 /// })
431 /// }
432 /// }
433 /// ```
434 fn mapped_rev_enumerator<F>(self: &Arc<Self>, maker: F) -> Enumerator
435 where
436 F: for<'a> FnOnce(
437 &'a Self,
438 )
439 -> Box<dyn DoubleEndedIterator<Item = Value> + Send + Sync + 'a>
440 + Send
441 + Sync
442 + 'static,
443 Self: Sized,
444 {
445 // Taken from `mapped_enumerator`.
446
447 struct Iter {
448 iter: Box<dyn DoubleEndedIterator<Item = Value> + Send + Sync + 'static>,
449 _object: DynObject,
450 }
451
452 impl Iterator for Iter {
453 type Item = Value;
454
455 fn next(&mut self) -> Option<Self::Item> {
456 self.iter.next()
457 }
458
459 fn size_hint(&self) -> (usize, Option<usize>) {
460 self.iter.size_hint()
461 }
462 }
463
464 impl DoubleEndedIterator for Iter {
465 fn next_back(&mut self) -> Option<Self::Item> {
466 self.iter.next_back()
467 }
468 }
469
470 // SAFETY: this is safe because the `Iter` will keep our object alive.
471 let iter = unsafe {
472 std::mem::transmute::<
473 Box<dyn DoubleEndedIterator<Item = _>>,
474 Box<dyn DoubleEndedIterator<Item = _> + Send + Sync>,
475 >(maker(self))
476 };
477 let _object = DynObject::new(self.clone());
478 Enumerator::RevIter(Box::new(Iter { iter, _object }))
479 }
480
481 impl_object_helpers!(&Arc<Self>);
482}
483
484impl<T: Object + Send + Sync + 'static> ObjectExt for T {}
485
486/// Enumerators help define iteration behavior for [`Object`]s.
487///
488/// When Jinja wants to know the length of an object, if it's empty or
489/// not or if it wants to iterate over it, it will ask the [`Object`] to
490/// enumerate itself with the [`enumerate`](Object::enumerate) method. The
491/// returned enumerator has enough information so that the object can be
492/// iterated over, but it does not necessarily mean that iteration actually
493/// starts or that it has the data to yield the right values.
494///
495/// In fact, you should never inspect an enumerator. You can create it or
496/// forward it. For actual iteration use [`ObjectExt::try_iter`] etc.
497#[non_exhaustive]
498pub enum Enumerator {
499 /// Marks non enumerable objects.
500 ///
501 /// Such objects cannot be iterated over, the length is unknown which
502 /// means they are not considered empty by the engine. This is a good
503 /// choice for plain objects.
504 ///
505 /// | Iterable | Length |
506 /// |----------|---------|
507 /// | no | unknown |
508 NonEnumerable,
509
510 /// The empty enumerator. It yields no elements.
511 ///
512 /// | Iterable | Length |
513 /// |----------|-------------|
514 /// | yes | known (`0`) |
515 Empty,
516
517 /// A slice of static strings.
518 ///
519 /// This is a useful enumerator to enumerate the attributes of an
520 /// object or the keys in a string hash map.
521 ///
522 /// | Iterable | Length |
523 /// |----------|--------------|
524 /// | yes | known |
525 Str(&'static [&'static str]),
526
527 /// A dynamic iterator over values.
528 ///
529 /// The length is known if the [`Iterator::size_hint`] has matching lower
530 /// and upper bounds. The logic used by the engine is the following:
531 ///
532 /// ```
533 /// # let iter = Some(1).into_iter();
534 /// let len = match iter.size_hint() {
535 /// (lower, Some(upper)) if lower == upper => Some(lower),
536 /// _ => None
537 /// };
538 /// ```
539 ///
540 /// Because the engine prefers repeatable iteration, it will keep creating
541 /// new enumerators every time the iteration should restart. Sometimes
542 /// that might not always be possible (eg: you stream data in) in which
543 /// case
544 ///
545 /// | Iterable | Length |
546 /// |----------|-----------------|
547 /// | yes | sometimes known |
548 Iter(Box<dyn Iterator<Item = Value> + Send + Sync>),
549
550 /// Like `Iter` but supports efficient reversing.
551 ///
552 /// This means that the iterator has to be of type [`DoubleEndedIterator`].
553 ///
554 /// | Iterable | Length |
555 /// |----------|-----------------|
556 /// | yes | sometimes known |
557 RevIter(Box<dyn DoubleEndedIterator<Item = Value> + Send + Sync>),
558
559 /// Indicates sequential iteration.
560 ///
561 /// This instructs the engine to iterate over an object by enumerating it
562 /// from `0` to `n` by calling [`Object::get_value`]. This is essentially the
563 /// way sequences are supposed to be enumerated.
564 ///
565 /// | Iterable | Length |
566 /// |----------|-----------------|
567 /// | yes | known |
568 Seq(usize),
569
570 /// A vector of known values to iterate over.
571 ///
572 /// The iterator will yield each value in the vector one after another.
573 ///
574 /// | Iterable | Length |
575 /// |----------|-----------------|
576 /// | yes | known |
577 Values(Vec<Value>),
578}
579
580/// Defines the natural representation of this object.
581///
582/// An [`ObjectRepr`] is a reduced form of
583/// [`ValueKind`](crate::value::ValueKind) which only contains value which can
584/// be represented by objects. For instance an object can never be a primitive
585/// and as such those kinds are unavailable.
586///
587/// The representation influences how values are serialized, stringified or
588/// what kind they report.
589#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
590#[non_exhaustive]
591pub enum ObjectRepr {
592 /// An object that has no reasonable representation.
593 ///
594 /// - **Default Render:** [`Debug`]
595 /// - **Collection Behavior:** none
596 /// - **Iteration Behavior:** none
597 /// - **Serialize:** [`Debug`] / [`render`](Object::render) output as string
598 Plain,
599
600 /// Represents a map or object.
601 ///
602 /// - **Default Render:** `{key: value,...}` pairs
603 /// - **Collection Behavior:** looks like a map, can be indexed by key, has a length
604 /// - **Iteration Behavior:** iterates over keys
605 /// - **Serialize:** Serializes as map
606 Map,
607
608 /// Represents a sequence (eg: array/list).
609 ///
610 /// - **Default Render:** `[value,...]`
611 /// - **Collection Behavior:** looks like a list, can be indexed by index, has a length
612 /// - **Iteration Behavior:** iterates over values
613 /// - **Serialize:** Serializes as list
614 Seq,
615
616 /// Represents a non indexable, iterable object.
617 ///
618 /// - **Default Render:** `[value,...]` (if length is known), `"<iterator>"` otherwise.
619 /// - **Collection Behavior:** looks like a list if length is known, cannot be indexed
620 /// - **Iteration Behavior:** iterates over values
621 /// - **Serialize:** Serializes as list
622 Iterable,
623}
624
625type_erase! {
626 pub trait Object => DynObject {
627 fn repr(&self) -> ObjectRepr;
628
629 fn get_value(&self, key: &Value) -> Option<Value>;
630
631 fn enumerate(&self) -> Enumerator;
632
633 fn is_true(&self) -> bool;
634
635 fn enumerator_len(&self) -> Option<usize>;
636
637 fn call(
638 &self,
639 state: &State<'_, '_>,
640 args: &[Value]
641 ) -> Result<Value, Error>;
642
643 fn call_method(
644 &self,
645 state: &State<'_, '_>,
646 method: &str,
647 args: &[Value]
648 ) -> Result<Value, Error>;
649
650 fn custom_cmp(&self, other: &DynObject) -> Option<Ordering>;
651
652 fn render(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
653
654 impl fmt::Debug {
655 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
656 }
657 }
658}
659
660unsafe impl Send for DynObject {}
661unsafe impl Sync for DynObject {}
662
663impl DynObject {
664 impl_object_helpers!(pub &Self);
665
666 /// Checks if this dyn object is the same as another.
667 pub(crate) fn is_same_object(&self, other: &DynObject) -> bool {
668 self.ptr == other.ptr && self.vtable == other.vtable
669 }
670
671 /// Checks if the two dyn objects are of the same type.
672 pub(crate) fn is_same_object_type(&self, other: &DynObject) -> bool {
673 self.type_id() == other.type_id()
674 }
675}
676
677impl Hash for DynObject {
678 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
679 if let Some(iter) = self.try_iter_pairs() {
680 for (key, value) in iter {
681 key.hash(state);
682 value.hash(state);
683 }
684 }
685 }
686}
687
688impl fmt::Display for DynObject {
689 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
690 self.render(f)
691 }
692}
693
694impl Enumerator {
695 fn query_len(&self) -> Option<usize> {
696 Some(match self {
697 Enumerator::Empty => 0,
698 Enumerator::Values(v) => v.len(),
699 Enumerator::Str(v) => v.len(),
700 Enumerator::Iter(i) => match i.size_hint() {
701 (a, Some(b)) if a == b => a,
702 _ => return None,
703 },
704 Enumerator::RevIter(i) => match i.size_hint() {
705 (a, Some(b)) if a == b => a,
706 _ => return None,
707 },
708 Enumerator::Seq(v) => *v,
709 Enumerator::NonEnumerable => return None,
710 })
711 }
712}
713
714macro_rules! impl_value_vec {
715 ($vec_type:ident) => {
716 impl<T> Object for $vec_type<T>
717 where
718 T: Into<Value> + Clone + Send + Sync + fmt::Debug + 'static,
719 {
720 fn repr(self: &Arc<Self>) -> ObjectRepr {
721 ObjectRepr::Seq
722 }
723
724 #[inline(always)]
725 fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
726 self.get(some!(key.as_usize())).cloned().map(|v| v.into())
727 }
728
729 fn enumerate(self: &Arc<Self>) -> Enumerator {
730 Enumerator::Seq(self.len())
731 }
732 }
733
734 impl<T> From<$vec_type<T>> for Value
735 where
736 T: Into<Value> + Clone + Send + Sync + fmt::Debug + 'static,
737 {
738 fn from(val: $vec_type<T>) -> Self {
739 Value::from_object(val)
740 }
741 }
742 };
743}
744
745#[allow(unused)]
746macro_rules! impl_value_iterable {
747 ($iterable_type:ident, $enumerator:ident) => {
748 impl<T> Object for $iterable_type<T>
749 where
750 T: Into<Value> + Clone + Send + Sync + fmt::Debug + 'static,
751 {
752 fn repr(self: &Arc<Self>) -> ObjectRepr {
753 ObjectRepr::Iterable
754 }
755
756 fn enumerate(self: &Arc<Self>) -> Enumerator {
757 self.clone()
758 .$enumerator(|this| Box::new(this.iter().map(|x| x.clone().into())))
759 }
760 }
761
762 impl<T> From<$iterable_type<T>> for Value
763 where
764 T: Into<Value> + Clone + Send + Sync + fmt::Debug + 'static,
765 {
766 fn from(val: $iterable_type<T>) -> Self {
767 Value::from_object(val)
768 }
769 }
770 };
771}
772
773macro_rules! impl_str_map_helper {
774 ($map_type:ident, $key_type:ty, $enumerator:ident) => {
775 impl<V> Object for $map_type<$key_type, V>
776 where
777 V: Into<Value> + Clone + Send + Sync + fmt::Debug + 'static,
778 {
779 #[inline(always)]
780 fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
781 self.get(some!(key.as_str())).cloned().map(|v| v.into())
782 }
783
784 fn enumerate(self: &Arc<Self>) -> Enumerator {
785 self.$enumerator(|this| Box::new(this.keys().map(|x| Value::from(x as &str))))
786 }
787
788 fn enumerator_len(self: &Arc<Self>) -> Option<usize> {
789 Some(self.len())
790 }
791 }
792 };
793}
794
795macro_rules! impl_str_map {
796 ($map_type:ident, $enumerator:ident) => {
797 impl_str_map_helper!($map_type, String, $enumerator);
798 impl_str_map_helper!($map_type, Arc<str>, $enumerator);
799
800 impl<V> From<$map_type<String, V>> for Value
801 where
802 V: Into<Value> + Send + Sync + Clone + fmt::Debug + 'static,
803 {
804 fn from(val: $map_type<String, V>) -> Self {
805 Value::from_object(val)
806 }
807 }
808
809 impl<V> From<$map_type<Arc<str>, V>> for Value
810 where
811 V: Into<Value> + Send + Sync + Clone + fmt::Debug + 'static,
812 {
813 fn from(val: $map_type<Arc<str>, V>) -> Self {
814 Value::from_object(val)
815 }
816 }
817
818 impl<'a, V> From<$map_type<&'a str, V>> for Value
819 where
820 V: Into<Value> + Send + Sync + Clone + fmt::Debug + 'static,
821 {
822 fn from(val: $map_type<&'a str, V>) -> Self {
823 Value::from(
824 val.into_iter()
825 .map(|(k, v)| (Arc::from(k), v))
826 .collect::<$map_type<Arc<str>, V>>(),
827 )
828 }
829 }
830
831 impl<'a, V> From<$map_type<Cow<'a, str>, V>> for Value
832 where
833 V: Into<Value> + Send + Sync + Clone + fmt::Debug + 'static,
834 {
835 fn from(val: $map_type<Cow<'a, str>, V>) -> Self {
836 Value::from(
837 val.into_iter()
838 .map(|(k, v)| (Arc::from(k), v))
839 .collect::<$map_type<Arc<str>, V>>(),
840 )
841 }
842 }
843 };
844}
845
846macro_rules! impl_value_map {
847 ($map_type:ident, $enumerator:ident) => {
848 impl<V> Object for $map_type<Value, V>
849 where
850 V: Into<Value> + Clone + Send + Sync + fmt::Debug + 'static,
851 {
852 #[inline(always)]
853 fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
854 self.get(key).cloned().map(|v| v.into())
855 }
856
857 fn enumerate(self: &Arc<Self>) -> Enumerator {
858 self.$enumerator(|this| Box::new(this.keys().cloned()))
859 }
860
861 fn enumerator_len(self: &Arc<Self>) -> Option<usize> {
862 Some(self.len())
863 }
864 }
865
866 impl<V> From<$map_type<Value, V>> for Value
867 where
868 V: Into<Value> + Send + Sync + Clone + fmt::Debug + 'static,
869 {
870 fn from(val: $map_type<Value, V>) -> Self {
871 Value::from_object(val)
872 }
873 }
874 };
875}
876
877impl_value_vec!(Vec);
878impl_value_map!(BTreeMap, mapped_rev_enumerator);
879impl_str_map!(BTreeMap, mapped_rev_enumerator);
880
881#[cfg(feature = "std_collections")]
882mod std_collections_impls {
883 use super::*;
884 use std::collections::{BTreeSet, HashMap, HashSet, LinkedList, VecDeque};
885
886 impl_value_iterable!(LinkedList, mapped_rev_enumerator);
887 impl_value_iterable!(HashSet, mapped_enumerator);
888 impl_value_iterable!(BTreeSet, mapped_rev_enumerator);
889 impl_str_map!(HashMap, mapped_enumerator);
890 impl_value_map!(HashMap, mapped_enumerator);
891 impl_value_vec!(VecDeque);
892}
893
894#[cfg(feature = "preserve_order")]
895mod preserve_order_impls {
896 use super::*;
897 use indexmap::IndexMap;
898
899 impl_value_map!(IndexMap, mapped_rev_enumerator);
900}