Skip to content

Commit

Permalink
Start work on #[repr(C, uX)] enums
Browse files Browse the repository at this point in the history
  • Loading branch information
p-avital committed Jun 22, 2024
1 parent 31dc42a commit b898cc6
Showing 1 changed file with 70 additions and 17 deletions.
87 changes: 70 additions & 17 deletions stabby-macros/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,33 @@ impl syn::parse::Parse for Repr {
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct FullRepr {
repr: Option<Repr>,
is_c: bool,
}
impl syn::parse::Parse for FullRepr {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let mut this = FullRepr {
repr: None,
is_c: false,
};
while !input.is_empty() {
match input.parse()? {
Repr::C => this.is_c = true,
repr => match this.repr {
None => this.repr = Some(repr),
Some(r) if repr == r => {}
_ => return Err(input.error("Determinants may only have one representation. You can use `#[repr(C, u8)]` to use a u8 as determinant while ensuring all variants have their data in C layout.")),
},
}
if !input.is_empty() {
let _: syn::token::Comma = input.parse()?;
}
}
Ok(this)
}
}

pub fn stabby(
attrs: Vec<Attribute>,
Expand All @@ -63,7 +90,7 @@ pub fn stabby(
) -> TokenStream {
let st = crate::tl_mod();
let unbound_generics = &generics.params;
let mut repr = None;
let mut repr: Option<FullRepr> = None;
let repr_ident = quote::format_ident!("repr");
let mut new_attrs = Vec::with_capacity(attrs.len());
for a in attrs {
Expand All @@ -77,6 +104,15 @@ pub fn stabby(
new_attrs.push(a)
}
}
if matches!(
repr,
Some(FullRepr {
repr: Some(Repr::Stabby),
is_c: true
})
) {
panic!("#[repr(C)] and #[repr(stabby)] connot be combined")
}
if data.variants.is_empty() {
todo!("empty enums are not supported by stabby YET")
}
Expand All @@ -87,31 +123,43 @@ pub fn stabby(
let mut report = Vec::new();
for variant in variants {
match &variant.fields {
syn::Fields::Named(f) if matches!(repr, Some(FullRepr { is_c: true, .. })) => {

Check failure on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run checks on macOS

unused variable: `f`

Check failure on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run checks on ubuntu-22.04

unused variable: `f`

Check failure on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run 1.72 checks on ubuntu-22.04

unused variable: `f`

Check failure on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run checks on macOS

unused variable: `f`

Check failure on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run 1.72 checks on ubuntu-22.04

unused variable: `f`

Check failure on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run checks on ubuntu-22.04

unused variable: `f`

Check failure on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run checks on windows-11

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on macOS

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on macOS

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on macOS

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on macOS

unused variable: `f`

Check failure on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run checks on windows-11

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on ubuntu-22.04

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on ubuntu-22.04

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on ubuntu-22.04

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on ubuntu-22.04

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on macOS

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on macOS

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on macOS

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on macOS

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on ubuntu-22.04

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on ubuntu-22.04

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on ubuntu-22.04

unused variable: `f`

Check warning on line 126 in stabby-macros/src/enums.rs

View workflow job for this annotation

GitHub Actions / Run tests on ubuntu-22.04

unused variable: `f`
todo!("stabby support for named fields is undergoing implementation...")
}
syn::Fields::Named(_) => {
panic!("stabby does not support named fields in enum variants")
panic!("stabby only supports named fields in #[repr(C, uX)] enums");
}
syn::Fields::Unnamed(f) => {
assert_eq!(
f.unnamed.len(),
1,
"stabby only supports one field per enum variant"
);
has_non_empty_fields = true;
let f = f.unnamed.first().unwrap();
let ty = &f.ty;
layout = quote!(#st::Union<#layout, core::mem::ManuallyDrop<#ty>>);
report.push((variant.ident.to_string(), ty));
if f.unnamed.len() != 1 && matches!(repr, Some(FullRepr { is_c: true, .. })) {
todo!(
"stabby support for multiple fields per enum is restricted to named fields"
)
} else {
assert_eq!(
f.unnamed.len(),
1,
"stabby only supports multiple fields per enum variant in #[repr(C, uX)] enums"
);
has_non_empty_fields = true;
let f = f.unnamed.first().unwrap();
let ty = &f.ty;
layout = quote!(#st::Union<#layout, core::mem::ManuallyDrop<#ty>>);
report.push((variant.ident.to_string(), ty));
}
}
syn::Fields::Unit => {
report.push((variant.ident.to_string(), &unit));
}
}
}
let report = crate::report(&report);
let repr = match repr {
let reprstr = match repr
.as_ref()
.and_then(|r| if r.is_c { Some(Repr::C) } else { r.repr })
{
None | Some(Repr::Stabby) => {
if !has_non_empty_fields {
panic!("Your enum doesn't have any field with values: use #[repr(C)] or #[repr(u*)] instead")
panic!("Your enum doesn't have any field with values: use #[repr(C)] or (preferably) #[repr(u*)] instead")
}
return repr_stabby(
&new_attrs,
Expand All @@ -135,13 +183,18 @@ pub fn stabby(
Some(Repr::I64) => "i64",
Some(Repr::Isize) => "isize",
};
let reprid = quote::format_ident!("{}", repr);
let reprid = quote::format_ident!("{}", reprstr);
let reprattr = if repr.map_or(false, |r| r.is_c) {
quote!(#[repr(C, #reprid)])
} else {
quote!(#[repr(#reprid)])
};
layout = quote!(#st::Tuple<#reprid, #layout>);
let sident = format!("{ident}");
let (report, report_bounds) = report;
quote! {
#(#new_attrs)*
#[repr(#reprid)]
#reprattr
#vis enum #ident #generics {
#variants
}
Expand All @@ -159,7 +212,7 @@ pub fn stabby(
module: #st::str::Str::new(core::module_path!()),
fields: unsafe {#st::StableLike::new(#report)},
version: 0,
tyty: #st::report::TyTy::Enum(#st::str::Str::new(#repr)),
tyty: #st::report::TyTy::Enum(#st::str::Str::new(#reprstr)),
};
const ID: u64 = #st::report::gen_id(Self::REPORT);
}
Expand Down

0 comments on commit b898cc6

Please sign in to comment.