зеркало из https://github.com/microsoft/com-rs.git
Add aggr attribute support for new coclass macro design
This commit is contained in:
Родитель
15f4eeb65d
Коммит
fbcbc79cb8
|
@ -1,6 +1,7 @@
|
|||
use proc_macro2::TokenStream as HelperTokenStream;
|
||||
use quote::quote;
|
||||
use syn::{Ident, ItemStruct, Fields};
|
||||
use std::collections::HashMap;
|
||||
|
||||
// #[repr(C)]
|
||||
// pub struct BritishShortHairCat {
|
||||
|
@ -17,7 +18,7 @@ use syn::{Ident, ItemStruct, Fields};
|
|||
/// ..ref count..
|
||||
/// ..init struct..
|
||||
/// }
|
||||
pub fn generate(base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTokenStream {
|
||||
pub fn generate(aggr_map: &HashMap<Ident, Vec<Ident>>, base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTokenStream {
|
||||
let struct_ident = &struct_item.ident;
|
||||
let vis = &struct_item.vis;
|
||||
|
||||
|
@ -33,11 +34,18 @@ pub fn generate(base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTo
|
|||
_ => panic!("Found non Named fields in struct.")
|
||||
};
|
||||
|
||||
let aggregates = aggr_map.iter().map(|(aggr_field_ident, aggr_base_itf_idents)| {
|
||||
quote!(
|
||||
#aggr_field_ident: *mut <dyn com::IUnknown as com::ComInterface>::VPtr
|
||||
)
|
||||
});
|
||||
|
||||
quote!(
|
||||
#[repr(C)]
|
||||
#vis struct #struct_ident {
|
||||
#(#bases_itf_idents,)*
|
||||
#ref_count_ident: u32,
|
||||
#(#aggregates,)*
|
||||
#fields
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use proc_macro2::TokenStream as HelperTokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{Ident, ItemStruct, Fields,};
|
||||
use std::collections::HashMap;
|
||||
|
||||
// impl BritishShortHairCat {
|
||||
// fn allocate(init_struct: InitBritishShortHairCat) -> Box<BritishShortHairCat> {
|
||||
|
@ -37,7 +38,7 @@ use syn::{Ident, ItemStruct, Fields,};
|
|||
/// Generates the allocate and get_class_object function for the COM object.
|
||||
/// 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 {
|
||||
pub fn generate(aggr_map: &HashMap<Ident, Vec<Ident>>, base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTokenStream {
|
||||
let struct_ident = &struct_item.ident;
|
||||
|
||||
// Allocate stuff
|
||||
|
@ -72,6 +73,14 @@ pub fn generate(base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTo
|
|||
quote!(#field_ident)
|
||||
});
|
||||
|
||||
let aggregate_inits = aggr_map.iter().map(|(aggr_field_ident, aggr_base_itf_idents)| {
|
||||
quote!(
|
||||
#aggr_field_ident: std::ptr::null_mut()
|
||||
)
|
||||
});
|
||||
|
||||
let set_aggregate_fns = gen_set_aggregate_fns(aggr_map);
|
||||
|
||||
quote!(
|
||||
impl #struct_ident {
|
||||
fn allocate(#fields) -> Box<#struct_ident> {
|
||||
|
@ -80,7 +89,8 @@ pub fn generate(base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTo
|
|||
let out = #struct_ident {
|
||||
#(#base_fields,)*
|
||||
#ref_count_ident: 0,
|
||||
#(#field_idents),*
|
||||
#(#aggregate_inits,)*
|
||||
#(#field_idents)*
|
||||
};
|
||||
Box::new(out)
|
||||
}
|
||||
|
@ -88,6 +98,25 @@ pub fn generate(base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTo
|
|||
pub fn get_class_object() -> Box<#class_factory_ident> {
|
||||
<#class_factory_ident>::new()
|
||||
}
|
||||
|
||||
#set_aggregate_fns
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn gen_set_aggregate_fns(aggr_map: &HashMap<Ident, Vec<Ident>>) -> HelperTokenStream {
|
||||
let mut fns = Vec::new();
|
||||
for (aggr_field_ident, aggr_base_itf_idents) in aggr_map.iter() {
|
||||
for base in aggr_base_itf_idents {
|
||||
let set_aggregate_fn_ident = format_ident!("set_aggregate_{}", macro_utils::camel_to_snake(&base.to_string()));
|
||||
fns.push(quote!(
|
||||
fn #set_aggregate_fn_ident(&mut self, aggr: *mut <dyn com::IUnknown as com::ComInterface>::VPtr) {
|
||||
// TODO: What happens if we are overwriting an existing aggregate?
|
||||
self.#aggr_field_ident = aggr
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
quote!(#(#fns)*)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use proc_macro2::TokenStream as HelperTokenStream;
|
||||
use quote::quote;
|
||||
use syn::{Ident, ItemStruct};
|
||||
use std::collections::HashMap;
|
||||
|
||||
// impl std::ops::Drop for BritishShortHairCat {
|
||||
// fn drop(&mut self) {
|
||||
|
@ -14,7 +15,7 @@ use syn::{Ident, ItemStruct};
|
|||
// }
|
||||
// }
|
||||
|
||||
pub fn generate(base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTokenStream {
|
||||
pub fn generate(aggr_map: &HashMap<Ident, Vec<Ident>>, base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTokenStream {
|
||||
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);
|
||||
|
@ -23,10 +24,23 @@ pub fn generate(base_itf_idents: &[Ident], struct_item: &ItemStruct) -> HelperTo
|
|||
)
|
||||
});
|
||||
|
||||
let aggregate_drops = aggr_map.iter().map(|(aggr_field_ident, _)| {
|
||||
quote!(
|
||||
if !self.#aggr_field_ident.is_null() {
|
||||
let mut aggr_itf_ptr: com::ComPtr<dyn com::IUnknown> = com::ComPtr::new(self.#aggr_field_ident as *mut winapi::ctypes::c_void);
|
||||
aggr_itf_ptr.release();
|
||||
core::mem::forget(aggr_itf_ptr);
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
quote!(
|
||||
impl std::ops::Drop for #struct_ident {
|
||||
fn drop(&mut self) {
|
||||
use com::IUnknown;
|
||||
|
||||
let _ = unsafe {
|
||||
#(#aggregate_drops)*
|
||||
#(#box_from_raws)*
|
||||
};
|
||||
}
|
||||
|
|
|
@ -124,9 +124,15 @@ pub fn generate(
|
|||
|
||||
quote!(
|
||||
else if #first_aggr_match_condition #(#rem_aggr_match_conditions)* {
|
||||
let mut aggr_itf_ptr: ComPtr<dyn IUnknown> = ComPtr::new(self.#aggr_field_ident as *mut winapi::ctypes::c_void);
|
||||
if self.#aggr_field_ident.is_null() {
|
||||
*ppv = std::ptr::null_mut::<winapi::ctypes::c_void>();
|
||||
return winapi::shared::winerror::E_NOINTERFACE;
|
||||
}
|
||||
|
||||
let mut aggr_itf_ptr: com::ComPtr<dyn com::IUnknown> = com::ComPtr::new(self.#aggr_field_ident as *mut winapi::ctypes::c_void);
|
||||
let hr = aggr_itf_ptr.query_interface(riid, ppv);
|
||||
if com::failed(hr) {
|
||||
*ppv = std::ptr::null_mut::<winapi::ctypes::c_void>();
|
||||
return winapi::shared::winerror::E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -135,7 +141,7 @@ pub fn generate(
|
|||
// outer object.
|
||||
aggr_itf_ptr.release();
|
||||
|
||||
forget(aggr_itf_ptr);
|
||||
core::mem::forget(aggr_itf_ptr);
|
||||
}
|
||||
)
|
||||
});
|
||||
|
|
|
@ -20,12 +20,15 @@ pub fn expand_com_class(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
let aggr_itf_idents = macro_utils::get_aggr_map(&input);
|
||||
|
||||
let mut out: Vec<TokenStream> = Vec::new();
|
||||
out.push(com_struct::generate(&base_itf_idents, &input).into());
|
||||
out.push(com_struct_impl::generate(&base_itf_idents, &input).into());
|
||||
out.push(com_struct::generate(&aggr_itf_idents, &base_itf_idents, &input).into());
|
||||
out.push(com_struct_impl::generate(&aggr_itf_idents, &base_itf_idents, &input).into());
|
||||
out.push(iunknown_impl::generate(&base_itf_idents, &aggr_itf_idents, &input).into());
|
||||
out.push(drop_impl::generate(&base_itf_idents, &input).into());
|
||||
out.push(drop_impl::generate(&aggr_itf_idents, &base_itf_idents, &input).into());
|
||||
out.push(deref_impl::generate(&input).into());
|
||||
out.push(class_factory::generate(&input).into());
|
||||
|
||||
TokenStream::from_iter(out)
|
||||
// TokenStream::from_iter(out)
|
||||
let result = TokenStream::from_iter(out);
|
||||
println!("Result:\n{}", result.to_string());
|
||||
result
|
||||
}
|
||||
|
|
|
@ -60,34 +60,37 @@ pub fn get_base_interface_idents(struct_item: &ItemStruct) -> Vec<Ident> {
|
|||
pub fn get_aggr_map(struct_item: &ItemStruct) -> HashMap<Ident, Vec<Ident>> {
|
||||
let mut aggr_map = HashMap::new();
|
||||
|
||||
let fields = match &struct_item.fields {
|
||||
Fields::Named(f) => &f.named,
|
||||
_ => panic!("Found field other than named fields in struct")
|
||||
};
|
||||
|
||||
for field in fields {
|
||||
for attr in &field.attrs {
|
||||
if let Ok(Meta::List(ref attr)) = attr.parse_meta() {
|
||||
if attr.path.segments.last().unwrap().ident != "aggr" {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut aggr_interfaces_idents = Vec::new();
|
||||
|
||||
|
||||
assert!(attr.nested.len() > 0, "Need to expose at least one interface from aggregated COM object.");
|
||||
|
||||
for item in &attr.nested {
|
||||
if let NestedMeta::Meta(Meta::Path(p)) = item {
|
||||
assert!(p.segments.len() == 1, "Incapable of handling multiple path segments yet.");
|
||||
aggr_interfaces_idents.push(p.segments.last().unwrap().ident.clone());
|
||||
}
|
||||
}
|
||||
let ident = field.ident.as_ref().unwrap().clone();
|
||||
aggr_map.insert(ident, aggr_interfaces_idents);
|
||||
for attr in &struct_item.attrs {
|
||||
if let Ok(Meta::List(ref attr)) = attr.parse_meta() {
|
||||
if attr.path.segments.last().unwrap().ident != "aggr" {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut aggr_interfaces_idents = Vec::new();
|
||||
|
||||
|
||||
assert!(attr.nested.len() > 0, "Need to expose at least one interface from aggregated COM object.");
|
||||
|
||||
for item in &attr.nested {
|
||||
if let NestedMeta::Meta(Meta::Path(p)) = item {
|
||||
assert!(p.segments.len() == 1, "Incapable of handling multiple path segments yet.");
|
||||
aggr_interfaces_idents.push(p.segments.last().unwrap().ident.clone());
|
||||
}
|
||||
}
|
||||
let ident = aggr_interfaces_idents.iter()
|
||||
.map(|base| {
|
||||
crate::camel_to_snake(&base.to_string())
|
||||
})
|
||||
.fold("aggr".to_owned(), |acc, base| {
|
||||
format!("{}_{}", acc, base)
|
||||
});
|
||||
aggr_map.insert(format_ident!("{}", ident), aggr_interfaces_idents);
|
||||
}
|
||||
}
|
||||
|
||||
for (ident, _) in aggr_map.iter() {
|
||||
println!("Ident found: {}", ident);
|
||||
}
|
||||
|
||||
aggr_map
|
||||
}
|
Загрузка…
Ссылка в новой задаче