#[doc(hidden)]
pub mod key;
#[doc(hidden)]
pub mod listeners;
#[doc(hidden)]
pub mod vcomp;
#[doc(hidden)]
pub mod vlist;
#[doc(hidden)]
pub mod vnode;
#[doc(hidden)]
pub mod vportal;
#[doc(hidden)]
pub mod vraw;
#[doc(hidden)]
pub mod vsuspense;
#[doc(hidden)]
pub mod vtag;
#[doc(hidden)]
pub mod vtext;
use std::hint::unreachable_unchecked;
use std::rc::Rc;
use indexmap::IndexMap;
use wasm_bindgen::JsValue;
#[doc(inline)]
pub use self::key::Key;
#[doc(inline)]
pub use self::listeners::*;
#[doc(inline)]
pub use self::vcomp::{VChild, VComp};
#[doc(inline)]
pub use self::vlist::VList;
#[doc(inline)]
pub use self::vnode::VNode;
#[doc(inline)]
pub use self::vportal::VPortal;
#[doc(inline)]
pub use self::vraw::VRaw;
#[doc(inline)]
pub use self::vsuspense::VSuspense;
#[doc(inline)]
pub use self::vtag::VTag;
#[doc(inline)]
pub use self::vtext::VText;
pub type AttrValue = implicit_clone::unsync::IString;
#[cfg(any(feature = "ssr", feature = "hydration"))]
mod feat_ssr_hydration {
#[cfg(debug_assertions)]
type ComponentName = &'static str;
#[cfg(not(debug_assertions))]
type ComponentName = std::marker::PhantomData<()>;
#[cfg(feature = "hydration")]
use std::borrow::Cow;
pub enum Collectable {
Component(ComponentName),
Raw,
Suspense,
}
impl Collectable {
#[cfg(not(debug_assertions))]
#[inline(always)]
pub fn for_component<T: 'static>() -> Self {
use std::marker::PhantomData;
let _comp_type: PhantomData<T> = PhantomData;
Self::Component(PhantomData)
}
#[cfg(debug_assertions)]
pub fn for_component<T: 'static>() -> Self {
let comp_name = std::any::type_name::<T>();
Self::Component(comp_name)
}
pub fn open_start_mark(&self) -> &'static str {
match self {
Self::Component(_) => "<[",
Self::Raw => "<#",
Self::Suspense => "<?",
}
}
pub fn close_start_mark(&self) -> &'static str {
match self {
Self::Component(_) => "</[",
Self::Raw => "</#",
Self::Suspense => "</?",
}
}
pub fn end_mark(&self) -> &'static str {
match self {
Self::Component(_) => "]>",
Self::Raw => ">",
Self::Suspense => ">",
}
}
#[cfg(feature = "hydration")]
pub fn name(&self) -> Cow<'static, str> {
match self {
#[cfg(debug_assertions)]
Self::Component(m) => format!("Component({m})").into(),
#[cfg(not(debug_assertions))]
Self::Component(_) => "Component".into(),
Self::Raw => "Raw".into(),
Self::Suspense => "Suspense".into(),
}
}
}
}
#[cfg(any(feature = "ssr", feature = "hydration"))]
pub(crate) use feat_ssr_hydration::*;
#[cfg(feature = "ssr")]
mod feat_ssr {
use std::fmt::Write;
use super::*;
use crate::platform::fmt::BufWriter;
impl Collectable {
pub(crate) fn write_open_tag(&self, w: &mut BufWriter) {
let _ = w.write_str("<!--");
let _ = w.write_str(self.open_start_mark());
#[cfg(debug_assertions)]
match self {
Self::Component(type_name) => {
let _ = w.write_str(type_name);
}
Self::Raw => {}
Self::Suspense => {}
}
let _ = w.write_str(self.end_mark());
let _ = w.write_str("-->");
}
pub(crate) fn write_close_tag(&self, w: &mut BufWriter) {
let _ = w.write_str("<!--");
let _ = w.write_str(self.close_start_mark());
#[cfg(debug_assertions)]
match self {
Self::Component(type_name) => {
let _ = w.write_str(type_name);
}
Self::Raw => {}
Self::Suspense => {}
}
let _ = w.write_str(self.end_mark());
let _ = w.write_str("-->");
}
}
}
#[allow(missing_docs)]
#[derive(PartialEq, Clone, Debug)]
pub enum AttributeOrProperty {
Static(&'static str),
Attribute(AttrValue),
Property(JsValue),
}
#[derive(PartialEq, Clone, Debug)]
pub enum Attributes {
Static(&'static [(&'static str, AttributeOrProperty)]),
Dynamic {
keys: &'static [&'static str],
values: Box<[Option<AttributeOrProperty>]>,
},
IndexMap(Rc<IndexMap<AttrValue, AttributeOrProperty>>),
}
impl Attributes {
pub fn new() -> Self {
Self::default()
}
pub fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (&'a str, &'a str)> + 'a> {
match self {
Self::Static(arr) => Box::new(arr.iter().filter_map(|(k, v)| match v {
AttributeOrProperty::Attribute(v) => Some((*k, v.as_ref())),
AttributeOrProperty::Property(_) => None,
AttributeOrProperty::Static(v) => Some((*k, v)),
})),
Self::Dynamic { keys, values } => {
Box::new(keys.iter().zip(values.iter()).filter_map(|(k, v)| match v {
Some(AttributeOrProperty::Attribute(v)) => Some((*k, v.as_ref())),
_ => None,
}))
}
Self::IndexMap(m) => Box::new(m.iter().filter_map(|(k, v)| match v {
AttributeOrProperty::Attribute(v) => Some((k.as_ref(), v.as_ref())),
_ => None,
})),
}
}
pub fn get_mut_index_map(&mut self) -> &mut IndexMap<AttrValue, AttributeOrProperty> {
macro_rules! unpack {
() => {
match self {
Self::IndexMap(m) => Rc::make_mut(m),
_ => unsafe { unreachable_unchecked() },
}
};
}
match self {
Self::IndexMap(m) => Rc::make_mut(m),
Self::Static(arr) => {
*self = Self::IndexMap(Rc::new(
arr.iter().map(|(k, v)| ((*k).into(), v.clone())).collect(),
));
unpack!()
}
Self::Dynamic { keys, values } => {
*self = Self::IndexMap(Rc::new(
std::mem::take(values)
.iter_mut()
.zip(keys.iter())
.filter_map(|(v, k)| v.take().map(|v| (AttrValue::from(*k), v)))
.collect(),
));
unpack!()
}
}
}
}
impl From<IndexMap<AttrValue, AttrValue>> for Attributes {
fn from(map: IndexMap<AttrValue, AttrValue>) -> Self {
let v = map
.into_iter()
.map(|(k, v)| (k, AttributeOrProperty::Attribute(v)))
.collect();
Self::IndexMap(Rc::new(v))
}
}
impl From<IndexMap<&'static str, AttrValue>> for Attributes {
fn from(v: IndexMap<&'static str, AttrValue>) -> Self {
let v = v
.into_iter()
.map(|(k, v)| (AttrValue::Static(k), (AttributeOrProperty::Attribute(v))))
.collect();
Self::IndexMap(Rc::new(v))
}
}
impl From<IndexMap<&'static str, JsValue>> for Attributes {
fn from(v: IndexMap<&'static str, JsValue>) -> Self {
let v = v
.into_iter()
.map(|(k, v)| (AttrValue::Static(k), (AttributeOrProperty::Property(v))))
.collect();
Self::IndexMap(Rc::new(v))
}
}
impl Default for Attributes {
fn default() -> Self {
Self::Static(&[])
}
}