Changed design for coclass macro

This commit is contained in:
adrianwithah 2019-09-09 18:45:33 +01:00
Родитель f4f9e06120
Коммит 15f4eeb65d
13 изменённых файлов: 82 добавлений и 93 удалений

Просмотреть файл

@ -2,14 +2,13 @@ use interface::{ianimal::IAnimal, icat::ICat, idomesticanimal::IDomesticAnimal};
use winapi::shared::winerror::{HRESULT, NOERROR};
use com::CoClass;
use com::{com_class, com_implements, aggr};
/// The implementation class
/// https://en.wikipedia.org/wiki/British_Shorthair
#[repr(C)]
#[derive(CoClass)]
#[com_class]
#[com_implements(ICat, IDomesticAnimal)]
pub struct InitBritishShortHairCat {
pub struct BritishShortHairCat {
num_owners: u32,
}
@ -36,7 +35,6 @@ impl IAnimal for BritishShortHairCat {
impl BritishShortHairCat {
pub(crate) fn new() -> Box<BritishShortHairCat> {
let init = InitBritishShortHairCat { num_owners: 20 };
BritishShortHairCat::allocate(init)
BritishShortHairCat::allocate(20)
}
}

Просмотреть файл

@ -14,5 +14,5 @@ syn = { version = "1.0.5", features = ["full"] }
quote = "1.0"
proc-macro2 = "1.0.1"
com_interface_attribute = { path="com_interface_attribute" }
co_class_derive = { path="co_class_derive" }
aggr_co_class_derive = { path="aggr_co_class_derive" }
co_class = { path="co_class" }
# aggr_co_class_derive = { path="aggr_co_class_derive" }

Просмотреть файл

@ -1,5 +1,5 @@
[package]
name = "co_class_derive"
name = "co_class"
version = "0.1.0"
authors = ["adrianwithah <lim.weiheng.hadrian@gmail.com>"]
edition = "2018"

Просмотреть файл

@ -128,8 +128,8 @@ use syn::ItemStruct;
// We manually generate a ClassFactory without macros, otherwise
// it leads to an infinite loop.
pub fn generate(struct_item: &ItemStruct) -> HelperTokenStream {
let real_ident = macro_utils::get_real_ident(&struct_item.ident);
let class_factory_ident = macro_utils::get_class_factory_ident(&real_ident);
let struct_ident = &struct_item.ident;
let class_factory_ident = macro_utils::get_class_factory_ident(&struct_ident);
quote!(
// We are not going to bother with using an Init_ struct here,
@ -150,12 +150,12 @@ pub fn generate(struct_item: &ItemStruct) -> HelperTokenStream {
// Bringing trait into scope to access IUnknown methods.
use com::IUnknown;
println!("Creating instance for {}", stringify!(#real_ident));
println!("Creating instance for {}", stringify!(#struct_ident));
if aggr != std::ptr::null_mut() {
return winapi::shared::winerror::CLASS_E_NOAGGREGATION;
}
let mut instance = #real_ident::new();
let mut instance = #struct_ident::new();
instance.add_ref();
let hr = instance.query_interface(riid, ppv);
instance.release();

Просмотреть файл

@ -1,6 +1,6 @@
use proc_macro2::TokenStream as HelperTokenStream;
use quote::quote;
use syn::{Ident, ItemStruct};
use syn::{Ident, ItemStruct, Fields};
// #[repr(C)]
// pub struct BritishShortHairCat {
@ -18,8 +18,7 @@ use syn::{Ident, ItemStruct};
/// ..init struct..
/// }
pub fn generate(base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTokenStream {
let init_ident = &struct_item.ident;
let real_ident = macro_utils::get_real_ident(&struct_item.ident);
let struct_ident = &struct_item.ident;
let vis = &struct_item.vis;
let bases_itf_idents = base_itf_idents.iter().map(|base| {
@ -28,14 +27,18 @@ pub fn generate(base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTo
});
let ref_count_ident = macro_utils::get_ref_count_ident();
let inner_init_field_ident = macro_utils::get_inner_init_field_ident();
let fields = match &struct_item.fields {
Fields::Named(f) => &f.named,
_ => panic!("Found non Named fields in struct.")
};
quote!(
#[repr(C)]
#vis struct #real_ident {
#vis struct #struct_ident {
#(#bases_itf_idents,)*
#ref_count_ident: u32,
#inner_init_field_ident: #init_ident
#fields
}
)
}

Просмотреть файл

@ -1,6 +1,6 @@
use proc_macro2::TokenStream as HelperTokenStream;
use quote::{format_ident, quote};
use syn::{Ident, ItemStruct};
use syn::{Ident, ItemStruct, Fields,};
// impl BritishShortHairCat {
// fn allocate(init_struct: InitBritishShortHairCat) -> Box<BritishShortHairCat> {
@ -38,8 +38,7 @@ use syn::{Ident, ItemStruct};
/// allocate: instantiates the COM fields, such as vpointers for the COM object.
/// get_class_object: Instantiate an instance to the class object.
pub fn generate(base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTokenStream {
let init_ident = &struct_item.ident;
let real_ident = macro_utils::get_real_ident(&struct_item.ident);
let struct_ident = &struct_item.ident;
// Allocate stuff
let mut offset_count: usize = 0;
@ -48,7 +47,7 @@ pub fn generate(base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTo
let vptr_field_ident = macro_utils::get_vptr_field_ident(&base);
let out = quote!(
let #vtable_var_ident = com::vtable!(#real_ident: #base, #offset_count);
let #vtable_var_ident = com::vtable!(#struct_ident: #base, #offset_count);
let #vptr_field_ident = Box::into_raw(Box::new(#vtable_var_ident));
);
@ -60,20 +59,28 @@ pub fn generate(base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTo
quote!(#vptr_field_ident)
});
let ref_count_ident = macro_utils::get_ref_count_ident();
let inner_init_field_ident = macro_utils::get_inner_init_field_ident();
// GetClassObject stuff
let class_factory_ident = macro_utils::get_class_factory_ident(&real_ident);
let class_factory_ident = macro_utils::get_class_factory_ident(&struct_ident);
let fields = match &struct_item.fields {
Fields::Named(f) => &f.named,
_ => panic!("Found non Named fields in struct.")
};
let field_idents = fields.iter().map(|field| {
let field_ident = field.ident.as_ref().unwrap().clone();
quote!(#field_ident)
});
quote!(
impl #real_ident {
fn allocate(init_struct: #init_ident) -> Box<#real_ident> {
println!("Allocating new VTable for {}", stringify!(#real_ident));
impl #struct_ident {
fn allocate(#fields) -> Box<#struct_ident> {
println!("Allocating new VTable for {}", stringify!(#struct_ident));
#(#base_inits)*
let out = #real_ident {
let out = #struct_ident {
#(#base_fields,)*
#ref_count_ident: 0,
#inner_init_field_ident: init_struct
#(#field_idents),*
};
Box::new(out)
}

Просмотреть файл

@ -0,0 +1,19 @@
use proc_macro2::TokenStream as HelperTokenStream;
use quote::quote;
use syn::ItemStruct;
// impl std::ops::Deref for BritishShortHairCat {
// type Target = InitBritishShortHairCat;
// fn deref(&self) -> &Self::Target {
// &self.__init_struct
// }
// }
// impl std::ops::DerefMut for BritishShortHairCat {
// fn deref_mut(&mut self) -> &mut Self::Target {
// &mut self.__init_struct
// }
// }
pub fn generate(struct_item: &ItemStruct) -> HelperTokenStream {
quote!()
}

Просмотреть файл

@ -15,7 +15,7 @@ use syn::{Ident, ItemStruct};
// }
pub fn generate(base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTokenStream {
let real_ident = macro_utils::get_real_ident(&struct_item.ident);
let struct_ident = &struct_item.ident;
let box_from_raws = base_itf_idents.iter().map(|base| {
let vptr_field_ident = macro_utils::get_vptr_field_ident(&base);
quote!(
@ -24,7 +24,7 @@ pub fn generate(base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTo
});
quote!(
impl std::ops::Drop for #real_ident {
impl std::ops::Drop for #struct_ident {
fn drop(&mut self) {
let _ = unsafe {
#(#box_from_raws)*

Просмотреть файл

@ -92,7 +92,7 @@ pub fn generate(
aggr_itf_idents: &HashMap<Ident, Vec<Ident>>,
struct_item: &ItemStruct,
) -> HelperTokenStream {
let real_ident = macro_utils::get_real_ident(&struct_item.ident);
let struct_ident = &struct_item.ident;
let ref_count_ident = macro_utils::get_ref_count_ident();
let first_vptr_field = macro_utils::get_vptr_field_ident(&base_itf_idents[0]);
@ -141,7 +141,7 @@ pub fn generate(
});
quote!(
impl com::IUnknown for #real_ident {
impl com::IUnknown for #struct_ident {
fn query_interface(
&mut self,
riid: *const winapi::shared::guiddef::IID,
@ -175,11 +175,11 @@ pub fn generate(
println!("Count now {}", self.#ref_count_ident);
let count = self.#ref_count_ident;
if count == 0 {
println!("Count is 0 for {}. Freeing memory...", stringify!(#real_ident));
println!("Count is 0 for {}. Freeing memory...", stringify!(#struct_ident));
// drop(self)
// TODO: This doesn't free the original heap allocation, as &mut self results
// in a copy from the raw pointer.
unsafe { Box::from_raw(self as *const _ as *mut #real_ident); }
unsafe { Box::from_raw(self as *const _ as *mut #struct_ident); }
}
count
}

Просмотреть файл

@ -12,7 +12,7 @@ mod drop_impl;
mod iunknown_impl;
// Macro expansion entry point.
pub fn expand_derive_com_class(item: TokenStream) -> TokenStream {
pub fn expand_com_class(attr: TokenStream, item: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(item as ItemStruct);
// Parse attributes

Просмотреть файл

@ -1,36 +0,0 @@
use proc_macro2::TokenStream as HelperTokenStream;
use quote::quote;
use syn::ItemStruct;
// impl std::ops::Deref for BritishShortHairCat {
// type Target = InitBritishShortHairCat;
// fn deref(&self) -> &Self::Target {
// &self.__init_struct
// }
// }
// impl std::ops::DerefMut for BritishShortHairCat {
// fn deref_mut(&mut self) -> &mut Self::Target {
// &mut self.__init_struct
// }
// }
pub fn generate(struct_item: &ItemStruct) -> HelperTokenStream {
let init_ident = &struct_item.ident;
let real_ident = macro_utils::get_real_ident(init_ident);
let inner_init_field_ident = macro_utils::get_inner_init_field_ident();
quote!(
impl std::ops::Deref for #real_ident {
type Target = #init_ident;
fn deref(&self) -> &Self::Target {
&self.#inner_init_field_ident
}
}
impl std::ops::DerefMut for #real_ident {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.#inner_init_field_ident
}
}
)
}

Просмотреть файл

@ -33,18 +33,6 @@ pub fn get_vptr_field_ident(trait_ident: &Ident) -> Ident {
format_ident!("__{}vptr", trait_ident.to_string().to_lowercase())
}
pub fn get_real_ident(struct_ident: &Ident) -> Ident {
if !struct_ident.to_string().starts_with("Init") {
panic!("The target struct's name must begin with Init")
}
format_ident!("{}", &struct_ident.to_string()[4..])
}
pub fn get_inner_init_field_ident() -> Ident {
format_ident!("__init_struct")
}
pub fn get_base_interface_idents(struct_item: &ItemStruct) -> Vec<Ident> {
let mut base_itf_idents = Vec::new();

Просмотреть файл

@ -1,5 +1,5 @@
use aggr_co_class_derive::expand_derive_aggr_com_class;
use co_class_derive::expand_derive_com_class;
// use aggr_co_class_derive::expand_derive_aggr_com_class;
use co_class::expand_com_class;
use com_interface_attribute::{expand_com_interface, expand_derive};
extern crate proc_macro;
@ -17,12 +17,22 @@ pub fn derive(input: TokenStream) -> TokenStream {
}
// Macro entry points.
#[proc_macro_derive(CoClass, attributes(com_implements, aggr))]
pub fn derive_com_class(item: TokenStream) -> TokenStream {
expand_derive_com_class(item)
#[proc_macro_attribute]
pub fn com_class(attr: TokenStream, item: TokenStream) -> TokenStream {
expand_com_class(attr, item)
}
#[proc_macro_derive(AggrCoClass, attributes(com_implements, aggr))]
pub fn derive_aggr_com_class(item: TokenStream) -> TokenStream {
expand_derive_aggr_com_class(item)
// #[proc_macro_derive(AggrCoClass, attributes(com_implements, aggr))]
// pub fn derive_aggr_com_class(item: TokenStream) -> TokenStream {
// expand_derive_aggr_com_class(item)
// }
#[proc_macro_attribute]
pub fn com_implements(attr: TokenStream, item: TokenStream) -> TokenStream {
item
}
#[proc_macro_attribute]
pub fn aggr(attr: TokenStream, item: TokenStream) -> TokenStream {
item
}