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