Skip to main content

iri_string/template/
value.rs

1//! Default visit impls for naively visitable types.
2
3use core::fmt;
4
5#[cfg(feature = "alloc")]
6use crate::template::context::AssocVisitor as _;
7use crate::template::context::{ListVisitor as _, Visitor};
8
9/// Make visitor visit the value that implements [`VisitValueNaive`] trait.
10pub fn visit_value_naive<V, T>(visitor: V, value: T) -> V::Result
11where
12    V: Visitor,
13    T: VisitValueNaive,
14{
15    value.visit_value(visitor)
16}
17
18/// A trait for types that are expected to have "naive" visit implementation.
19///
20/// This trait can be implemented when a type of a value has a default variable
21/// type in template expansion context, and the value (or its Rust type) itself
22/// knows the type in template expansion context.
23pub trait VisitValueNaive {
24    /// Make visitor visit the value.
25    fn visit_value<V: Visitor>(&self, visitor: V) -> V::Result;
26}
27
28impl<T: ?Sized + VisitValueNaive> VisitValueNaive for &T {
29    #[inline]
30    fn visit_value<V: Visitor>(&self, visitor: V) -> V::Result {
31        (*self).visit_value(visitor)
32    }
33}
34
35impl VisitValueNaive for core::convert::Infallible {
36    fn visit_value<V: Visitor>(&self, _visitor: V) -> V::Result {
37        match *self {}
38    }
39}
40
41impl VisitValueNaive for () {
42    fn visit_value<V: Visitor>(&self, visitor: V) -> V::Result {
43        visitor.visit_undefined()
44    }
45}
46
47impl<T: VisitValueNaive> VisitValueNaive for Option<T> {
48    #[inline]
49    fn visit_value<V: Visitor>(&self, visitor: V) -> V::Result {
50        match self {
51            Some(v) => v.visit_value(visitor),
52            None => visitor.visit_undefined(),
53        }
54    }
55}
56
57/// Implement [`VisitValueNaive`] trait for simple (non-composite) types.
58macro_rules! impl_visit_value_naive_for_display_single {
59    ($ty_val:ty, $($rest:ty),* $(,)?) => {
60        impl_visit_value_naive_for_display_single!($ty_val);
61        impl_visit_value_naive_for_display_single!($($rest),*);
62    };
63    ($ty_val:ty) => {
64        impl VisitValueNaive for $ty_val {
65            fn visit_value<V: Visitor>(&self, visitor: V) -> V::Result {
66                visitor.visit_string(self)
67            }
68        }
69    };
70}
71impl_visit_value_naive_for_display_single!(i8, i16, i32, i64, i128, isize);
72impl_visit_value_naive_for_display_single!(u8, u16, u32, u64, u128, usize);
73impl_visit_value_naive_for_display_single!(str);
74#[cfg(feature = "alloc")]
75impl_visit_value_naive_for_display_single!(
76    alloc::string::String,
77    alloc::boxed::Box<str>,
78    alloc::borrow::Cow<'_, str>,
79);
80
81/// Implement [`VisitValueNaive`] trait for list types.
82macro_rules! impl_visit_value_naive_for_display_list {
83    ($ty_val:ty, $($rest:ty),* $(,)?) => {
84        impl_visit_value_naive_for_display_list!($ty_val);
85        impl_visit_value_naive_for_display_list!($($rest),*);
86    };
87    ($ty_val:ty) => {
88        impl<T: fmt::Display> VisitValueNaive for $ty_val {
89            fn visit_value<V: Visitor>(&self, visitor: V) -> V::Result {
90                visitor.visit_list().visit_items_and_finish(self)
91            }
92        }
93    };
94}
95// NOTE: By implementing list formatting for `[T]`, it becomes impossible to
96// add implementation of associative array formatting for `[(K, V)]`. Since it
97// would be hard to support both (think of the case when `(K, V)` itself has
98// `Display` implementation), only supporting list formatting is a reasonable
99// compromise... at least it's better than providing nothing for `[T]`.
100impl_visit_value_naive_for_display_list!([T]);
101#[cfg(feature = "alloc")]
102impl_visit_value_naive_for_display_list!(alloc::vec::Vec<T>, alloc::collections::BTreeSet<T>);
103#[cfg(feature = "std")]
104impl_visit_value_naive_for_display_list!(std::collections::HashSet<T>);
105
106impl<T: fmt::Display, const N: usize> VisitValueNaive for [T; N] {
107    #[inline]
108    fn visit_value<V: Visitor>(&self, visitor: V) -> V::Result {
109        visitor.visit_list().visit_items_and_finish(self)
110    }
111}
112
113/// Implement [`VisitValueNaive`] trait for associative array types.
114#[cfg(feature = "alloc")]
115macro_rules! impl_visit_value_naive_for_display_assoc {
116    ($ty_val:ty, $($rest:ty),* $(,)?) => {
117        impl_visit_value_naive_for_display_assoc!($ty_val);
118        impl_visit_value_naive_for_display_assoc!($($rest),*);
119    };
120    ($ty_val:ty) => {
121        impl<K: fmt::Display, T: fmt::Display> VisitValueNaive for $ty_val {
122            fn visit_value<V: Visitor>(&self, visitor: V) -> V::Result {
123                visitor.visit_assoc().visit_entries_and_finish(self)
124            }
125        }
126    };
127}
128#[cfg(feature = "alloc")]
129impl_visit_value_naive_for_display_assoc!(alloc::collections::BTreeMap<K, T>);
130#[cfg(feature = "std")]
131impl_visit_value_naive_for_display_assoc!(std::collections::HashMap<K, T>);