use super::{
Mountable, Position, PositionState, Render, RenderHtml, ToTemplate,
};
use crate::{
html::attribute::any_attribute::AnyAttribute,
hydration::Cursor,
no_attrs,
renderer::{CastFrom, Rndr},
};
use std::{borrow::Cow, rc::Rc, sync::Arc};
no_attrs!(&'a str);
no_attrs!(String);
no_attrs!(Arc<str>);
no_attrs!(Cow<'a, str>);
pub struct StrState<'a> {
pub(crate) node: crate::renderer::types::Text,
str: &'a str,
}
impl<'a> Render for &'a str {
type State = StrState<'a>;
fn build(self) -> Self::State {
let node = Rndr::create_text_node(self);
StrState { node, str: self }
}
fn rebuild(self, state: &mut Self::State) {
let StrState { node, str } = state;
if &self != str {
Rndr::set_text(node, self);
*str = self;
}
}
}
impl RenderHtml for &str {
type AsyncOutput = Self;
type Owned = String;
const MIN_LENGTH: usize = 0;
fn dry_resolve(&mut self) {}
async fn resolve(self) -> Self::AsyncOutput {
self
}
fn html_len(&self) -> usize {
self.len()
}
fn to_html_with_buf(
self,
buf: &mut String,
position: &mut Position,
escape: bool,
_mark_branches: bool,
_extra_attrs: Vec<AnyAttribute>,
) {
if matches!(position, Position::NextChildAfterText) {
buf.push_str("<!>")
}
if self.is_empty() && escape {
buf.push(' ');
} else if escape {
let escaped = html_escape::encode_text(self);
buf.push_str(&escaped);
} else {
buf.push_str(self);
}
*position = Position::NextChildAfterText;
}
fn hydrate<const FROM_SERVER: bool>(
self,
cursor: &Cursor,
position: &PositionState,
) -> Self::State {
if position.get() == Position::FirstChild {
cursor.child();
} else {
cursor.sibling();
}
if matches!(position.get(), Position::NextChildAfterText) {
cursor.sibling();
}
let node = cursor.current();
let node = crate::renderer::types::Text::cast_from(node.clone())
.unwrap_or_else(|| {
crate::hydration::failed_to_cast_text_node(node)
});
if !FROM_SERVER {
Rndr::set_text(&node, self);
}
position.set(Position::NextChildAfterText);
StrState { node, str: self }
}
fn into_owned(self) -> Self::Owned {
self.to_string()
}
}
impl ToTemplate for &str {
const TEMPLATE: &'static str = " <!>";
fn to_template(
buf: &mut String,
_class: &mut String,
_style: &mut String,
_inner_html: &mut String,
position: &mut Position,
) {
if matches!(*position, Position::NextChildAfterText) {
buf.push_str("<!>")
}
buf.push(' ');
*position = Position::NextChildAfterText;
}
}
impl Mountable for StrState<'_> {
fn unmount(&mut self) {
self.node.unmount()
}
fn mount(
&mut self,
parent: &crate::renderer::types::Element,
marker: Option<&crate::renderer::types::Node>,
) {
Rndr::insert_node(parent, self.node.as_ref(), marker);
}
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
self.node.insert_before_this(child)
}
fn elements(&self) -> Vec<crate::renderer::types::Element> {
vec![]
}
}
pub struct StringState {
node: crate::renderer::types::Text,
str: String,
}
impl Render for String {
type State = StringState;
fn build(self) -> Self::State {
let node = Rndr::create_text_node(&self);
StringState { node, str: self }
}
fn rebuild(self, state: &mut Self::State) {
let StringState { node, str } = state;
if &self != str {
Rndr::set_text(node, &self);
*str = self;
}
}
}
impl RenderHtml for String {
const MIN_LENGTH: usize = 0;
type AsyncOutput = Self;
type Owned = Self;
fn dry_resolve(&mut self) {}
async fn resolve(self) -> Self::AsyncOutput {
self
}
fn html_len(&self) -> usize {
self.len()
}
fn to_html_with_buf(
self,
buf: &mut String,
position: &mut Position,
escape: bool,
mark_branches: bool,
extra_attrs: Vec<AnyAttribute>,
) {
<&str as RenderHtml>::to_html_with_buf(
self.as_str(),
buf,
position,
escape,
mark_branches,
extra_attrs,
)
}
fn hydrate<const FROM_SERVER: bool>(
self,
cursor: &Cursor,
position: &PositionState,
) -> Self::State {
let StrState { node, .. } =
self.as_str().hydrate::<FROM_SERVER>(cursor, position);
StringState { node, str: self }
}
fn into_owned(self) -> Self::Owned {
self
}
}
impl ToTemplate for String {
const TEMPLATE: &'static str = <&str as ToTemplate>::TEMPLATE;
fn to_template(
buf: &mut String,
class: &mut String,
style: &mut String,
inner_html: &mut String,
position: &mut Position,
) {
<&str as ToTemplate>::to_template(
buf, class, style, inner_html, position,
)
}
}
impl Mountable for StringState {
fn unmount(&mut self) {
self.node.unmount()
}
fn mount(
&mut self,
parent: &crate::renderer::types::Element,
marker: Option<&crate::renderer::types::Node>,
) {
Rndr::insert_node(parent, self.node.as_ref(), marker);
}
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
self.node.insert_before_this(child)
}
fn elements(&self) -> Vec<crate::renderer::types::Element> {
vec![]
}
}
pub struct RcStrState {
node: crate::renderer::types::Text,
str: Rc<str>,
}
impl Render for Rc<str> {
type State = RcStrState;
fn build(self) -> Self::State {
let node = Rndr::create_text_node(&self);
RcStrState { node, str: self }
}
fn rebuild(self, state: &mut Self::State) {
let RcStrState { node, str } = state;
if !Rc::ptr_eq(&self, str) {
Rndr::set_text(node, &self);
*str = self;
}
}
}
impl ToTemplate for Rc<str> {
const TEMPLATE: &'static str = <&str as ToTemplate>::TEMPLATE;
fn to_template(
buf: &mut String,
class: &mut String,
style: &mut String,
inner_html: &mut String,
position: &mut Position,
) {
<&str as ToTemplate>::to_template(
buf, class, style, inner_html, position,
)
}
}
impl Mountable for RcStrState {
fn unmount(&mut self) {
self.node.unmount()
}
fn mount(
&mut self,
parent: &crate::renderer::types::Element,
marker: Option<&crate::renderer::types::Node>,
) {
Rndr::insert_node(parent, self.node.as_ref(), marker);
}
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
self.node.insert_before_this(child)
}
fn elements(&self) -> Vec<crate::renderer::types::Element> {
vec![]
}
}
pub struct ArcStrState {
node: crate::renderer::types::Text,
str: Arc<str>,
}
impl Render for Arc<str> {
type State = ArcStrState;
fn build(self) -> Self::State {
let node = Rndr::create_text_node(&self);
ArcStrState { node, str: self }
}
fn rebuild(self, state: &mut Self::State) {
let ArcStrState { node, str } = state;
if self != *str {
Rndr::set_text(node, &self);
*str = self;
}
}
}
impl RenderHtml for Arc<str> {
type AsyncOutput = Self;
type Owned = Self;
const MIN_LENGTH: usize = 0;
fn dry_resolve(&mut self) {}
async fn resolve(self) -> Self::AsyncOutput {
self
}
fn html_len(&self) -> usize {
self.len()
}
fn to_html_with_buf(
self,
buf: &mut String,
position: &mut Position,
escape: bool,
mark_branches: bool,
extra_attrs: Vec<AnyAttribute>,
) {
<&str as RenderHtml>::to_html_with_buf(
&self,
buf,
position,
escape,
mark_branches,
extra_attrs,
)
}
fn hydrate<const FROM_SERVER: bool>(
self,
cursor: &Cursor,
position: &PositionState,
) -> Self::State {
let this: &str = self.as_ref();
let StrState { node, .. } =
this.hydrate::<FROM_SERVER>(cursor, position);
ArcStrState { node, str: self }
}
fn into_owned(self) -> Self::Owned {
self
}
}
impl ToTemplate for Arc<str> {
const TEMPLATE: &'static str = <&str as ToTemplate>::TEMPLATE;
fn to_template(
buf: &mut String,
class: &mut String,
style: &mut String,
inner_html: &mut String,
position: &mut Position,
) {
<&str as ToTemplate>::to_template(
buf, class, style, inner_html, position,
)
}
}
impl Mountable for ArcStrState {
fn unmount(&mut self) {
self.node.unmount()
}
fn mount(
&mut self,
parent: &crate::renderer::types::Element,
marker: Option<&crate::renderer::types::Node>,
) {
Rndr::insert_node(parent, self.node.as_ref(), marker);
}
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
self.node.insert_before_this(child)
}
fn elements(&self) -> Vec<crate::renderer::types::Element> {
vec![]
}
}
pub struct CowStrState<'a> {
node: crate::renderer::types::Text,
str: Cow<'a, str>,
}
impl<'a> Render for Cow<'a, str> {
type State = CowStrState<'a>;
fn build(self) -> Self::State {
let node = Rndr::create_text_node(&self);
CowStrState { node, str: self }
}
fn rebuild(self, state: &mut Self::State) {
let CowStrState { node, str } = state;
if self != *str {
Rndr::set_text(node, &self);
*str = self;
}
}
}
impl RenderHtml for Cow<'_, str> {
type AsyncOutput = Self;
type Owned = String;
const MIN_LENGTH: usize = 0;
fn dry_resolve(&mut self) {}
async fn resolve(self) -> Self::AsyncOutput {
self
}
fn html_len(&self) -> usize {
self.len()
}
fn to_html_with_buf(
self,
buf: &mut String,
position: &mut Position,
escape: bool,
mark_branches: bool,
extra_attrs: Vec<AnyAttribute>,
) {
<&str as RenderHtml>::to_html_with_buf(
&self,
buf,
position,
escape,
mark_branches,
extra_attrs,
)
}
fn hydrate<const FROM_SERVER: bool>(
self,
cursor: &Cursor,
position: &PositionState,
) -> Self::State {
let this: &str = self.as_ref();
let StrState { node, .. } =
this.hydrate::<FROM_SERVER>(cursor, position);
CowStrState { node, str: self }
}
fn into_owned(self) -> <Self as RenderHtml>::Owned {
self.into_owned()
}
}
impl ToTemplate for Cow<'_, str> {
const TEMPLATE: &'static str = <&str as ToTemplate>::TEMPLATE;
fn to_template(
buf: &mut String,
class: &mut String,
style: &mut String,
inner_html: &mut String,
position: &mut Position,
) {
<&str as ToTemplate>::to_template(
buf, class, style, inner_html, position,
)
}
}
impl Mountable for CowStrState<'_> {
fn unmount(&mut self) {
self.node.unmount()
}
fn mount(
&mut self,
parent: &crate::renderer::types::Element,
marker: Option<&crate::renderer::types::Node>,
) {
Rndr::insert_node(parent, self.node.as_ref(), marker);
}
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
self.node.insert_before_this(child)
}
fn elements(&self) -> Vec<crate::renderer::types::Element> {
vec![]
}
}