@@ -157,8 +157,8 @@ use proc_macro2::{Ident, Span};
157157use proc_macro_roids:: { namespace_parameters, FieldsExt } ;
158158use quote:: quote;
159159use syn:: {
160- parse_macro_input, parse_quote, Attribute , Data , DataEnum , DeriveInput , Field , Fields , Lit ,
161- Meta , NestedMeta , Path ,
160+ parse_macro_input, parse_quote, Attribute , Data , DataEnum , DeriveInput , Field , Fields , LitStr ,
161+ Meta , Path ,
162162} ;
163163
164164/// Attributes that should be copied across.
@@ -187,52 +187,70 @@ fn enum_variant_type_impl(ast: DeriveInput) -> proc_macro2::TokenStream {
187187 let mut wrap_in_module = None :: < Ident > ;
188188 let mut derive_for_all_variants = None :: < Attribute > ;
189189 let mut marker_trait_paths = Vec :: < Path > :: new ( ) ;
190+ let mut repr_c = false ;
190191
191192 for attr in ast. attrs . iter ( ) {
192- if attr. path . is_ident ( "evt" ) {
193- if let Ok ( Meta :: List ( list) ) = attr. parse_meta ( ) {
194- for item in list. nested . iter ( ) {
195- match item {
196- NestedMeta :: Meta ( Meta :: NameValue ( name_value) ) => {
197- if let ( true , Lit :: Str ( lit_str) ) =
198- ( name_value. path . is_ident ( "module" ) , & name_value. lit )
199- {
200- wrap_in_module =
201- Some ( Ident :: new ( & lit_str. value ( ) , Span :: call_site ( ) ) ) ;
202- } else {
203- panic ! ( "Expected `evt` attribute argument in the form: `#[evt(module = \" some_module_name\" )]`" ) ;
204- }
205- }
206- NestedMeta :: Meta ( Meta :: List ( list) ) => {
207- if list. path . is_ident ( "derive" ) {
208- let items = list. nested . iter ( ) . map ( |nested_meta| {
209- if let NestedMeta :: Meta ( Meta :: Path ( path) ) = nested_meta {
210- path. clone ( )
211- } else {
212- panic ! ( "Expected `evt` attribute argument in the form: `#[evt(derive(Clone, Debug))]`" ) ;
213- }
214- } ) ;
215- derive_for_all_variants = Some ( parse_quote ! {
216- #[ derive( #( #items) , * ) ]
217- } ) ;
218- } else if list. path . is_ident ( "implement_marker_traits" ) {
219- marker_trait_paths = list. nested
220- . iter ( )
221- . map ( |nested| if let NestedMeta :: Meta ( Meta :: Path ( path) ) = nested {
222- path. clone ( )
223- } else {
224- panic ! ( "Expected `evt` attribute argument in the form #[evt(implement_marker_traits(MarkerTrait1, MarkerTrait2))]" ) ;
225- } ) . collect ( ) ;
226- }
227- }
228- _ => {
229- panic ! ( "Unexpected usage of `evt` attribute, please see examples at:\n <https://docs.rs/enum_variant_type/>" )
230- }
193+ if attr. path ( ) . is_ident ( "repr" ) {
194+ // wrap each enum struct in "repr(C)" ?
195+ if let Meta :: List ( list) = & attr. meta {
196+ list. parse_nested_meta ( |parse_nested_meta| {
197+ if parse_nested_meta. path . is_ident ( "C" ) {
198+ repr_c = true ;
231199 }
232- }
233- } else {
234- panic ! ( "Unexpected usage of `evt` attribute, please see examples at: \n <https://docs.rs/enum_variant_type/>" )
200+ Ok ( ( ) )
201+ } )
202+ . unwrap_or_else ( |e| panic ! ( "Failed to parse repr attribute. Error: {}" , e ) ) ;
235203 }
204+ } else if attr. path ( ) . is_ident ( "evt" ) {
205+ attr. parse_nested_meta ( |nested_meta| {
206+ if nested_meta. path . is_ident ( "module" ) {
207+ // `#[evt(module = \"some_module_name\")]`
208+ let module_name: LitStr = nested_meta
209+ . value ( )
210+ . and_then ( |value| value. parse ( ) )
211+ . unwrap_or_else ( |e| {
212+ panic ! (
213+ "Expected `evt` attribute argument in the form: \
214+ `#[evt(module = \" some_module_name\" )]`. Error: {}",
215+ e
216+ )
217+ } ) ;
218+
219+ wrap_in_module = Some ( Ident :: new ( & module_name. value ( ) , Span :: call_site ( ) ) ) ;
220+ return Ok ( ( ) ) ;
221+ }
222+ // `#[evt(derive(Clone, Debug))]`
223+ if nested_meta. path . is_ident ( "derive" ) {
224+ let mut items = Vec :: new ( ) ;
225+ nested_meta. parse_nested_meta ( |parse_nested_meta| {
226+ items. push ( parse_nested_meta. path ) ;
227+ Ok ( ( ) )
228+ } ) ?;
229+
230+ derive_for_all_variants = Some ( parse_quote ! {
231+ #[ derive( #( #items) , * ) ]
232+ } ) ;
233+ return Ok ( ( ) ) ;
234+ }
235+
236+ // `#[evt(implement_marker_traits(MarkerTrait1, MarkerTrait2))]`
237+ if nested_meta. path . is_ident ( "implement_marker_traits" ) {
238+ nested_meta. parse_nested_meta ( |parse_nested_meta| {
239+ marker_trait_paths. push ( parse_nested_meta. path ) ;
240+ Ok ( ( ) )
241+ } ) ?;
242+
243+ return Ok ( ( ) ) ;
244+ }
245+
246+ panic ! (
247+ "Unexpected usage of `evt` attribute, please see examples at:\n \
248+ <https://docs.rs/enum_variant_type/>"
249+ )
250+ } )
251+ . unwrap_or_else ( |e| {
252+ panic ! ( "Failed to process evt attribute. Error: {}" , e) ;
253+ } ) ;
236254 }
237255 }
238256
@@ -251,12 +269,12 @@ fn enum_variant_type_impl(ast: DeriveInput) -> proc_macro2::TokenStream {
251269 . filter ( |attribute| {
252270 ATTRIBUTES_TO_COPY
253271 . iter ( )
254- . any ( |attr_to_copy| attribute. path . is_ident ( attr_to_copy) )
272+ . any ( |attr_to_copy| attribute. path ( ) . is_ident ( attr_to_copy) )
255273 } )
256274 . collect :: < Vec < & Attribute > > ( ) ;
257275
258276 let evt_meta_lists = namespace_parameters ( & variant. attrs , & ns) ;
259- let variant_struct_attrs = evt_meta_lists
277+ let mut variant_struct_attrs = evt_meta_lists
260278 . into_iter ( )
261279 . fold (
262280 proc_macro2:: TokenStream :: new ( ) ,
@@ -265,6 +283,13 @@ fn enum_variant_type_impl(ast: DeriveInput) -> proc_macro2::TokenStream {
265283 attrs_tokens
266284 } ,
267285 ) ;
286+
287+ if repr_c {
288+ variant_struct_attrs. extend ( quote ! {
289+ #[ repr( C ) ]
290+ } )
291+ }
292+
268293 let variant_fields = & variant. fields ;
269294
270295 // Need to attach visibility modifier to fields.
@@ -683,4 +708,64 @@ mod tests {
683708
684709 assert_eq ! ( expected_tokens. to_string( ) , actual_tokens. to_string( ) ) ;
685710 }
711+
712+ #[ test]
713+ fn derive_marker_repr ( ) {
714+ let ast: DeriveInput = parse_quote ! {
715+ #[ derive( Debug ) ]
716+ #[ repr( C ) ]
717+ pub enum MyEnum {
718+ A { i: i64 } ,
719+ B { i: i64 } ,
720+ }
721+ } ;
722+
723+ let actual_tokens = enum_variant_type_impl ( ast) ;
724+ let expected_tokens = quote ! {
725+
726+ #[ repr( C ) ]
727+ pub struct A { pub i: i64 , }
728+
729+ impl core:: convert:: From <A > for MyEnum {
730+ fn from( variant_struct: A ) -> Self {
731+ let A { i, } = variant_struct;
732+ MyEnum :: A { i, }
733+ }
734+ }
735+
736+ impl core:: convert:: TryFrom <MyEnum > for A {
737+ type Error = MyEnum ;
738+ fn try_from( enum_variant: MyEnum ) -> Result <Self , Self :: Error > {
739+ if let MyEnum :: A { i, } = enum_variant {
740+ core:: result:: Result :: Ok ( A { i, } )
741+ } else {
742+ core:: result:: Result :: Err ( enum_variant)
743+ }
744+ }
745+ }
746+
747+ #[ repr( C ) ]
748+ pub struct B { pub i: i64 , }
749+
750+ impl core:: convert:: From <B > for MyEnum {
751+ fn from( variant_struct: B ) -> Self {
752+ let B { i, } = variant_struct;
753+ MyEnum :: B { i, }
754+ }
755+ }
756+
757+ impl core:: convert:: TryFrom <MyEnum > for B {
758+ type Error = MyEnum ;
759+ fn try_from( enum_variant: MyEnum ) -> Result <Self , Self :: Error > {
760+ if let MyEnum :: B { i, } = enum_variant {
761+ core:: result:: Result :: Ok ( B { i, } )
762+ } else {
763+ core:: result:: Result :: Err ( enum_variant)
764+ }
765+ }
766+ }
767+ } ;
768+
769+ assert_eq ! ( expected_tokens. to_string( ) , actual_tokens. to_string( ) ) ;
770+ }
686771}
0 commit comments