Skip to content

Commit

Permalink
Merge branch 'MHS-0-qol'
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Glotfelty committed Jan 12, 2025
2 parents b023d23 + c791507 commit 4beb2c9
Show file tree
Hide file tree
Showing 13 changed files with 132 additions and 55 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ members = [
"strum_tests",
"strum_nostd_tests"
]
resolver = "2"
5 changes: 3 additions & 2 deletions strum/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "strum"
version = "0.26.3"
edition = "2018"
edition = "2021"
authors = ["Peter Glotfelty <[email protected]>"]
license = "MIT"

Expand All @@ -13,10 +13,11 @@ documentation = "https://docs.rs/strum"
homepage = "https://github.com/Peternator7/strum"
repository = "https://github.com/Peternator7/strum"
readme = "../README.md"
rust-version = "1.66.1"

[dependencies]
strum_macros = { path = "../strum_macros", optional = true, version = "0.26.3" }
phf = { version = "0.10", features = ["macros"], optional = true }
phf = { version = "0.11", features = ["macros"], optional = true }

[dev-dependencies]
strum_macros = { path = "../strum_macros", version = "0.26" }
Expand Down
22 changes: 9 additions & 13 deletions strum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,8 @@ pub trait EnumMessage {

/// `EnumProperty` is a trait that makes it possible to store additional information
/// with enum variants. This trait is designed to be used with the macro of the same
/// name in the `strum_macros` crate. Currently, the only string literals are supported
/// in attributes, the other methods will be implemented as additional attribute types
/// become stabilized.
/// name in the `strum_macros` crate. Currently, the string, integer and bool literals
/// are supported in attributes.
///
/// # Example
///
Expand All @@ -168,27 +167,24 @@ pub trait EnumMessage {
///
/// #[derive(PartialEq, Eq, Debug, EnumProperty)]
/// enum Class {
/// #[strum(props(Teacher="Ms.Frizzle", Room="201"))]
/// #[strum(props(Teacher="Ms.Frizzle", Room="201", students=16, mandatory=true))]
/// History,
/// #[strum(props(Teacher="Mr.Smith"))]
/// #[strum(props(Room="103"))]
/// #[strum(props(Room="103", students=10))]
/// Mathematics,
/// #[strum(props(Time="2:30"))]
/// #[strum(props(Time="2:30", mandatory=true))]
/// Science,
/// }
///
/// let history = Class::History;
/// assert_eq!("Ms.Frizzle", history.get_str("Teacher").unwrap());
/// assert_eq!(16, history.get_int("students").unwrap());
/// assert!(history.get_bool("mandatory").unwrap());
/// ```
pub trait EnumProperty {
fn get_str(&self, prop: &str) -> Option<&'static str>;
fn get_int(&self, _prop: &str) -> Option<usize> {
Option::None
}

fn get_bool(&self, _prop: &str) -> Option<bool> {
Option::None
}
fn get_int(&self, _prop: &str) -> Option<i64>;
fn get_bool(&self, _prop: &str) -> Option<bool>;
}

/// A cheap reference-to-reference conversion. Used to convert a value to a
Expand Down
3 changes: 2 additions & 1 deletion strum_macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "strum_macros"
version = "0.26.4"
edition = "2018"
edition = "2021"
authors = ["Peter Glotfelty <[email protected]>"]
license = "MIT"

Expand All @@ -13,6 +13,7 @@ documentation = "https://docs.rs/strum"
homepage = "https://github.com/Peternator7/strum"
repository = "https://github.com/Peternator7/strum"
readme = "../README.md"
rust-version = "1.66.1"

[lib]
proc-macro = true
Expand Down
4 changes: 2 additions & 2 deletions strum_macros/src/helpers/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ pub enum VariantMeta {
},
Props {
kw: kw::props,
props: Vec<(LitStr, LitStr)>,
props: Vec<(LitStr, Lit)>,
},
}

Expand Down Expand Up @@ -267,7 +267,7 @@ impl Parse for VariantMeta {
}
}

struct Prop(Ident, LitStr);
struct Prop(Ident, Lit);

