Skip to content

Commit f9e726b

Browse files
committed
refactor(util-schemas): make error enum private
1 parent a0201cd commit f9e726b

File tree

4 files changed

+90
-48
lines changed

4 files changed

+90
-48
lines changed

crates/cargo-util-schemas/src/core/package_id_spec.rs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ use url::Url;
66

77
use crate::core::GitReference;
88
use crate::core::PartialVersion;
9+
use crate::core::PartialVersionError;
910
use crate::core::SourceKind;
1011
use crate::manifest::PackageName;
12+
use crate::restricted_names::NameValidationError;
1113

1214
type Result<T> = std::result::Result<T, PackageIdSpecError>;
1315

@@ -83,10 +85,11 @@ impl PackageIdSpec {
8385
if abs.exists() {
8486
let maybe_url = Url::from_file_path(abs)
8587
.map_or_else(|_| "a file:// URL".to_string(), |url| url.to_string());
86-
return Err(PackageIdSpecError::MaybeFilePath {
88+
return Err(ErrorKind::MaybeFilePath {
8789
spec: spec.into(),
8890
maybe_url,
89-
});
91+
}
92+
.into());
9093
}
9194
}
9295
let mut parts = spec.splitn(2, [':', '@']);
@@ -117,34 +120,34 @@ impl PackageIdSpec {
117120
}
118121
"registry" => {
119122
if url.query().is_some() {
120-
return Err(PackageIdSpecError::UnexpectedQueryString(url));
123+
return Err(ErrorKind::UnexpectedQueryString(url).into());
121124
}
122125
kind = Some(SourceKind::Registry);
123126
url = strip_url_protocol(&url);
124127
}
125128
"sparse" => {
126129
if url.query().is_some() {
127-
return Err(PackageIdSpecError::UnexpectedQueryString(url));
130+
return Err(ErrorKind::UnexpectedQueryString(url).into());
128131
}
129132
kind = Some(SourceKind::SparseRegistry);
130133
// Leave `sparse` as part of URL, see `SourceId::new`
131134
// url = strip_url_protocol(&url);
132135
}
133136
"path" => {
134137
if url.query().is_some() {
135-
return Err(PackageIdSpecError::UnexpectedQueryString(url));
138+
return Err(ErrorKind::UnexpectedQueryString(url).into());
136139
}
137140
if scheme != "file" {
138-
return Err(PackageIdSpecError::UnsupportedPathPlusScheme(scheme.into()));
141+
return Err(ErrorKind::UnsupportedPathPlusScheme(scheme.into()).into());
139142
}
140143
kind = Some(SourceKind::Path);
141144
url = strip_url_protocol(&url);
142145
}
143-
kind => return Err(PackageIdSpecError::UnsupportedProtocol(kind.into())),
146+
kind => return Err(ErrorKind::UnsupportedProtocol(kind.into()).into()),
144147
}
145148
} else {
146149
if url.query().is_some() {
147-
return Err(PackageIdSpecError::UnexpectedQueryString(url));
150+
return Err(ErrorKind::UnexpectedQueryString(url).into());
148151
}
149152
}
150153

