Skip to main content

toml_spanner/
table.rs

1#![allow(unsafe_code)]
2
3#[cfg(test)]
4#[path = "./table_tests.rs"]
5mod tests;
6
7use crate::value::{
8    FLAG_HEADER, FLAG_MASK, FLAG_SHIFT, FLAG_TABLE, Item, Key, MaybeItem, NONE, TAG_MASK,
9    TAG_SHIFT, TAG_TABLE,
10};
11use crate::{Deserialize, Error, ErrorKind, Span};
12use std::mem::size_of;
13use std::ptr::NonNull;
14
15use crate::arena::Arena;
16
17type TableEntry<'de> = (Key<'de>, Item<'de>);
18
19const MIN_CAP: u32 = 2;
20
21/// A TOML table: a flat list of key-value pairs with linear lookup.
22pub(crate) struct InnerTable<'de> {
23    len: u32,
24    cap: u32,
25    ptr: NonNull<TableEntry<'de>>,
26}
27
28impl<'de> InnerTable<'de> {
29    /// Creates an empty table.
30    #[inline]
31    pub fn new() -> Self {
32        Self {
33            len: 0,
34            cap: 0,
35            ptr: NonNull::dangling(),
36        }
37    }
38
39    /// Inserts a key-value pair. Does **not** check for duplicates.
40    pub fn insert(
41        &mut self,
42        key: Key<'de>,
43        value: Item<'de>,
44        arena: &Arena,
45    ) -> &mut TableEntry<'de> {
46        let len = self.len;
47        if self.len == self.cap {
48            self.grow(arena);
49        }
50        unsafe {
51            let ptr = self.ptr.as_ptr().add(len as usize);
52            ptr.write((key, value));
53            self.len = len + 1;
54            &mut (*ptr)
55        }
56    }
57
58    /// Returns the number of entries.
59    #[inline]
60    pub fn len(&self) -> usize {
61        self.len as usize
62    }
63
64    /// Returns `true` if the table has no entries.
65    #[inline]
66    pub fn is_empty(&self) -> bool {
67        self.len == 0
68    }
69
70    /// Linear scan for a key, returning both key and value references.
71    pub fn get_key_value(&self, name: &str) -> Option<(&Key<'de>, &Item<'de>)> {
72        for entry in self.entries() {
73            if entry.0.name == name {
74                return Some((&entry.0, &entry.1));
75            }
76        }
77        None
78    }
79
80    /// Returns a reference to the value for `name`.
81    pub fn get(&self, name: &str) -> Option<&Item<'de>> {
82        for entry in self.entries() {
83            if entry.0.name == name {
84                return Some(&entry.1);
85            }
86        }
87        None
88    }
89
90    /// Returns a mutable reference to the value for `name`.
91    pub fn get_mut(&mut self, name: &str) -> Option<&mut Item<'de>> {
92        for entry in self.entries_mut() {
93            if entry.0.name == name {
94                return Some(&mut entry.1);
95            }
96        }
97        None
98    }
99
100    /// Returns `true` if the table contains the key.
101    #[inline]
102    pub fn contains_key(&self, name: &str) -> bool {
103        self.get(name).is_some()
104    }
105
106    /// Removes the first entry matching `name`, returning its value.
107    /// Uses swap-remove, so the ordering of remaining entries may change.
108    pub fn remove(&mut self, name: &str) -> Option<Item<'de>> {
109        self.remove_entry(name).map(|(_, v)| v)
110    }
111
112    /// Removes the first entry matching `name`, returning the key-value pair.
113    /// Uses swap-remove, so the ordering of remaining entries may change.
114    pub fn remove_entry(&mut self, name: &str) -> Option<(Key<'de>, Item<'de>)> {
115        let idx = self.find_index(name)?;
116        Some(self.remove_at(idx))
117    }
118
119    /// Returns an iterator over mutable references to the values.
120    pub fn values_mut(&mut self) -> impl Iterator<Item = &mut Item<'de>> {
121        self.entries_mut().iter_mut().map(|(_, v)| v)
122    }
123
124    /// Returns the span start of the first key. Used as a table discriminator
125    /// in the parser's hash index.
126    ///
127    /// # Panics
128    ///
129    /// Debug-asserts that the table is non-empty.
130    #[inline]
131    pub(crate) unsafe fn first_key_span_start_unchecked(&self) -> u32 {
132        debug_assert!(self.len > 0);
133        unsafe { (*self.ptr.as_ptr()).0.span.start }
134    }
135
136    /// Returns a slice of all entries.
137    #[inline]
138    pub fn entries(&self) -> &[TableEntry<'de>] {
139        unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len as usize) }
140    }
141
142    #[inline]
143    pub(crate) fn entries_mut(&mut self) -> &mut [TableEntry<'de>] {
144        unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len as usize) }
145    }
146
147    pub(crate) fn find_index(&self, name: &str) -> Option<usize> {
148        for (i, entry) in self.entries().iter().enumerate() {
149            if entry.0.name == name {
150                return Some(i);
151            }
152        }
153        None
154    }
155
156    /// Remove entry at `idx` by swapping it with the last entry.
157    fn remove_at(&mut self, idx: usize) -> (Key<'de>, Item<'de>) {
158        let last = self.len as usize - 1;
159        let ptr = unsafe { self.ptr.as_ptr().add(idx) };
160        let entry = unsafe { ptr.read() };
161        if idx != last {
162            // Safety: `last` is a valid, initialized index distinct from `idx`.
163            unsafe {
164                ptr.write(self.ptr.as_ptr().add(last).read());
165            }
166        }
167        self.len -= 1;
168        entry
169    }
170
171    #[cold]
172    fn grow(&mut self, arena: &Arena) {
173        let new_cap = if self.cap == 0 {
174            MIN_CAP
175        } else {
176            self.cap.checked_mul(2).expect("capacity overflow")
177        };
178        self.grow_to(new_cap, arena);
179    }
180
181    fn grow_to(&mut self, new_cap: u32, arena: &Arena) {
182        let new_size = new_cap as usize * size_of::<TableEntry<'_>>();
183        if self.cap > 0 {
184            let old_size = self.cap as usize * size_of::<TableEntry<'_>>();
185            // Safety: ptr was returned by a prior arena alloc of old_size bytes.
186            self.ptr = unsafe { arena.realloc(self.ptr.cast(), old_size, new_size).cast() };
187        } else {
188            self.ptr = arena.alloc(new_size).cast();
189        }
190        self.cap = new_cap;
191    }
192}
193
194impl std::fmt::Debug for InnerTable<'_> {
195    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
196        let mut map = f.debug_map();
197        for (k, v) in self.entries() {
198            map.entry(k, v);
199        }
200        map.finish()
201    }
202}
203
204/// Consuming iterator over a [`Table`], yielding `(`[`Key`]`, `[`Item`]`)` pairs.
205pub struct IntoIter<'de> {
206    table: InnerTable<'de>,
207    index: u32,
208}
209
210impl<'de> Iterator for IntoIter<'de> {
211    type Item = (Key<'de>, Item<'de>);
212
213    fn next(&mut self) -> Option<Self::Item> {
214        if self.index < self.table.len {
215            let entry = unsafe { self.table.ptr.as_ptr().add(self.index as usize).read() };
216            self.index += 1;
217            Some(entry)
218        } else {
219            None
220        }
221    }
222
223    fn size_hint(&self) -> (usize, Option<usize>) {
224        let remaining = (self.table.len - self.index) as usize;
225        (remaining, Some(remaining))
226    }
227}
228
229impl ExactSizeIterator for IntoIter<'_> {}
230
231/// A TOML table with span information.
232///
233/// A `Table` is the top-level value returned by [`parse`](crate::parse) and is
234/// also the value inside any `[section]` or inline `{ ... }` table in TOML.
235/// It stores `(`[`Key`]`, `[`Item`]`)` pairs in insertion order.
236///
237/// # Accessing values
238///
239/// - **Index operators** — `table["key"]` returns a [`MaybeItem`] that never
240///   panics on missing keys, and supports chained indexing.
241/// - **`get` / `get_mut`** — return `Option<&Item>` / `Option<&mut Item>`.
242/// - **`required` / `optional`** — deserialize and *remove* a field in one
243///   step, used when implementing [`Deserialize`](crate::Deserialize).
244///   After extracting all expected fields, call [`expect_empty`](Self::expect_empty)
245///   to reject unknown keys.
246///
247/// # Constructing tables
248///
249/// Tables are normally obtained from [`parse`](crate::parse). To build one
250/// programmatically, create a table with [`Table::new`] and insert entries
251/// with [`Table::insert`]. An [`Arena`](crate::Arena) is required for
252/// insertion because entries are arena-allocated.
253///
254/// # Iteration
255///
256/// `Table` implements [`IntoIterator`] (both by reference and by value),
257/// yielding `(`[`Key`]`, `[`Item`]`)` pairs.
258///
259/// Removal via [`remove`](Self::remove), [`required`](Self::required), and
260/// [`optional`](Self::optional) uses swap-remove and may reorder remaining
261/// entries.
262#[repr(C)]
263pub struct Table<'de> {
264    pub(crate) value: InnerTable<'de>,
265    /// Bits 2-0: tag, bits 31-3: span.start
266    start_and_tag: u32,
267    /// Bit 0: flag bit (parser-internal), bits 31-1: span.end
268    end_and_flag: u32,
269}
270
271impl<'de> Table<'de> {
272    /// Creates an empty table with the given span.
273    pub fn new(span: Span) -> Table<'de> {
274        Table {
275            start_and_tag: span.start << TAG_SHIFT | TAG_TABLE,
276            end_and_flag: (span.end << FLAG_SHIFT) | FLAG_TABLE,
277            value: InnerTable::new(),
278        }
279    }
280    /// Returns the byte-offset span of this table in the source document.
281    pub fn span(&self) -> Span {
282        Span {
283            start: self.start_and_tag >> TAG_SHIFT,
284            end: self.end_and_flag >> FLAG_SHIFT,
285        }
286    }
287}
288
289impl<'de> Default for Table<'de> {
290    fn default() -> Self {
291        Self::new(Span::default())
292    }
293}
294
295impl std::fmt::Debug for Table<'_> {
296    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
297        self.value.fmt(f)
298    }
299}
300
301impl<'de> Table<'de> {
302    /// Inserts a key-value pair. Does **not** check for duplicates.
303    pub fn insert(&mut self, key: Key<'de>, value: Item<'de>, arena: &Arena) {
304        self.value.insert(key, value, arena);
305    }
306
307    /// Returns the number of entries.
308    #[inline]
309    pub fn len(&self) -> usize {
310        self.value.len()
311    }
312
313    /// Returns `true` if the table has no entries.
314    #[inline]
315    pub fn is_empty(&self) -> bool {
316        self.value.is_empty()
317    }
318
319    /// Linear scan for a key, returning both key and value references.
320    pub fn get_key_value(&self, name: &str) -> Option<(&Key<'de>, &Item<'de>)> {
321        self.value.get_key_value(name)
322    }
323
324    /// Returns a reference to the value for `name`.
325    pub fn get(&self, name: &str) -> Option<&Item<'de>> {
326        self.value.get(name)
327    }
328
329    /// Returns a mutable reference to the value for `name`.
330    pub fn get_mut(&mut self, name: &str) -> Option<&mut Item<'de>> {
331        self.value.get_mut(name)
332    }
333
334    /// Returns `true` if the table contains the key.
335    #[inline]
336    pub fn contains_key(&self, name: &str) -> bool {
337        self.value.contains_key(name)
338    }
339
340    /// Removes the first entry matching `name`, returning its value.
341    /// Uses swap-remove, so the ordering of remaining entries may change.
342    pub fn remove(&mut self, name: &str) -> Option<Item<'de>> {
343        self.value.remove(name)
344    }
345
346    /// Removes the first entry matching `name`, returning the key-value pair.
347    /// Uses swap-remove, so the ordering of remaining entries may change.
348    pub fn remove_entry(&mut self, name: &str) -> Option<(Key<'de>, Item<'de>)> {
349        self.value.remove_entry(name)
350    }
351
352    /// Returns an iterator over mutable references to the values.
353    pub fn values_mut(&mut self) -> impl Iterator<Item = &mut Item<'de>> {
354        self.value.values_mut()
355    }
356
357    /// Returns a slice of all entries.
358    #[inline]
359    pub fn entries(&self) -> &[TableEntry<'de>] {
360        self.value.entries()
361    }
362
363    /// Converts this `Table` into an [`Item`] with the same span and payload.
364    pub fn into_item(self) -> Item<'de> {
365        let span = self.span();
366        Item::table(self.value, span)
367    }
368
369    /// Removes and deserializes a field, returning an error if the key is missing.
370    pub fn required<T: Deserialize<'de>>(&mut self, name: &'static str) -> Result<T, Error> {
371        let Some(mut val) = self.value.remove(name) else {
372            return Err(Error {
373                kind: ErrorKind::MissingField(name),
374                span: self.span(),
375            });
376        };
377
378        T::deserialize(&mut val)
379    }
380
381    /// Removes and deserializes a field, returning [`None`] if the key is missing.
382    pub fn optional<T: Deserialize<'de>>(&mut self, name: &str) -> Result<Option<T>, Error> {
383        let Some(mut val) = self.value.remove(name) else {
384            return Ok(None);
385        };
386
387        match T::deserialize(&mut val) {
388            Ok(value) => Ok(Some(value)),
389            Err(err) => Err(err),
390        }
391    }
392
393    /// Returns an error if the table still has unconsumed entries.
394    ///
395    /// Call this after extracting all expected fields with [`required`](Self::required)
396    /// and [`optional`](Self::optional) to reject unknown keys.
397    pub fn expect_empty(&self) -> Result<(), Error> {
398        if self.value.is_empty() {
399            return Ok(());
400        }
401
402        // let keys = self
403        //     .value
404        //     .entries()
405        //     .iter()
406        //     .map(|(key, _)| (key.name.into(), key.span))
407        //     .collect();
408        // Note: collect version ends up generating a lot of code bloat
409        // despite being more efficient in theory.
410        let mut keys = Vec::with_capacity(self.value.len());
411        for (key, _) in self.value.entries() {
412            keys.push((key.name.into(), key.span));
413        }
414
415        Err(Error::from((
416            ErrorKind::UnexpectedKeys { keys },
417            self.span(),
418        )))
419    }
420}
421
422impl<'a, 'de> IntoIterator for &'a mut Table<'de> {
423    type Item = &'a mut (Key<'de>, Item<'de>);
424    type IntoIter = std::slice::IterMut<'a, TableEntry<'de>>;
425
426    fn into_iter(self) -> Self::IntoIter {
427        self.value.entries_mut().iter_mut()
428    }
429}
430impl<'a, 'de> IntoIterator for &'a Table<'de> {
431    type Item = &'a (Key<'de>, Item<'de>);
432    type IntoIter = std::slice::Iter<'a, TableEntry<'de>>;
433
434    fn into_iter(self) -> Self::IntoIter {
435        self.value.entries().iter()
436    }
437}
438
439impl<'de> IntoIterator for Table<'de> {
440    type Item = (Key<'de>, Item<'de>);
441    type IntoIter = IntoIter<'de>;
442
443    fn into_iter(self) -> Self::IntoIter {
444        IntoIter {
445            table: self.value,
446            index: 0,
447        }
448    }
449}
450
451const _: () = assert!(std::mem::size_of::<Table<'_>>() == std::mem::size_of::<Item<'_>>());
452const _: () = assert!(std::mem::align_of::<Table<'_>>() == std::mem::align_of::<Item<'_>>());
453
454impl<'de> Table<'de> {
455    #[inline]
456    pub(crate) fn span_start(&self) -> u32 {
457        self.start_and_tag >> TAG_SHIFT
458    }
459
460    #[inline]
461    pub(crate) fn set_span_start(&mut self, v: u32) {
462        self.start_and_tag = (v << TAG_SHIFT) | (self.start_and_tag & TAG_MASK);
463    }
464
465    #[inline]
466    pub(crate) fn set_span_end(&mut self, v: u32) {
467        self.end_and_flag = (v << FLAG_SHIFT) | (self.end_and_flag & FLAG_MASK);
468    }
469
470    #[inline]
471    pub(crate) fn extend_span_end(&mut self, new_end: u32) {
472        let old = self.end_and_flag;
473        let current = old >> FLAG_SHIFT;
474        self.end_and_flag = (current.max(new_end) << FLAG_SHIFT) | (old & FLAG_MASK);
475    }
476
477    #[inline]
478    pub(crate) fn set_header_flag(&mut self) {
479        self.end_and_flag = (self.end_and_flag & !FLAG_MASK) | FLAG_HEADER;
480    }
481}
482
483impl<'de> std::ops::Index<&str> for Table<'de> {
484    type Output = MaybeItem<'de>;
485
486    #[inline]
487    fn index(&self, index: &str) -> &Self::Output {
488        if let Some(item) = self.get(index) {
489            return MaybeItem::from_ref(item);
490        }
491        &NONE
492    }
493}