derive(FromRepr)
This commit is contained in:
@@ -6,12 +6,13 @@ members = [
|
|||||||
"sub/core",
|
"sub/core",
|
||||||
"sub/libm",
|
"sub/libm",
|
||||||
"sub/pe",
|
"sub/pe",
|
||||||
"sub/winu"
|
"sub/winu",
|
||||||
|
"sub/_macros"
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
sub_sample = { path = "sub/sample" }
|
|
||||||
sub_core = { path = "sub/core" }
|
sub_core = { path = "sub/core" }
|
||||||
sub_libm = { path = "sub/libm" }
|
sub_libm = { path = "sub/libm" }
|
||||||
sub_pe = { path = "sub/pe" }
|
sub_pe = { path = "sub/pe" }
|
||||||
sub_winu = { path = "sub/winu" }
|
sub_winu = { path = "sub/winu" }
|
||||||
|
sub_macros = { path = "sub/_macros" }
|
||||||
|
|||||||
13
sub/_macros/Cargo.toml
Normal file
13
sub/_macros/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "sub_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
quote = "1"
|
||||||
|
proc-macro2 = "1"
|
||||||
|
syn = { version = "2", features = ["full"] }
|
||||||
|
|
||||||
64
sub/_macros/src/from_repr.rs
Normal file
64
sub/_macros/src/from_repr.rs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
|
const VALID: &[&'static str] = &[
|
||||||
|
"u8", "u16", "u32", "u64", "u128",
|
||||||
|
"i8", "i16", "i32", "i64", "i128",
|
||||||
|
];
|
||||||
|
|
||||||
|
pub fn derive_from_repr(input: TokenStream) -> TokenStream {
|
||||||
|
let syn::DeriveInput { attrs, ident, data, .. } = syn::parse_macro_input!(input);
|
||||||
|
let edata = match data {
|
||||||
|
syn::Data::Enum(edata) => edata,
|
||||||
|
_invalid => return TokenStream::from(quote::quote! { compile_error!("The identifier should not be empty"); }),
|
||||||
|
};
|
||||||
|
|
||||||
|
let repr_type = attrs.iter()
|
||||||
|
.filter_map(|attribute| {
|
||||||
|
// verify it is a repr type
|
||||||
|
attribute.path().get_ident()?
|
||||||
|
.to_string().eq("repr")
|
||||||
|
.then_some(())?;
|
||||||
|
let mut repr_type: Option<syn::Path> = None;
|
||||||
|
let _ = attribute.parse_nested_meta(|meta| {
|
||||||
|
for &v in VALID {
|
||||||
|
if meta.path.is_ident(v) {
|
||||||
|
repr_type = Some(meta.path);
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(meta.error("unrecognized repr"))
|
||||||
|
});
|
||||||
|
repr_type
|
||||||
|
}).next();
|
||||||
|
|
||||||
|
let repr = match repr_type {
|
||||||
|
Some(repr) => repr,
|
||||||
|
None => {
|
||||||
|
return TokenStream::from(quote::quote! {
|
||||||
|
compile_error!("PrimitiveEnum requires the #[repr(u/i*)] attribute");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let values = edata.variants.iter().filter_map(|variant| {
|
||||||
|
if let Some((_, desc)) = &variant.discriminant {
|
||||||
|
let variant = &variant.ident;
|
||||||
|
Some(quote::quote! {
|
||||||
|
#desc => Some(Self::#variant),
|
||||||
|
})
|
||||||
|
} else { None }
|
||||||
|
});
|
||||||
|
|
||||||
|
let name = &ident;
|
||||||
|
TokenStream::from(quote::quote! {
|
||||||
|
impl x::FromRepr for #name {
|
||||||
|
type Repr = #repr;
|
||||||
|
fn from_repr(repr: #repr) -> Option<Self> {
|
||||||
|
match repr {
|
||||||
|
#(#values)*
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
14
sub/_macros/src/lib.rs
Normal file
14
sub/_macros/src/lib.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
mod from_repr;
|
||||||
|
|
||||||
|
|
||||||
|
#[proc_macro_derive(FromRepr)]
|
||||||
|
pub fn derive_from_repr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
from_repr::derive_from_repr(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -6,13 +6,16 @@ edition = "2021"
|
|||||||
[features]
|
[features]
|
||||||
default = ["core"]
|
default = ["core"]
|
||||||
core = ["sub_core"]
|
core = ["sub_core"]
|
||||||
|
macros = ["sub_macros"]
|
||||||
libm = ["sub_libm"]
|
libm = ["sub_libm"]
|
||||||
pe = ["sub_pe"]
|
pe = ["sub_pe"]
|
||||||
|
|
||||||
|
|
||||||
winuser = ["sub_winu", "pe", "sub_pe/windows"]
|
winuser = ["sub_winu", "pe", "sub_pe/windows"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
sub_core = { workspace = true, optional = true }
|
sub_core = { workspace = true, optional = true }
|
||||||
sub_libm = { workspace = true, optional = true}
|
sub_libm = { workspace = true, optional = true}
|
||||||
sub_pe = { workspace = true, optional = true }
|
sub_pe = { workspace = true, optional = true }
|
||||||
sub_winu = { workspace = true, optional = true }
|
sub_winu = { workspace = true, optional = true }
|
||||||
|
sub_macros = { workspace = true, optional = true }
|
||||||
@@ -14,8 +14,13 @@ macro_rules! import {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
import!(sub_core, core, "core");
|
import!(sub_core, core, "core");
|
||||||
import!(sub_libm, libm, "libm");
|
import!(sub_libm, libm, "libm");
|
||||||
import!(sub_pe, pe, "pe");
|
import!(sub_pe, pe, "pe");
|
||||||
import!(sub_winu, win, "winuser");
|
import!(sub_winu, win, "winuser");
|
||||||
|
|
||||||
|
/// the macro crate is a proc macro, so it is a bit different.
|
||||||
|
#[cfg(feature = "macros")]
|
||||||
|
pub use sub_macros::{
|
||||||
|
FromRepr
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user