use self::add_attr::AddAnyAttr;
use crate::{
html::attribute::any_attribute::AnyAttribute, hydration::Cursor,
ssr::StreamBuilder,
};
use or_poisoned::OrPoisoned;
use std::{
cell::RefCell,
future::Future,
rc::Rc,
sync::{Arc, RwLock},
};
pub mod add_attr;
pub mod any_view;
pub mod either;
pub mod error_boundary;
pub mod fragment;
pub mod iterators;
pub mod keyed;
mod primitives;
#[cfg(all(feature = "nightly", rustc_nightly))]
pub mod static_types;
pub mod strings;
pub mod template;
pub mod tuples;
pub trait Render: Sized {
type State: Mountable;
fn build(self) -> Self::State;
fn rebuild(self, state: &mut Self::State);
}
#[doc(hidden)]
pub trait MarkBranch {
fn open_branch(&mut self, branch_id: &str);
fn close_branch(&mut self, branch_id: &str);
}
impl MarkBranch for String {
fn open_branch(&mut self, branch_id: &str) {
self.push_str("<!--bo-");
self.push_str(branch_id);
self.push_str("-->");
}
fn close_branch(&mut self, branch_id: &str) {
self.push_str("<!--bc-");
self.push_str(branch_id);
self.push_str("-->");
}
}
impl MarkBranch for StreamBuilder {
fn open_branch(&mut self, branch_id: &str) {
self.sync_buf.push_str("<!--bo-");
self.sync_buf.push_str(branch_id);
self.sync_buf.push_str("-->");
}
fn close_branch(&mut self, branch_id: &str) {
self.sync_buf.push_str("<!--bc-");
self.sync_buf.push_str(branch_id);
self.sync_buf.push_str("-->");
}
}
pub trait RenderHtml
where
Self: Render + AddAnyAttr + Send,
{
type AsyncOutput: RenderHtml;
type Owned: RenderHtml + 'static;
const MIN_LENGTH: usize;
const EXISTS: bool = true;
fn dry_resolve(&mut self);
fn resolve(self) -> impl Future<Output = Self::AsyncOutput> + Send;
fn html_len(&self) -> usize {
Self::MIN_LENGTH
}
fn to_html(self) -> String
where
Self: Sized,
{
let mut buf = String::with_capacity(self.html_len());
self.to_html_with_buf(
&mut buf,
&mut Position::FirstChild,
true,
false,
vec![],
);
buf
}
fn to_html_branching(self) -> String
where
Self: Sized,
{
let mut buf = String::with_capacity(self.html_len());
self.to_html_with_buf(
&mut buf,
&mut Position::FirstChild,
true,
true,
vec![],
);
buf
}
fn to_html_stream_in_order(self) -> StreamBuilder
where
Self: Sized,
{
let mut builder = StreamBuilder::with_capacity(self.html_len(), None);
self.to_html_async_with_buf::<false>(
&mut builder,
&mut Position::FirstChild,
true,
false,
vec![],
);
builder.finish()
}
fn to_html_stream_in_order_branching(self) -> StreamBuilder
where
Self: Sized,
{
let mut builder = StreamBuilder::with_capacity(self.html_len(), None);
self.to_html_async_with_buf::<false>(
&mut builder,
&mut Position::FirstChild,
true,
true,
vec![],
);
builder.finish()
}
fn to_html_stream_out_of_order(self) -> StreamBuilder
where
Self: Sized,
{
let mut builder =
StreamBuilder::with_capacity(self.html_len(), Some(vec![0]));
self.to_html_async_with_buf::<true>(
&mut builder,
&mut Position::FirstChild,
true,
false,
vec![],
);
builder.finish()
}
fn to_html_stream_out_of_order_branching(self) -> StreamBuilder
where
Self: Sized,
{
let mut builder =
StreamBuilder::with_capacity(self.html_len(), Some(vec![0]));
self.to_html_async_with_buf::<true>(
&mut builder,
&mut Position::FirstChild,
true,
true,
vec![],
);
builder.finish()
}
fn to_html_with_buf(
self,
buf: &mut String,
position: &mut Position,
escape: bool,
mark_branches: bool,
extra_attrs: Vec<AnyAttribute>,
);
fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
self,
buf: &mut StreamBuilder,
position: &mut Position,
escape: bool,
mark_branches: bool,
extra_attrs: Vec<AnyAttribute>,
) where
Self: Sized,
{
buf.with_buf(|buf| {
self.to_html_with_buf(
buf,
position,
escape,
mark_branches,
extra_attrs,
)
});
}
fn hydrate<const FROM_SERVER: bool>(
self,
cursor: &Cursor,
position: &PositionState,
) -> Self::State;
fn hydrate_async(
self,
cursor: &Cursor,
position: &PositionState,
) -> impl Future<Output = Self::State> {
async { self.hydrate::<true>(cursor, position) }
}
fn hydrate_from<const FROM_SERVER: bool>(
self,
el: &crate::renderer::types::Element,
) -> Self::State
where
Self: Sized,
{
self.hydrate_from_position::<FROM_SERVER>(el, Position::default())
}
fn hydrate_from_position<const FROM_SERVER: bool>(
self,
el: &crate::renderer::types::Element,
position: Position,
) -> Self::State
where
Self: Sized,
{
let cursor = Cursor::new(el.clone());
let position = PositionState::new(position);
self.hydrate::<FROM_SERVER>(&cursor, &position)
}
fn into_owned(self) -> Self::Owned;
}
pub trait Mountable {
fn unmount(&mut self);
fn mount(
&mut self,
parent: &crate::renderer::types::Element,
marker: Option<&crate::renderer::types::Node>,
);
fn try_mount(
&mut self,
parent: &crate::renderer::types::Element,
marker: Option<&crate::renderer::types::Node>,
) -> bool {
self.mount(parent, marker);
true
}
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool;
fn insert_before_this_or_marker(
&self,
parent: &crate::renderer::types::Element,
child: &mut dyn Mountable,
marker: Option<&crate::renderer::types::Node>,
) {
if !self.insert_before_this(child) {
child.mount(parent, marker);
}
}
fn elements(&self) -> Vec<crate::renderer::types::Element>;
}
pub enum MountKind {
Before(crate::renderer::types::Node),
Append,
}
impl<T> Mountable for Option<T>
where
T: Mountable,
{
fn unmount(&mut self) {
if let Some(ref mut mounted) = self {
mounted.unmount()
}
}
fn mount(
&mut self,
parent: &crate::renderer::types::Element,
marker: Option<&crate::renderer::types::Node>,
) {
if let Some(ref mut inner) = self {
inner.mount(parent, marker);
}
}
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
self.as_ref()
.map(|inner| inner.insert_before_this(child))
.unwrap_or(false)
}
fn elements(&self) -> Vec<crate::renderer::types::Element> {
self.as_ref()
.map(|inner| inner.elements())
.unwrap_or_default()
}
}
impl<T> Mountable for Rc<RefCell<T>>
where
T: Mountable,
{
fn unmount(&mut self) {
self.borrow_mut().unmount()
}
fn mount(
&mut self,
parent: &crate::renderer::types::Element,
marker: Option<&crate::renderer::types::Node>,
) {
self.borrow_mut().mount(parent, marker);
}
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
self.borrow().insert_before_this(child)
}
fn elements(&self) -> Vec<crate::renderer::types::Element> {
self.borrow().elements()
}
}
pub trait ToTemplate {
const TEMPLATE: &'static str = "";
const CLASS: &'static str = "";
const STYLE: &'static str = "";
const LEN: usize = Self::TEMPLATE.len();
fn to_template(
buf: &mut String,
class: &mut String,
style: &mut String,
inner_html: &mut String,
position: &mut Position,
);
fn to_template_attribute(
buf: &mut String,
class: &mut String,
style: &mut String,
inner_html: &mut String,
position: &mut Position,
) {
Self::to_template(buf, class, style, inner_html, position);
}
}
#[derive(Debug, Default, Clone)]
pub struct PositionState(Arc<RwLock<Position>>);
impl PositionState {
pub fn new(position: Position) -> Self {
Self(Arc::new(RwLock::new(position)))
}
pub fn set(&self, position: Position) {
*self.0.write().or_poisoned() = position;
}
pub fn get(&self) -> Position {
*self.0.read().or_poisoned()
}
pub fn deep_clone(&self) -> Self {
let current = self.get();
Self(Arc::new(RwLock::new(current)))
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
pub enum Position {
Current,
#[default]
FirstChild,
NextChild,
NextChildAfterText,
OnlyChild,
LastChild,
}
pub trait IntoRender {
type Output;
fn into_render(self) -> Self::Output;
}
impl<T> IntoRender for T
where
T: Render,
{
type Output = Self;
fn into_render(self) -> Self::Output {
self
}
}