Skip to main content

deser_core/
source.rs

1use alloc::sync::Arc;
2use core::fmt;
3
4use crate::State;
5
6/// The source the input ranges refer to.
7///
8/// Formats can publish the byte range in the input of every event (see
9/// [`State::input_range`](crate::State::input_range)).  This is cheap, but
10/// resolving the ranges into lines and columns (see
11/// [`Position::of`](crate::Position::of)) requires the source.  As
12/// this requires a copy of the input, formats only provide it when asked to
13/// with [`TrackLocations`].  They store it in the [`State`] as an extension
14/// value with [`set`](Self::set) before they emit the first event:
15///
16/// ```
17/// use deser::de::DeserializeDriver;
18/// use deser::Source;
19///
20/// let mut out = None::<bool>;
21/// let mut driver = DeserializeDriver::new(&mut out);
22/// Source("true".into()).set(driver.state_mut());
23/// assert_eq!(&*driver.state().get::<Source>().unwrap().0, "true");
24/// ```
25#[derive(Clone, Default)]
26pub struct Source(pub Arc<str>);
27
28impl Source {
29    /// Sets the source in the state.
30    #[inline]
31    pub fn set(self, state: &mut State) {
32        *state.get_mut::<Source>() = self;
33    }
34}
35
36impl fmt::Debug for Source {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        // the source can be large, it's not included
39        f.debug_struct("Source")
40            .field("len", &self.0.len())
41            .finish()
42    }
43}
44
45/// Asks the formats to provide the [`Source`] (a value of the
46/// [`Context`](crate::Context)).
47///
48/// Formats publish the byte range of every event, resolving them into
49/// lines and columns (for instance with the `Spanned` type of
50/// [`deser-location`](https://docs.rs/deser-location)) also requires the
51/// source, which is a copy of the input.  Formats only provide it if this
52/// is set to `true` in the context (or the state).  The errors a
53/// deserialization fails with have their line and column either way, but
54/// for instance the keys collected with
55/// [`UnknownFields::Collect`](crate::de::UnknownFields::Collect) only
56/// have them with the source:
57///
58/// ```
59/// use deser::de::{Deserializer, IgnoredFields, UnknownFields};
60/// use deser::{Context, Deserialize, TrackLocations};
61///
62/// #[derive(Deserialize)]
63/// struct Config {
64///     name: String,
65/// }
66///
67/// let config = deser_json::DeserializerConfig::builder()
68///     .context(Context::with(TrackLocations(true)))
69///     .build();
70/// let input = "{\n  \"name\": \"demo\",\n  \"nmae\": \"x\"\n}";
71/// let ignored = IgnoredFields::new();
72/// deser_json::Deserializer::from_str_with_config(input, config)
73///     .deserialize_with::<Config, _>(|driver| {
74///         UnknownFields::Collect(ignored.clone()).set(driver.state_mut())
75///     })
76///     .unwrap();
77/// let ignored = ignored.take();
78/// assert_eq!((ignored[0].line(), ignored[0].column()), (Some(3), Some(3)));
79/// ```
80///
81/// Formats check this with [`of`](Self::of) and set the [`Source`] before
82/// they emit the first event:
83///
84/// ```
85/// use deser::de::{DeserializeDriver, Deserializer};
86/// use deser::{Error, Source, TrackLocations};
87///
88/// /// A format which provides the source if asked to.
89/// struct Text<'a>(&'a str);
90///
91/// impl<'de> Deserializer<'de> for Text<'de> {
92///     fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'de>) -> Result<(), Error> {
93///         if TrackLocations::of(driver.state()) {
94///             Source(self.0.into()).set(driver.state_mut());
95///         }
96///         driver.state_mut().set_input_range(0, self.0.len());
97///         driver.emit(self.0)
98///     }
99/// }
100/// ```
101#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
102pub struct TrackLocations(pub bool);
103
104impl TrackLocations {
105    /// Returns `true` if the formats provide the source.
106    // not inlined: formats read it once per value
107    #[inline(never)]
108    pub fn of(state: &State) -> bool {
109        state.get::<TrackLocations>().is_some_and(|track| track.0)
110    }
111
112    /// Sets if the formats provide the source.
113    #[inline]
114    pub fn set(self, state: &mut State) {
115        *state.get_mut::<TrackLocations>() = self;
116    }
117}