зеркало из https://github.com/microsoft/com-rs.git
Changed design for coclass macro
This commit is contained in:
Родитель
f4f9e06120
Коммит
15f4eeb65d
|
@ -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
|
||||
}
|
Загрузка…
Ссылка в новой задаче