Use strum crate to derive enum↔string conversions

type: reform
This commit is contained in:
Casey Rodarmor 2020-03-27 18:41:35 -07:00
parent 6996d1a3ea
commit 362a81d42f
No known key found for this signature in database
GPG Key ID: 556186B153EC6FE0
7 changed files with 58 additions and 84 deletions

20
Cargo.lock generated
View File

@ -342,6 +342,8 @@ dependencies = [
"snafu",
"static_assertions",
"structopt",
"strum",
"strum_macros",
"syn",
"tempfile",
"temptree",
@ -778,6 +780,24 @@ dependencies = [
"syn",
]
[[package]]
name = "strum"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b"
[[package]]
name = "strum_macros"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.16"

View File

@ -32,6 +32,8 @@ serde_with = "1.4.0"
sha1 = "0.6.0"
snafu = "0.6.0"
static_assertions = "1.0.0"
strum = "0.18.0"
strum_macros = "0.18.0"
syn = "1.0.14"
tempfile = "3.0.0"
unicode-width = "0.1.0"

View File

@ -4,7 +4,7 @@ pub(crate) use std::{
char,
cmp::{Ordering, Reverse},
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
convert::{Infallible, TryInto},
convert::TryInto,
env,
ffi::{OsStr, OsString},
fmt::{self, Display, Formatter},
@ -39,6 +39,8 @@ pub(crate) use structopt::{
clap::{AppSettings, ArgSettings},
StructOpt,
};
pub(crate) use strum::VariantNames;
pub(crate) use strum_macros::{EnumString, EnumVariantNames, IntoStaticStr};
pub(crate) use unicode_width::UnicodeWidthStr;
pub(crate) use url::{Host, Url};
pub(crate) use walkdir::WalkDir;

View File

@ -1,6 +1,9 @@
use crate::common::*;
#[derive(Eq, PartialEq, Debug, Copy, Clone, Ord, PartialOrd)]
#[derive(
Eq, PartialEq, Debug, Copy, Clone, Ord, PartialOrd, EnumVariantNames, IntoStaticStr, EnumString,
)]
#[strum(serialize_all = "kebab-case")]
pub(crate) enum Lint {
PrivateTrackerless,
SmallPieceLength,
@ -8,36 +11,8 @@ pub(crate) enum Lint {
}
impl Lint {
const PRIVATE_TRACKERLESS: &'static str = "private-trackerless";
const SMALL_PIECE_LENGTH: &'static str = "small-piece-length";
const UNEVEN_PIECE_LENGTH: &'static str = "uneven-piece-length";
pub(crate) const VALUES: &'static [&'static str] = &[
Self::PRIVATE_TRACKERLESS,
Self::SMALL_PIECE_LENGTH,
Self::UNEVEN_PIECE_LENGTH,
];
pub(crate) fn name(self) -> &'static str {
match self {
Self::PrivateTrackerless => Self::PRIVATE_TRACKERLESS,
Self::SmallPieceLength => Self::SMALL_PIECE_LENGTH,
Self::UnevenPieceLength => Self::UNEVEN_PIECE_LENGTH,
}
}
}
impl FromStr for Lint {
type Err = Error;
fn from_str(text: &str) -> Result<Self, Self::Err> {
match text.replace('_', "-").to_lowercase().as_str() {
Self::PRIVATE_TRACKERLESS => Ok(Self::PrivateTrackerless),
Self::SMALL_PIECE_LENGTH => Ok(Self::SmallPieceLength),
Self::UNEVEN_PIECE_LENGTH => Ok(Self::UnevenPieceLength),
_ => Err(Error::LintUnknown {
text: text.to_string(),
}),
}
self.into()
}
}
@ -51,22 +26,24 @@ impl Display for Lint {
mod tests {
use super::*;
#[test]
fn variants() {
assert_eq!(
Lint::VARIANTS,
&[
"private-trackerless",
"small-piece-length",
"uneven-piece-length"
]
);
}
#[test]
fn from_str_ok() {
assert_eq!(
Lint::UnevenPieceLength,
"uneven_piece_length".parse().unwrap()
);
assert_eq!(
Lint::UnevenPieceLength,
"uneven-piece-length".parse().unwrap()
);
assert_eq!(
Lint::UnevenPieceLength,
"UNEVEN-piece-length".parse().unwrap()
);
}
#[test]
@ -74,6 +51,7 @@ mod tests {
fn case(text: &str, value: Lint) {
assert_eq!(value, text.parse().unwrap());
assert_eq!(value.name(), text);
assert_eq!(value.to_string(), value.name());
}
case("private-trackerless", Lint::PrivateTrackerless);
@ -85,7 +63,7 @@ mod tests {
fn from_str_err() {
assert_matches!(
"foo".parse::<Lint>(),
Err(Error::LintUnknown { text }) if text == "foo"
Err(strum::ParseError::VariantNotFound)
);
}
}

View File

@ -14,9 +14,8 @@ pub(crate) struct Options {
#[structopt(
long = "color",
value_name = "WHEN",
default_value = UseColor::AUTO,
set = ArgSettings::CaseInsensitive,
possible_values = UseColor::VALUES,
default_value = UseColor::Auto.into(),
possible_values = UseColor::VARIANTS,
help = "Print colorful output according to `WHEN`. When `auto`, the default, colored output \
is only enabled if imdl detects that it is connected to a terminal, the `NO_COLOR` \
environment variable is not set, and the `TERM` environment variable is not set to \

View File

@ -22,8 +22,7 @@ pub(crate) struct Create {
long = "allow",
short = "A",
value_name = "LINT",
possible_values = Lint::VALUES,
set(ArgSettings::CaseInsensitive),
possible_values = Lint::VARIANTS,
help = "Allow `LINT`. Lints check for conditions which, although permitted, are not usually \
desirable. For example, piece length can be any non-zero value, but probably \
shouldn't be below 16 KiB. The lint `small-piece-size` checks for this, and \
@ -2254,7 +2253,7 @@ Content Size 9 bytes
"foo",
"--private",
"--allow",
"private-trackerLESS",
"private-trackerless",
],
tree: {
foo: "",

View File

@ -1,52 +1,26 @@
use crate::common::*;
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, EnumVariantNames, EnumString, IntoStaticStr)]
#[strum(serialize_all = "kebab-case")]
pub(crate) enum UseColor {
Auto,
Always,
Never,
}
impl UseColor {
pub(crate) const ALWAYS: &'static str = "always";
pub(crate) const AUTO: &'static str = "auto";
pub(crate) const NEVER: &'static str = "never";
pub(crate) const VALUES: &'static [&'static str] = &[Self::AUTO, Self::ALWAYS, Self::NEVER];
}
impl FromStr for UseColor {
type Err = Infallible;
fn from_str(text: &str) -> Result<Self, Self::Err> {
match text.to_lowercase().as_str() {
Self::AUTO => Ok(Self::Auto),
Self::ALWAYS => Ok(Self::Always),
Self::NEVER => Ok(Self::Never),
_ => unreachable!(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn variants() {
assert_eq!(UseColor::VARIANTS, &["auto", "always", "never"]);
}
#[test]
fn from_str() {
assert_eq!(UseColor::Auto, UseColor::AUTO.parse().unwrap());
assert_eq!(UseColor::Always, UseColor::ALWAYS.parse().unwrap());
assert_eq!(UseColor::Never, UseColor::NEVER.parse().unwrap());
assert_eq!(
UseColor::Auto,
UseColor::AUTO.to_uppercase().parse().unwrap()
);
assert_eq!(
UseColor::Always,
UseColor::ALWAYS.to_uppercase().parse().unwrap()
);
assert_eq!(
UseColor::Never,
UseColor::NEVER.to_uppercase().parse().unwrap()
);
assert_eq!(UseColor::Auto, "auto".parse().unwrap());
assert_eq!(UseColor::Always, "always".parse().unwrap());
assert_eq!(UseColor::Never, "never".parse().unwrap());
}
}