Skip to main content

toml_spanner/item/
to_toml.rs

1use super::array::Array;
2use super::table::Table;
3use super::{FLAG_MASK, HINTS_BIT, Item, ItemMetadata, NOT_PROJECTED, TAG_MASK, TAG_SHIFT};
4
5/// Bit 30 of `end_and_flag`: marks a full match during reprojection.
6pub(crate) const FULL_MATCH_BIT: u32 = 1 << 30;
7/// Bit 29 of `end_and_flag`: when set in format-hints mode, disables
8/// source-position reordering for this table's immediate entries.
9pub(crate) const IGNORE_SOURCE_ORDER_BIT: u32 = 1 << 29;
10/// Bit 28 of `end_and_flag`: when set in format-hints mode, disables
11/// copying structural styles from source during reprojection.
12pub(crate) const IGNORE_SOURCE_STYLE_BIT: u32 = 1 << 28;
13/// Bit 27 of `end_and_flag`: marks an array element as reordered during
14/// reprojection. Prevents the emitter from sorting this element back to
15/// its original source position in the parent array, without affecting
16/// source-ordering of the element's own children.
17pub(crate) const ARRAY_REORDERED_BIT: u32 = 1 << 27;
18/// Bit 25 of `end_and_flag`: when set in format-hints mode, indicates that
19/// an inline array should be emitted in multiline format with one element
20/// per line and trailing commas.
21pub(crate) const EXPANDED_BIT: u32 = 1 << 25;
22
23impl ItemMetadata {
24    /// Returns the projected index (bits 3-31 of `start_and_tag`).
25    #[inline]
26    pub(crate) fn projected_index(&self) -> u32 {
27        self.start_and_tag >> TAG_SHIFT
28    }
29
30    /// Branchless mask: span mode -> FLAG_MASK (clears stale span data),
31    /// hints mode -> 0xFFFFFFFF (preserves existing hint bits).
32    #[inline]
33    fn hints_preserve_mask(&self) -> u32 {
34        ((self.end_and_flag as i32) >> 31) as u32 | FLAG_MASK
35    }
36
37    /// Stores a reprojected index, preserving user-set hint bits when
38    /// already in hints mode. Returns `false` if the index doesn't fit.
39    #[inline]
40    pub(crate) fn set_reprojected_index(&mut self, index: usize) -> bool {
41        if index <= (u32::MAX >> TAG_SHIFT) as usize {
42            self.start_and_tag = (self.start_and_tag & TAG_MASK) | ((index as u32) << TAG_SHIFT);
43            self.end_and_flag = (self.end_and_flag & self.hints_preserve_mask()) | HINTS_BIT;
44            true
45        } else {
46            false
47        }
48    }
49
50    /// Marks as not projected, preserving user-set hint bits when already
51    /// in hints mode and clearing full-match.
52    #[inline]
53    pub(crate) fn set_reprojected_to_none(&mut self) {
54        self.start_and_tag |= NOT_PROJECTED;
55        self.end_and_flag =
56            (self.end_and_flag & (self.hints_preserve_mask() & !FULL_MATCH_BIT)) | HINTS_BIT;
57    }
58
59    #[inline]
60    pub(crate) fn set_reprojected_full_match(&mut self) {
61        self.end_and_flag |= FULL_MATCH_BIT;
62    }
63
64    #[inline]
65    pub(crate) fn is_reprojected_full_match(&self) -> bool {
66        self.end_and_flag & FULL_MATCH_BIT != 0
67    }
68
69    /// Disables source-position reordering for this table's entries.
70    #[inline]
71    pub(crate) fn set_ignore_source_order(&mut self) {
72        self.end_and_flag |= HINTS_BIT | IGNORE_SOURCE_ORDER_BIT;
73    }
74
75    /// Returns `true` if source-position reordering is disabled.
76    /// Gates on `HINTS_BIT` so stale span-end bits cannot false-positive.
77    #[inline]
78    pub(crate) fn ignore_source_order(&self) -> bool {
79        self.end_and_flag & (HINTS_BIT | IGNORE_SOURCE_ORDER_BIT)
80            == (HINTS_BIT | IGNORE_SOURCE_ORDER_BIT)
81    }
82
83    /// Marks an array element as reordered during reprojection.
84    #[inline]
85    pub(crate) fn set_array_reordered(&mut self) {
86        self.end_and_flag |= HINTS_BIT | ARRAY_REORDERED_BIT;
87    }
88
89    /// Returns `true` if this element was reordered during array reprojection.
90    #[inline]
91    pub(crate) fn array_reordered(&self) -> bool {
92        self.end_and_flag & (HINTS_BIT | ARRAY_REORDERED_BIT) == (HINTS_BIT | ARRAY_REORDERED_BIT)
93    }
94
95    /// Disables copying structural styles from source during reprojection.
96    #[inline]
97    pub(crate) fn set_ignore_source_style(&mut self) {
98        self.end_and_flag |= HINTS_BIT | IGNORE_SOURCE_STYLE_BIT;
99    }
100
101    /// Returns `true` if source-style copying is disabled for this table.
102    #[inline]
103    pub(crate) fn ignore_source_style(&self) -> bool {
104        self.end_and_flag & (HINTS_BIT | IGNORE_SOURCE_STYLE_BIT)
105            == (HINTS_BIT | IGNORE_SOURCE_STYLE_BIT)
106    }
107
108    #[inline]
109    pub(crate) fn set_expanded(&mut self) {
110        self.end_and_flag |= HINTS_BIT | EXPANDED_BIT;
111    }
112
113    #[inline]
114    pub(crate) fn is_expanded(&self) -> bool {
115        self.end_and_flag & (HINTS_BIT | EXPANDED_BIT) == (HINTS_BIT | EXPANDED_BIT)
116    }
117
118    #[inline]
119    pub(crate) fn clear_expanded(&mut self) {
120        self.end_and_flag &= !EXPANDED_BIT;
121    }
122}
123
124impl<'de> Item<'de> {
125    /// Access projected item from source computed in reprojection.
126    pub(crate) fn projected<'a>(&self, inputs: &[&'a Item<'a>]) -> Option<&'a Item<'a>> {
127        let index = self.meta.projected_index();
128        inputs.get(index as usize).copied()
129    }
130    pub(crate) fn set_reprojected_to_none(&mut self) {
131        self.meta.set_reprojected_to_none();
132    }
133    pub(crate) fn set_reprojected_index(&mut self, index: usize) -> bool {
134        self.meta.set_reprojected_index(index)
135    }
136    /// Marks this item as a full match during reprojection.
137    pub(crate) fn set_reprojected_full_match(&mut self) {
138        self.meta.set_reprojected_full_match();
139    }
140    /// Returns whether this item was marked as a full match during reprojection.
141    pub(crate) fn is_reprojected_full_match(&self) -> bool {
142        self.meta.is_reprojected_full_match()
143    }
144
145    /// Returns `true` if this item is emitted as a subsection rather than
146    /// as part of the body: `[header]` tables, implicit tables, and
147    /// `[[array-of-tables]]`.
148    #[inline]
149    pub(crate) fn is_subsection(&self) -> bool {
150        self.has_header_bit() || self.is_implicit_table() || self.is_aot()
151    }
152
153    #[inline]
154    #[cfg(test)]
155    pub(crate) fn set_flag(&mut self, flag: u32) {
156        self.meta.set_flag(flag);
157    }
158}
159
160impl<'de> Table<'de> {
161    /// Disables source-position reordering for this table's immediate entries
162    /// during emission. Non-recursive: child tables are unaffected.
163    pub fn set_ignore_source_order(&mut self) {
164        self.meta.set_ignore_source_order();
165    }
166
167    /// Returns `true` if source-position reordering is disabled for this table.
168    #[must_use]
169    pub fn ignore_source_order(&self) -> bool {
170        self.meta.ignore_source_order()
171    }
172
173    /// Disables copying structural styles (TableStyle/ArrayStyle) from source
174    /// during reprojection for this table's immediate entries. Key spans and
175    /// reprojection indices are still copied. Non-recursive.
176    pub fn set_ignore_source_style(&mut self) {
177        self.meta.set_ignore_source_style();
178    }
179
180    /// Returns `true` if source-style copying is disabled for this table.
181    #[must_use]
182    pub fn ignore_source_style(&self) -> bool {
183        self.meta.ignore_source_style()
184    }
185
186    /// Returns `true` if this table has automatic style resolution pending.
187    #[must_use]
188    pub fn is_auto_style(&self) -> bool {
189        self.meta.is_auto_style()
190    }
191}
192
193impl<'de> Array<'de> {
194    /// Returns `true` if this array has automatic style resolution pending.
195    #[must_use]
196    pub fn is_auto_style(&self) -> bool {
197        self.meta.is_auto_style()
198    }
199
200    /// Returns `true` if this inline array should be emitted in multiline
201    /// format with one element per line.
202    #[must_use]
203    pub fn is_expanded(&self) -> bool {
204        self.meta.is_expanded()
205    }
206
207    /// Marks this inline array for multiline emission.
208    pub fn set_expanded(&mut self) {
209        self.meta.set_expanded();
210    }
211
212    /// Clears the multiline emission hint.
213    pub fn clear_expanded(&mut self) {
214        self.meta.clear_expanded();
215    }
216}