Skip to main content

dioxus_core_template/
op.rs

1/// One operation in a flat static template tape.
2#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
3#[repr(transparent)]
4#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
5pub(crate) struct TemplateOp(u16);
6
7impl TemplateOp {
8    const ENTER_MAX_CODE: u16 = 0x7fff;
9    const ATTR_CODE: u16 = 0x8000;
10    const ATTR_CUSTOM_NS_CODE: u16 = 0x8001;
11    const TEXT_CODE: u16 = 0x8002;
12    const STATIC_BASE: u16 = 0x8003;
13    pub(crate) const MAX_CAP: usize = 16_383;
14
15    /// Create a packed enter op.
16    pub(crate) const fn enter(skip: u16, namespace: bool) -> Self {
17        if skip as usize > Self::MAX_CAP {
18            panic!("op skip exceeds packed op capacity");
19        }
20        Self((skip << 1) | namespace as u16)
21    }
22
23    /// Create a packed static attribute op.
24    pub(crate) const fn attr(namespace: bool) -> Self {
25        if namespace {
26            Self(Self::ATTR_CUSTOM_NS_CODE)
27        } else {
28            Self(Self::ATTR_CODE)
29        }
30    }
31
32    /// Create a packed text marker op.
33    pub(crate) const fn text() -> Self {
34        Self(Self::TEXT_CODE)
35    }
36
37    /// Create a packed static string reference op.
38    pub(crate) const fn static_text(id: u16) -> Self {
39        if id as usize >= Self::MAX_CAP {
40            panic!("static op id exceeds packed op capacity");
41        }
42        Self(Self::STATIC_BASE + id)
43    }
44
45    /// Decode this packed op.
46    pub(crate) const fn decode(self) -> DecodedTemplateOp {
47        if self.0 <= Self::ENTER_MAX_CODE {
48            DecodedTemplateOp::Enter {
49                skip: self.0 >> 1,
50                namespace: self.0 & 1 == 1,
51            }
52        } else if self.0 == Self::ATTR_CODE {
53            DecodedTemplateOp::Attr { namespace: false }
54        } else if self.0 == Self::ATTR_CUSTOM_NS_CODE {
55            DecodedTemplateOp::Attr { namespace: true }
56        } else if self.0 == Self::TEXT_CODE {
57            DecodedTemplateOp::Text
58        } else {
59            DecodedTemplateOp::Static(self.0 - Self::STATIC_BASE)
60        }
61    }
62
63    /// Get the bits of this packed op.
64    pub(crate) const fn bits(self) -> u16 {
65        self.0
66    }
67}
68
69impl std::fmt::Debug for TemplateOp {
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        self.decode().fmt(f)
72    }
73}
74
75/// Decoded representation of a packed template operation.
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub enum DecodedTemplateOp {
78    /// Enter an element. `skip` is the number of ops in this element subtree.
79    Enter {
80        /// Number of ops to skip to move past this element and its children.
81        skip: u16,
82        /// Whether the reserved namespace string slot contains a namespace.
83        namespace: bool,
84    },
85    /// A static attribute on the current element.
86    Attr {
87        /// Whether a custom namespace string follows the static attr name/value.
88        namespace: bool,
89    },
90    /// A text node marker. The next op is a [`Self::Static`] string reference.
91    Text,
92    /// A static string pool reference.
93    Static(u16),
94}