1use super::{
2 maybe_next_attr_erasure_macros::next_attr_output_type, NextAttribute,
3};
4use crate::{
5 html::attribute::{
6 maybe_next_attr_erasure_macros::next_attr_combine, Attribute,
7 AttributeValue, NamedAttributeKey,
8 },
9 view::{add_attr::AddAnyAttr, Position, ToTemplate},
10};
11use std::{borrow::Cow, sync::Arc};
12
13#[inline(always)]
15pub fn custom_attribute<K, V>(key: K, value: V) -> CustomAttr<K, V>
16where
17 K: CustomAttributeKey,
18 V: AttributeValue,
19{
20 CustomAttr { key, value }
21}
22
23#[derive(Debug)]
25pub struct CustomAttr<K, V>
26where
27 K: CustomAttributeKey,
28 V: AttributeValue,
29{
30 key: K,
31 value: V,
32}
33
34impl<K, V> Clone for CustomAttr<K, V>
35where
36 K: CustomAttributeKey,
37 V: AttributeValue + Clone,
38{
39 fn clone(&self) -> Self {
40 Self {
41 key: self.key.clone(),
42 value: self.value.clone(),
43 }
44 }
45}
46
47impl<K, V> Attribute for CustomAttr<K, V>
48where
49 K: CustomAttributeKey,
50 V: AttributeValue,
51{
52 const MIN_LENGTH: usize = 0;
53 type AsyncOutput = CustomAttr<K, V::AsyncOutput>;
54 type State = V::State;
55 type Cloneable = CustomAttr<K, V::Cloneable>;
56 type CloneableOwned = CustomAttr<K, V::CloneableOwned>;
57
58 fn html_len(&self) -> usize {
59 self.key.as_ref().len() + 3 + self.value.html_len()
60 }
61
62 fn to_html(
63 self,
64 buf: &mut String,
65 _class: &mut String,
66 _style: &mut String,
67 _inner_html: &mut String,
68 ) {
69 self.value.to_html(self.key.as_ref(), buf);
70 }
71
72 fn hydrate<const FROM_SERVER: bool>(
73 self,
74 el: &crate::renderer::types::Element,
75 ) -> Self::State {
76 if !K::KEY.is_empty() {
77 self.value.hydrate::<FROM_SERVER>(self.key.as_ref(), el)
78 } else {
79 self.value.build(el, self.key.as_ref())
80 }
81 }
82
83 fn build(self, el: &crate::renderer::types::Element) -> Self::State {
84 self.value.build(el, self.key.as_ref())
85 }
86
87 fn rebuild(self, state: &mut Self::State) {
88 self.value.rebuild(self.key.as_ref(), state);
89 }
90
91 fn into_cloneable(self) -> Self::Cloneable {
92 CustomAttr {
93 key: self.key,
94 value: self.value.into_cloneable(),
95 }
96 }
97
98 fn into_cloneable_owned(self) -> Self::CloneableOwned {
99 CustomAttr {
100 key: self.key,
101 value: self.value.into_cloneable_owned(),
102 }
103 }
104
105 fn dry_resolve(&mut self) {
106 self.value.dry_resolve();
107 }
108
109 async fn resolve(self) -> Self::AsyncOutput {
110 CustomAttr {
111 key: self.key,
112 value: self.value.resolve().await,
113 }
114 }
115
116 fn keys(&self) -> Vec<NamedAttributeKey> {
117 vec![NamedAttributeKey::Attribute(
118 self.key.as_ref().to_string().into(),
119 )]
120 }
121}
122
123impl<K, V> NextAttribute for CustomAttr<K, V>
124where
125 K: CustomAttributeKey,
126 V: AttributeValue,
127{
128 next_attr_output_type!(Self, NewAttr);
129
130 fn add_any_attr<NewAttr: Attribute>(
131 self,
132 new_attr: NewAttr,
133 ) -> Self::Output<NewAttr> {
134 next_attr_combine!(self, new_attr)
135 }
136}
137
138impl<K, V> ToTemplate for CustomAttr<K, V>
139where
140 K: CustomAttributeKey,
141 V: AttributeValue,
142{
143 fn to_template(
144 buf: &mut String,
145 _class: &mut String,
146 _style: &mut String,
147 _inner_html: &mut String,
148 _position: &mut Position,
149 ) {
150 if !K::KEY.is_empty() {
151 V::to_template(K::KEY, buf);
152 }
153 }
154}
155
156pub trait CustomAttributeKey: Clone + AsRef<str> + Send + 'static {
159 const KEY: &'static str;
161}
162
163impl CustomAttributeKey for &'static str {
164 const KEY: &'static str = "";
165}
166
167impl CustomAttributeKey for Cow<'static, str> {
168 const KEY: &'static str = "";
169}
170
171impl CustomAttributeKey for String {
172 const KEY: &'static str = "";
173}
174
175impl CustomAttributeKey for Arc<str> {
176 const KEY: &'static str = "";
177}
178
179#[cfg(all(feature = "nightly", rustc_nightly))]
180impl<const K: &'static str> CustomAttributeKey
181 for crate::view::static_types::Static<K>
182{
183 const KEY: &'static str = K;
184}
185
186pub trait CustomAttribute<K, V>
188where
189 K: CustomAttributeKey,
190 V: AttributeValue,
191
192 Self: Sized + AddAnyAttr,
193{
194 fn attr(
196 self,
197 key: K,
198 value: V,
199 ) -> <Self as AddAnyAttr>::Output<CustomAttr<K, V>> {
200 self.add_any_attr(custom_attribute(key, value))
201 }
202}
203
204impl<T, K, V> CustomAttribute<K, V> for T
205where
206 T: AddAnyAttr,
207 K: CustomAttributeKey,
208 V: AttributeValue,
209{
210}