use crate::core::component::{Component, Context};
use crate::html::{html, Markup};
use crate::{builder_fn, AutoDefault, UniqueId};
use parking_lot::Mutex;
pub use parking_lot::MutexGuard as ComponentGuard;
use std::fmt;
use std::vec::IntoIter;
#[derive(AutoDefault)]
pub struct Child(Option<Mutex<Box<dyn Component>>>);
impl Clone for Child {
fn clone(&self) -> Self {
Child(self.0.as_ref().map(|m| Mutex::new(m.lock().clone_box())))
}
}
impl fmt::Debug for Child {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
None => write!(f, "Child(None)"),
Some(c) => write!(f, "Child({})", c.lock().name()),
}
}
}
impl Child {
pub fn with(component: impl Component) -> Self {
Child(Some(Mutex::new(Box::new(component))))
}
#[builder_fn]
pub fn with_component<C: Component>(mut self, component: Option<C>) -> Self {
self.0 = component.map(|c| Mutex::new(Box::new(c) as Box<dyn Component>));
self
}
#[inline]
pub fn id(&self) -> Option<String> {
self.0.as_ref().and_then(|c| c.lock().id())
}
pub fn render(&self, cx: &mut Context) -> Markup {
self.0.as_ref().map_or(html! {}, |c| c.lock().render(cx))
}
#[inline]
fn type_id(&self) -> Option<UniqueId> {
self.0.as_ref().map(|c| c.lock().type_id())
}
}
impl<C: Component + 'static> From<Embed<C>> for Child {
fn from(embed: Embed<C>) -> Self {
if let Some(m) = embed.0 {
Child(Some(Mutex::new(
Box::new(m.into_inner()) as Box<dyn Component>
)))
} else {
Child(None)
}
}
}
impl<T: Component + 'static> From<T> for Child {
#[inline]
fn from(component: T) -> Self {
Child::with(component)
}
}
impl<T: Component + 'static> From<T> for ChildOp {
#[inline]
fn from(component: T) -> Self {
ChildOp::Add(Child::with(component))
}
}
impl From<Child> for ChildOp {
#[inline]
fn from(child: Child) -> Self {
ChildOp::Add(child)
}
}
#[derive(AutoDefault)]
pub struct Embed<C: Component>(Option<Mutex<C>>);
impl<C: Component + Clone> Clone for Embed<C> {
fn clone(&self) -> Self {
Embed(self.0.as_ref().map(|m| Mutex::new(m.lock().clone())))
}
}
impl<C: Component> fmt::Debug for Embed<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
None => write!(f, "Embed(None)"),
Some(c) => write!(f, "Embed({})", c.lock().name()),
}
}
}
impl<C: Component> Embed<C> {
pub fn with(component: C) -> Self {
Embed(Some(Mutex::new(component)))
}
#[builder_fn]
pub fn with_component(mut self, component: Option<C>) -> Self {
self.0 = component.map(Mutex::new);
self
}
#[inline]
pub fn id(&self) -> Option<String> {
self.0.as_ref().and_then(|c| c.lock().id())
}
pub fn get(&self) -> Option<ComponentGuard<'_, C>> {
self.0.as_ref().map(|m| m.lock())
}
pub fn render(&self, cx: &mut Context) -> Markup {
self.0.as_ref().map_or(html! {}, |c| c.lock().render(cx))
}
}
pub enum ChildOp {
Add(Child),
AddIfEmpty(Child),
AddMany(Vec<Child>),
InsertAfterId(&'static str, Child),
InsertBeforeId(&'static str, Child),
Prepend(Child),
PrependMany(Vec<Child>),
RemoveById(&'static str),
ReplaceById(&'static str, Child),
Reset,
}
#[derive(AutoDefault, Clone, Debug)]
pub struct Children(Vec<Child>);
impl Children {
pub fn new() -> Self {
Self::default()
}
pub fn with(child: Child) -> Self {
Self::default().with_child(child)
}
#[builder_fn]
pub fn with_child(mut self, op: impl Into<ChildOp>) -> Self {
match op.into() {
ChildOp::Add(any) => self.add(any),
ChildOp::AddIfEmpty(any) => self.add_if_empty(any),
ChildOp::AddMany(many) => self.add_many(many),
ChildOp::InsertAfterId(id, any) => self.insert_after_id(id, any),
ChildOp::InsertBeforeId(id, any) => self.insert_before_id(id, any),
ChildOp::Prepend(any) => self.prepend(any),
ChildOp::PrependMany(many) => self.prepend_many(many),
ChildOp::RemoveById(id) => self.remove_by_id(id),
ChildOp::ReplaceById(id, any) => self.replace_by_id(id, any),
ChildOp::Reset => self.reset(),
}
}
#[inline]
pub(crate) fn add(&mut self, child: Child) -> &mut Self {
self.0.push(child);
self
}
#[inline]
pub(crate) fn add_if_empty(&mut self, child: Child) -> &mut Self {
if self.0.is_empty() {
self.0.push(child);
}
self
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn get_by_id(&self, id: impl AsRef<str>) -> Option<&Child> {
let id = Some(id.as_ref());
self.0.iter().find(|c| c.id().as_deref() == id)
}
pub fn iter_by_id<'a>(&'a self, id: &'a str) -> impl Iterator<Item = &'a Child> + 'a {
self.0.iter().filter(move |c| c.id().as_deref() == Some(id))
}
pub fn iter_by_type_id(&self, type_id: UniqueId) -> impl Iterator<Item = &Child> {
self.0.iter().filter(move |c| c.type_id() == Some(type_id))
}
pub fn render(&self, cx: &mut Context) -> Markup {
html! {
@for c in &self.0 {
(c.render(cx))
}
}
}
#[inline]
fn add_many<I>(&mut self, iter: I) -> &mut Self
where
I: IntoIterator<Item = Child>,
{
self.0.extend(iter);
self
}
#[inline]
fn insert_after_id(&mut self, id: impl AsRef<str>, child: Child) -> &mut Self {
let id = Some(id.as_ref());
match self.0.iter().position(|c| c.id().as_deref() == id) {
Some(index) => self.0.insert(index + 1, child),
_ => self.0.push(child),
};
self
}
#[inline]
fn insert_before_id(&mut self, id: impl AsRef<str>, child: Child) -> &mut Self {
let id = Some(id.as_ref());
match self.0.iter().position(|c| c.id().as_deref() == id) {
Some(index) => self.0.insert(index, child),
_ => self.0.insert(0, child),
};
self
}
#[inline]
fn prepend(&mut self, child: Child) -> &mut Self {
self.0.insert(0, child);
self
}
#[inline]
fn prepend_many<I>(&mut self, iter: I) -> &mut Self
where
I: IntoIterator<Item = Child>,
{
let buf: Vec<Child> = iter.into_iter().collect();
self.0.splice(0..0, buf);
self
}
#[inline]
fn remove_by_id(&mut self, id: impl AsRef<str>) -> &mut Self {
let id = Some(id.as_ref());
if let Some(index) = self.0.iter().position(|c| c.id().as_deref() == id) {
self.0.remove(index);
}
self
}
#[inline]
fn replace_by_id(&mut self, id: impl AsRef<str>, child: Child) -> &mut Self {
let id = Some(id.as_ref());
for c in &mut self.0 {
if c.id().as_deref() == id {
*c = child;
break;
}
}
self
}
#[inline]
fn reset(&mut self) -> &mut Self {
self.0.clear();
self
}
}
impl IntoIterator for Children {
type Item = Child;
type IntoIter = IntoIter<Child>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a Children {
type Item = &'a Child;
type IntoIter = std::slice::Iter<'a, Child>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a> IntoIterator for &'a mut Children {
type Item = &'a mut Child;
type IntoIter = std::slice::IterMut<'a, Child>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}