Skip to main content

substrate_data/schema/reader/
reader.rs

1//! [`Reader`]: the state of reading a value against a schema.
2
3use super::Found;
4use super::keys::is_metadata_key;
5use super::suggest::{closest, found_text};
6use crate::Diagnostic;
7use crate::diagnostic::Problem;
8use crate::model::borrowed::{MapRef, ValueRef};
9use crate::model::value::{Path, Ref, RefKey, Seg};
10use crate::schema::{Expected, Resolve, Schema};
11
12/// The state of reading a value: where it is, the problems so far, and the
13/// references met (for the build to check against the content there is).
14#[derive(Default)]
15pub struct Reader<'r> {
16    /// Where it is, as steps: a field's name stays `&'static` until a
17    /// problem or a reference needs the whole [`Path`].
18    pub(crate) path: Vec<Step>,
19    /// Don't keep the references met (who only wants the value).
20    pub(crate) value_only: bool,
21    /// What the tool makes of references (none: kept as written).
22    pub(crate) resolver: Option<&'r mut dyn Resolve>,
23    /// The problems found so far.
24    pub problems: Vec<Diagnostic>,
25    /// The references met so far (unless it only reads values).
26    pub refs: Vec<Found<Ref>>,
27    /// Keys a struct being read doesn't report as unknown (an enum's tag).
28    pub(crate) allowed: Vec<&'static str>,
29    /// How many expanded values are being read inside one another.
30    pub(crate) expanding: usize,
31}
32
33impl std::fmt::Debug for Reader<'_> {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        f.debug_struct("Reader")
36            .field("path", &self.path())
37            .field("value_only", &self.value_only)
38            .field("resolves", &self.resolver.is_some())
39            .field("problems", &self.problems)
40            .field("refs", &self.refs)
41            .finish_non_exhaustive()
42    }
43}
44
45/// A step of [`Reader`]'s path.
46pub(crate) enum Step {
47    Seg(Seg),
48    Field(&'static str),
49}
50
51impl<'r> Reader<'r> {
52    /// A reader at the root, keeping the references it meets.
53    #[must_use]
54    pub fn new() -> Self {
55        Self::default()
56    }
57
58    /// A reader handing references to `resolver`.
59    pub fn with_resolver(resolver: &'r mut dyn Resolve) -> Self {
60        Self {
61            resolver: Some(resolver),
62            ..Self::default()
63        }
64    }
65
66    /// `r` resolved (a problem if it's wrong); its id without a resolver.
67    pub fn resolve_ref(&mut self, r: &Ref) -> Option<RefKey> {
68        let result = match &mut self.resolver {
69            Some(res) => res.reference(r, &Self::built(&self.path)),
70            None => Ok(r.id.clone()),
71        };
72        result
73            .map_err(|e| self.problem_of(Problem::Unresolved, e.to_string()))
74            .ok()
75    }
76
77    /// [`Reader::resolve_ref`], taking `r`: without a resolver the id moves.
78    pub fn take_ref(&mut self, r: Ref) -> Option<RefKey> {
79        if self.resolver.is_none() {
80            return Some(r.id);
81        }
82        self.resolve_ref(&r)
83    }
84
85    /// Whether references are kept for the caller ([`read_value`](crate::schema::read_value) doesn't).
86    #[must_use]
87    pub fn keeps_found(&self) -> bool {
88        !self.value_only
89    }
90
91    /// Whether references go through a resolver (else kept as written).
92    #[must_use]
93    pub fn resolves(&self) -> bool {
94        self.resolver.is_some()
95    }
96
97    /// Where the reader is.
98    #[must_use]
99    pub fn path(&self) -> Path {
100        Self::built(&self.path)
101    }
102
103    fn built(steps: &[Step]) -> Path {
104        let mut p = Path::root();
105        for s in steps {
106            p.push(match s {
107                Step::Seg(s) => s.clone(),
108                Step::Field(k) => Seg::Key((*k).to_string()),
109            });
110        }
111        p
112    }
113
114    /// Reports a problem with the value being read.
115    pub fn problem(&mut self, message: impl Into<String>) {
116        self.problem_of(Problem::Invalid, message);
117    }
118
119    /// Reports a `problem` with the value being read.
120    pub fn problem_of(&mut self, problem: Problem, message: impl Into<String>) {
121        let found = Diagnostic::error(problem, message.into()).at_path(self.path());
122        self.problems.push(found);
123    }
124
125    /// "expected X, found Y".
126    pub fn expected(&mut self, what: Expected, found: &ValueRef<'_>) {
127        self.problem_of(
128            Problem::Expected,
129            format!("expected {what}, found {}", found_text(found)),
130        );
131    }
132
133    /// Runs `f` one step deeper.
134    pub fn at<T>(&mut self, seg: Seg, f: impl FnOnce(&mut Self) -> T) -> T {
135        self.path.push(Step::Seg(seg));
136        let r = f(self);
137        self.path.pop();
138        r
139    }
140
141    /// Runs `f` in field `key` (no allocation for the step).
142    fn in_field<T>(&mut self, key: &'static str, f: impl FnOnce(&mut Self) -> T) -> T {
143        self.path.push(Step::Field(key));
144        let r = f(self);
145        self.path.pop();
146        r
147    }
148
149    /// Keeps `r`, met at the current path (unless it only reads values).
150    pub fn note_ref(&mut self, r: Ref) {
151        if self.value_only {
152            return;
153        }
154        let path = self.path();
155        self.refs.push(Found { value: r, path });
156    }
157
158    /// `v` as an object, or a problem.
159    pub fn map<'v>(&mut self, v: &ValueRef<'v>) -> Option<MapRef<'v>> {
160        match v {
161            ValueRef::Map(m) => Some(*m),
162            other => {
163                self.expected(Expected::Object, other);
164                None
165            }
166        }
167    }
168
169    /// Reports keys of `map` that aren't `known` (nor metadata, nor allowed by an enclosing enum).
170    pub fn unknown_keys(&mut self, map: MapRef<'_>, known: &[&str]) {
171        for key in map.keys() {
172            if known.contains(&key) || is_metadata_key(key) || self.allowed.contains(&key) {
173                continue;
174            }
175            let hint = closest(key, known).map_or_else(
176                || {
177                    if known.is_empty() {
178                        String::new()
179                    } else {
180                        format!(
181                            " (expected {})",
182                            known
183                                .iter()
184                                .map(|k| format!("`{k}`"))
185                                .collect::<Vec<_>>()
186                                .join(", ")
187                        )
188                    }
189                },
190                |k| format!(" — did you mean `{k}`?"),
191            );
192            let mut found = Diagnostic::error(
193                Problem::UnknownField,
194                format!("unknown field `{key}`{hint}"),
195            )
196            .at_path(self.path().key(key));
197            found.on_key = true;
198            self.problems.push(found);
199        }
200    }
201
202    /// Reports a name that isn't one of `known` (an enum's variant).
203    pub fn unknown_name(&mut self, name: &str, known: &[&str]) {
204        let hint = match closest(name, known) {
205            Some(k) => format!(" — did you mean `{k}`?"),
206            None => format!(
207                " (expected {})",
208                known
209                    .iter()
210                    .map(|k| format!("`{k}`"))
211                    .collect::<Vec<_>>()
212                    .join(", ")
213            ),
214        };
215        self.problem(format!("unknown `{name}`{hint}"));
216    }
217
218    /// Field `key` of `map`: read, or its absent value, or a problem.
219    pub fn field<T: Schema>(&mut self, map: MapRef<'_>, key: &'static str) -> Option<T> {
220        match map.get(key) {
221            Some(v) => self.at(Seg::Key(key.to_string()), |cx| T::read(v, cx)),
222            None => T::absent().or_else(|| {
223                self.problem_of(Problem::MissingField, format!("missing `{key}`"));
224                None
225            }),
226        }
227    }
228
229    /// Field `key` of `map`, `default()` when it isn't there.
230    pub fn field_or<T: Schema>(
231        &mut self,
232        map: MapRef<'_>,
233        key: &'static str,
234        default: impl FnOnce() -> T,
235    ) -> Option<T> {
236        match map.get(key) {
237            Some(v) => self.at(Seg::Key(key.to_string()), |cx| T::read(v, cx)),
238            None => Some(default()),
239        }
240    }
241
242    /// Field `key` of `map` through codec `W`.
243    pub fn field_with<W: crate::with::With<F>, F>(
244        &mut self,
245        map: MapRef<'_>,
246        key: &'static str,
247    ) -> Option<F> {
248        match map.get(key) {
249            Some(v) => self.in_field(key, |cx| W::read(v, cx)),
250            None => W::absent().or_else(|| {
251                self.problem_of(Problem::MissingField, format!("missing `{key}`"));
252                None
253            }),
254        }
255    }
256
257    /// Field `key` of `map` through codec `W`, `default()` when it isn't there.
258    pub fn field_or_with<W: crate::with::With<F>, F>(
259        &mut self,
260        map: MapRef<'_>,
261        key: &'static str,
262        default: impl FnOnce() -> F,
263    ) -> Option<F> {
264        match map.get(key) {
265            Some(v) => self.in_field(key, |cx| W::read(v, cx)),
266            None => Some(default()),
267        }
268    }
269
270    /// Reads `v` as `T` with `key` allowed in it — the tag of the enum variant `T` is.
271    pub fn with_allowed<T>(&mut self, key: &'static str, f: impl FnOnce(&mut Self) -> T) -> T {
272        self.allowed.push(key);
273        let r = f(self);
274        self.allowed.pop();
275        r
276    }
277
278    /// Reads with every one of `keys` allowed (the fields of a struct read
279    /// from the same object — see [`read_both`](crate::schema::read_both)).
280    pub fn with_allowed_all<T>(
281        &mut self,
282        keys: &[&'static str],
283        f: impl FnOnce(&mut Self) -> T,
284    ) -> T {
285        let before = self.allowed.len();
286        self.allowed.extend_from_slice(keys);
287        let r = f(self);
288        self.allowed.truncate(before);
289        r
290    }
291
292    /// Reads a struct's own keys with no allowance inherited from outside.
293    pub fn own_keys<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
294        let saved = std::mem::take(&mut self.allowed);
295        let r = f(self);
296        self.allowed = saved;
297        r
298    }
299}