sledgehammer/
element.rs

1#![allow(non_camel_case_types)]
2
3use crate::{attribute::AnyAttribute, batch::Batch, InNamespace, NodeId};
4
5use self::sealed::Sealed;
6
7mod sealed {
8    use crate::{Element, InNamespace};
9
10    pub trait Sealed {}
11
12    impl Sealed for Element {}
13    impl<'a> Sealed for &'a str {}
14    impl<'a> Sealed for InNamespace<'a, Element> {}
15    impl<'a, 'b> Sealed for InNamespace<'a, &'b str> {}
16}
17
18pub enum AnyElement<'a, 'b> {
19    Element(Element),
20    InNamespace(InNamespace<'a, Element>),
21    Str(&'a str),
22    InNamespaceStr(InNamespace<'a, &'b str>),
23}
24
25impl AnyElement<'_, '_> {
26    pub fn encode(&self, v: &mut Batch) {
27        match self {
28            AnyElement::Element(a) => a.encode(v),
29            AnyElement::InNamespace(a) => a.encode(v),
30            AnyElement::Str(a) => a.encode(v),
31            AnyElement::InNamespaceStr(a) => a.encode(v),
32        }
33    }
34}
35
36/// Anything that can be turned into an element name
37pub trait IntoElement<'a, 'b>: Sealed + Into<AnyElement<'a, 'b>> {
38    /// If the element name can be encoded in a single byte
39    const SINGLE_BYTE: bool = false;
40
41    /// Encode the element into the message channel
42    fn encode(&self, v: &mut Batch);
43
44    /// Encode the element into the message channel with memory pre-allocated
45    /// # Safety
46    ///
47    /// This is only safe if the batch is preallocated to the correct size
48    unsafe fn encode_prealloc(&self, v: &mut Batch)
49    where
50        Self: Sized,
51    {
52        self.encode(v);
53    }
54}
55
56impl<'a, 'b> Element {
57    pub const fn any_element_const(self) -> AnyElement<'a, 'b> {
58        AnyElement::Element(self)
59    }
60}
61
62impl<'a, 'b> IntoElement<'a, 'b> for Element {
63    const SINGLE_BYTE: bool = true;
64
65    #[inline(always)]
66    fn encode(&self, v: &mut Batch) {
67        v.msg.push(*self as u8);
68    }
69
70    #[inline(always)]
71    unsafe fn encode_prealloc(&self, v: &mut Batch)
72    where
73        Self: Sized,
74    {
75        unsafe {
76            let ptr: *mut u8 = v.msg.as_mut_ptr();
77            let old_len = v.msg.len();
78            *ptr.add(old_len) = *self as u8;
79            v.msg.set_len(old_len + 1);
80        }
81    }
82}
83
84impl<'a, 'b> From<Element> for AnyElement<'a, 'b> {
85    fn from(e: Element) -> Self {
86        AnyElement::Element(e)
87    }
88}
89
90impl<'a, 'b> InNamespace<'a, Element> {
91    /// Turn into an [`AnyElement`] in a const context
92    pub const fn any_element_const(self) -> AnyElement<'a, 'b> {
93        AnyElement::InNamespace(self)
94    }
95}
96
97impl<'a, 'b> IntoElement<'a, 'b> for InNamespace<'a, Element> {
98    fn encode(&self, v: &mut Batch) {
99        v.msg.push(255);
100        v.msg.push(self.0 as u8);
101        v.encode_str(self.1);
102    }
103}
104
105impl<'a, 'b> From<InNamespace<'a, Element>> for AnyElement<'a, 'b> {
106    fn from(e: InNamespace<'a, Element>) -> Self {
107        AnyElement::InNamespace(e)
108    }
109}
110
111impl<'a, 'b> IntoElement<'a, 'b> for &'a str {
112    fn encode(&self, v: &mut Batch) {
113        v.msg.push(254);
114        v.encode_str(*self);
115    }
116}
117
118impl<'a, 'b> From<&'a str> for AnyElement<'a, 'b> {
119    fn from(e: &'a str) -> Self {
120        AnyElement::Str(e)
121    }
122}
123
124impl<'a, 'b> IntoElement<'a, 'b> for InNamespace<'a, &'b str> {
125    fn encode(&self, v: &mut Batch) {
126        v.msg.push(253);
127        v.encode_str(self.0);
128        v.encode_str(self.1);
129    }
130}
131
132impl<'a, 'b> From<InNamespace<'a, &'b str>> for AnyElement<'a, 'b> {
133    fn from(e: InNamespace<'a, &'b str>) -> Self {
134        AnyElement::InNamespaceStr(e)
135    }
136}
137
138impl<'a, 'b> InNamespace<'a, &'b str> {
139    pub const fn any_element_const(self) -> AnyElement<'a, 'b> {
140        AnyElement::InNamespaceStr(self)
141    }
142}
143
144/// A builder for any node
145pub enum NodeBuilder<'a> {
146    Text(TextBuilder<'a>),
147    Element(ElementBuilder<'a>),
148}
149
150impl NodeBuilder<'_> {
151    /// Encode the node into a batch
152    pub(crate) fn encode(&self, v: &mut Batch) {
153        match self {
154            NodeBuilder::Text(t) => t.encode(v),
155            NodeBuilder::Element(e) => e.encode(v),
156        }
157    }
158}
159
160impl<'a> From<TextBuilder<'a>> for NodeBuilder<'a> {
161    fn from(t: TextBuilder<'a>) -> Self {
162        NodeBuilder::Text(t)
163    }
164}
165
166impl<'a> From<ElementBuilder<'a>> for NodeBuilder<'a> {
167    fn from(e: ElementBuilder<'a>) -> Self {
168        NodeBuilder::Element(e)
169    }
170}
171
172/// A builder for an text node with a id, and text
173pub struct TextBuilder<'a> {
174    id: Option<NodeId>,
175    text: &'a str,
176}
177
178impl<'a> TextBuilder<'a> {
179    /// Create a new text builder
180    pub const fn new(text: &'a str) -> Self {
181        Self { id: None, text }
182    }
183
184    /// Set the id of the text node
185    pub const fn id(mut self, id: NodeId) -> Self {
186        self.id = Some(id);
187        self
188    }
189
190    /// Encode the text node into a batch
191    pub(crate) fn encode(&self, v: &mut Batch) {
192        match self.id {
193            Some(id) => {
194                v.msg.push(3);
195                v.encode_id(id);
196            }
197            None => {
198                v.msg.push(2);
199            }
200        }
201        v.encode_str(self.text);
202    }
203}
204
205/// A builder for a element with an id, kind, attributes, and children
206///
207/// /// Example:
208/// ```rust
209/// let mut channel = MsgChannel::default();
210
211/// // create an element using sledgehammer
212/// channel.build_full_element(
213///     ElementBuilder::new("div".into())
214///         .id(NodeId(1))
215///         .attrs(&[(Attribute::style.into(), "color: blue")])
216///         .children(&[
217///             ElementBuilder::new(Element::p.into())
218///                 .into(),
219///             TextBuilder::new("Hello from sledgehammer!").into(),
220///         ]),
221/// );
222/// channel.flush();
223/// ```
224pub struct ElementBuilder<'a> {
225    id: Option<NodeId>,
226    kind: AnyElement<'a, 'a>,
227    attrs: &'a [(AnyAttribute<'a, 'a>, &'a str)],
228    children: &'a [NodeBuilder<'a>],
229}
230
231impl<'a> ElementBuilder<'a> {
232    /// Create a new element builder
233    pub const fn new(kind: AnyElement<'a, 'a>) -> Self {
234        Self {
235            id: None,
236            kind,
237            attrs: &[],
238            children: &[],
239        }
240    }
241
242    /// Set the id of the element
243    pub const fn id(mut self, id: NodeId) -> Self {
244        self.id = Some(id);
245        self
246    }
247
248    /// Set the attributes of the element
249    pub const fn attrs(mut self, attrs: &'a [(AnyAttribute<'a, 'a>, &'a str)]) -> Self {
250        self.attrs = attrs;
251        self
252    }
253
254    /// Set the children of the element
255    pub const fn children(mut self, children: &'a [NodeBuilder<'a>]) -> Self {
256        self.children = children;
257        self
258    }
259
260    /// Encode the element into the a batch
261    pub(crate) fn encode(&self, v: &mut Batch) {
262        match self.id {
263            Some(id) => {
264                v.msg.push(1);
265                v.encode_id(id);
266            }
267            None => {
268                v.msg.push(0);
269            }
270        }
271        self.kind.encode(v);
272        // these are packed together so they can be read as a u16
273        v.msg.push(self.attrs.len() as u8);
274        v.msg.push(self.children.len() as u8);
275        for (attr, value) in self.attrs {
276            attr.encode_u8_discriminant(v);
277            v.encode_str(*value);
278        }
279        for child in self.children {
280            child.encode(v);
281        }
282    }
283}
284
285/// All built-in elements
286/// These are the element can be encoded with a single byte so they are more efficient (but less flexable) than a &str element
287#[allow(unused)]
288#[derive(Copy, Clone)]
289pub enum Element {
290    a,
291    abbr,
292    acronym,
293    address,
294    applet,
295    area,
296    article,
297    aside,
298    audio,
299    b,
300    base,
301    bdi,
302    bdo,
303    bgsound,
304    big,
305    blink,
306    blockquote,
307    body,
308    br,
309    button,
310    canvas,
311    caption,
312    center,
313    cite,
314    code,
315    col,
316    colgroup,
317    content,
318    data,
319    datalist,
320    dd,
321    del,
322    details,
323    dfn,
324    dialog,
325    dir,
326    div,
327    dl,
328    dt,
329    em,
330    embed,
331    fieldset,
332    figcaption,
333    figure,
334    font,
335    footer,
336    form,
337    frame,
338    frameset,
339    h1,
340    head,
341    header,
342    hgroup,
343    hr,
344    html,
345    i,
346    iframe,
347    image,
348    img,
349    input,
350    ins,
351    kbd,
352    keygen,
353    label,
354    legend,
355    li,
356    link,
357    main,
358    map,
359    mark,
360    marquee,
361    menu,
362    menuitem,
363    meta,
364    meter,
365    nav,
366    nobr,
367    noembed,
368    noframes,
369    noscript,
370    object,
371    ol,
372    optgroup,
373    option,
374    output,
375    p,
376    param,
377    picture,
378    plaintext,
379    portal,
380    pre,
381    progress,
382    q,
383    rb,
384    rp,
385    rt,
386    rtc,
387    ruby,
388    s,
389    samp,
390    script,
391    section,
392    select,
393    shadow,
394    slot,
395    small,
396    source,
397    spacer,
398    span,
399    strike,
400    strong,
401    style,
402    sub,
403    summary,
404    sup,
405    table,
406    tbody,
407    td,
408    template,
409    textarea,
410    tfoot,
411    th,
412    thead,
413    time,
414    title,
415    tr,
416    track,
417    tt,
418    u,
419    ul,
420    var,
421    video,
422    wbr,
423    xmp,
424}