Skip to content

Commit

Permalink
Add the prefix attribute (#296)
Browse files Browse the repository at this point in the history
* implement prefix enum attribute

* `cargo fmt`

* undo changes

---------

Co-authored-by: Peter Glotfelty <glotfelty.2@osu.edu>
  • Loading branch information
chanman3388 and Peternator7 authored Dec 28, 2023
1 parent ffe8873 commit 216e4de
Show file tree
Hide file tree
Showing 12 changed files with 78 additions and 20 deletions.
3 changes: 2 additions & 1 deletion strum_macros/src/helpers/case_style.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use heck::{
ToKebabCase, ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToTitleCase, ToUpperCamelCase, ToTrainCase,
ToKebabCase, ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToTitleCase, ToTrainCase,
ToUpperCamelCase,
};
use std::str::FromStr;
use syn::{
Expand Down
10 changes: 10 additions & 0 deletions strum_macros/src/helpers/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod kw {
// enum metadata
custom_keyword!(serialize_all);
custom_keyword!(use_phf);
custom_keyword!(prefix);

// enum discriminant metadata
custom_keyword!(derive);
Expand Down Expand Up @@ -45,6 +46,10 @@ pub enum EnumMeta {
crate_module_path: Path,
},
UsePhf(kw::use_phf),
Prefix {
kw: kw::prefix,
prefix: LitStr,
},
}

impl Parse for EnumMeta {
Expand All @@ -69,6 +74,11 @@ impl Parse for EnumMeta {
Ok(EnumMeta::AsciiCaseInsensitive(input.parse()?))
} else if lookahead.peek(kw::use_phf) {
Ok(EnumMeta::UsePhf(input.parse()?))
} else if lookahead.peek(kw::prefix) {
let kw = input.parse::<kw::prefix>()?;
input.parse::<Token![=]>()?;
let prefix = input.parse()?;
Ok(EnumMeta::Prefix { kw, prefix })
} else {
Err(lookahead.error())
}
Expand Down
2 changes: 1 addition & 1 deletion strum_macros/src/helpers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub use self::case_style::{CaseStyleHelpers, snakify};
pub use self::case_style::{snakify, CaseStyleHelpers};
pub use self::type_props::HasTypeProperties;
pub use self::variant_props::HasStrumVariantProperties;

Expand Down
12 changes: 11 additions & 1 deletion strum_macros/src/helpers/type_props.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use proc_macro2::TokenStream;
use quote::quote;
use std::default::Default;
use syn::{parse_quote, DeriveInput, Ident, Path, Visibility};
use syn::{parse_quote, DeriveInput, Ident, LitStr, Path, Visibility};

use super::case_style::CaseStyle;
use super::metadata::{DeriveInputExt, EnumDiscriminantsMeta, EnumMeta};
Expand All @@ -21,6 +21,7 @@ pub struct StrumTypeProperties {
pub discriminant_others: Vec<TokenStream>,
pub discriminant_vis: Option<Visibility>,
pub use_phf: bool,
pub prefix: Option<LitStr>,
pub enum_repr: Option<TokenStream>,
}

Expand All @@ -35,6 +36,7 @@ impl HasTypeProperties for DeriveInput {
let mut ascii_case_insensitive_kw = None;
let mut use_phf_kw = None;
let mut crate_module_path_kw = None;
let mut prefix_kw = None;
for meta in strum_meta {
match meta {
EnumMeta::SerializeAll { case_style, kw } => {
Expand Down Expand Up @@ -72,6 +74,14 @@ impl HasTypeProperties for DeriveInput {
crate_module_path_kw = Some(kw);
output.crate_module_path = Some(crate_module_path);
}
EnumMeta::Prefix { prefix, kw } => {
if let Some(fst_kw) = prefix_kw {
return Err(occurrence_error(fst_kw, kw, "prefix"));
}

prefix_kw = Some(kw);
output.prefix = Some(prefix);
}
}
}

Expand Down
19 changes: 11 additions & 8 deletions strum_macros/src/macros/enum_messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,17 @@ pub fn enum_message_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
if !documentation.is_empty() {
let params = params.clone();
// Strip a single leading space from each documentation line.
let documentation: Vec<LitStr> = documentation.iter().map(|lit_str| {
let line = lit_str.value();
if line.starts_with(' ') {
LitStr::new(&line.as_str()[1..], lit_str.span())
} else {
lit_str.clone()
}
}).collect();
let documentation: Vec<LitStr> = documentation
.iter()
.map(|lit_str| {
let line = lit_str.value();
if line.starts_with(' ') {
LitStr::new(&line.as_str()[1..], lit_str.span())
} else {
lit_str.clone()
}
})
.collect();
if documentation.len() == 1 {
let text = &documentation[0];
documentation_arms
Expand Down
4 changes: 2 additions & 2 deletions strum_macros/src/macros/enum_variant_names.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput};
use syn::{Data, DeriveInput, LitStr};

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

Expand All @@ -24,7 +24,7 @@ pub fn enum_variant_names_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
let props = v.get_variant_properties()?;
Ok(props.get_preferred_name(type_properties.case_style))
})
.collect::<syn::Result<Vec<_>>>()?;
.collect::<syn::Result<Vec<LitStr>>>()?;

Ok(quote! {
impl #impl_generics #strum_module_path::VariantNames for #name #ty_generics #where_clause {
Expand Down
7 changes: 5 additions & 2 deletions strum_macros/src/macros/strings/display.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Fields};
use syn::{Data, DeriveInput, Fields, LitStr};

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

Expand All @@ -24,7 +24,10 @@ pub fn display_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
}

// Look at all the serialize attributes.
let output = variant_properties.get_preferred_name(type_properties.case_style);
let mut output = variant_properties.get_preferred_name(type_properties.case_style);
if let Some(prefix) = &type_properties.prefix {
output = LitStr::new(&(prefix.value() + &output.value()), output.span());
}

let params = match variant.fields {
Fields::Unit => quote! {},
Expand Down
2 changes: 1 addition & 1 deletion strum_macros/src/macros/strings/from_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub fn from_string_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
phf_exact_match_arms.push(quote! { #serialization => #name::#ident #params, });

if is_ascii_case_insensitive {
// Store the lowercase and UPPERCASE variants in the phf map to capture
// Store the lowercase and UPPERCASE variants in the phf map to capture
let ser_string = serialization.value();

let lower =
Expand Down
9 changes: 7 additions & 2 deletions strum_tests/tests/enum_is.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@ enum LifeTimeTest<'a>{
enum Foo {
Unit,
Named0 {},
Named1 { _a: char },
Named2 { _a: u32, _b: String },
Named1 {
_a: char,
},
Named2 {
_a: u32,
_b: String,
},
Unnamed0(),
Unnamed1(Option<u128>),
Unnamed2(bool, u8),
Expand Down
5 changes: 4 additions & 1 deletion strum_tests/tests/enum_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ fn only_detailed_message() {

#[test]
fn documentation() {
assert_eq!("I eat birds.\n\nAnd fish.\n", (Pets::Cat).get_documentation().unwrap());
assert_eq!(
"I eat birds.\n\nAnd fish.\n",
(Pets::Cat).get_documentation().unwrap()
);
assert_eq!("I'm a fish.", (Pets::Fish).get_documentation().unwrap());
assert_eq!("I'm a bird.", (Pets::Bird).get_documentation().unwrap());
}
Expand Down
5 changes: 4 additions & 1 deletion strum_tests/tests/enum_try_as.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ enum Foo {
#[allow(dead_code)]
Unit,
#[allow(dead_code)]
Named { _a: u32, _b: String },
Named {
_a: u32,
_b: String,
},
}

#[test]
Expand Down
20 changes: 20 additions & 0 deletions strum_tests/tests/prefix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use strum::{Display, EnumString};

#[allow(dead_code)]
#[derive(Debug, EnumString, Display)]
#[strum(prefix = "colour/")]
enum Color {
#[strum(to_string = "RedRed")]
Red,
#[strum(serialize = "b", to_string = "blue")]
Blue { hue: usize },
#[strum(serialize = "y", serialize = "yellow")]
Yellow,
#[strum(default)]
Green(String),
}

#[test]
fn prefix_redred() {
assert_eq!(String::from("colour/RedRed"), (Color::Red).to_string());
}

0 comments on commit 216e4de

Please sign in to comment.