|
@@ -6,7 +6,7 @@
|
|
|
use quote::quote;
|
|
|
use syn::{
|
|
|
parse_macro_input, parse_quote, punctuated::Punctuated, spanned::Spanned, token::Comma, Data,
|
|
|
- DeriveInput, Field, Fields, Ident, Meta, Path, Token, Type, Variant, Visibility,
|
|
|
+ DeriveInput, Field, Fields, FieldsUnnamed, Ident, Meta, Path, Token, Type, Variant, Visibility,
|
|
|
};
|
|
|
|
|
|
mod utils;
|
|
@@ -33,6 +33,35 @@ fn get_fields<'a>(
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+fn get_unnamed_field<'a>(input: &'a DeriveInput, msg: &str) -> Result<&'a Field, MacroError> {
|
|
|
+ if let Data::Struct(s) = &input.data {
|
|
|
+ let unnamed = match &s.fields {
|
|
|
+ Fields::Unnamed(FieldsUnnamed {
|
|
|
+ unnamed: ref fields,
|
|
|
+ ..
|
|
|
+ }) => fields,
|
|
|
+ _ => {
|
|
|
+ return Err(MacroError::Message(
|
|
|
+ format!("Tuple struct required for {}", msg),
|
|
|
+ s.fields.span(),
|
|
|
+ ))
|
|
|
+ }
|
|
|
+ };
|
|
|
+ if unnamed.len() != 1 {
|
|
|
+ return Err(MacroError::Message(
|
|
|
+ format!("A single field is required for {}", msg),
|
|
|
+ s.fields.span(),
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ Ok(&unnamed[0])
|
|
|
+ } else {
|
|
|
+ Err(MacroError::Message(
|
|
|
+ format!("Struct required for {}", msg),
|
|
|
+ input.ident.span(),
|
|
|
+ ))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
fn is_c_repr(input: &DeriveInput, msg: &str) -> Result<(), MacroError> {
|
|
|
let expected = parse_quote! { #[repr(C)] };
|
|
|
|
|
@@ -46,6 +75,19 @@ fn is_c_repr(input: &DeriveInput, msg: &str) -> Result<(), MacroError> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+fn is_transparent_repr(input: &DeriveInput, msg: &str) -> Result<(), MacroError> {
|
|
|
+ let expected = parse_quote! { #[repr(transparent)] };
|
|
|
+
|
|
|
+ if input.attrs.iter().any(|attr| attr == &expected) {
|
|
|
+ Ok(())
|
|
|
+ } else {
|
|
|
+ Err(MacroError::Message(
|
|
|
+ format!("#[repr(transparent)] required for {}", msg),
|
|
|
+ input.ident.span(),
|
|
|
+ ))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
fn derive_object_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, MacroError> {
|
|
|
is_c_repr(&input, "#[derive(Object)]")?;
|
|
|
|
|
@@ -72,6 +114,52 @@ pub fn derive_object(input: TokenStream) -> TokenStream {
|
|
|
TokenStream::from(expanded)
|
|
|
}
|
|
|
|
|
|
+fn derive_opaque_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, MacroError> {
|
|
|
+ is_transparent_repr(&input, "#[derive(Wrapper)]")?;
|
|
|
+
|
|
|
+ let name = &input.ident;
|
|
|
+ let field = &get_unnamed_field(&input, "#[derive(Wrapper)]")?;
|
|
|
+ let typ = &field.ty;
|
|
|
+
|
|
|
+ // TODO: how to add "::qemu_api"? For now, this is only used in the
|
|
|
+ // qemu_api crate so it's not a problem.
|
|
|
+ Ok(quote! {
|
|
|
+ unsafe impl crate::cell::Wrapper for #name {
|
|
|
+ type Wrapped = <#typ as crate::cell::Wrapper>::Wrapped;
|
|
|
+ }
|
|
|
+ impl #name {
|
|
|
+ pub unsafe fn from_raw<'a>(ptr: *mut <Self as crate::cell::Wrapper>::Wrapped) -> &'a Self {
|
|
|
+ let ptr = ::std::ptr::NonNull::new(ptr).unwrap().cast::<Self>();
|
|
|
+ unsafe { ptr.as_ref() }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub const fn as_mut_ptr(&self) -> *mut <Self as crate::cell::Wrapper>::Wrapped {
|
|
|
+ self.0.as_mut_ptr()
|
|
|
+ }
|
|
|
+
|
|
|
+ pub const fn as_ptr(&self) -> *const <Self as crate::cell::Wrapper>::Wrapped {
|
|
|
+ self.0.as_ptr()
|
|
|
+ }
|
|
|
+
|
|
|
+ pub const fn as_void_ptr(&self) -> *mut ::core::ffi::c_void {
|
|
|
+ self.0.as_void_ptr()
|
|
|
+ }
|
|
|
+
|
|
|
+ pub const fn raw_get(slot: *mut Self) -> *mut <Self as crate::cell::Wrapper>::Wrapped {
|
|
|
+ slot.cast()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+#[proc_macro_derive(Wrapper)]
|
|
|
+pub fn derive_opaque(input: TokenStream) -> TokenStream {
|
|
|
+ let input = parse_macro_input!(input as DeriveInput);
|
|
|
+ let expanded = derive_opaque_or_error(input).unwrap_or_else(Into::into);
|
|
|
+
|
|
|
+ TokenStream::from(expanded)
|
|
|
+}
|
|
|
+
|
|
|
#[rustfmt::skip::macros(quote)]
|
|
|
fn derive_offsets_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, MacroError> {
|
|
|
is_c_repr(&input, "#[derive(offsets)]")?;
|