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