Skip to main content

xidl_parser/versioning/
error.rs

1use std::error::Error;
2use std::fmt;
3
4/// Diagnostics raised while analysing or projecting API versioning annotations.
5#[derive(Debug, Clone)]
6pub enum VersioningError {
7    /// `@version` applied to a declaration that is not an enum.
8    VersionOutsideEnum { target: String },
9    /// Two enums in one specification carry the `@version` marker.
10    DuplicateVersionEnum { first: String, second: String },
11    /// The `@version` enum declares no members.
12    EmptyVersionEnum { ident: String },
13    /// Two version members resolve to the same display value.
14    DuplicateVersionValue {
15        value: String,
16        first: String,
17        second: String,
18    },
19    /// A lifecycle annotation appears without a `@version` enum in the specification.
20    MissingVersionEnum { annotation: String, decl: String },
21    /// A lifecycle annotation argument is not an `Enum::member` reference.
22    MalformedVersionReference { annotation: String, decl: String },
23    /// A raw version marker failed to lower into a valid typed annotation.
24    MalformedVersionMarker { decl: String },
25    /// A version parameter violates its argument or wire-location contract.
26    MalformedVersionParameter { decl: String, reason: String },
27    /// A version timeline declares more than one version marker or parameter.
28    DuplicateVersionParameter { decl: String },
29    /// A lifecycle annotation references a version the timeline does not declare.
30    UnknownVersionReference {
31        annotation: String,
32        decl: String,
33        reference: String,
34        declared: String,
35    },
36    /// A rejected versioning annotation has no supported contract semantics.
37    UnsupportedVersionAnnotation { name: String, decl: String },
38    /// A lifecycle annotation applied to a declaration that cannot carry it.
39    UnsupportedVersionTarget { annotation: String, target: String },
40    /// The `@version` enum itself carries a lifecycle annotation.
41    VersionedVersionEnum { annotation: String, ident: String },
42    /// The same lifecycle annotation appears twice on one declaration.
43    DuplicateLifecycleAnnotation { annotation: String, decl: String },
44    /// `@added` and `@removed` leave an empty availability interval.
45    EmptyAvailability {
46        decl: String,
47        added: String,
48        removed: String,
49    },
50    /// A child's annotated interval reaches outside its parent's interval.
51    ChildOutsideParent {
52        decl: String,
53        parent: String,
54        version: String,
55    },
56    /// A surviving declaration references a declaration the projection drops.
57    DanglingReference {
58        decl: String,
59        reference: String,
60        version: String,
61    },
62    /// A version selection was requested for a specification without a `@version` enum.
63    UnversionedSpecification { selection: String },
64    /// A requested version is not declared by the timeline.
65    UnknownSelectedVersion { selection: String, declared: String },
66    /// A requested version matches both a member ident and another member's value.
67    AmbiguousSelectedVersion {
68        selection: String,
69        first: String,
70        second: String,
71    },
72    /// The projector received a version position outside the timeline.
73    UnknownVersion { index: usize },
74    /// Both version selection properties were set.
75    ConflictingSelection { first: String, second: String },
76    /// The requested version selection is empty.
77    EmptySelection,
78    /// `api_version` received `*`, which only `api_versions` accepts.
79    SelectionRequiresOneVersion { selection: String },
80    /// The version layout property holds an unknown value.
81    UnknownVersionLayout { value: String },
82    /// Two declarations available in the same version resolve to the same
83    /// effective wire name inside one container.
84    DuplicateWireName {
85        container: String,
86        wire: String,
87        first: String,
88        second: String,
89        version: Option<String>,
90    },
91}
92
93impl fmt::Display for VersioningError {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        match self {
96            Self::VersionOutsideEnum { target } => write!(
97                f,
98                "xidl versioning: @version is only valid on an enum declaration, not on {target}"
99            ),
100            Self::DuplicateVersionEnum { first, second } => write!(
101                f,
102                "xidl versioning: multiple @version enums declared: {first} and {second}"
103            ),
104            Self::EmptyVersionEnum { ident } => write!(
105                f,
106                "xidl versioning: the @version enum {ident} declares no versions"
107            ),
108            Self::DuplicateVersionValue {
109                value,
110                first,
111                second,
112            } => write!(
113                f,
114                "xidl versioning: versions {first} and {second} both resolve to value \"{value}\""
115            ),
116            Self::MissingVersionEnum { annotation, decl } => write!(
117                f,
118                "xidl versioning: {annotation} on {decl} requires a @version enum in the specification"
119            ),
120            Self::MalformedVersionReference { annotation, decl } => write!(
121                f,
122                "xidl versioning: {annotation} on {decl} requires a version reference like Versions::v1"
123            ),
124            Self::MalformedVersionMarker { decl } => {
125                write!(
126                    f,
127                    "xidl versioning: @version on {decl} must be bare or declare in=... and name=..."
128                )
129            }
130            Self::MalformedVersionParameter { decl, reason } => {
131                write!(f, "xidl versioning: @version on {decl}: {reason}")
132            }
133            Self::DuplicateVersionParameter { decl } => write!(
134                f,
135                "xidl versioning: @version on {decl} is declared more than once"
136            ),
137            Self::UnknownVersionReference {
138                annotation,
139                decl,
140                reference,
141                declared,
142            } => write!(
143                f,
144                "xidl versioning: {annotation} on {decl} references {reference}, which is not declared ({declared})"
145            ),
146            Self::UnsupportedVersionAnnotation { name, decl } => {
147                write!(f, "xidl versioning: {name} on {decl} is not supported; ")?;
148                if name.eq_ignore_ascii_case("@renamedFrom") {
149                    write!(
150                        f,
151                        "use @rename(\"wire_name\") for the serialized name; use @added/@removed declarations for changes between versions"
152                    )
153                } else {
154                    write!(
155                        f,
156                        "use @version, @added and @removed for version availability"
157                    )
158                }
159            }
160            Self::UnsupportedVersionTarget { annotation, target } => write!(
161                f,
162                "xidl versioning: {annotation} cannot be applied to {target}"
163            ),
164            Self::VersionedVersionEnum { annotation, ident } => write!(
165                f,
166                "xidl versioning: the @version enum {ident} cannot carry {annotation}"
167            ),
168            Self::DuplicateLifecycleAnnotation { annotation, decl } => {
169                write!(f, "xidl versioning: duplicate {annotation} on {decl}")
170            }
171            Self::EmptyAvailability {
172                decl,
173                added,
174                removed,
175            } => write!(
176                f,
177                "xidl versioning: {decl} is unavailable in every version (@added({added}) and @removed({removed}) leave an empty interval)"
178            ),
179            Self::ChildOutsideParent {
180                decl,
181                parent,
182                version,
183            } => write!(
184                f,
185                "xidl versioning: {decl} is annotated at {version}, outside the availability of {parent}"
186            ),
187            Self::DanglingReference {
188                decl,
189                reference,
190                version,
191            } => write!(
192                f,
193                "xidl versioning: {decl} references {reference}, which does not exist in {version}"
194            ),
195            Self::UnversionedSpecification { selection } => write!(
196                f,
197                "xidl versioning: version selection {selection} requires a @version enum in the specification"
198            ),
199            Self::UnknownSelectedVersion {
200                selection,
201                declared,
202            } => write!(
203                f,
204                "xidl versioning: version {selection} is not declared ({declared})"
205            ),
206            Self::AmbiguousSelectedVersion {
207                selection,
208                first,
209                second,
210            } => write!(
211                f,
212                "xidl versioning: version {selection} matches both {first} and {second}; use the member ident"
213            ),
214            Self::UnknownVersion { index } => write!(
215                f,
216                "xidl versioning: version position {index} is not part of the declared timeline"
217            ),
218            Self::ConflictingSelection { first, second } => write!(
219                f,
220                "xidl versioning: {first} and {second} cannot both be set"
221            ),
222            Self::EmptySelection => write!(
223                f,
224                "xidl versioning: the version selection is empty; name at least one version or use \"*\""
225            ),
226            Self::SelectionRequiresOneVersion { selection } => write!(
227                f,
228                "xidl versioning: {selection} selects one version; use the plural version property with \"*\" for every version"
229            ),
230            Self::UnknownVersionLayout { value } => write!(
231                f,
232                "xidl versioning: unknown version layout \"{value}\"; expected \"merged\" or \"per_version\""
233            ),
234            Self::DuplicateWireName {
235                container,
236                wire,
237                first,
238                second,
239                version,
240            } => match version {
241                Some(version) => write!(
242                    f,
243                    "xidl versioning: {first} and {second} both serialize as \"{wire}\" in version {version}; effective wire names must stay unique inside {container} for every version"
244                ),
245                None => write!(
246                    f,
247                    "xidl versioning: {first} and {second} both serialize as \"{wire}\"; effective wire names must stay unique inside {container}"
248                ),
249            },
250        }
251    }
252}
253
254impl Error for VersioningError {}