Skip to main content

topcoat_view/
node.rs

1#[cfg(feature = "http")]
2use http::{HeaderMap, HeaderName, HeaderValue, StatusCode};
3use topcoat_core::context::Cx;
4
5#[cfg(feature = "http")]
6use crate::ViewPart;
7use crate::{PartsWriter, Unescaped, View};
8
9/// Converts a value used in node position into view parts.
10///
11/// When this trait is implemented on a type, it can be used in the node position of an element
12/// in the [`view!`](https://docs.rs/topcoat/latest/topcoat/view/macro.view.html) macro:
13///
14/// ```rust
15/// # use topcoat::view::{component, view};
16/// # #[component]
17/// # async fn example() -> topcoat::Result {
18/// # let my_value = "value";
19/// view! {
20///     <div>(my_value)</div>
21/// }
22/// # }
23/// ```
24pub trait NodeViewParts {
25    /// Appends this value to the view being built.
26    fn into_view_parts(self, cx: &Cx, parts: &mut PartsWriter<'_>);
27}
28
29impl NodeViewParts for View {
30    #[inline]
31    fn into_view_parts(self, _cx: &Cx, parts: &mut PartsWriter<'_>) {
32        parts.push_part(self.into_part());
33    }
34}
35
36macro_rules! impl_primitive {
37    ($ty:ty, $method:ident) => {
38        impl NodeViewParts for $ty {
39            #[inline]
40            fn into_view_parts(self, _cx: &Cx, parts: &mut PartsWriter<'_>) {
41                parts.$method(self);
42            }
43        }
44    };
45    ($ty:ty, $method:ident, ref) => {
46        impl_primitive!($ty, $method);
47
48        impl NodeViewParts for &$ty {
49            #[inline]
50            fn into_view_parts(self, cx: &Cx, parts: &mut PartsWriter<'_>) {
51                (*self).into_view_parts(cx, parts)
52            }
53        }
54    };
55}
56
57impl_primitive!(bool, push_bool, ref);
58impl_primitive!(char, push_char, ref);
59impl_primitive!(i8, push_i8, ref);
60impl_primitive!(i16, push_i16, ref);
61impl_primitive!(i32, push_i32, ref);
62impl_primitive!(i64, push_i64, ref);
63impl_primitive!(i128, push_i128, ref);
64impl_primitive!(isize, push_isize, ref);
65impl_primitive!(u8, push_u8, ref);
66impl_primitive!(u16, push_u16, ref);
67impl_primitive!(u32, push_u32, ref);
68impl_primitive!(u64, push_u64, ref);
69impl_primitive!(u128, push_u128, ref);
70impl_primitive!(usize, push_usize, ref);
71impl_primitive!(f32, push_f32, ref);
72impl_primitive!(f64, push_f64, ref);
73impl_primitive!(String, push_str);
74
75impl NodeViewParts for &str {
76    #[inline]
77    fn into_view_parts(self, _cx: &Cx, parts: &mut PartsWriter<'_>) {
78        parts.push_str(self.to_owned());
79    }
80}
81
82impl NodeViewParts for Unescaped<String> {
83    #[inline]
84    fn into_view_parts(self, _cx: &Cx, parts: &mut PartsWriter<'_>) {
85        parts.push_str_unescaped(self.0);
86    }
87}
88
89impl NodeViewParts for Unescaped<&'static str> {
90    #[inline]
91    fn into_view_parts(self, _cx: &Cx, parts: &mut PartsWriter<'_>) {
92        parts.push_str_unescaped(self.0);
93    }
94}
95
96impl NodeViewParts for &String {
97    #[inline]
98    fn into_view_parts(self, cx: &Cx, parts: &mut PartsWriter<'_>) {
99        self.as_str().into_view_parts(cx, parts);
100    }
101}
102
103/// Sets the response status code; renders no content.
104///
105/// Competing status codes resolve by render order: the first one rendered
106/// wins. Place a status code before nested content to override whatever the
107/// content declares, or after it to provide a fallback. To display a status
108/// code as text instead, render one of its accessors, such as
109/// [`as_u16`](StatusCode::as_u16).
110#[cfg(feature = "http")]
111impl NodeViewParts for StatusCode {
112    #[inline]
113    fn into_view_parts(self, _cx: &Cx, parts: &mut PartsWriter<'_>) {
114        parts.push_part(ViewPart::StatusCode(self));
115    }
116}
117
118/// Adds response headers; renders no content.
119///
120/// Competing headers resolve by render order: the first part that mentions a
121/// header name provides all of that name's values. Place headers before
122/// nested content to override the entries the content declares, or after it
123/// to provide fallbacks.
124#[cfg(feature = "http")]
125impl NodeViewParts for HeaderMap {
126    #[inline]
127    fn into_view_parts(self, _cx: &Cx, parts: &mut PartsWriter<'_>) {
128        parts.push_part(ViewPart::Headers(Box::new(self)));
129    }
130}
131
132/// Adds a single response header; renders no content.
133///
134/// Equivalent to a [`HeaderMap`] holding just this entry.
135#[cfg(feature = "http")]
136impl NodeViewParts for (HeaderName, HeaderValue) {
137    fn into_view_parts(self, cx: &Cx, parts: &mut PartsWriter<'_>) {
138        let (name, value) = self;
139        let mut headers = HeaderMap::with_capacity(1);
140        headers.insert(name, value);
141        headers.into_view_parts(cx, parts);
142    }
143}
144
145impl<'b, T: ?Sized> NodeViewParts for &&'b T
146where
147    &'b T: NodeViewParts,
148{
149    #[inline]
150    fn into_view_parts(self, cx: &Cx, parts: &mut PartsWriter<'_>) {
151        (*self).into_view_parts(cx, parts);
152    }
153}
154
155impl<T> NodeViewParts for Option<T>
156where
157    T: NodeViewParts,
158{
159    #[inline]
160    fn into_view_parts(self, cx: &Cx, parts: &mut PartsWriter<'_>) {
161        if let Some(value) = self {
162            value.into_view_parts(cx, parts);
163        }
164    }
165}
166
167impl<T> NodeViewParts for Vec<T>
168where
169    T: NodeViewParts,
170{
171    #[inline]
172    fn into_view_parts(self, cx: &Cx, parts: &mut PartsWriter<'_>) {
173        for value in self {
174            value.into_view_parts(cx, parts);
175        }
176    }
177}
178
179macro_rules! impl_tuple {
180    ($($ty:ident),+) => {
181        impl<$($ty),+> NodeViewParts for ($($ty,)+)
182        where
183            $($ty: NodeViewParts,)+
184        {
185            #[inline]
186            #[allow(non_snake_case)]
187            fn into_view_parts(self, cx: &Cx, parts: &mut PartsWriter<'_>) {
188                let ($($ty,)+) = self;
189                $($ty.into_view_parts(cx, parts);)+
190            }
191        }
192    };
193}
194
195impl_tuple!(T1);
196impl_tuple!(T1, T2);
197impl_tuple!(T1, T2, T3);
198impl_tuple!(T1, T2, T3, T4);
199impl_tuple!(T1, T2, T3, T4, T5);
200impl_tuple!(T1, T2, T3, T4, T5, T6);
201impl_tuple!(T1, T2, T3, T4, T5, T6, T7);
202impl_tuple!(T1, T2, T3, T4, T5, T6, T7, T8);
203impl_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
204impl_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
205impl_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
206impl_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);