Add custom macro for ReprC impl

This commit is contained in:
hodasemi 2023-02-01 13:10:52 +01:00
parent f34f5974ac
commit b5af5fbe70
6 changed files with 118 additions and 0 deletions

View file

@ -10,6 +10,7 @@ rand = "0.8.5"
backtrace = "0.3.67"
assetpath = { git = "https://gavania.de/hodasemi/vulkan_lib.git" }
anyhow = { version = "1.0.68", features = ["backtrace"] }
reprc_proc_macro = { path = "src/reprc_proc_macro" }
# networking
serde = { version = "1.0.152", features = ["derive"] }

View file

@ -14,4 +14,7 @@ pub mod try_lock_guard;
pub mod arc_unique_vec;
pub mod rc_unique_vec;
#[macro_use]
mod repr_c;
pub mod unsafe_life_time;

View file

@ -27,3 +27,6 @@ pub use crate::try_lock_guard::TryLockGuard;
// unsafe life time trickery
pub use crate::unsafe_life_time::*;
pub use crate::repr_c::ReprC;
pub use reprc_proc_macro::DeriveReprC;

36
src/repr_c.rs Normal file
View file

@ -0,0 +1,36 @@
use reprc_proc_macro::DeriveReprC;
#[macro_export]
macro_rules! impl_reprc {
(
$(#[$meta: meta])*
$v:vis struct $struct_name:ident {
$( $(#[$field_meta:meta])* $member:ident : $t:ty, )+
}
) => {
#[repr(C)]
#[derive(Debug, Clone, DeriveReprC)]
$(#[$meta])*
$v struct $struct_name {
$(
$( #[$field_meta] )*
pub $member: $t,
)+
}
};
}
impl_reprc!(
struct Test {
#[assume_reprc]
i1: i32,
#[assume_reprc]
i2: i32,
#[assume_reprc]
v1: Vec<i32>,
}
);
pub unsafe trait ReprC {
fn is_repr_c(&self) -> bool;
}

View file

@ -0,0 +1,13 @@
[package]
name = "reprc_proc_macro"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
syn = { version = "1.0.107", features = ["full", "fold"] }
quote = "1.0.23"

View file

@ -0,0 +1,62 @@
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse_macro_input, Data, DeriveInput, Ident};
const REPRC_ATTRIBUTE: &'static str = "assume_reprc";
#[proc_macro_derive(DeriveReprC, attributes(assume_reprc))]
pub fn reprc_builder(item: TokenStream) -> TokenStream {
let ast = parse_macro_input!(item as DeriveInput);
let struct_name = ast.ident;
let generics = ast.generics.to_token_stream();
match ast.data {
Data::Struct(data_struct) => match data_struct.fields {
syn::Fields::Named(named_fields) => {
let reprc_fields: Vec<Ident> = named_fields
.named
.iter()
.filter_map(|field| {
if field
.attrs
.iter()
.find(|attribute| {
let segments = &attribute.path.segments;
if segments.len() < 1 {
return false;
}
segments[0].ident == REPRC_ATTRIBUTE
})
.is_some()
{
None
} else {
Some(field.ident.clone())
}
})
.map(|i| i.unwrap())
.collect();
TokenStream::from(quote! {
unsafe impl #generics ReprC for #struct_name #generics {
fn is_repr_c(&self) -> bool {
true
#(
&& self. #reprc_fields.to_tokens() .is_repr_c()
)*
}
}
})
}
syn::Fields::Unnamed(_) => todo!("Unnamed Field not supported"),
syn::Fields::Unit => todo!("Unit not supported"),
},
Data::Enum(_) => todo!("Enum not supported"),
Data::Union(_) => todo!("Union not supported"),
}
}