use wasm_bindgen::JsValue;
use crate::{AnyNode, AnyNodeValue, Children, IntoElement, Keyed};
pub trait Node {
fn to_node(&self) -> AnyNode;
#[inline]
fn to_children(&self) -> Option<Children> {
Some(Children::from_single(self.to_node()))
}
#[inline]
fn into_node(self) -> AnyNode
where
Self: Sized,
{
self.to_node()
}
#[inline]
fn into_children(self) -> Option<Children>
where
Self: Sized,
{
self.to_children()
}
}
impl Node for () {
#[inline]
fn to_node(&self) -> AnyNode {
AnyNode::Null
}
#[inline]
fn to_children(&self) -> Option<Children> {
None
}
}
impl<T: Node> Node for Option<T> {
#[inline]
fn to_node(&self) -> AnyNode {
if let Some(node) = self {
node.to_node()
} else {
AnyNode::Null
}
}
#[inline]
fn to_children(&self) -> Option<Children> {
self.as_ref().and_then(Node::to_children)
}
#[inline]
fn into_node(self) -> AnyNode {
self.map(Node::into_node).unwrap_or(AnyNode::Null)
}
#[inline]
fn into_children(self) -> Option<Children> {
self.and_then(Node::into_children)
}
}
macro_rules! into_js_node {
(into_f64: $($n:ty)*) => ($(
impl Node for $n {
#[inline]
fn to_node(&self) -> AnyNode {
(*self).into_node()
}
#[inline]
fn into_node(self) -> AnyNode {
AnyNode::Value(AnyNodeValue::unsafe_from_js_react_node(JsValue::from_f64(self.into())))
}
}
)*);
(deref: $($n:ty)*) => ($(
impl Node for $n {
#[inline]
fn to_node(&self) -> AnyNode {
AnyNode::Value(AnyNodeValue::unsafe_from_js_react_node(JsValue::from(*self)))
}
}
)*);
(bigint_to_string: $($n:ty)*) => ($(
impl Node for $n {
#[inline]
fn to_node(&self) -> AnyNode {
(*self).into_node()
}
#[inline]
fn into_node(self) -> AnyNode {
let js_bigint = js_sys::BigInt::from(self);
let js_string = js_bigint.to_string(10).unwrap();
AnyNode::Value(AnyNodeValue::unsafe_from_js_react_node(JsValue::from(js_string)))
}
}
)*);
($($n:ty)*) => ($(
impl Node for $n {
#[inline]
fn to_node(&self) -> AnyNode {
AnyNode::Value(AnyNodeValue::unsafe_from_js_react_node(JsValue::from(self)))
}
}
)*);
}
into_js_node! {
str
react_sys::Element
String
js_sys::JsString
js_sys::Number
js_sys::BigInt
js_sys::Boolean
}
into_js_node! {
into_f64:
i8 u8 i16 u16 i32 u32 f32 f64
}
into_js_node! {
bigint_to_string:
i64 u64 i128 u128 isize usize
}
into_js_node! {
deref:
bool
}
#[inline]
fn into_keyed_element<E: IntoElement>(el: Keyed<E>) -> Keyed<crate::Element> {
Keyed(el.0.into_element())
}
#[inline]
fn option_into_keyed_element<E: IntoElement>(
el: Option<Keyed<E>>,
) -> Option<Keyed<crate::Element>> {
el.map(into_keyed_element)
}
macro_rules! impl_node_for_iter {
(impl into_children) => {
#[inline]
fn into_children(self) -> Option<Children> {
Some(Children::from_single(self.into_node()))
}
};
(impl sized) => {
#[inline]
fn into_node(self) -> AnyNode {
AnyNode::Multiple(std::rc::Rc::new(self.into_iter().map(into_keyed_element).collect()))
}
impl_node_for_iter! { impl into_children }
};
(impl sized opt) => {
#[inline]
fn into_node(self) -> AnyNode {
AnyNode::Multiple(std::rc::Rc::new(
self.into_iter()
.filter_map(option_into_keyed_element)
.collect()
))
}
impl_node_for_iter! { impl into_children }
};
( $($sized:ident)? {$($t:tt)+} {$($t_opt:tt)+}) => {
$($t)+ {
#[inline]
fn to_node(&self) -> AnyNode {
self.to_vec().into_node()
}
$( impl_node_for_iter! { impl $sized } )?
}
$($t_opt)+ {
#[inline]
fn to_node(&self) -> AnyNode {
self.iter().filter_map(Clone::clone).collect::<Vec<_>>().into_node()
}
$( impl_node_for_iter! { impl $sized opt } )?
}
};
}
impl_node_for_iter! {
sized
{ impl<E: IntoElement + Clone> Node for Vec<Keyed<E>> }
{ impl<E: IntoElement + Clone> Node for Vec<Option<Keyed<E>>> }
}
impl_node_for_iter! {
{ impl<E: IntoElement + Clone> Node for [Keyed<E>] }
{ impl<E: IntoElement + Clone> Node for [Option<Keyed<E>>] }
}
impl_node_for_iter! {
sized
{ impl<E: IntoElement + Clone, const S: usize> Node for [Keyed<E>; S] }
{ impl<E: IntoElement + Clone, const S: usize> Node for [Option<Keyed<E>>; S] }
}
macro_rules! impl_node_for_tuple {
(@impl ( $($t:ident),+ $(,)? )) => {
impl<$($t: Node),+> Node for ($($t),+ ,) {
#[inline]
fn to_node(&self) -> AnyNode {
#![allow(non_snake_case)]
let ($($t),+ ,) = self;
let v = Children::from_static_nodes([
$($t.to_node()),+
]);
v.to_node()
}
#[inline]
fn to_children(&self) -> Option<Children> {
#![allow(non_snake_case)]
let ($($t),+ ,) = self;
let v = Children::from_static_nodes([
$($t.to_node()),+
]);
Some(v)
}
#[inline]
fn into_node(self) -> AnyNode {
#![allow(non_snake_case)]
let ($($t),+ ,) = self;
let v = Children::from_static_nodes([
$($t.into_node()),+
]);
v.into_node()
}
#[inline]
fn into_children(self) -> Option<Children> {
#![allow(non_snake_case)]
let ($($t),+ ,) = self;
Some(Children::from_static_nodes([
$($t.into_node()),+
]))
}
}
};
( $(( $($t:ident),+ $(,)? ))* ) => {
$(
impl_node_for_tuple! { @impl ($($t),+ ,) }
)*
};
}
impl_node_for_tuple! {
(T0,)
(T0,T1)
(T0,T1,T2)
(T0,T1,T2,T3)
(T0,T1,T2,T3,T4)
(T0,T1,T2,T3,T4,T5)
(T0,T1,T2,T3,T4,T5,T6)
(T0,T1,T2,T3,T4,T5,T6,T7)
(T0,T1,T2,T3,T4,T5,T6,T7,T8)
(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9)
(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10)
(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11)
(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12)
(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13)
(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14)
(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15)
(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16)
}
impl<N: Node> Node for Box<N> {
#[inline]
fn to_node(&self) -> AnyNode {
self.as_ref().to_node()
}
#[inline]
fn to_children(&self) -> Option<Children> {
self.as_ref().to_children()
}
#[inline]
fn into_node(self) -> AnyNode {
(*self).into_node()
}
#[inline]
fn into_children(self) -> Option<Children> {
(*self).into_children()
}
}
impl<N: ?Sized + Node> Node for &N {
#[inline]
fn to_node(&self) -> AnyNode {
(*self).to_node()
}
#[inline]
fn to_children(&self) -> Option<Children> {
(*self).to_children()
}
}