1use ::syn::parse::Parser;
2use proc_macro::TokenStream;
3use quote::quote;
4
5enum CapeOpenObjectMacroArg {
6 Interfaces(Vec<syn::Path>),
7 CreateArguments(Vec<syn::Ident>),
8 NewArguments(Vec<syn::Ident>),
9}
10
11impl syn::parse::Parse for CapeOpenObjectMacroArg {
12 fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> {
13 let name: syn::Ident = input.parse()?;
14 input.parse::<syn::Token![=]>()?;
15 if name=="interfaces" {
16 let content;
17 syn::braced!(content in input);
18 let paths : syn::punctuated::Punctuated::<syn::Path, syn::Token![,]> = content.parse_terminated(syn::Path::parse)?;
19 let mut items : Vec<syn::Path> = Vec::with_capacity(paths.len());
21 for p in paths {
22 items.push(p);
23 }
24 Ok(CapeOpenObjectMacroArg::Interfaces(items))
25 } else if name=="create_arguments" {
26 let content;
27 syn::braced!(content in input);
28 let idents : syn::punctuated::Punctuated::<syn::Ident, syn::Token![,]> = content.parse_terminated(syn::Ident::parse)?;
29 let mut items : Vec<syn::Ident> = Vec::with_capacity(idents.len());
31 for p in idents {
32 items.push(p);
33 }
34 Ok(CapeOpenObjectMacroArg::CreateArguments(items))
35 } else if name=="new_arguments" {
36 let content;
37 syn::braced!(content in input);
38 let idents : syn::punctuated::Punctuated::<syn::Ident, syn::Token![,]> = content.parse_terminated(syn::Ident::parse)?;
39 let mut items : Vec<syn::Ident> = Vec::with_capacity(idents.len());
41 for p in idents {
42 items.push(p);
43 }
44 Ok(CapeOpenObjectMacroArg::NewArguments(items))
45 } else {
46 Err(syn::parse::Error::new(name.span(),format!("Unknown argument: {}",name)))
47 }
48 }
49}
50
51
52#[proc_macro_attribute]
98pub fn cape_object_implementation(attr: TokenStream, item: TokenStream) -> TokenStream {
99 let arguments = syn::punctuated::Punctuated::<CapeOpenObjectMacroArg, syn::Token![,]>::parse_terminated
101 .parse2(attr.into())
102 .expect("Incorrect format of cape_object_implementation attributes");
103 let mut interfaces : Vec<syn::Path> = Vec::new();
105 let mut creation_arguments : Option<CapeOpenObjectMacroArg> = None;
106 for arg in arguments {
107 match arg {
108 CapeOpenObjectMacroArg::Interfaces(ifaces) => {
109 interfaces.extend(ifaces)
110 },
111 CapeOpenObjectMacroArg::CreateArguments(_args) => {
112 if creation_arguments.is_some() {
113 panic!("Multiple create_arguments or new_arguments specified");
114 }
115 creation_arguments= Some(CapeOpenObjectMacroArg::CreateArguments(_args));
116 },
117 CapeOpenObjectMacroArg::NewArguments(_args) => {
118 if creation_arguments.is_some() {
119 panic!("Multiple create_arguments or new_arguments specified");
120 }
121 creation_arguments= Some(CapeOpenObjectMacroArg::NewArguments(_args));
122 },
123 }
124 }
125 if interfaces.len()==0 {
126 panic!("No interfaces specified");
127 }
128
129 let mut struct_desc = syn::parse_macro_input!(item as syn::ItemStruct);
130 let structname = &struct_desc.ident;
131 let (impl_generics, ty_generics, where_clause) = struct_desc.generics.split_for_impl();
132 let cobiainfostruct = quote::format_ident!("{}{}", structname.to_string(), "CobiaObjectData");
133 let ptr_name= structname
135 .to_string()
136 .chars()
137 .map(|c| if c.is_uppercase() { format!("_{}", c.to_lowercase()) } else { c.to_string() })
138 .collect::<String>();
139 let ptr_name= quote::format_ident!("{}_boxed_ptr", ptr_name);
140
141 let mut object_creation = proc_macro2::TokenStream::new();
147 let mut create_arguments_def = proc_macro2::TokenStream::new();
148 let mut create_arguments = proc_macro2::TokenStream::new();
149
150 match struct_desc.fields {
151 syn::Fields::Named(ref mut fields) => {
152 match creation_arguments {
153 None => {
154 object_creation= quote! {
155 std::default::Default::default()
156 };
157 }
158 Some(CapeOpenObjectMacroArg::CreateArguments(ref args)) | Some(CapeOpenObjectMacroArg::NewArguments(ref args)) => {
159 let struct_items : std::collections::HashMap<String, syn::Type> = fields
161 .named
162 .iter()
163 .map(|f| {
164 (f.ident.as_ref().unwrap().to_string(), f.ty.clone())
165 })
166 .collect();
167 for id in args {
168 let typ = struct_items.get(&id.to_string());
169 if typ.is_none() {
170 panic!("Field '{}' not found in struct", &id);
171 }
172 let typ = typ.unwrap();
173 let arg = &id;
174 create_arguments_def.extend(quote! {
175 #arg : #typ,
176 });
177 create_arguments.extend(quote! {
178 #arg,
179 });
180 }
181 match creation_arguments {
182 Some(CapeOpenObjectMacroArg::CreateArguments(_)) => {
183 let create_arg_set=std::collections::HashSet::<String>::from_iter(args.iter().map(|x| x.to_string()));
184 let mut create_arguments = proc_macro2::TokenStream::new();
185 for f in fields.named.iter() {
186 let id=&f.ident;
187 if create_arg_set.contains(&f.ident.as_ref().unwrap().to_string()) {
188 create_arguments.extend(quote! {
189 #id,
190 });
191 } else {
192 create_arguments.extend(quote! {
193 #id : std::default::Default::default(),
194 });
195 }
196 };
197 create_arguments.extend(quote! {
198 cobia_object_data : std::default::Default::default(),
199 });
200 object_creation.extend(quote! {
201 Self {
202 #create_arguments
203 }
204 });
205 }
206 Some(CapeOpenObjectMacroArg::NewArguments(_)) => {
207 object_creation.extend(quote! {
208 Self::new(#create_arguments)
209 });
210 }
211 _ => {
212 panic!("Internal error");
213 }
214 }
215
216 }
217 _ => {
218 panic!("Internal error");
219 }
220 };
221 fields.named.push(
222 syn::Field::parse_named
223 .parse2(quote! {
224 cobia_object_data : #cobiainfostruct
226 })
227 .expect("Unable to format info struct"),
228 );
229 }
230 syn::Fields::Unnamed(_) => {
231 return TokenStream::from(
232 syn::Error::new(
233 syn::spanned::Spanned::span(&struct_desc),
234 "unexpected tuple struct",
235 )
236 .to_compile_error(),
237 );
238 }
239 syn::Fields::Unit => {
240 return TokenStream::from(
241 syn::Error::new(
242 syn::spanned::Spanned::span(&struct_desc),
243 "unexpected unit struct",
244 )
245 .to_compile_error(),
246 );
247 }
248 }
249 let mut struc_fields = proc_macro2::TokenStream::new();
251 let mut struc_init_statements = proc_macro2::TokenStream::new();
252 let mut struc_field_init = proc_macro2::TokenStream::new();
253 let mut interface_impls = proc_macro2::TokenStream::new();
254 let mut member_set : std::collections::HashSet<String> = std::collections::HashSet::new();
256 member_set.insert("cape_object_data".to_string()); for iface in interfaces {
259 let mut impl_path = iface.clone();
261 impl_path.segments.last_mut().unwrap().ident =
262 quote::format_ident!("{}{}", impl_path.segments.last().unwrap().ident, "Impl");
263 let mut struc_member_name: String;
265 if iface.segments.len()==1 {
266 struc_member_name=iface.segments.last().unwrap().ident.to_string();
267 } else {
268 struc_member_name=iface.segments[iface.segments.len()-2].ident.to_string();
269 struc_member_name.push_str(&iface.segments.last().unwrap().ident.to_string());
270 }
271 struc_member_name = struc_member_name
273 .chars()
274 .map(|c| if c.is_uppercase() { format!("_{}", c.to_lowercase()) } else { c.to_string() })
275 .collect::<String>();
276 let mut i = 1;
278 while member_set.contains(&struc_member_name) {
279 struc_member_name = format!("{}_{}", struc_member_name, i);
280 i += 1;
281 }
282 member_set.insert(struc_member_name.clone());
283 let struc_member_name = quote::format_ident!("{}",struc_member_name);
285 let comment:proc_macro2::TokenStream=format!("/// Native {} interface", iface.segments.last().unwrap().ident).parse().unwrap();
286 struc_fields.extend(quote! {
288 #comment
289 #struc_member_name : cobia::C::ICapeInterface,
290 });
291 struc_init_statements.extend(quote! {
293 <Self as #impl_path>::init(u);
294 });
295 struc_field_init.extend(quote! {
297 #struc_member_name : <#structname as #impl_path>::init_interface(),
298 });
299 interface_impls.extend(quote! {
301 impl #impl_generics #impl_path for #structname #ty_generics #where_clause {
302 type T = #structname #ty_generics;
303 fn as_interface_pointer(&mut self) -> *mut cobia::C::ICapeInterface{
304 &mut self.cobia_object_data.#struc_member_name as *mut cobia::C::ICapeInterface
305 }
306
307 }
308 });
309 }
310 let mut fn_create_instance = proc_macro2::TokenStream::new();
311 fn_create_instance.extend(quote! {
312 fn create_instance(#ptr_name : *mut *mut cobia::C::ICapeInterface,#create_arguments_def) -> cobia::CapeResult {
313 let obj:Self=#object_creation;
314 let object_ptr=Box::into_raw(Box::new(obj)); let u : &mut Self= unsafe {&mut *object_ptr as &mut Self};
316 #struc_init_statements
317 unsafe {*#ptr_name=cobia::ICapeInterfaceImpl::init(u)};
318 cobia::COBIAERR_NOERROR
319 }
320 });
321 let mut cape_create_instance = proc_macro2::TokenStream::new();
322 let provide_cape_create_instance=match creation_arguments {
323 None => true,
324 Some(CapeOpenObjectMacroArg::CreateArguments(args)) => args.len()==0,
325 Some(CapeOpenObjectMacroArg::NewArguments(args)) => args.len()==0,
326 _ => {
327 panic!("Internal error");
328 }
329 };
330 if provide_cape_create_instance {
331 cape_create_instance.extend(quote! {
333 impl #impl_generics cobia::CapeCreateInstance for #structname #ty_generics #where_clause {
334 #fn_create_instance
335 }
336 });
337 fn_create_instance = proc_macro2::TokenStream::new();
339 }
340
341 quote! {
342
343 #struct_desc
344
345 struct #cobiainfostruct {
350 cape_object_data : cobia::CapeObjectData,
352 #struc_fields
353 }
354
355 #cape_create_instance
356
357 use cobia::prelude::CapeSmartPointer;
358
359 impl #impl_generics #structname #ty_generics #where_clause {
360 #fn_create_instance
361 pub(crate) fn create<T:cobia::prelude::CapeSmartPointer>(#create_arguments_def) -> T {
367 let mut #ptr_name: *mut C::ICapeInterface=std::ptr::null_mut();
368 Self::create_instance(&mut #ptr_name as *mut *mut C::ICapeInterface,#create_arguments);
369 match T::from_cape_interface_pointer(#ptr_name) {
370 Ok(smart_pointer) => smart_pointer,
371 Err(e) => {
372 let _obj=CapeObject::from_interface_pointer(#ptr_name);
374 panic!("Error creating smart pointer: {}", e);
375 },
376 }
377 }
378 pub(crate) fn try_create<T:cobia::prelude::CapeSmartPointer>(#create_arguments_def) -> Result<T,COBIAError> {
383 let mut #ptr_name: *mut C::ICapeInterface=std::ptr::null_mut();
384 Self::create_instance(&mut #ptr_name as *mut *mut C::ICapeInterface,#create_arguments);
385 let p=CapeObject::from_interface_pointer(#ptr_name);
386 T::from_object(&p)
387 }
388 pub(crate) unsafe fn borrow<T:cobia::prelude::CapeSmartPointer>(smart_pointer:&T) -> &Self {
401 let p=smart_pointer.as_cape_interface_pointer();
402 let me=unsafe {(*p).me};
403 let p = me as *const Self;
404 unsafe {&*p}
405 }
406 pub(crate) unsafe fn borrow_mut<T:cobia::prelude::CapeSmartPointer>(smart_pointer:&mut T) -> &mut Self {
420 let p=smart_pointer.as_cape_interface_pointer();
421 let me=unsafe {(*p).me};
422 let p = me as *mut Self;
423 unsafe {&mut *p}
424 }
425 }
426
427 impl Default for #cobiainfostruct {
428 fn default() -> #cobiainfostruct {
429 #cobiainfostruct::new()
430 }
431 }
432
433 impl #cobiainfostruct {
434 fn new() -> #cobiainfostruct {
435 #cobiainfostruct {
436 cape_object_data : <#structname as cobia::ICapeInterfaceImpl>::create_object_data::<#structname>(),
437 #struc_field_init
438 }
439 }
440 }
441
442 impl #impl_generics cobia::ICapeInterfaceImpl for #structname #ty_generics #where_clause {
443 type T = #structname #ty_generics;
444 fn get_object_data(&mut self) -> &mut cobia::CapeObjectData {
445 &mut self.cobia_object_data.cape_object_data
446 }
447 fn get_self(&mut self) -> *mut #structname {
448 self as *mut #structname
449 }
450 }
451
452 #interface_impls
453
454 }
455 .into()
456}
457
458
459#[proc_macro_attribute]
492pub fn cape_smart_pointer(attr: TokenStream, item: TokenStream) -> TokenStream {
493 let struct_desc = syn::parse_macro_input!(item as syn::ItemStruct);
495 let structname = &struct_desc.ident;
496 let mut interface_type = None;
499 match struct_desc.fields {
500 syn::Fields::Named(ref fields) => {
501 for field in fields.named.iter() {
503 if field.ident.as_ref().expect("Unable to obtain field identifier") == "interface" {
504 match field.ty {
505 syn::Type::Ptr(ref type_ptr) => {
506 match type_ptr.mutability {
507 Some(_) => {}
508 None => {
509 return TokenStream::from(
510 syn::Error::new(
511 syn::spanned::Spanned::span(&field),
512 "invalid interface member; must be a *mut to an interface type",
513 )
514 .to_compile_error(),
515 );
516 }
517 }
518 match *type_ptr.elem {
519 syn::Type::Path(ref type_path) => {
520 interface_type = Some(type_path.path.clone());
521 }
522 _ => {
523 return TokenStream::from(
524 syn::Error::new(
525 syn::spanned::Spanned::span(&field),
526 "invalid interface member; must be a *mut to an interface type",
527 )
528 .to_compile_error(),
529 );
530 }
531 }
532 }
533 _ => {
534 return TokenStream::from(
535 syn::Error::new(
536 syn::spanned::Spanned::span(&field),
537 "invalid interface member; must be a *mut to an interface type",
538 )
539 .to_compile_error(),
540 );
541 }
542
543 }
544 break;
545 }
546 }
547 }
548 syn::Fields::Unnamed(_) => {
549 return TokenStream::from(
550 syn::Error::new(
551 syn::spanned::Spanned::span(&struct_desc),
552 "unexpected tuple struct",
553 )
554 .to_compile_error(),
555 );
556 }
557 syn::Fields::Unit => {
558 return TokenStream::from(
559 syn::Error::new(
560 syn::spanned::Spanned::span(&struct_desc),
561 "unexpected unit struct",
562 )
563 .to_compile_error(),
564 );
565 }
566 }
567 if interface_type.is_none() {
568 return TokenStream::from(
569 syn::Error::new(
570 syn::spanned::Spanned::span(&struct_desc),
571 "interface field not found",
572 )
573 .to_compile_error(),
574 );
575 }
576 let interface_type=interface_type.expect("Invalid interface type");
577 let interface_id=proc_macro2::TokenStream::from(attr);
579 let genericdef = struct_desc.generics.clone();
580 let mut genericref = syn::Generics{
581 lt_token: None,
582 params: syn::punctuated::Punctuated::new(),
583 gt_token: None,
584 where_clause: None,
585 };
586 if !genericdef.params.is_empty() {
587 genericref=genericdef.clone();
588 genericref.params.iter_mut().for_each(|param| {
589 match param {
590 syn::GenericParam::Type(type_param) => {
591 type_param.attrs.clear();
592 type_param.colon_token=None;
593 type_param.bounds=syn::punctuated::Punctuated::new();
594 type_param.eq_token=None;
595 type_param.default=None;
596 },
597 _ => {}
598 }
599 });
600 }
601
602
603 let mut extra_initializers = proc_macro2::TokenStream::new();
605 for field in struct_desc.fields.iter() {
606 let field = field.ident.as_ref().expect("Unable to obtain field identifier");
607 if field == "interface" {
608 continue;
609 }
610 extra_initializers.extend(quote! {
611 #field : std::default::Default::default(),
612 });
613 }
614
615 quote! {
616
617 #struct_desc
618
619 impl #genericdef CapeSmartPointer for #structname #genericref {
620 type Interface = #interface_type;
621 fn as_interface_pointer(&self) -> *mut Self::Interface {
622 self.interface
623 }
624 fn as_cape_interface_pointer(&self) -> *mut C::ICapeInterface {
625 self.interface as *mut C::ICapeInterface
626 }
627 fn get_interface_id() -> &'static CapeUUID {
628 & #interface_id
629 }
630 fn from_object<T:CapeSmartPointer>(smart_pointer : &T) -> Result<Self,COBIAError> {
631 let mut interface : * mut C::ICapeInterface=std::ptr::null_mut();
632 let res=unsafe {
633 let other_interface=smart_pointer.as_cape_interface_pointer();
634 ((*(*other_interface).vTbl).queryInterface.unwrap())((*other_interface).me,Self::get_interface_id(),&mut interface as *mut *mut C::ICapeInterface)
635 };
636 if res==COBIAERR_NOERROR {
637 if interface.is_null() {
638 Err(COBIAError::Code(COBIAERR_NULLPOINTER))
639 } else {
640 Ok(Self::attach(interface as *mut #interface_type))
641 }
642 } else {
643 Err(COBIAError::from_object(res,smart_pointer))
644 }
645 }
646 fn from_interface_pointer(interface: *mut Self::Interface) -> Self {
647 if interface.is_null() {
648 panic!("Null pointer in creation of ICapeIdentificationSmartPtr");
649 }
650 unsafe {((*(*(interface as *mut C::ICapeInterface)).vTbl).addReference.unwrap())((*interface).me)};
651 Self {
652 interface,
653 #extra_initializers
654 }
655 }
656 fn attach(interface: *mut Self::Interface) -> Self {
657 if interface.is_null() {
658 panic!("Null pointer in creation of ICapeIdentificationSmartPtr");
659 }
660 Self {
661 interface,
662 #extra_initializers
663 }
664 }
665 fn detach(self) -> *mut Self::Interface {
666 let res=self.interface;
667 std::mem::forget(self); res
669 }
670 fn from_cape_interface_pointer(interface : *mut C::ICapeInterface) -> Result<Self,COBIAError> {
671 let mut my_interface : * mut C::ICapeInterface=std::ptr::null_mut();
672 let res=unsafe {
673 ((*(*interface).vTbl).queryInterface.unwrap())((*interface).me,Self::get_interface_id(),&mut my_interface as *mut *mut C::ICapeInterface)
674 };
675 if res==COBIAERR_NOERROR {
676 if my_interface.is_null() {
677 Err(COBIAError::Code(COBIAERR_NULLPOINTER))
678 } else {
679 Ok(Self::attach(my_interface as *mut #interface_type))
680 }
681 } else {
682 Err(COBIAError::from_cape_interface_pointer(res,interface))
683 }
684 }
685 fn last_error(&self) -> Option<CapeError> {
686 let mut interface : * mut C::ICapeError=std::ptr::null_mut();
687 let res=unsafe {
688 ((*(*(self.interface as *mut C::ICapeInterface)).vTbl).getLastError.unwrap())((*self.interface).me,&mut interface as *mut *mut C::ICapeError)
689 };
690 if res==COBIAERR_NOERROR {
691 if interface.is_null() {
692 None
693 } else {
694 Some(CapeError::attach(interface))
695 }
696 } else {
697 None
698 }
699 }
700 }
701
702 impl #genericdef Drop for #structname #genericref {
703 fn drop(&mut self) {
704 let interface=self.as_cape_interface_pointer();
705 unsafe {
706 ((*(*interface).vTbl).release.unwrap())((*interface).me);
707 }
708 }
709 }
710
711 impl #genericdef Clone for #structname #genericref {
712 fn clone(&self) -> Self {
713 let interface=self.as_cape_interface_pointer();
714 Self::from_interface_pointer(interface as *mut #interface_type)
715 }
716 }
717
718 }
719 .into()
720}
721