@@ -153,7 +156,7 @@ impl PackageIdSpec {
153156

154157
let (name, version) = {
155158
let Some(path_name) = url.path_segments().and_then(|mut p| p.next_back()) else {
156-
return Err(PackageIdSpecError::MissingUrlPath(url));
159+
return Err(ErrorKind::MissingUrlPath(url).into());
157160
};
158161
match frag {
159162
Some(fragment) => match fragment.split_once([':', '@']) {
@@ -269,9 +272,26 @@ impl<'de> de::Deserialize<'de> for PackageIdSpec {
269272
}
270273

271274
/// Error parsing a [`PackageIdSpec`].
275+
#[derive(Debug, thiserror::Error)]
276+
#[error(transparent)]
277+
pub struct PackageIdSpecError(#[from] ErrorKind);
278+
279+
impl From<PartialVersionError> for PackageIdSpecError {
280+
fn from(value: PartialVersionError) -> Self {
281+
ErrorKind::PartialVersion(value).into()
282+
}
283+
}
284+
285+
impl From<NameValidationError> for PackageIdSpecError {
286+
fn from(value: NameValidationError) -> Self {
287+
ErrorKind::NameValidation(value).into()
288+
}
289+
}
290+
291+
/// Non-public error kind for [`PackageIdSpecError`].
272292
#[non_exhaustive]
273293
#[derive(Debug, thiserror::Error)]
274-
pub enum PackageIdSpecError {
294+
enum ErrorKind {
275295
#[error("unsupported source protocol: {0}")]
276296
UnsupportedProtocol(String),
277297

crates/cargo-util-schemas/src/core/partial_version.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,19 +84,17 @@ impl std::str::FromStr for PartialVersion {
8484

8585
fn from_str(value: &str) -> Result<Self, Self::Err> {
8686
if is_req(value) {
87-
return Err(PartialVersionError::VersionReq);
87+
return Err(ErrorKind::VersionReq.into());
8888
}
8989
match semver::Version::parse(value) {
9090
Ok(ver) => Ok(ver.into()),
9191
Err(_) => {
9292
// HACK: Leverage `VersionReq` for partial version parsing
9393
let mut version_req = match semver::VersionReq::parse(value) {
9494
Ok(req) => req,
95-
Err(_) if value.contains('-') => return Err(PartialVersionError::Prerelease),
96-
Err(_) if value.contains('+') => {
97-
return Err(PartialVersionError::BuildMetadata)
98-
}
99-
Err(_) => return Err(PartialVersionError::Unexpected),
95+
Err(_) if value.contains('-') => return Err(ErrorKind::Prerelease.into()),
96+
Err(_) if value.contains('+') => return Err(ErrorKind::BuildMetadata.into()),
97+
Err(_) => return Err(ErrorKind::Unexpected.into()),
10098
};
10199
assert_eq!(version_req.comparators.len(), 1, "guaranteed by is_req");
102100
let comp = version_req.comparators.pop().unwrap();
@@ -160,9 +158,14 @@ impl<'de> serde::Deserialize<'de> for PartialVersion {
160158
}
161159

162160
/// Error parsing a [`PartialVersion`].
161+
#[derive(Debug, thiserror::Error)]
162+
#[error(transparent)]
163+
pub struct PartialVersionError(#[from] ErrorKind);
164+
165+
/// Non-public error kind for [`PartialVersionError`].
163166
#[non_exhaustive]
164167
#[derive(Debug, thiserror::Error)]
165-
pub enum PartialVersionError {
168+
enum ErrorKind {
166169
#[error("unexpected version requirement, expected a version like \"1.32\"")]
167170
VersionReq,
168171

crates/cargo-util-schemas/src/manifest.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,12 +1339,13 @@ impl std::str::FromStr for RustVersion {
13391339
type Err = RustVersionError;
13401340

13411341
fn from_str(value: &str) -> Result<Self, Self::Err> {
1342-
let partial = value.parse::<PartialVersion>()?;
1342+
let partial = value.parse::<PartialVersion>();
1343+
let partial = partial.map_err(RustVersionErrorKind::PartialVersion)?;
13431344
if partial.pre.is_some() {
1344-
return Err(RustVersionError::Prerelease);
1345+
return Err(RustVersionErrorKind::Prerelease.into());
13451346
}
13461347
if partial.build.is_some() {
1347-
return Err(RustVersionError::BuildMetadata);
1348+
return Err(RustVersionErrorKind::BuildMetadata.into());
13481349
}
13491350
Ok(Self(partial))
13501351
}
@@ -1368,10 +1369,15 @@ impl Display for RustVersion {
13681369
}
13691370
}
13701371

1371-
/// Error parsing a [`PartialVersion`].
1372+
/// Error parsing a [`RustVersion`].
1373+
#[derive(Debug, thiserror::Error)]
1374+
#[error(transparent)]
1375+
pub struct RustVersionError(#[from] RustVersionErrorKind);
1376+
1377+
/// Non-public error kind for [`RustVersionError`].
13721378
#[non_exhaustive]
13731379
#[derive(Debug, thiserror::Error)]
1374-
pub enum RustVersionError {
1380+
enum RustVersionErrorKind {
13751381
#[error("unexpected prerelease field, expected a version like \"1.32\"")]
13761382
Prerelease,
13771383

crates/cargo-util-schemas/src/restricted_names.rs

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@
33
type Result<T> = std::result::Result<T, NameValidationError>;
44

55
/// Error validating names in Cargo.
6+
#[derive(Debug, thiserror::Error)]
7+
#[error(transparent)]
8+
pub struct NameValidationError(#[from] ErrorKind);
9+
10+
/// Non-public error kind for [`NameValidationError`].
611
#[non_exhaustive]
712
#[derive(Debug, thiserror::Error)]
8-
pub enum NameValidationError {
13+
enum ErrorKind {
914
#[error("{0} cannot be empty")]
1015
Empty(&'static str),
1116

@@ -36,39 +41,42 @@ pub enum NameValidationError {
3641
/// reserved names. crates.io has even more restrictions.
3742
pub(crate) fn validate_package_name(name: &str, what: &'static str) -> Result<()> {
3843
if name.is_empty() {
39-
return Err(NameValidationError::Empty(what));
44+
return Err(ErrorKind::Empty(what).into());
4045
}
4146

4247
let mut chars = name.chars();
4348
if let Some(ch) = chars.next() {
4449
if ch.is_digit(10) {
4550
// A specific error for a potentially common case.
46-
return Err(NameValidationError::InvalidCharacter {
51+
return Err(ErrorKind::InvalidCharacter {
4752
ch,
4853
what,
4954
name: name.into(),
5055
reason: "the name cannot start with a digit",
51-
});
56+
}
57+
.into());
5258
}
5359
if !(unicode_xid::UnicodeXID::is_xid_start(ch) || ch == '_') {
54-
return Err(NameValidationError::InvalidCharacter {
60+
return Err(ErrorKind::InvalidCharacter {
5561
ch,
5662
what,
5763
name: name.into(),
5864
reason: "the first character must be a Unicode XID start character \
5965
(most letters or `_`)",
60-
});
66+
}
67+
.into());
6168
}
6269
}
6370
for ch in chars {
6471
if !(unicode_xid::UnicodeXID::is_xid_continue(ch) || ch == '-') {
65-
return Err(NameValidationError::InvalidCharacter {
72+
return Err(ErrorKind::InvalidCharacter {
6673
ch,
6774
what,
6875
name: name.into(),
6976
reason: "characters must be Unicode XID characters \
7077
(numbers, `-`, `_`, or most letters)",
71-
});
78+
}
79+
.into());
7280
}
7381
}
7482
Ok(())
@@ -103,28 +111,31 @@ pub(crate) fn validate_profile_name(name: &str) -> Result<()> {
103111
.chars()
104112
.find(|ch| !ch.is_alphanumeric() && *ch != '_' && *ch != '-')
105113
{
106-
return Err(NameValidationError::InvalidCharacter {
114+
return Err(ErrorKind::InvalidCharacter {
107115
ch,
108116
what: "profile name",
109117
name: name.into(),
110118
reason: "allowed characters are letters, numbers, underscore, and hyphen",
111-
});
119+
}
120+
.into());
112121
}
113122

114123
let lower_name = name.to_lowercase();
115124
if lower_name == "debug" {
116-
return Err(NameValidationError::ProfileNameReservedKeyword {
125+
return Err(ErrorKind::ProfileNameReservedKeyword {
117126
name: name.into(),
118127
help: "To configure the default development profile, \
119128
use the name `dev` as in [profile.dev]",
120-
});
129+
}
130+
.into());
121131
}
122132
if lower_name == "build-override" {
123-
return Err(NameValidationError::ProfileNameReservedKeyword {
133+
return Err(ErrorKind::ProfileNameReservedKeyword {
124134
name: name.into(),
125135
help: "To configure build dependency settings, use [profile.dev.build-override] \
126136
and [profile.release.build-override]",
127-
});
137+
}
138+
.into());
128139
}
129140

130141
// These are some arbitrary reservations. We have no plans to use
@@ -155,10 +166,11 @@ pub(crate) fn validate_profile_name(name: &str) -> Result<()> {
155166
| "uninstall"
156167
) || lower_name.starts_with("cargo")
157168
{
158-
return Err(NameValidationError::ProfileNameReservedKeyword {
169+
return Err(ErrorKind::ProfileNameReservedKeyword {
159170
name: name.into(),
160171
help: "Please choose a different name.",
161-
});
172+
}
173+
.into());
162174
}
163175

164176
Ok(())
@@ -167,43 +179,44 @@ pub(crate) fn validate_profile_name(name: &str) -> Result<()> {
167179
pub(crate) fn validate_feature_name(name: &str) -> Result<()> {
168180
let what = "feature name";
169181
if name.is_empty() {
170-
return Err(NameValidationError::Empty(what));
182+
return Err(ErrorKind::Empty(what).into());
171183
}
172184

173185
if name.starts_with("dep:") {
174-
return Err(NameValidationError::FeatureNameStartsWithDepColon(
175-
name.into(),
176-
));
186+
return Err(ErrorKind::FeatureNameStartsWithDepColon(name.into()).into());
177187
}
178188
if name.contains('/') {
179-
return Err(NameValidationError::InvalidCharacter {
189+
return Err(ErrorKind::InvalidCharacter {
180190
ch: '/',
181191
what,
182192
name: name.into(),
183193
reason: "feature name is not allowed to contain slashes",
184-
});
194+
}
195+
.into());
185196
}
186197
let mut chars = name.chars();
187198
if let Some(ch) = chars.next() {
188199
if !(unicode_xid::UnicodeXID::is_xid_start(ch) || ch == '_' || ch.is_digit(10)) {
189-
return Err(NameValidationError::InvalidCharacter {
200+
return Err(ErrorKind::InvalidCharacter {
190201
ch,
191202
what,
192203
name: name.into(),
193204
reason: "the first character must be a Unicode XID start character or digit \
194205
(most letters or `_` or `0` to `9`)",
195-
});
206+
}
207+
.into());
196208
}
197209
}
198210
for ch in chars {
199211
if !(unicode_xid::UnicodeXID::is_xid_continue(ch) || ch == '-' || ch == '+' || ch == '.') {
200-
return Err(NameValidationError::InvalidCharacter {
212+
return Err(ErrorKind::InvalidCharacter {
201213
ch,
202214
what,
203215
name: name.into(),
204216
reason: "characters must be Unicode XID characters, '-', `+`, or `.` \
205217
(numbers, `+`, `-`, `_`, `.`, or most letters)",
206-
});
218+
}
219+
.into());
207220
}
208221
}
209222
Ok(())

0 commit comments

Comments
 (0)