Skip to content

Commit 92a3354

Browse files
authored
Merge pull request #12 from MageSlayer/master
2 parents 2da8f00 + 4585d20 commit 92a3354

4 files changed

Lines changed: 160 additions & 59 deletions

File tree

CHANGELOG.md

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,46 @@
11
# Changelog
22

3+
## unreleased
4+
5+
* Propagate `#[repr(C)]` onto generated structs. ([#11][#11], [#12][#12])
6+
* Update to `syn` `2`. ([#12][#12])
7+
8+
[#11]: https://github.com/azriel91/enum_variant_type/issues/11
9+
[#12]: https://github.com/azriel91/enum_variant_type/pull/12
10+
11+
312
## 0.3.1 (2021-12-22)
413

5-
* Import all items from parent scope when generating structs in submodule. ([#9])
14+
* Import all items from parent scope when generating structs in submodule. ([#9][#9])
15+
16+
[#9]: https://github.com/azriel91/enum_variant_type/pull/9
617

7-
[#9]: https://github.com/azriel91/enum_variant_type/pulls/9
818

919
## 0.3.0 (2021-12-18)
1020

11-
* `#[evt(derive(..))]` on enum adds derives on every variant. ([#6], [#7])
12-
* `#[evt(module = "module1")]` generates structs inside `mod module1`. ([#5], [#7])
13-
* `#[evt(implement_marker_traits(MarkerTrait1))]` on enum generates `impl MarkerTrait1` for all generated structs. ([#7])
21+
* `#[evt(derive(..))]` on enum adds derives on every variant. ([#6][#6], [#7][#7])
22+
* `#[evt(module = "module1")]` generates structs inside `mod module1`. ([#5][#5], [#7][#7])
23+
* `#[evt(implement_marker_traits(MarkerTrait1))]` on enum generates `impl MarkerTrait1` for all generated structs. ([#7][#7])
1424

1525
[#5]: https://github.com/azriel91/enum_variant_type/issues/5
1626
[#6]: https://github.com/azriel91/enum_variant_type/issues/6
17-
[#7]: https://github.com/azriel91/enum_variant_type/pulls/7
27+
[#7]: https://github.com/azriel91/enum_variant_type/pull/7
28+
1829

1930
## 0.2.1 (2021-04-24)
2031

21-
* `no-std` support by default. ([#2], [#3])
32+
* `no-std` support by default. ([#2][#2], [#3][#3])
2233

2334
[#2]: https://github.com/azriel91/enum_variant_type/issues/2
2435
[#3]: https://github.com/azriel91/enum_variant_type/pull/3
2536

37+
2638
## 0.2.0 (2020-01-13)
2739

2840
* Allow variants to be skipped using `#[evt(skip)]`.
2941
* ***Breaking:*** `#[evt(..)]` specifies the attributes to attach to the generated type (previously `#[evt_attr(..)]`).
3042

43+
3144
## 0.1.0 (2020-01-10)
3245

3346
* Generates unit, tuple, named struct for each enum variant.

Cargo.toml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@ path = "src/lib.rs"
1515
proc-macro = true
1616

1717
[dependencies]
18-
proc-macro2 = "1.0.34"
19-
proc_macro_roids = "0.7.0"
20-
quote = "1.0.10"
21-
syn = { version = "1.0.82", features = ["extra-traits", "visit"] }
18+
proc-macro2 = "1.0.106"
19+
proc_macro_roids = "0.8.0"
20+
quote = "1.0.44"
21+
syn = { version = "2.0.117", features = ["extra-traits", "visit"] }
2222

2323
[dev-dependencies]
24-
pretty_assertions = "1.0.0"
24+
pretty_assertions = "1.4.1"
25+
26+
[lints.rust]
27+
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(tarpaulin_include)"] }

rustfmt.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
format_code_in_doc_comments = true
2-
merge_imports = true
2+
imports_granularity = "crate"

src/lib.rs

Lines changed: 131 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ use proc_macro2::{Ident, Span};
157157
use proc_macro_roids::{namespace_parameters, FieldsExt};
158158
use quote::quote;
159159
use 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

Comments
 (0)