sledgehammer/
attribute.rs

1#![allow(non_camel_case_types)]
2
3use self::sealed::Sealed;
4use crate::{batch::Batch, InNamespace};
5
6mod sealed {
7    use crate::{Attribute, InNamespace};
8
9    pub trait Sealed {}
10
11    impl Sealed for Attribute {}
12    impl<'a> Sealed for InNamespace<'a, Attribute> {}
13    impl<'a> Sealed for &'a str {}
14    impl<'a, 'b> Sealed for InNamespace<'b, &'a str> {}
15}
16
17pub enum AnyAttribute<'a, 'b> {
18    Attribute(Attribute),
19    InNamespace(InNamespace<'a, Attribute>),
20    Str(&'a str),
21    InNamespaceStr(InNamespace<'a, &'b str>),
22}
23
24impl AnyAttribute<'_, '_> {
25    pub fn encode_u8_discriminant(&self, v: &mut Batch) {
26        match self {
27            AnyAttribute::Attribute(a) => a.encode_u8_discriminant(v),
28            AnyAttribute::InNamespace(a) => a.encode_u8_discriminant(v),
29            AnyAttribute::Str(a) => a.encode_u8_discriminant(v),
30            AnyAttribute::InNamespaceStr(a) => a.encode_u8_discriminant(v),
31        }
32    }
33}
34
35/// Anything that can be turned into an attribute
36pub trait IntoAttribue<'a, 'b>: Sealed + Into<AnyAttribute<'a, 'b>> {
37    /// If the attribute can be encoded in a single byte
38    const SINGLE_BYTE: bool = false;
39
40    /// Encode the attribute into the message channel
41    fn encode(self, v: &mut Batch);
42
43    /// Encode the attribute into the message channel with memory pre-allocated
44    /// # Safety
45    ///
46    /// This is only safe if the batch is preallocated to the correct size
47    unsafe fn encode_prealloc(self, v: &mut Batch)
48    where
49        Self: Sized,
50    {
51        self.encode(v);
52    }
53
54    /// Encode the attribute into the message channel with a u8 desciminant instead of bit packed bools
55    fn encode_u8_discriminant(&self, v: &mut Batch);
56}
57
58impl<'a, 'b> Attribute {
59    /// Turn into an [`AnyAttribute`] in a const context
60    pub const fn any_attr_const(self) -> AnyAttribute<'a, 'b> {
61        AnyAttribute::Attribute(self)
62    }
63}
64
65impl<'a, 'b> IntoAttribue<'a, 'b> for Attribute {
66    const SINGLE_BYTE: bool = true;
67
68    #[inline(always)]
69    fn encode(self, v: &mut Batch) {
70        v.encode_bool(false);
71        v.encode_bool(false);
72        v.msg.push(self as u8);
73    }
74
75    #[inline(always)]
76    unsafe fn encode_prealloc(self, v: &mut Batch) {
77        v.encode_bool(false);
78        v.encode_bool(false);
79        unsafe {
80            let ptr: *mut u8 = v.msg.as_mut_ptr();
81            *ptr.add(v.msg.len()) = self as u8;
82            v.msg.set_len(v.msg.len() + 1);
83        }
84    }
85
86    fn encode_u8_discriminant(&self, v: &mut Batch) {
87        v.msg.push(*self as u8)
88    }
89}
90
91impl<'a, 'b> From<Attribute> for AnyAttribute<'a, 'b> {
92    fn from(a: Attribute) -> Self {
93        AnyAttribute::Attribute(a)
94    }
95}
96
97impl<'a, 'b> InNamespace<'a, Attribute> {
98    pub const fn any_attr_const(self) -> AnyAttribute<'a, 'b> {
99        AnyAttribute::InNamespace(self)
100    }
101}
102
103impl<'a, 'b> IntoAttribue<'a, 'b> for InNamespace<'a, Attribute> {
104    fn encode(self, v: &mut Batch) {
105        v.encode_bool(false);
106        v.msg.push(self.0 as u8);
107        v.encode_bool(true);
108        v.encode_str(self.1);
109    }
110
111    fn encode_u8_discriminant(&self, v: &mut Batch) {
112        v.msg.push(255);
113        v.msg.push(self.0 as u8);
114        v.encode_str(self.1);
115    }
116}
117
118impl<'a, 'b> From<InNamespace<'a, Attribute>> for AnyAttribute<'a, 'b> {
119    fn from(a: InNamespace<'a, Attribute>) -> Self {
120        AnyAttribute::InNamespace(a)
121    }
122}
123
124impl<'a, 'b> IntoAttribue<'a, 'b> for &'a str {
125    fn encode(self, v: &mut Batch) {
126        v.encode_bool(true);
127        v.encode_cachable_str(self);
128        v.encode_bool(false);
129    }
130
131    fn encode_u8_discriminant(&self, v: &mut Batch) {
132        v.msg.push(254);
133        v.encode_cachable_str(*self);
134    }
135}
136
137impl<'a, 'b> From<&'a str> for AnyAttribute<'a, 'b> {
138    fn from(a: &'a str) -> Self {
139        AnyAttribute::Str(a)
140    }
141}
142
143impl<'a, 'b> InNamespace<'a, &'b str> {
144    pub const fn any_attr_const(self) -> AnyAttribute<'a, 'b> {
145        AnyAttribute::InNamespaceStr(self)
146    }
147}
148
149impl<'a, 'b> IntoAttribue<'a, 'b> for InNamespace<'a, &'b str> {
150    fn encode(self, v: &mut Batch) {
151        v.encode_bool(true);
152        v.encode_cachable_str(self.0);
153        v.encode_bool(true);
154        v.encode_cachable_str(self.1);
155    }
156
157    fn encode_u8_discriminant(&self, v: &mut Batch) {
158        v.msg.push(253);
159        v.encode_cachable_str(self.0);
160        v.encode_cachable_str(self.1);
161    }
162}
163
164impl<'a, 'b> From<InNamespace<'a, &'b str>> for AnyAttribute<'a, 'b> {
165    fn from(a: InNamespace<'a, &'b str>) -> Self {
166        AnyAttribute::InNamespaceStr(a)
167    }
168}
169
170/// All built-in attributes
171/// These are the attributes can be encoded with a single byte so they are more efficient (but less flexable) than a &str attribute
172#[derive(Copy, Clone)]
173pub enum Attribute {
174    accept_charset,
175    accept,
176    accesskey,
177    action,
178    align,
179    allow,
180    alt,
181    aria_atomic,
182    aria_busy,
183    aria_controls,
184    aria_current,
185    aria_describedby,
186    aria_description,
187    aria_details,
188    aria_disabled,
189    aria_dropeffect,
190    aria_errormessage,
191    aria_flowto,
192    aria_grabbed,
193    aria_haspopup,
194    aria_hidden,
195    aria_invalid,
196    aria_keyshortcuts,
197    aria_label,
198    aria_labelledby,
199    aria_live,
200    aria_owns,
201    aria_relevant,
202    aria_roledescription,
203    r#async,
204    autocapitalize,
205    autocomplete,
206    autofocus,
207    autoplay,
208    background,
209    bgcolor,
210    border,
211    buffered,
212    capture,
213    challenge,
214    charset,
215    checked,
216    cite,
217    class,
218    code,
219    codebase,
220    color,
221    cols,
222    colspan,
223    content,
224    contenteditable,
225    contextmenu,
226    controls,
227    coords,
228    crossorigin,
229    csp,
230    data,
231    datetime,
232    decoding,
233    default,
234    defer,
235    dir,
236    dirname,
237    disabled,
238    download,
239    draggable,
240    enctype,
241    enterkeyhint,
242    r#for,
243    form,
244    formaction,
245    formenctype,
246    formmethod,
247    formnovalidate,
248    formtarget,
249    headers,
250    height,
251    hidden,
252    high,
253    href,
254    hreflang,
255    http_equiv,
256    icon,
257    id,
258    importance,
259    inputmode,
260    integrity,
261    intrinsicsize,
262    ismap,
263    itemprop,
264    keytype,
265    kind,
266    label,
267    lang,
268    language,
269    list,
270    loading,
271    r#loop,
272    low,
273    manifest,
274    max,
275    maxlength,
276    media,
277    method,
278    min,
279    minlength,
280    multiple,
281    muted,
282    name,
283    novalidate,
284    open,
285    optimum,
286    pattern,
287    ping,
288    placeholder,
289    poster,
290    preload,
291    radiogroup,
292    readonly,
293    referrerpolicy,
294    rel,
295    required,
296    reversed,
297    role,
298    rows,
299    rowspan,
300    sandbox,
301    scope,
302    scoped,
303    selected,
304    shape,
305    size,
306    sizes,
307    slot,
308    span,
309    spellcheck,
310    src,
311    srcdoc,
312    srclang,
313    srcset,
314    start,
315    step,
316    style,
317    summary,
318    tabindex,
319    target,
320    title,
321    translate,
322    r#type,
323    usemap,
324    value,
325    width,
326    wrap,
327}