use super::attribute::{Attribute, NextAttribute};
use crate::{
prelude::AddAnyAttr,
view::{Position, ToTemplate},
};
use send_wrapper::SendWrapper;
use std::{marker::PhantomData, sync::Arc};
pub trait DirectiveAttribute<T, P, D>
where
D: IntoDirective<T, P>,
{
type Output;
fn directive(self, handler: D, param: P) -> Self::Output;
}
impl<V, T, P, D> DirectiveAttribute<T, P, D> for V
where
V: AddAnyAttr,
D: IntoDirective<T, P>,
P: Clone + 'static,
T: 'static,
{
type Output = <Self as AddAnyAttr>::Output<Directive<T, D, P>>;
fn directive(self, handler: D, param: P) -> Self::Output {
self.add_any_attr(directive(handler, param))
}
}
#[inline(always)]
pub fn directive<T, P, D>(handler: D, param: P) -> Directive<T, D, P>
where
D: IntoDirective<T, P>,
{
Directive(Some(SendWrapper::new(DirectiveInner {
handler,
param,
t: PhantomData,
})))
}
#[derive(Debug)]
pub struct Directive<T, D, P>(Option<SendWrapper<DirectiveInner<T, D, P>>>);
impl<T, D, P> Clone for Directive<T, D, P>
where
P: Clone + 'static,
D: Clone,
{
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
#[derive(Debug)]
struct DirectiveInner<T, D, P> {
handler: D,
param: P,
t: PhantomData<T>,
}
impl<T, D, P> Clone for DirectiveInner<T, D, P>
where
P: Clone + 'static,
D: Clone,
{
fn clone(&self) -> Self {
Self {
handler: self.handler.clone(),
param: self.param.clone(),
t: PhantomData,
}
}
}
impl<T, P, D> Attribute for Directive<T, D, P>
where
D: IntoDirective<T, P>,
P: Clone + 'static, T: 'static,
{
const MIN_LENGTH: usize = 0;
type AsyncOutput = Self;
type State = crate::renderer::types::Element;
type Cloneable = Directive<T, D::Cloneable, P>;
type CloneableOwned = Directive<T, D::Cloneable, P>;
fn html_len(&self) -> usize {
0
}
fn to_html(
self,
_buf: &mut String,
_class: &mut String,
_style: &mut String,
_inner_html: &mut String,
) {
}
fn hydrate<const FROM_SERVER: bool>(
self,
el: &crate::renderer::types::Element,
) -> Self::State {
let inner = self.0.expect("directive removed early").take();
inner.handler.run(el.clone(), inner.param);
el.clone()
}
fn build(self, el: &crate::renderer::types::Element) -> Self::State {
let inner = self.0.expect("directive removed early").take();
inner.handler.run(el.clone(), inner.param);
el.clone()
}
fn rebuild(self, state: &mut Self::State) {
let inner = self.0.expect("directive removed early").take();
inner.handler.run(state.clone(), inner.param);
}
fn into_cloneable(self) -> Self::Cloneable {
self.into_cloneable_owned()
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
let inner = self.0.map(|inner| {
let DirectiveInner { handler, param, t } = inner.take();
SendWrapper::new(DirectiveInner {
handler: handler.into_cloneable(),
param,
t,
})
});
Directive(inner)
}
fn dry_resolve(&mut self) {
self.0.take();
}
async fn resolve(self) -> Self::AsyncOutput {
self
}
}
impl<T, D, P> NextAttribute for Directive<T, D, P>
where
D: IntoDirective<T, P>,
P: Clone + 'static,
T: 'static,
{
type Output<NewAttr: Attribute> = (Self, NewAttr);
fn add_any_attr<NewAttr: Attribute>(
self,
new_attr: NewAttr,
) -> Self::Output<NewAttr> {
(self, new_attr)
}
}
impl<T, D, P> ToTemplate for Directive<T, D, P> {
const CLASS: &'static str = "";
fn to_template(
_buf: &mut String,
_class: &mut String,
_style: &mut String,
_inner_html: &mut String,
_position: &mut Position,
) {
}
}
pub trait IntoDirective<T: ?Sized, P> {
type Cloneable: IntoDirective<T, P> + Clone + 'static;
fn run(&self, el: crate::renderer::types::Element, param: P);
fn into_cloneable(self) -> Self::Cloneable;
}
impl<F> IntoDirective<(crate::renderer::types::Element,), ()> for F
where
F: Fn(crate::renderer::types::Element) + 'static,
{
type Cloneable = Arc<dyn Fn(crate::renderer::types::Element)>;
fn run(&self, el: crate::renderer::types::Element, _: ()) {
self(el)
}
fn into_cloneable(self) -> Self::Cloneable {
Arc::new(self)
}
}
impl IntoDirective<(crate::renderer::types::Element,), ()>
for Arc<dyn Fn(crate::renderer::types::Element)>
{
type Cloneable = Arc<dyn Fn(crate::renderer::types::Element)>;
fn run(&self, el: crate::renderer::types::Element, _: ()) {
self(el)
}
fn into_cloneable(self) -> Self::Cloneable {
self
}
}
impl<F, P> IntoDirective<(crate::renderer::types::Element, P), P> for F
where
F: Fn(crate::renderer::types::Element, P) + 'static,
P: 'static,
{
type Cloneable = Arc<dyn Fn(crate::renderer::types::Element, P)>;
fn run(&self, el: crate::renderer::types::Element, param: P) {
self(el, param);
}
fn into_cloneable(self) -> Self::Cloneable {
Arc::new(self)
}
}
impl<P> IntoDirective<(crate::renderer::types::Element, P), P>
for Arc<dyn Fn(crate::renderer::types::Element, P)>
where
P: 'static,
{
type Cloneable = Arc<dyn Fn(crate::renderer::types::Element, P)>;
fn run(&self, el: crate::renderer::types::Element, param: P) {
self(el, param)
}
fn into_cloneable(self) -> Self::Cloneable {
self
}
}