1use super::attribute::{
2 maybe_next_attr_erasure_macros::next_attr_output_type, Attribute,
3 NextAttribute,
4};
5use crate::{
6 html::attribute::maybe_next_attr_erasure_macros::next_attr_combine,
7 prelude::AddAnyAttr,
8 view::{Position, ToTemplate},
9};
10use send_wrapper::SendWrapper;
11use std::{marker::PhantomData, sync::Arc};
12
13pub trait DirectiveAttribute<T, P, D>
16where
17 D: IntoDirective<T, P>,
18{
19 type Output;
21
22 fn directive(self, handler: D, param: P) -> Self::Output;
25}
26
27impl<V, T, P, D> DirectiveAttribute<T, P, D> for V
28where
29 V: AddAnyAttr,
30 D: IntoDirective<T, P>,
31 P: Clone + 'static,
32 T: 'static,
33{
34 type Output = <Self as AddAnyAttr>::Output<Directive<T, D, P>>;
35
36 fn directive(self, handler: D, param: P) -> Self::Output {
37 self.add_any_attr(directive(handler, param))
38 }
39}
40
41#[inline(always)]
44pub fn directive<T, P, D>(handler: D, param: P) -> Directive<T, D, P>
45where
46 D: IntoDirective<T, P>,
47{
48 Directive(Some(SendWrapper::new(DirectiveInner {
49 handler,
50 param,
51 t: PhantomData,
52 })))
53}
54
55#[derive(Debug)]
57pub struct Directive<T, D, P>(Option<SendWrapper<DirectiveInner<T, D, P>>>);
58
59impl<T, D, P> Clone for Directive<T, D, P>
60where
61 P: Clone + 'static,
62 D: Clone,
63{
64 fn clone(&self) -> Self {
65 Self(self.0.clone())
66 }
67}
68
69#[derive(Debug)]
70struct DirectiveInner<T, D, P> {
71 handler: D,
72 param: P,
73 t: PhantomData<T>,
74}
75
76impl<T, D, P> Clone for DirectiveInner<T, D, P>
77where
78 P: Clone + 'static,
79 D: Clone,
80{
81 fn clone(&self) -> Self {
82 Self {
83 handler: self.handler.clone(),
84 param: self.param.clone(),
85 t: PhantomData,
86 }
87 }
88}
89
90impl<T, P, D> Attribute for Directive<T, D, P>
91where
92 D: IntoDirective<T, P>,
93 P: Clone + 'static, T: 'static,
95{
96 const MIN_LENGTH: usize = 0;
97
98 type AsyncOutput = Self;
99 type State = crate::renderer::types::Element;
100 type Cloneable = Directive<T, D::Cloneable, P>;
101 type CloneableOwned = Directive<T, D::Cloneable, P>;
102
103 fn html_len(&self) -> usize {
104 0
105 }
106
107 fn to_html(
108 self,
109 _buf: &mut String,
110 _class: &mut String,
111 _style: &mut String,
112 _inner_html: &mut String,
113 ) {
114 }
115
116 fn hydrate<const FROM_SERVER: bool>(
117 self,
118 el: &crate::renderer::types::Element,
119 ) -> Self::State {
120 let inner = self.0.expect("directive removed early").take();
121 inner.handler.run(el.clone(), inner.param);
122 el.clone()
123 }
124
125 fn build(self, el: &crate::renderer::types::Element) -> Self::State {
126 let inner = self.0.expect("directive removed early").take();
127 inner.handler.run(el.clone(), inner.param);
128 el.clone()
129 }
130
131 fn rebuild(self, state: &mut Self::State) {
132 let inner = self.0.expect("directive removed early").take();
133 inner.handler.run(state.clone(), inner.param);
134 }
135
136 fn into_cloneable(self) -> Self::Cloneable {
137 self.into_cloneable_owned()
138 }
139
140 fn into_cloneable_owned(self) -> Self::CloneableOwned {
141 let inner = self.0.map(|inner| {
142 let DirectiveInner { handler, param, t } = inner.take();
143 SendWrapper::new(DirectiveInner {
144 handler: handler.into_cloneable(),
145 param,
146 t,
147 })
148 });
149 Directive(inner)
150 }
151
152 fn dry_resolve(&mut self) {
153 self.0.take();
158 }
159
160 async fn resolve(self) -> Self::AsyncOutput {
161 self
162 }
163}
164
165impl<T, D, P> NextAttribute for Directive<T, D, P>
166where
167 D: IntoDirective<T, P>,
168 P: Clone + 'static,
169 T: 'static,
170{
171 next_attr_output_type!(Self, NewAttr);
172
173 fn add_any_attr<NewAttr: Attribute>(
174 self,
175 new_attr: NewAttr,
176 ) -> Self::Output<NewAttr> {
177 next_attr_combine!(self, new_attr)
178 }
179}
180
181impl<T, D, P> ToTemplate for Directive<T, D, P> {
182 const CLASS: &'static str = "";
183
184 fn to_template(
185 _buf: &mut String,
186 _class: &mut String,
187 _style: &mut String,
188 _inner_html: &mut String,
189 _position: &mut Position,
190 ) {
191 }
192}
193
194pub trait IntoDirective<T: ?Sized, P> {
241 type Cloneable: IntoDirective<T, P> + Clone + 'static;
243
244 fn run(&self, el: crate::renderer::types::Element, param: P);
246
247 fn into_cloneable(self) -> Self::Cloneable;
249}
250
251impl<F> IntoDirective<(crate::renderer::types::Element,), ()> for F
252where
253 F: Fn(crate::renderer::types::Element) + 'static,
254{
255 type Cloneable = Arc<dyn Fn(crate::renderer::types::Element)>;
256
257 fn run(&self, el: crate::renderer::types::Element, _: ()) {
258 self(el)
259 }
260
261 fn into_cloneable(self) -> Self::Cloneable {
262 Arc::new(self)
263 }
264}
265
266impl IntoDirective<(crate::renderer::types::Element,), ()>
267 for Arc<dyn Fn(crate::renderer::types::Element)>
268{
269 type Cloneable = Arc<dyn Fn(crate::renderer::types::Element)>;
270
271 fn run(&self, el: crate::renderer::types::Element, _: ()) {
272 self(el)
273 }
274
275 fn into_cloneable(self) -> Self::Cloneable {
276 self
277 }
278}
279
280impl<F, P> IntoDirective<(crate::renderer::types::Element, P), P> for F
281where
282 F: Fn(crate::renderer::types::Element, P) + 'static,
283 P: 'static,
284{
285 type Cloneable = Arc<dyn Fn(crate::renderer::types::Element, P)>;
286
287 fn run(&self, el: crate::renderer::types::Element, param: P) {
288 self(el, param);
289 }
290
291 fn into_cloneable(self) -> Self::Cloneable {
292 Arc::new(self)
293 }
294}
295
296impl<P> IntoDirective<(crate::renderer::types::Element, P), P>
297 for Arc<dyn Fn(crate::renderer::types::Element, P)>
298where
299 P: 'static,
300{
301 type Cloneable = Arc<dyn Fn(crate::renderer::types::Element, P)>;
302
303 fn run(&self, el: crate::renderer::types::Element, param: P) {
304 self(el, param)
305 }
306
307 fn into_cloneable(self) -> Self::Cloneable {
308 self
309 }
310}