diff --git a/strum_macros/src/helpers/metadata.rs b/strum_macros/src/helpers/metadata.rs index cd36f60..e8b3558 100644 --- a/strum_macros/src/helpers/metadata.rs +++ b/strum_macros/src/helpers/metadata.rs @@ -4,7 +4,7 @@ use syn::{ parse::{Parse, ParseStream}, punctuated::Punctuated, spanned::Spanned, - Attribute, DeriveInput, Ident, LitStr, Path, Token, Variant, + Attribute, DeriveInput, Ident, LitStr, Path, Token, Variant, Visibility, }; use super::case_style::CaseStyle; @@ -18,6 +18,7 @@ pub mod kw { // enum discriminant metadata custom_keyword!(derive); custom_keyword!(name); + custom_keyword!(vis); // variant metadata custom_keyword!(message); @@ -56,6 +57,7 @@ impl Spanned for EnumMeta { pub enum EnumDiscriminantsMeta { Derive { kw: kw::derive, paths: Vec }, Name { kw: kw::name, name: Ident }, + Vis { kw: kw::vis, vis: Visibility }, Other { path: Path, nested: TokenStream }, } @@ -76,6 +78,12 @@ impl Parse for EnumDiscriminantsMeta { parenthesized!(content in input); let name = content.parse()?; Ok(EnumDiscriminantsMeta::Name { kw, name }) + } else if input.peek(kw::vis) { + let kw = input.parse()?; + let content; + parenthesized!(content in input); + let vis = content.parse()?; + Ok(EnumDiscriminantsMeta::Vis { kw, vis }) } else { let path = input.parse()?; let content; @@ -91,6 +99,7 @@ impl Spanned for EnumDiscriminantsMeta { match self { EnumDiscriminantsMeta::Derive { kw, .. } => kw.span, EnumDiscriminantsMeta::Name { kw, .. } => kw.span, + EnumDiscriminantsMeta::Vis { kw, .. } => kw.span, EnumDiscriminantsMeta::Other { path, .. } => path.span(), } } diff --git a/strum_macros/src/helpers/type_props.rs b/strum_macros/src/helpers/type_props.rs index c942c5d..1e9c1e4 100644 --- a/strum_macros/src/helpers/type_props.rs +++ b/strum_macros/src/helpers/type_props.rs @@ -1,7 +1,7 @@ use proc_macro2::TokenStream; use quote::quote; use std::default::Default; -use syn::{DeriveInput, Ident, Path}; +use syn::{DeriveInput, Ident, Path, Visibility}; use super::case_style::CaseStyle; use super::metadata::{DeriveInputExt, EnumDiscriminantsMeta, EnumMeta}; @@ -17,6 +17,7 @@ pub struct StrumTypeProperties { pub discriminant_derives: Vec, pub discriminant_name: Option, pub discriminant_others: Vec, + pub discriminant_vis: Option, } impl HasTypeProperties for DeriveInput { @@ -41,6 +42,7 @@ impl HasTypeProperties for DeriveInput { } let mut name_kw = None; + let mut vis_kw = None; for meta in discriminants_meta { match meta { EnumDiscriminantsMeta::Derive { paths, .. } => { @@ -54,6 +56,14 @@ impl HasTypeProperties for DeriveInput { name_kw = Some(kw); output.discriminant_name = Some(name); } + EnumDiscriminantsMeta::Vis { vis, kw } => { + if let Some(fst_kw) = vis_kw { + return Err(occurrence_error(fst_kw, kw, "vis")); + } + + vis_kw = Some(kw); + output.discriminant_vis = Some(vis); + } EnumDiscriminantsMeta::Other { path, nested } => { output.discriminant_others.push(quote! { #path(#nested) }); } diff --git a/strum_macros/src/lib.rs b/strum_macros/src/lib.rs index f36a0e2..444794b 100644 --- a/strum_macros/src/lib.rs +++ b/strum_macros/src/lib.rs @@ -586,7 +586,7 @@ pub fn enum_properties(input: proc_macro::TokenStream) -> proc_macro::TokenStrea /// Variant1 { a: NonDefault }, /// } /// -/// // You can also rename the generated enum using the `#[strum_discriminants(name(OtherName))]` attribute: +/// // You can rename the generated enum using the `#[strum_discriminants(name(OtherName))]` attribute: /// # #[allow(dead_code)] /// #[derive(Debug, EnumDiscriminants)] /// #[strum_discriminants(derive(EnumIter))] @@ -607,6 +607,34 @@ pub fn enum_properties(input: proc_macro::TokenStream) -> proc_macro::TokenStrea /// MyVariants::iter().collect::>() /// ); /// ``` +/// +/// It is also possible to specify the visibility (e.g. `pub`/`pub(crate)`/etc.) +/// of the generated enum. By default, the generated enum inherits the +/// visibility of the parent enum it was generated from. +/// +/// ```nocompile +/// use strum_macros::EnumDiscriminants; +/// +/// // You can set the visibility of the generated enum using the `#[strum_discriminants(vis(..))]` attribute: +/// mod inner { +/// use strum_macros::EnumDiscriminants; +/// +/// # #[allow(dead_code)] +/// #[derive(Debug, EnumDiscriminants)] +/// #[strum_discriminants(vis(pub))] +/// #[strum_discriminants(name(PubDiscriminants))] +/// enum PrivateEnum { +/// Variant0(bool), +/// Variant1 { a: bool }, +/// } +/// } +/// +/// // test visibility example, `PrivateEnum` should not be accessible here +/// assert_ne!( +/// inner::PubDiscriminants::Variant0, +/// inner::PubDiscriminants::Variant1, +/// ); +/// ``` #[cfg_attr( feature = "verbose-enumdiscriminants-name", proc_macro_derive(StrumEnumDiscriminants, attributes(strum, strum_discriminants)) diff --git a/strum_macros/src/macros/enum_discriminants.rs b/strum_macros/src/macros/enum_discriminants.rs index 991b8f7..1aac79e 100644 --- a/strum_macros/src/macros/enum_discriminants.rs +++ b/strum_macros/src/macros/enum_discriminants.rs @@ -36,6 +36,7 @@ pub fn enum_discriminants_inner(ast: &DeriveInput) -> syn::Result { ); let discriminants_name = type_properties.discriminant_name.unwrap_or(default_name); + let discriminants_vis = type_properties.discriminant_vis.unwrap_or_else(|| vis.clone()); // Pass through all other attributes let pass_though_attributes = type_properties.discriminant_others; @@ -127,7 +128,7 @@ pub fn enum_discriminants_inner(ast: &DeriveInput) -> syn::Result { /// Auto-generated discriminant enum variants #derives #(#[ #pass_though_attributes ])* - #vis enum #discriminants_name { + #discriminants_vis enum #discriminants_name { #(#discriminants),* } diff --git a/strum_tests/build.rs b/strum_tests/build.rs index 9cf597e..2f7ff23 100644 --- a/strum_tests/build.rs +++ b/strum_tests/build.rs @@ -2,5 +2,6 @@ fn main() { // Check if version of rustc is >= 1.34 if let Some(true) = version_check::is_min_version("1.34.0") { println!("cargo:rustc-cfg=try_from"); + println!("cargo:rustc-cfg=bare_pub"); } } diff --git a/strum_tests/tests/enum_discriminants.rs b/strum_tests/tests/enum_discriminants.rs index 04af86b..0bdd69b 100644 --- a/strum_tests/tests/enum_discriminants.rs +++ b/strum_tests/tests/enum_discriminants.rs @@ -215,3 +215,45 @@ fn filter_variant_attributes_pass_through() { VariantFilterAttrDiscs::from_str("dark_black").unwrap() ); } + +#[cfg(bare_pub)] +#[test] +fn override_visibility() { + mod private { + use super::*; + + #[allow(dead_code)] + #[derive(EnumDiscriminants)] + #[strum_discriminants(name(PubDiscriminants), vis(pub))] + enum PrivateEnum { + VariantA(bool), + VariantB(bool), + } + } + + assert_ne!( + private::PubDiscriminants::VariantA, + private::PubDiscriminants::VariantB, + ); +} + +#[cfg(not(bare_pub))] +#[test] +fn override_visibility() { + mod private { + use super::*; + + #[allow(dead_code)] + #[derive(EnumDiscriminants)] + #[strum_discriminants(name(PubDiscriminants), vis(r#pub))] + enum PrivateEnum { + VariantA(bool), + VariantB(bool), + } + } + + assert_ne!( + private::PubDiscriminants::VariantA, + private::PubDiscriminants::VariantB, + ); +}