Skip to main content

pedant_types/resolution/
wire.rs

1//! Incremental report decoding through the same validator `finish` uses.
2
3use std::fmt;
4use std::sync::Arc;
5
6use rustc_hash::FxHashSet;
7use serde::de::{DeserializeSeed, Error as DeserializeError, MapAccess, SeqAccess, Visitor};
8use serde::{Deserialize, Deserializer};
9
10use super::builder::ResolutionReportLimits;
11use super::definition::SymbolDefinition;
12use super::error::ReportCollection;
13use super::record::ResolutionRecord;
14use super::reference::SymbolReference;
15use super::report::{ResolutionReport, ResolutionTier};
16use super::span::SourceSpan;
17use super::unit::ResolutionUnit;
18use super::validate::validate;
19use super::wire_field::ReportField;
20use super::wire_sequence::LimitedSequenceDecoder;
21
22const REPORT_FIELDS: &[&str] = &["tier", "units", "definitions", "references", "resolutions"];
23
24/// Deserialize one validated report without retaining entries past `limits`.
25pub(super) fn deserialize_with_limits<'de, D>(
26    deserializer: D,
27    limits: ResolutionReportLimits,
28) -> Result<ResolutionReport, D::Error>
29where
30    D: Deserializer<'de>,
31{
32    WireReportDecoder { limits }.deserialize(deserializer)
33}
34
35impl<'de> Deserialize<'de> for ResolutionReport {
36    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
37    where
38        D: Deserializer<'de>,
39    {
40        deserialize_with_limits(deserializer, ResolutionReportLimits::default())
41    }
42}
43
44/// Private seed and visitor carrying limits through the report map.
45struct WireReportDecoder {
46    limits: ResolutionReportLimits,
47}
48
49impl<'de> DeserializeSeed<'de> for WireReportDecoder {
50    type Value = ResolutionReport;
51
52    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
53    where
54        D: Deserializer<'de>,
55    {
56        deserializer.deserialize_struct("ResolutionReport", REPORT_FIELDS, self)
57    }
58}
59
60impl<'de> Visitor<'de> for WireReportDecoder {
61    type Value = ResolutionReport;
62
63    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
64        formatter.write_str("a resolution report")
65    }
66
67    fn visit_seq<A>(self, mut sequence: A) -> Result<Self::Value, A::Error>
68    where
69        A: SeqAccess<'de>,
70    {
71        let tier = require_next(&mut sequence, "tier")?;
72        let units = require_next_seed(
73            &mut sequence,
74            LimitedSequenceDecoder::new(self.limits.max_units, ReportCollection::Units),
75            "units",
76        )?;
77        let definitions = require_next_seed(
78            &mut sequence,
79            LimitedSequenceDecoder::new(self.limits.max_definitions, ReportCollection::Definitions),
80            "definitions",
81        )?;
82        let references = require_next_seed(
83            &mut sequence,
84            LimitedSequenceDecoder::new(self.limits.max_references, ReportCollection::References),
85            "references",
86        )?;
87        let resolutions = require_next_seed(
88            &mut sequence,
89            LimitedSequenceDecoder::new(self.limits.max_references, ReportCollection::Resolutions),
90            "resolutions",
91        )?;
92        finish_report(tier, units, definitions, references, resolutions)
93    }
94
95    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
96    where
97        A: MapAccess<'de>,
98    {
99        let mut tier = None;
100        let mut units = None;
101        let mut definitions = None;
102        let mut references = None;
103        let mut resolutions = None;
104
105        while let Some(field) = map.next_key()? {
106            match field {
107                ReportField::Tier => {
108                    reject_duplicate(&tier, "tier")?;
109                    tier = Some(map.next_value()?);
110                }
111                ReportField::Units => {
112                    reject_duplicate(&units, "units")?;
113                    units = Some(map.next_value_seed(LimitedSequenceDecoder::new(
114                        self.limits.max_units,
115                        ReportCollection::Units,
116                    ))?);
117                }
118                ReportField::Definitions => {
119                    reject_duplicate(&definitions, "definitions")?;
120                    definitions = Some(map.next_value_seed(LimitedSequenceDecoder::new(
121                        self.limits.max_definitions,
122                        ReportCollection::Definitions,
123                    ))?);
124                }
125                ReportField::References => {
126                    reject_duplicate(&references, "references")?;
127                    references = Some(map.next_value_seed(LimitedSequenceDecoder::new(
128                        self.limits.max_references,
129                        ReportCollection::References,
130                    ))?);
131                }
132                ReportField::Resolutions => {
133                    reject_duplicate(&resolutions, "resolutions")?;
134                    resolutions = Some(map.next_value_seed(LimitedSequenceDecoder::new(
135                        self.limits.max_references,
136                        ReportCollection::Resolutions,
137                    ))?);
138                }
139            }
140        }
141
142        finish_report(
143            require_field(tier, "tier")?,
144            require_field(units, "units")?,
145            require_field(definitions, "definitions")?,
146            require_field(references, "references")?,
147            require_field(resolutions, "resolutions")?,
148        )
149    }
150}
151
152fn finish_report<E>(
153    tier: ResolutionTier,
154    units: Box<[ResolutionUnit]>,
155    mut definitions: Box<[SymbolDefinition]>,
156    mut references: Box<[SymbolReference]>,
157    resolutions: Box<[ResolutionRecord]>,
158) -> Result<ResolutionReport, E>
159where
160    E: DeserializeError,
161{
162    intern_paths(&mut definitions, &mut references);
163    let report = ResolutionReport::new(tier, units, definitions, references, resolutions);
164    validate(&report).map_err(E::custom)?;
165    Ok(report)
166}
167
168fn require_next<'de, A, T>(sequence: &mut A, name: &'static str) -> Result<T, A::Error>
169where
170    A: SeqAccess<'de>,
171    T: Deserialize<'de>,
172{
173    sequence
174        .next_element()?
175        .ok_or_else(|| A::Error::missing_field(name))
176}
177
178fn require_next_seed<'de, A, S>(
179    sequence: &mut A,
180    seed: S,
181    name: &'static str,
182) -> Result<S::Value, A::Error>
183where
184    A: SeqAccess<'de>,
185    S: DeserializeSeed<'de>,
186{
187    sequence
188        .next_element_seed(seed)?
189        .ok_or_else(|| A::Error::missing_field(name))
190}
191
192fn reject_duplicate<T, E>(field: &Option<T>, name: &'static str) -> Result<(), E>
193where
194    E: DeserializeError,
195{
196    match field.is_some() {
197        true => Err(E::duplicate_field(name)),
198        false => Ok(()),
199    }
200}
201
202fn require_field<T, E>(field: Option<T>, name: &'static str) -> Result<T, E>
203where
204    E: DeserializeError,
205{
206    field.ok_or_else(|| E::missing_field(name))
207}
208
209/// Point every span that names one path at one path value.
210///
211/// Serde's `rc` support allocates on the way in rather than restoring the
212/// sharing the report was serialized from, so a decoded report would otherwise
213/// hold one copy of a file name per site in it. One pass, before validation, so
214/// no consumer ever sees the unshared shape.
215fn intern_paths(definitions: &mut [SymbolDefinition], references: &mut [SymbolReference]) {
216    let mut paths: FxHashSet<Arc<str>> = FxHashSet::default();
217    for definition in definitions {
218        intern(&mut paths, definition.span_mut());
219    }
220    for reference in references {
221        intern(&mut paths, reference.span_mut());
222    }
223}
224
225fn intern(paths: &mut FxHashSet<Arc<str>>, span: &mut SourceSpan) {
226    let canonical = paths.get(span.file()).map(Arc::clone);
227    match canonical {
228        Some(canonical) => span.adopt_file(canonical),
229        None => {
230            paths.insert(Arc::clone(span.shared_file()));
231        }
232    }
233}