mirror of
https://git.intege.rs/xlib/x.git
synced 2025-12-05 20:35:01 +00:00
from_repr
This commit is contained in:
64
proc_macro/src/from_repr.rs
Normal file
64
proc_macro/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 eset::FromRepr for #name {
|
||||||
|
type Repr = #repr;
|
||||||
|
fn from_repr(repr: #repr) -> Option<Self> {
|
||||||
|
match repr {
|
||||||
|
#(#values)*
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -5,8 +5,14 @@
|
|||||||
use proc_macro::*;
|
use proc_macro::*;
|
||||||
|
|
||||||
mod sigscan;
|
mod sigscan;
|
||||||
|
mod from_repr;
|
||||||
|
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn signature(input: TokenStream) -> TokenStream {
|
pub fn signature(input: TokenStream) -> TokenStream {
|
||||||
sigscan::macro_proc(input)
|
sigscan::macro_proc(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(FromRepr)]
|
||||||
|
pub fn derive_from_repr(input: TokenStream) -> TokenStream {
|
||||||
|
from_repr::derive_from_repr(input)
|
||||||
}
|
}
|
||||||
13
src/lib.rs
13
src/lib.rs
@@ -32,9 +32,6 @@ pub mod win32;
|
|||||||
#[cfg(feature = "win32")]
|
#[cfg(feature = "win32")]
|
||||||
pub use win32::{ image_base, image_header, find_kernel32, process_executable };
|
pub use win32::{ image_base, image_header, find_kernel32, process_executable };
|
||||||
|
|
||||||
/// re-export the signature macro
|
|
||||||
pub use xgen::signature;
|
|
||||||
|
|
||||||
mod time;
|
mod time;
|
||||||
pub use time::dur;
|
pub use time::dur;
|
||||||
|
|
||||||
@@ -45,4 +42,12 @@ mod strings;
|
|||||||
pub use strings::*;
|
pub use strings::*;
|
||||||
|
|
||||||
mod iter_tools;
|
mod iter_tools;
|
||||||
pub use iter_tools::*;
|
pub use iter_tools::*;
|
||||||
|
|
||||||
|
/// re-export the signature macro
|
||||||
|
pub use xgen::signature;
|
||||||
|
pub use xgen::FromRepr;
|
||||||
|
pub trait FromRepr: Sized {
|
||||||
|
type Repr;
|
||||||
|
fn from_repr(repr: Self::Repr) -> Option<Self>;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user