Skip to main content

toml_spanner/
de.rs

1#[cfg(test)]
2#[path = "./de_tests.rs"]
3mod tests;
4
5use std::num::NonZeroU64;
6
7use foldhash::HashMap;
8
9use crate::{
10    Arena, Error, ErrorKind, Key, Span, Table,
11    parser::{INDEXED_TABLE_THRESHOLD, KeyRef},
12    value::{self, Item},
13};
14
15/// Guides deserialization of a [`Table`] by tracking which fields have been
16/// consumed.
17///
18/// Create one via [`Root::helper`](crate::Root::helper) for the root table,
19/// or [`Item::table_helper`] / [`TableHelper::new`] for nested tables.
20/// Then extract fields with [`required`](Self::required) and
21/// [`optional`](Self::optional), and finish with
22/// [`expect_empty`](Self::expect_empty) to reject unknown keys.
23///
24/// Errors are accumulated in the shared [`Context`] rather than failing on
25/// the first problem, so a single parse pass can report multiple issues.
26///
27/// # Examples
28///
29/// ```
30/// use toml_spanner::{Arena, Deserialize, Item, Context, Failed, TableHelper};
31///
32/// struct Config {
33///     name: String,
34///     port: u16,
35///     debug: bool,
36/// }
37///
38/// impl<'de> Deserialize<'de> for Config {
39///     fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
40///         let mut th = value.table_helper(ctx)?;
41///         let name = th.required("name")?;
42///         let port = th.required("port")?;
43///         let debug = th.optional("debug").unwrap_or(false);
44///         th.expect_empty()?;
45///         Ok(Config { name, port, debug })
46///     }
47/// }
48/// ```
49pub struct TableHelper<'ctx, 'table, 'de> {
50    pub ctx: &'ctx mut Context<'de>,
51    pub table: &'table Table<'de>,
52    // -1 means don't use table index.
53    table_id: i32,
54    // Used for detecting unused fields or iterating over remaining for flatten into collection.
55    used_count: u32,
56    used: &'de mut FixedBitset,
57}
58
59#[repr(transparent)]
60struct FixedBitset([u64]);
61
62impl FixedBitset {
63    #[allow(clippy::mut_from_ref)]
64    pub fn new(capacity: usize, arena: &Arena) -> &mut FixedBitset {
65        let bitset_len = capacity.div_ceil(64);
66        let bitset = arena.alloc(bitset_len).cast::<u64>();
67        for offset in 0..bitset_len {
68            unsafe {
69                bitset.add(offset).write(0);
70            }
71        }
72        let slice = unsafe { std::slice::from_raw_parts_mut(bitset.as_ptr(), bitset_len) };
73        unsafe { &mut *(slice as *mut [u64] as *mut FixedBitset) }
74    }
75
76    pub fn insert(&mut self, index: usize) -> bool {
77        let offset = index >> 6;
78        let bit = 1 << (index & 63);
79        let old = self.0[offset];
80        self.0[offset] |= bit;
81        old & bit == 0
82    }
83
84    pub fn get(&self, index: usize) -> bool {
85        let offset = index >> 6;
86        let bit = 1 << (index & 63);
87        self.0[offset] & bit != 0
88    }
89}
90
91/// An iterator over table entries that were **not** consumed by
92/// [`TableHelper::required`], [`TableHelper::optional`] or similar methods.
93///
94/// Obtained via [`TableHelper::into_remaining`].
95pub struct RemainingEntriesIter<'t, 'de> {
96    entries: &'t [(Key<'de>, Item<'de>)],
97    remaining_cells: std::slice::Iter<'de, u64>,
98    bits: u64,
99}
100impl RemainingEntriesIter<'_, '_> {
101    fn next_bucket(&mut self) -> bool {
102        if let Some(bucket) = self.remaining_cells.next() {
103            debug_assert!(self.entries.len() > 64);
104            if let Some(remaining) = self.entries.get(64..) {
105                self.entries = remaining;
106            } else {
107                // Shouldn't occur in practice, but no need to panic here.
108                return false;
109            }
110            self.bits = !*bucket;
111            true
112        } else {
113            false
114        }
115    }
116}
117
118impl<'t, 'de> Iterator for RemainingEntriesIter<'t, 'de> {
119    type Item = &'t (Key<'de>, Item<'de>);
120
121    fn next(&mut self) -> Option<Self::Item> {
122        loop {
123            if let Some(bits) = NonZeroU64::new(self.bits) {
124                let bit_index = bits.trailing_zeros() as usize;
125                self.bits &= self.bits - 1;
126                return self.entries.get(bit_index);
127            }
128            if !self.next_bucket() {
129                return None;
130            }
131        }
132    }
133}
134
135impl<'ctx, 't, 'de> TableHelper<'ctx, 't, 'de> {
136    /// Creates a new helper for the given table.
137    ///
138    /// Prefer [`Item::table_helper`] when implementing [`Deserialize`], or
139    /// [`Root::helper`](crate::Root::helper) for the root table.
140    pub fn new(ctx: &'ctx mut Context<'de>, table: &'t Table<'de>) -> Self {
141        let table_id = if table.len() > INDEXED_TABLE_THRESHOLD {
142            // Note due to 512MB limit this will fit in i32.
143            table.entries()[0].0.span.start as i32
144        } else {
145            -1
146        };
147        Self {
148            used: FixedBitset::new(table.len(), ctx.arena),
149            ctx,
150            table,
151            table_id,
152            used_count: 0,
153        }
154    }
155    /// Looks up a key-value entry without marking it as consumed.
156    ///
157    /// This is useful for peeking at a field before deciding how to
158    /// deserialize it. The entry will still be flagged as unexpected by
159    /// [`expect_empty`](Self::expect_empty) unless it is later consumed by
160    /// [`required`](Self::required) or [`optional`](Self::optional).
161    pub fn get_entry(&self, key: &str) -> Option<&'t (Key<'de>, Item<'de>)> {
162        if self.table_id < 0 {
163            for entry in self.table.entries() {
164                if entry.0.name == key {
165                    return Some(entry);
166                }
167            }
168            None
169        } else {
170            match self.ctx.index.get(&KeyRef::new(key, self.table_id as u32)) {
171                Some(index) => Some(&self.table.entries()[*index]),
172                None => None,
173            }
174        }
175    }
176
177    /// Extracts a required field and transforms it with `func`.
178    ///
179    /// Looks up `name`, marks it as consumed, and passes the [`Item`] to
180    /// `func`. This is useful for parsing string values via
181    /// [`Item::parse`] or applying custom validation without implementing
182    /// [`Deserialize`].
183    ///
184    /// # Errors
185    ///
186    /// Returns [`Failed`] if the key is absent or if `func` returns an error.
187    /// In both cases the error is pushed onto the shared [`Context`].
188    pub fn required_mapped<T>(
189        &mut self,
190        name: &'static str,
191        func: fn(&Item<'de>) -> Result<T, Error>,
192    ) -> Result<T, Failed> {
193        let Some((_, item)) = self.optional_entry(name) else {
194            return Err(self.report_missing_field(name));
195        };
196
197        func(item).map_err(|err| {
198            self.ctx.push_error(Error {
199                kind: ErrorKind::Custom(std::borrow::Cow::Owned(err.to_string())),
200                span: item.span(),
201            })
202        })
203    }
204
205    /// Extracts an optional field and transforms it with `func`.
206    ///
207    /// Returns [`None`] if the key is missing (no error recorded) or if
208    /// `func` returns an error (the error is pushed onto the [`Context`]).
209    /// The field is marked as consumed so
210    /// [`expect_empty`](Self::expect_empty) will not flag it as unexpected.
211    pub fn optional_mapped<T>(
212        &mut self,
213        name: &'static str,
214        func: fn(&Item<'de>) -> Result<T, Error>,
215    ) -> Option<T> {
216        let Some((_, item)) = self.optional_entry(name) else {
217            return None;
218        };
219
220        func(item)
221            .map_err(|err| {
222                self.ctx.push_error(Error {
223                    kind: ErrorKind::Custom(std::borrow::Cow::Owned(err.to_string())),
224                    span: item.span(),
225                })
226            })
227            .ok()
228    }
229
230    /// Returns the raw [`Item`] for a required field.
231    ///
232    /// Like [`required`](Self::required) but skips deserialization, giving
233    /// direct access to the parsed value. The field is marked as consumed.
234    ///
235    /// # Errors
236    ///
237    /// Returns [`Failed`] and records a
238    /// [`MissingField`](crate::ErrorKind::MissingField) error if the key is
239    /// absent.
240    pub fn required_item(&mut self, name: &'static str) -> Result<&'t Item<'de>, Failed> {
241        self.required_entry(name).map(|(_, value)| value)
242    }
243
244    /// Returns the raw [`Item`] for an optional field.
245    ///
246    /// Like [`optional`](Self::optional) but skips deserialization, giving
247    /// direct access to the parsed value. Returns [`None`] when the key is
248    /// missing (no error recorded). The field is marked as consumed.
249    pub fn optional_item(&mut self, name: &'static str) -> Option<&'t Item<'de>> {
250        self.optional_entry(name).map(|(_, value)| value)
251    }
252
253    /// Returns the `(`[`Key`]`, `[`Item`]`)` pair for a required field.
254    ///
255    /// Use this when you need the key's [`Span`](crate::Span) in addition to
256    /// the value. The field is marked as consumed.
257    ///
258    /// # Errors
259    ///
260    /// Returns [`Failed`] and records a
261    /// [`MissingField`](crate::ErrorKind::MissingField) error if the key is
262    /// absent.
263    pub fn required_entry(
264        &mut self,
265        name: &'static str,
266    ) -> Result<&'t (Key<'de>, Item<'de>), Failed> {
267        match self.optional_entry(name) {
268            Some(entry) => Ok(entry),
269            None => Err(self.report_missing_field(name)),
270        }
271    }
272
273    /// Returns the `(`[`Key`]`, `[`Item`]`)` pair for an optional field.
274    ///
275    /// Returns [`None`] when the key is missing (no error recorded). Use
276    /// this when you need the key's [`Span`](crate::Span) in addition to
277    /// the value. The field is marked as consumed.
278    pub fn optional_entry(&mut self, key: &str) -> Option<&'t (Key<'de>, Item<'de>)> {
279        let entry = self.get_entry(key)?;
280        let index = unsafe {
281            let ptr = entry as *const (Key<'de>, Item<'de>);
282            let base = self.table.entries().as_ptr();
283            ptr.offset_from(base) as usize
284        };
285        if self.used.insert(index) {
286            self.used_count += 1;
287        }
288        Some(entry)
289    }
290
291    #[cold]
292    fn report_missing_field(&mut self, name: &'static str) -> Failed {
293        self.ctx.errors.push(Error {
294            kind: ErrorKind::MissingField(name),
295            span: self.table.span(),
296        });
297        Failed
298    }
299
300    /// Deserializes a required field, recording an error if the key is missing.
301    ///
302    /// The field is marked as consumed so [`expect_empty`](Self::expect_empty)
303    /// will not flag it as unexpected.
304    ///
305    /// # Errors
306    ///
307    /// Returns [`Failed`] if the key is absent or if `T::deserialize` fails.
308    /// In both cases the error is pushed onto the shared [`Context`].
309    pub fn required<T: Deserialize<'de>>(&mut self, name: &'static str) -> Result<T, Failed> {
310        let Some((_, val)) = self.optional_entry(name) else {
311            return Err(self.report_missing_field(name));
312        };
313
314        T::deserialize(self.ctx, val)
315    }
316
317    /// Deserializes an optional field, returning [`None`] if the key is missing
318    /// or deserialization fails (recording the error in the [`Context`]).
319    ///
320    /// The field is marked as consumed so [`expect_empty`](Self::expect_empty)
321    /// will not flag it as unexpected.
322    pub fn optional<T: Deserialize<'de>>(&mut self, name: &str) -> Option<T> {
323        let Some((_, val)) = self.optional_entry(name) else {
324            return None;
325        };
326
327        #[allow(clippy::manual_ok_err)]
328        match T::deserialize(self.ctx, val) {
329            Ok(value) => Some(value),
330            // Note: The parent will already have recorded the error
331            Err(_) => None,
332        }
333    }
334
335    /// Returns the number of unused entries remaining in the table.
336    pub fn remaining_count(&self) -> usize {
337        self.table.len() - self.used_count as usize
338    }
339
340    /// Iterate over unused `&(Key<'de>, Item<'de>)` entries in the table.
341    pub fn into_remaining(self) -> RemainingEntriesIter<'t, 'de> {
342        let entries = self.table.entries();
343        let mut remaining_cells = self.used.0.iter();
344        RemainingEntriesIter {
345            bits: if let Some(value) = remaining_cells.next() {
346                !*value
347            } else {
348                0
349            },
350            entries,
351            remaining_cells,
352        }
353    }
354
355    /// Finishes deserialization, recording an error if any fields were not
356    /// consumed by [`required`](Self::required) or
357    /// [`optional`](Self::optional).
358    ///
359    /// Call this as the last step in a [`Deserialize`] implementation to
360    /// reject unknown keys.
361    ///
362    /// # Errors
363    ///
364    /// Returns [`Failed`] and pushes an [`ErrorKind::UnexpectedKeys`](crate::ErrorKind::UnexpectedKeys)
365    /// error if unconsumed fields remain.
366    #[inline(never)]
367    pub fn expect_empty(self) -> Result<(), Failed> {
368        if self.used_count as usize == self.table.len() {
369            return Ok(());
370        }
371
372        let mut keys = Vec::new();
373        for (i, (key, _)) in self.table.entries().iter().enumerate() {
374            if !self.used.get(i) {
375                keys.push((key.name.into(), key.span));
376            }
377        }
378
379        if keys.is_empty() {
380            return Ok(());
381        }
382
383        self.ctx.errors.push(Error::from((
384            ErrorKind::UnexpectedKeys { keys },
385            self.table.span(),
386        )));
387        Err(Failed)
388    }
389}
390
391/// Shared deserialization state that accumulates errors and holds the arena.
392///
393/// A `Context` is created by [`parse`](crate::parse) and lives inside
394/// [`Root`](crate::Root). Pass it into [`TableHelper::new`] or
395/// [`Item::table_helper`] when implementing [`Deserialize`].
396///
397/// Multiple errors can be recorded during a single deserialization pass;
398/// inspect them afterwards via [`Root::errors`](crate::Root::errors).
399pub struct Context<'de> {
400    pub arena: &'de Arena,
401    pub(crate) index: HashMap<KeyRef<'de>, usize>,
402    pub errors: Vec<Error>,
403}
404
405impl<'de> Context<'de> {
406    /// Records a "expected X, found Y" type-mismatch error and returns [`Failed`].
407    #[cold]
408    pub fn error_expected_but_found(&mut self, message: &'static str, found: &Item<'_>) -> Failed {
409        self.errors.push(Error {
410            kind: ErrorKind::Wanted {
411                expected: message,
412                found: found.type_str(),
413            },
414            span: found.span(),
415        });
416        Failed
417    }
418
419    /// Records a custom error message at the given span and returns [`Failed`].
420    #[cold]
421    pub fn error_message_at(&mut self, message: &'static str, at: Span) -> Failed {
422        self.errors.push(Error {
423            kind: ErrorKind::Custom(std::borrow::Cow::Borrowed(message)),
424            span: at,
425        });
426        Failed
427    }
428    /// Pushes a pre-built [`Error`] and returns [`Failed`].
429    #[cold]
430    pub fn push_error(&mut self, error: Error) -> Failed {
431        self.errors.push(error);
432        Failed
433    }
434
435    /// Records an out-of-range error for the type `name` and returns [`Failed`].
436    #[cold]
437    pub fn error_out_of_range(&mut self, name: &'static str, span: Span) -> Failed {
438        self.errors.push(Error {
439            kind: ErrorKind::OutOfRange(name),
440            span,
441        });
442        Failed
443    }
444}
445
446/// Sentinel indicating that a deserialization error has been recorded in the
447/// [`Context`].
448///
449/// `Failed` carries no data — the actual error details live in
450/// [`Context::errors`](Context::errors). Return `Err(Failed)` from
451/// [`Deserialize::deserialize`] after calling one of the `Context::error_*`
452/// methods.
453#[derive(Debug)]
454pub struct Failed;
455
456/// Trait for types that can be deserialized from a TOML [`Item`].
457///
458/// Implement this on your own types to enable extraction via
459/// [`TableHelper::required`] and [`TableHelper::optional`].
460/// Built-in implementations are provided for primitive types, `String`,
461/// `Vec<T>`, `Box<T>`, `Option<T>` (via `optional`), and more.
462///
463/// # Examples
464///
465/// ```
466/// use toml_spanner::{Item, Context, Deserialize, Failed, TableHelper};
467///
468/// struct Point {
469///     x: f64,
470///     y: f64,
471/// }
472///
473/// impl<'de> Deserialize<'de> for Point {
474///     fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
475///         let mut th = value.table_helper(ctx)?;
476///         let x = th.required("x")?;
477///         let y = th.required("y")?;
478///         th.expect_empty()?;
479///         Ok(Point { x, y })
480///     }
481/// }
482/// ```
483pub trait Deserialize<'de>: Sized {
484    /// Attempts to produce `Self` from a TOML [`Item`].
485    ///
486    /// On failure, records one or more errors in `ctx` and returns
487    /// `Err(`[`Failed`]`)`.
488    fn deserialize(ctx: &mut Context<'de>, item: &Item<'de>) -> Result<Self, Failed>;
489}
490
491impl<'de, T: Deserialize<'de>, const N: usize> Deserialize<'de> for [T; N] {
492    fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
493        let boxed_slice = Box::<[T]>::deserialize(ctx, value)?;
494        match <Box<[T; N]>>::try_from(boxed_slice) {
495            Ok(array) => Ok(*array),
496            Err(res) => Err(ctx.push_error(Error {
497                kind: ErrorKind::Custom(std::borrow::Cow::Owned(format!(
498                    "Expect Array Size: found {} but expected {}",
499                    res.len(),
500                    N
501                ))),
502                span: value.span(),
503            })),
504        }
505    }
506}
507
508impl<'de> Deserialize<'de> for String {
509    fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
510        match value.as_str() {
511            Some(s) => Ok(s.to_string()),
512            None => Err(ctx.error_expected_but_found("a string", value)),
513        }
514    }
515}
516
517impl<'de, T: Deserialize<'de>> Deserialize<'de> for Box<T> {
518    fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
519        match T::deserialize(ctx, value) {
520            Ok(v) => Ok(Box::new(v)),
521            Err(e) => Err(e),
522        }
523    }
524}
525impl<'de, T: Deserialize<'de>> Deserialize<'de> for Box<[T]> {
526    fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
527        match Vec::<T>::deserialize(ctx, value) {
528            Ok(vec) => Ok(vec.into_boxed_slice()),
529            Err(e) => Err(e),
530        }
531    }
532}
533impl<'de> Deserialize<'de> for Box<str> {
534    fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
535        match value.value() {
536            value::Value::String(&s) => Ok(s.into()),
537            _ => Err(ctx.error_expected_but_found("a string", value)),
538        }
539    }
540}
541impl<'de> Deserialize<'de> for &'de str {
542    fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
543        match value.value() {
544            value::Value::String(s) => Ok(*s),
545            _ => Err(ctx.error_expected_but_found("a string", value)),
546        }
547    }
548}
549
550impl<'de> Deserialize<'de> for std::borrow::Cow<'de, str> {
551    fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
552        match value.value() {
553            value::Value::String(s) => Ok(std::borrow::Cow::Borrowed(*s)),
554            _ => Err(ctx.error_expected_but_found("a string", value)),
555        }
556    }
557}
558
559impl<'de> Deserialize<'de> for bool {
560    fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
561        match value.as_bool() {
562            Some(b) => Ok(b),
563            None => Err(ctx.error_expected_but_found("a bool", value)),
564        }
565    }
566}
567
568fn deser_integer_ctx(
569    ctx: &mut Context<'_>,
570    value: &Item<'_>,
571    min: i64,
572    max: i64,
573    name: &'static str,
574) -> Result<i64, Failed> {
575    let span = value.span();
576    match value.as_i64() {
577        Some(i) if i >= min && i <= max => Ok(i),
578        Some(_) => Err(ctx.error_out_of_range(name, span)),
579        None => Err(ctx.error_expected_but_found("an integer", value)),
580    }
581}
582
583macro_rules! integer_new {
584    ($($num:ty),+) => {$(
585        impl<'de> Deserialize<'de> for $num {
586            fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
587                match deser_integer_ctx(ctx, value, <$num>::MIN as i64, <$num>::MAX as i64, stringify!($num)) {
588                    Ok(i) => Ok(i as $num),
589                    Err(e) => Err(e),
590                }
591            }
592        }
593    )+};
594}
595
596integer_new!(i8, i16, i32, isize, u8, u16, u32);
597
598impl<'de> Deserialize<'de> for i64 {
599    fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
600        deser_integer_ctx(ctx, value, i64::MIN, i64::MAX, "i64")
601    }
602}
603
604impl<'de> Deserialize<'de> for u64 {
605    fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
606        match deser_integer_ctx(ctx, value, 0, i64::MAX, "u64") {
607            Ok(i) => Ok(i as u64),
608            Err(e) => Err(e),
609        }
610    }
611}
612
613impl<'de> Deserialize<'de> for usize {
614    fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
615        const MAX: i64 = if usize::BITS < 64 {
616            usize::MAX as i64
617        } else {
618            i64::MAX
619        };
620        match deser_integer_ctx(ctx, value, 0, MAX, "usize") {
621            Ok(i) => Ok(i as usize),
622            Err(e) => Err(e),
623        }
624    }
625}
626
627impl<'de> Deserialize<'de> for f32 {
628    fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
629        match value.as_f64() {
630            Some(f) => Ok(f as f32),
631            None => Err(ctx.error_expected_but_found("a float", value)),
632        }
633    }
634}
635
636impl<'de> Deserialize<'de> for f64 {
637    fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
638        match value.as_f64() {
639            Some(f) => Ok(f),
640            None => Err(ctx.error_expected_but_found("a float", value)),
641        }
642    }
643}
644
645impl<'de, T> Deserialize<'de> for Vec<T>
646where
647    T: Deserialize<'de>,
648{
649    fn deserialize(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
650        let arr = value.expect_array(ctx)?;
651        let mut result = Vec::with_capacity(arr.len());
652        let mut had_error = false;
653        for item in arr {
654            match T::deserialize(ctx, item) {
655                Ok(v) => result.push(v),
656                Err(_) => had_error = true,
657            }
658        }
659        if had_error { Err(Failed) } else { Ok(result) }
660    }
661}
662
663impl<'de> Item<'de> {
664    /// Returns a string, or records an error with a custom `expected` message.
665    ///
666    /// Use this instead of [`expect_string`](Self::expect_string) when the
667    /// expected value is more specific than just "a string" — for example,
668    /// `"an IPv4 address"` or `"a hex color"`.
669    pub fn expect_custom_string(
670        &self,
671        ctx: &mut Context<'de>,
672        expected: &'static str,
673    ) -> Result<&'de str, Failed> {
674        match self.value() {
675            value::Value::String(s) => Ok(*s),
676            _ => Err(ctx.error_expected_but_found(expected, self)),
677        }
678    }
679    /// Returns a string, or records an error if this is not a string.
680    pub fn expect_string(&self, ctx: &mut Context<'de>) -> Result<&'de str, Failed> {
681        match self.value() {
682            value::Value::String(s) => Ok(*s),
683            _ => Err(ctx.error_expected_but_found("a string", self)),
684        }
685    }
686
687    /// Returns an array reference, or records an error if this is not an array.
688    pub fn expect_array(&self, ctx: &mut Context<'de>) -> Result<&crate::Array<'de>, Failed> {
689        match self.as_array() {
690            Some(arr) => Ok(arr),
691            None => Err(ctx.error_expected_but_found("an array", self)),
692        }
693    }
694
695    /// Returns a table reference, or records an error if this is not a table.
696    pub fn expect_table(&self, ctx: &mut Context<'de>) -> Result<&crate::Table<'de>, Failed> {
697        match self.as_table() {
698            Some(table) => Ok(table),
699            None => Err(ctx.error_expected_but_found("a table", self)),
700        }
701    }
702
703    /// Creates a [`TableHelper`] for this item, returning an error if it is not a table.
704    ///
705    /// This is the typical entry point for implementing [`Deserialize`].
706    pub fn table_helper<'ctx, 'item>(
707        &'item self,
708        ctx: &'ctx mut Context<'de>,
709    ) -> Result<TableHelper<'ctx, 'item, 'de>, Failed> {
710        let Some(table) = self.as_table() else {
711            return Err(ctx.error_expected_but_found("a table", self));
712        };
713        Ok(TableHelper::new(ctx, table))
714    }
715}