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", "snafu",
"static_assertions", "static_assertions",
"structopt", "structopt",
"strum",
"strum_macros",
"syn", "syn",
"tempfile", "tempfile",
"temptree", "temptree",
@ -778,6 +780,24 @@ dependencies = [
"syn", "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]] [[package]]
name = "syn" name = "syn"
version = "1.0.16" version = "1.0.16"

View File

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

View File

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

View File

@ -1,6 +1,9 @@
use crate::common::*; 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 { pub(crate) enum Lint {
PrivateTrackerless, PrivateTrackerless,
SmallPieceLength, SmallPieceLength,
@ -8,36 +11,8 @@ pub(crate) enum Lint {
} }
impl 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 { pub(crate) fn name(self) -> &'static str {
match self { self.into()
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(),
}),
}
} }
} }
@ -51,22 +26,24 @@ impl Display for Lint {
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn variants() {
assert_eq!(
Lint::VARIANTS,
&[
"private-trackerless",
"small-piece-length",
"uneven-piece-length"
]
);
}
#[test] #[test]
fn from_str_ok() { fn from_str_ok() {
assert_eq!(
Lint::UnevenPieceLength,
"uneven_piece_length".parse().unwrap()
);
assert_eq!( assert_eq!(
Lint::UnevenPieceLength, Lint::UnevenPieceLength,
"uneven-piece-length".parse().unwrap() "uneven-piece-length".parse().unwrap()
); );
assert_eq!(
Lint::UnevenPieceLength,
"UNEVEN-piece-length".parse().unwrap()
);
} }
#[test] #[test]
@ -74,6 +51,7 @@ mod tests {
fn case(text: &str, value: Lint) { fn case(text: &str, value: Lint) {
assert_eq!(value, text.parse().unwrap()); assert_eq!(value, text.parse().unwrap());
assert_eq!(value.name(), text); assert_eq!(value.name(), text);
assert_eq!(value.to_string(), value.name());
} }
case("private-trackerless", Lint::PrivateTrackerless); case("private-trackerless", Lint::PrivateTrackerless);
@ -85,7 +63,7 @@ mod tests {
fn from_str_err() { fn from_str_err() {
assert_matches!( assert_matches!(
"foo".parse::<Lint>(), "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( #[structopt(
long = "color", long = "color",
value_name = "WHEN", value_name = "WHEN",
default_value = UseColor::AUTO, default_value = UseColor::Auto.into(),
set = ArgSettings::CaseInsensitive, possible_values = UseColor::VARIANTS,
possible_values = UseColor::VALUES,
help = "Print colorful output according to `WHEN`. When `auto`, the default, colored output \ 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` \ 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 \ 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", long = "allow",
short = "A", short = "A",
value_name = "LINT", value_name = "LINT",
possible_values = Lint::VALUES, possible_values = Lint::VARIANTS,
set(ArgSettings::CaseInsensitive),
help = "Allow `LINT`. Lints check for conditions which, although permitted, are not usually \ 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 \ 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 \ shouldn't be below 16 KiB. The lint `small-piece-size` checks for this, and \
@ -2254,7 +2253,7 @@ Content Size 9 bytes
"foo", "foo",
"--private", "--private",
"--allow", "--allow",
"private-trackerLESS", "private-trackerless",
], ],
tree: { tree: {
foo: "", foo: "",

View File

@ -1,52 +1,26 @@
use crate::common::*; 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 { pub(crate) enum UseColor {
Auto, Auto,
Always, Always,
Never, 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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn variants() {
assert_eq!(UseColor::VARIANTS, &["auto", "always", "never"]);
}
#[test] #[test]
fn from_str() { fn from_str() {
assert_eq!(UseColor::Auto, UseColor::AUTO.parse().unwrap()); assert_eq!(UseColor::Auto, "auto".parse().unwrap());
assert_eq!(UseColor::Always, UseColor::ALWAYS.parse().unwrap()); assert_eq!(UseColor::Always, "always".parse().unwrap());
assert_eq!(UseColor::Never, UseColor::NEVER.parse().unwrap()); assert_eq!(UseColor::Never, "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()
);
} }
} }