This is unreleased documentation for Yew Next version.
For up-to-date documentation, see the latest version on docs.rs.

yew/utils/
mod.rs

1//! This module contains useful utilities to get information about the current document.
2
3use std::marker::PhantomData;
4use std::rc::Rc;
5
6use implicit_clone::unsync::IArray;
7use implicit_clone::ImplicitClone;
8use yew::html::ChildrenRenderer;
9
10/// Map `IntoIterator<Item = Into<T>>` to `Iterator<Item = T>`
11pub fn into_node_iter<IT, T, R>(it: IT) -> impl Iterator<Item = R>
12where
13    IT: IntoIterator<Item = T>,
14    T: Into<R>,
15{
16    it.into_iter().map(|n| n.into())
17}
18
19fn array_single<T: ImplicitClone + 'static>(singl: T) -> IArray<T> {
20    IArray::Rc(Rc::new([singl]))
21}
22
23/// A special type necessary for flattening components returned from nested html macros.
24#[derive(Debug)]
25pub struct NodeSeq<IN, OUT: ImplicitClone + 'static>(IArray<OUT>, PhantomData<IN>);
26
27impl<IN: Into<OUT>, OUT: ImplicitClone + 'static> From<IN> for NodeSeq<IN, OUT> {
28    fn from(val: IN) -> Self {
29        Self(array_single(val.into()), PhantomData)
30    }
31}
32
33impl<IN: Into<OUT>, OUT: ImplicitClone + 'static> From<Option<IN>> for NodeSeq<IN, OUT> {
34    fn from(val: Option<IN>) -> Self {
35        Self(
36            val.map(|s| array_single(s.into())).unwrap_or_default(),
37            PhantomData,
38        )
39    }
40}
41
42impl<IN: Into<OUT>, OUT: ImplicitClone + 'static> From<Vec<IN>> for NodeSeq<IN, OUT> {
43    fn from(mut val: Vec<IN>) -> Self {
44        if val.len() == 1 {
45            let item = val.pop().unwrap();
46            Self(array_single(item.into()), PhantomData)
47        } else {
48            Self(val.into_iter().map(|x| x.into()).collect(), PhantomData)
49        }
50    }
51}
52
53impl<IN: Into<OUT> + ImplicitClone, OUT: ImplicitClone + 'static> From<IArray<IN>>
54    for NodeSeq<IN, OUT>
55{
56    fn from(val: IArray<IN>) -> Self {
57        Self(val.into_iter().map(|x| x.into()).collect(), PhantomData)
58    }
59}
60
61impl<IN: Into<OUT> + ImplicitClone, OUT: ImplicitClone + 'static> From<&IArray<IN>>
62    for NodeSeq<IN, OUT>
63{
64    fn from(val: &IArray<IN>) -> Self {
65        Self(
66            val.clone().into_iter().map(|x| x.into()).collect(),
67            PhantomData,
68        )
69    }
70}
71
72impl<IN: Into<OUT> + Clone, OUT: ImplicitClone + 'static> From<&ChildrenRenderer<IN>>
73    for NodeSeq<IN, OUT>
74{
75    fn from(val: &ChildrenRenderer<IN>) -> Self {
76        Self(val.iter().map(|x| x.into()).collect(), PhantomData)
77    }
78}
79
80impl<IN, OUT: ImplicitClone + 'static> IntoIterator for NodeSeq<IN, OUT> {
81    type IntoIter = implicit_clone::unsync::IArrayIntoIter<Self::Item>;
82    type Item = OUT;
83
84    fn into_iter(self) -> Self::IntoIter {
85        self.0.into_iter()
86    }
87}
88
89/// Hack to force type mismatch compile errors in yew-macro.
90// TODO: replace with `compile_error!`, when `type_name_of_val` is stabilised (https://github.com/rust-lang/rust/issues/66359).
91#[doc(hidden)]
92pub fn __ensure_type<T>(_: T) {}
93
94/// Print the [web_sys::Node]'s contents as a string for debugging purposes
95pub fn print_node(n: &web_sys::Node) -> String {
96    use wasm_bindgen::JsCast;
97
98    match n.dyn_ref::<web_sys::Element>() {
99        Some(el) => el.outer_html(),
100        None => n.text_content().unwrap_or_default(),
101    }
102}
103
104// NOTE: replace this by Rc::unwrap_or_clone() when it becomes stable
105pub(crate) trait RcExt<T: Clone> {
106    fn unwrap_or_clone(this: Self) -> T;
107}
108
109impl<T: Clone> RcExt<T> for std::rc::Rc<T> {
110    fn unwrap_or_clone(this: Self) -> T {
111        std::rc::Rc::try_unwrap(this).unwrap_or_else(|rc| (*rc).clone())
112    }
113}