Skip to content

Commit e21dc0e

Browse files
committed
experimental enum codegen.
1 parent da30a65 commit e21dc0e

File tree

2 files changed

+95
-21
lines changed

2 files changed

+95
-21
lines changed

src/generate/enumm.rs

Lines changed: 93 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::HashMap;
2+
13
use anyhow::Result;
24
use proc_macro2::TokenStream;
35
use proc_macro2::{Ident, Span};
@@ -10,7 +12,9 @@ use super::sorted;
1012

1113
pub fn render(_opts: &super::Options, _ir: &IR, e: &Enum, path: &str) -> Result<TokenStream> {
1214
let span = Span::call_site();
13-
let mut items = TokenStream::new();
15+
16+
// For very "sparse" enums, generate a newtype wrapping the uX.
17+
let newtype = e.bit_size > 8 || (e.variants.len() < 6 && e.bit_size > 4);
1418

1519
let ty = match e.bit_size {
1620
1..=8 => quote!(u8),
@@ -20,30 +24,100 @@ pub fn render(_opts: &super::Options, _ir: &IR, e: &Enum, path: &str) -> Result<
2024
_ => panic!("Invalid bit_size {}", e.bit_size),
2125
};
2226

23-
for f in sorted(&e.variants, |f| (f.value, f.name.clone())) {
24-
let name = Ident::new(&f.name, span);
25-
let value = util::hex(f.value);
26-
let doc = util::doc(&f.description);
27-
items.extend(quote!(
28-
#doc
29-
pub const #name: Self = Self(#value);
30-
));
31-
}
32-
3327
let (_, name) = super::split_path(path);
3428
let name = Ident::new(name, span);
3529
let doc = util::doc(&e.description);
30+
let mask = util::hex(1u64.wrapping_shl(e.bit_size).wrapping_sub(1));
31+
32+
let mut out = TokenStream::new();
3633

37-
let out = quote! {
38-
#doc
39-
#[repr(transparent)]
40-
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
41-
pub struct #name (pub #ty);
34+
if newtype {
35+
let mut items = TokenStream::new();
4236

43-
impl #name {
44-
#items
37+
for f in sorted(&e.variants, |f| (f.value, f.name.clone())) {
38+
let name = Ident::new(&f.name, span);
39+
let value = util::hex(f.value);
40+
let doc = util::doc(&f.description);
41+
items.extend(quote!(
42+
#doc
43+
pub const #name: Self = Self(#value);
44+
));
4545
}
46-
};
46+
47+
out.extend(quote! {
48+
#doc
49+
#[repr(transparent)]
50+
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
51+
pub struct #name (pub #ty);
52+
53+
impl #name {
54+
#items
55+
}
56+
57+
impl #name {
58+
pub const fn from_bits(val: #ty) -> #name {
59+
Self(val & #mask)
60+
}
61+
62+
pub const fn to_bits(self) -> #ty {
63+
self.0
64+
}
65+
}
66+
});
67+
} else {
68+
let variants: HashMap<_, _> = e.variants.iter().map(|v| (v.value, v)).collect();
69+
let mut items = TokenStream::new();
70+
for val in 0..(1 << e.bit_size) {
71+
if let Some(f) = variants.get(&val) {
72+
let name = Ident::new(&f.name, span);
73+
let value = util::hex(f.value);
74+
let doc = util::doc(&f.description);
75+
items.extend(quote!(
76+
#doc
77+
#name = #value,
78+
));
79+
} else {
80+
let name = Ident::new(&format!("_RESERVED_{:x}", val), span);
81+
let value = util::hex(val);
82+
items.extend(quote!(
83+
#name = #value,
84+
));
85+
}
86+
}
87+
88+
out.extend(quote! {
89+
#doc
90+
#[repr(#ty)]
91+
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
92+
pub enum #name {
93+
#items
94+
}
95+
96+
impl #name {
97+
pub const fn from_bits(val: #ty) -> #name {
98+
unsafe { core::mem::transmute(val & #mask) }
99+
}
100+
101+
pub const fn to_bits(self) -> #ty {
102+
unsafe { core::mem::transmute(self) }
103+
}
104+
}
105+
});
106+
}
107+
108+
out.extend(quote! {
109+
impl From<#ty> for #name {
110+
fn from(val: #ty) -> #name {
111+
#name::from_bits(val)
112+
}
113+
}
114+
115+
impl From<#name> for #ty {
116+
fn from(val: #name) -> #ty {
117+
#name::to_bits(val)
118+
}
119+
}
120+
});
47121

48122
Ok(out)
49123
}

src/generate/fieldset.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ pub fn render(_opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Res
4545
};
4646

4747
field_ty = util::relative_path(e_path, path);
48-
to_bits = quote!(val.0 as #ty);
49-
from_bits = quote!(#field_ty(val as #enum_ty));
48+
to_bits = quote!(val.to_bits() as #ty);
49+
from_bits = quote!(#field_ty::from_bits(val as #enum_ty));
5050
} else {
5151
field_ty = match f.bit_size {
5252
1 => quote!(bool),

0 commit comments

Comments
 (0)