impl Parse for Prop {
fn parse(input: ParseStream) -> syn::Result<Self> {
Expand Down
2 changes: 1 addition & 1 deletion strum_macros/src/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use syn::spanned::Spanned;
pub fn missing_parse_err_attr_error() -> syn::Error {
syn::Error::new(
Span::call_site(),
"`parse_err_ty` and `parse_err_fn` attribute is both required.",
"`parse_err_ty` and `parse_err_fn` attributes are both required.",
)
}

Expand Down
6 changes: 3 additions & 3 deletions strum_macros/src/helpers/variant_props.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::default::Default;
use syn::{Ident, LitStr, Variant};
use syn::{Ident, Lit, LitStr, Variant};

use super::case_style::{CaseStyle, CaseStyleHelpers};
use super::metadata::{kw, VariantExt, VariantMeta};
Expand All @@ -18,7 +18,7 @@ pub struct StrumVariantProperties {
pub message: Option<LitStr>,
pub detailed_message: Option<LitStr>,
pub documentation: Vec<LitStr>,
pub string_props: Vec<(LitStr, LitStr)>,
pub props: Vec<(LitStr, Lit)>,
serialize: Vec<LitStr>,
pub to_string: Option<LitStr>,
ident: Option<Ident>,
Expand Down Expand Up @@ -143,7 +143,7 @@ impl HasStrumVariantProperties for Variant {
output.ascii_case_insensitive = Some(value);
}
VariantMeta::Props { props, .. } => {
output.string_props.extend(props);
output.props.extend(props);
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions strum_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,8 @@ pub fn variant_names_deprecated(input: proc_macro::TokenStream) -> proc_macro::T
/// meaning that the variants must not have any data.
///
/// ```
/// use strum::VariantArray;
/// use strum::VariantArray as _;
/// use strum_macros::VariantArray;
///
/// #[derive(VariantArray, Debug, PartialEq, Eq)]
/// enum Op {
Expand Down Expand Up @@ -830,8 +831,8 @@ pub fn enum_properties(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
/// ```
/// // Bring trait into scope
/// use std::str::FromStr;
/// use strum::{IntoEnumIterator, EnumMessage};
/// use strum_macros::{EnumDiscriminants, EnumIter, EnumString};
/// use strum::{IntoEnumIterator, EnumMessage as _};
/// use strum_macros::{EnumDiscriminants, EnumIter, EnumString, EnumMessage};
///
/// #[derive(Debug)]
/// struct NonDefault;
Expand Down
84 changes: 68 additions & 16 deletions strum_macros/src/macros/enum_properties.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
use std::collections::HashMap;

use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Fields};
use syn::{Data, DeriveInput, Fields, Lit};

use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};

#[derive(Hash, PartialEq, Eq)]
enum PropertyType {
String,
Integer,
Bool,
}

const PROPERTY_TYPES: [PropertyType; 3] = [
PropertyType::String,
PropertyType::Integer,
PropertyType::Bool,
];

pub fn enum_properties_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
let name = &ast.ident;
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
Expand All @@ -14,11 +29,12 @@ pub fn enum_properties_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
let type_properties = ast.get_type_properties()?;
let strum_module_path = type_properties.crate_module_path();

let mut arms = Vec::new();
let mut built_arms: HashMap<_, _> = PROPERTY_TYPES.iter().map(|p| (p, Vec::new())).collect();

for variant in variants {
let ident = &variant.ident;
let variant_properties = variant.get_variant_properties()?;
let mut string_arms = Vec::new();
let mut arms: HashMap<_, _> = PROPERTY_TYPES.iter().map(|p| (p, Vec::new())).collect();
// But you can disable the messages.
if variant_properties.disabled.is_some() {
continue;
Expand All @@ -30,33 +46,69 @@ pub fn enum_properties_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
Fields::Named(..) => quote! { {..} },
};

for (key, value) in variant_properties.string_props {
string_arms.push(quote! { #key => ::core::option::Option::Some( #value )});
}
for (key, value) in variant_properties.props {
let property_type = match value {
Lit::Str(..) => PropertyType::String,
Lit::Bool(..) => PropertyType::Bool,
Lit::Int(..) => PropertyType::Integer,
_ => todo!("TODO"),
};

string_arms.push(quote! { _ => ::core::option::Option::None });
arms.get_mut(&property_type)
.unwrap()
.push(quote! { #key => ::core::option::Option::Some( #value )});
}

arms.push(quote! {
&#name::#ident #params => {
match prop {
#(#string_arms),*
for property in &PROPERTY_TYPES {
arms.get_mut(&property)
.unwrap()
.push(quote! { _ => ::core::option::Option::None });
let arms_as_string = &arms[property];
built_arms.get_mut(&property).unwrap().push(quote! {
&#name::#ident #params => {
match prop {
#(#arms_as_string),*
}
}
}
});
});
}
}

if arms.len() < variants.len() {
arms.push(quote! { _ => ::core::option::Option::None });
for (_, arms) in built_arms.iter_mut() {
if arms.len() < variants.len() {
arms.push(quote! { _ => ::core::option::Option::None });
}
}

let (built_string_arms, built_int_arms, built_bool_arms) = (
&built_arms[&PropertyType::String],
&built_arms[&PropertyType::Integer],
&built_arms[&PropertyType::Bool],
);

Ok(quote! {
impl #impl_generics #strum_module_path::EnumProperty for #name #ty_generics #where_clause {
#[inline]
fn get_str(&self, prop: &str) -> ::core::option::Option<&'static str> {
match self {
#(#arms),*
#(#built_string_arms),*
}
}

#[inline]
fn get_int(&self, prop: &str) -> ::core::option::Option<i64> {
match self {
#(#built_int_arms),*
}
}

#[inline]
fn get_bool(&self, prop: &str) -> ::core::option::Option<bool> {
match self {
#(#built_bool_arms),*
}
}

}
})
}
7 changes: 3 additions & 4 deletions strum_nostd_tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
[package]
name = "strum_nostd_tests"
version = "0.26.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
edition = "2021"
rust-version = "1.66.1"

[dependencies]
strum = { path = "../strum", features = ["derive"] }
strum_macros = { path = "../strum_macros", features = [] }

[dev-dependencies]
rustversion = "1.0"
rustversion = "1.0"
8 changes: 4 additions & 4 deletions strum_tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
[package]
name = "strum_tests"
version = "0.26.0"
edition = "2018"
edition = "2021"
authors = ["Peter Glotfelty <[email protected]>"]
rust-version = "1.66.1"

[features]
default = []
Expand All @@ -11,10 +12,9 @@ test_phf = ["strum/phf"]
[dependencies]
strum = { path = "../strum", features = ["derive"] }
strum_macros = { path = "../strum_macros", features = [] }
clap = "=2.33.0"
clap = "=4.2.7"
enum_variant_type = "=0.2.0"
structopt = "0.2.18"
bitflags = "=1.2"
structopt = "=0.3.26"

[dev-dependencies]
rustversion = "1.0"
27 changes: 27 additions & 0 deletions strum_tests/tests/enum_props.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,30 @@ fn crate_module_path_test() {
let a = Test::A;
assert_eq!("value", a.get_str("key").unwrap());
}

#[derive(Debug, EnumProperty)]
enum TestGet {
#[strum(props(weight = 42, flat = true, big = false))]
A,
#[strum(props(weight = -42, flat = false))]
B,
C,
}

#[test]
fn get_bool_test() {
const BOOL_KEY: &str = "flat";
assert_eq!(Some(true), TestGet::A.get_bool(BOOL_KEY));
assert_eq!(Some(false), TestGet::B.get_bool(BOOL_KEY));
assert_eq!(None, TestGet::C.get_bool(BOOL_KEY));
assert_eq!(None, TestGet::A.get_bool("weight"));
}

#[test]
fn get_int_test() {
const INT_KEY: &str = "weight";
assert_eq!(Some(42), TestGet::A.get_int(INT_KEY));
assert_eq!(Some(-42), TestGet::B.get_int(INT_KEY));
assert_eq!(None, TestGet::C.get_int(INT_KEY));
assert_eq!(None, TestGet::A.get_int("flat"));
}
10 changes: 5 additions & 5 deletions strum_tests/tests/enum_variant_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ fn clap_and_structopt() {
#[structopt(
long = "color",
default_value = "Color::Blue",
raw(possible_values = "Color::VARIANTS")
possible_values = Color::VARIANTS
)]
color: Color,
}
Expand All @@ -99,11 +99,11 @@ fn clap_and_structopt() {
&["red", "blue", "yellow", "rebecca-purple"]
);

let _clap_example = clap::App::new("app").arg(
clap::Arg::with_name("color")
let _clap_example = clap::Command::new("app").arg(
clap::Arg::new("color")
.long("color")
.possible_values(Color::VARIANTS)
.case_insensitive(true),
.value_names(Color::VARIANTS)
.ignore_case(true),
);
}

Expand Down

0 comments on commit 4beb2c9

Please sign in to comment.