@@ -2,7 +2,8 @@ use crate::gen::namespace::Namespace;
2
2
use crate :: gen:: out:: OutFile ;
3
3
use crate :: gen:: { include, Opt } ;
4
4
use crate :: syntax:: atom:: Atom :: { self , * } ;
5
- use crate :: syntax:: { Api , ExternFn , Signature , Struct , Type , Types , Var } ;
5
+ use crate :: syntax:: { Api , ExternFn , ExternType , Receiver , Signature , Struct , Type , Types , Var } ;
6
+ use itertools:: Itertools ;
6
7
use proc_macro2:: Ident ;
7
8
8
9
pub ( super ) fn gen (
@@ -44,10 +45,30 @@ pub(super) fn gen(
44
45
}
45
46
}
46
47
48
+ let methods_for_type = apis. iter ( ) . filter_map ( |api| match api {
49
+ Api :: RustFunction ( efn) => match & efn. sig . receiver {
50
+ Some ( rcvr) => Some ( ( & rcvr. ident , efn) ) ,
51
+ _ => None ,
52
+ } ,
53
+ _ => None ,
54
+ } ) . into_group_map ( ) ;
55
+
47
56
for api in apis {
48
- if let Api :: Struct ( strct) = api {
49
- out. next_section ( ) ;
50
- write_struct ( out, strct) ;
57
+ match api {
58
+ Api :: Struct ( strct) => {
59
+ out. next_section ( ) ;
60
+ write_struct ( out, strct) ;
61
+ }
62
+ Api :: RustType ( ety) => {
63
+ match methods_for_type. get ( & ety. ident ) {
64
+ Some ( methods) => {
65
+ out. next_section ( ) ;
66
+ write_struct_with_methods ( out, ety, methods) ;
67
+ } ,
68
+ _ => { }
69
+ }
70
+ }
71
+ _ => { }
51
72
}
52
73
}
53
74
@@ -300,6 +321,23 @@ fn write_struct_using(out: &mut OutFile, ident: &Ident) {
300
321
writeln ! ( out, "using {} = {};" , ident, ident) ;
301
322
}
302
323
324
+ fn write_struct_with_methods ( out : & mut OutFile , ety : & ExternType , methods : & Vec < & ExternFn > ) {
325
+ for line in ety. doc . to_string ( ) . lines ( ) {
326
+ writeln ! ( out, "//{}" , line) ;
327
+ }
328
+ writeln ! ( out, "struct {} final {{" , ety. ident) ;
329
+ writeln ! ( out, " {}() = delete;" , ety. ident) ;
330
+ writeln ! ( out, " {}(const {}&) = delete;" , ety. ident, ety. ident) ;
331
+ for method in methods {
332
+ write ! ( out, " " ) ;
333
+ let sig = & method. sig ;
334
+ let local_name = method. ident . to_string ( ) ;
335
+ write_rust_function_shim_decl ( out, & local_name, sig, None , false ) ;
336
+ writeln ! ( out, ";" ) ;
337
+ }
338
+ writeln ! ( out, "}};" ) ;
339
+ }
340
+
303
341
fn write_exception_glue ( out : & mut OutFile , apis : & [ Api ] ) {
304
342
let mut has_cxx_throws = false ;
305
343
for api in apis {
@@ -326,9 +364,16 @@ fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
326
364
} else {
327
365
write_extern_return_type_space ( out, & efn. ret , types) ;
328
366
}
329
- write ! ( out, "{}cxxbridge02${}(" , out. namespace, efn. ident) ;
367
+ let receiver_type = match & efn. receiver {
368
+ Some ( base) => base. ident . to_string ( ) ,
369
+ None => "_" . to_string ( ) ,
370
+ } ;
371
+ write ! ( out, "{}cxxbridge02${}${}(" , out. namespace, receiver_type, efn. ident) ;
372
+ if let Some ( base) = & efn. receiver {
373
+ write ! ( out, "{} *__receiver$" , base. ident) ;
374
+ }
330
375
for ( i, arg) in efn. args . iter ( ) . enumerate ( ) {
331
- if i > 0 {
376
+ if i > 0 || efn . receiver . is_some ( ) {
332
377
write ! ( out, ", " ) ;
333
378
}
334
379
if arg. ty == RustString {
@@ -347,14 +392,27 @@ fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
347
392
writeln ! ( out, ") noexcept {{" ) ;
348
393
write ! ( out, " " ) ;
349
394
write_return_type ( out, & efn. ret ) ;
350
- write ! ( out, "(*{}$)(" , efn. ident) ;
395
+ match & efn. receiver {
396
+ None => write ! ( out, "(*{}$)(" , efn. ident) ,
397
+ Some ( base) => write ! ( out, "({}::*{}$)(" , base. ident, efn. ident) ,
398
+ }
351
399
for ( i, arg) in efn. args . iter ( ) . enumerate ( ) {
352
400
if i > 0 {
353
401
write ! ( out, ", " ) ;
354
402
}
355
403
write_type ( out, & arg. ty ) ;
356
404
}
357
- writeln ! ( out, ") = {};" , efn. ident) ;
405
+ write ! ( out, ")" ) ;
406
+ match & efn. receiver {
407
+ Some ( Receiver { mutability : None , ident : _ } ) => write ! ( out, " const" ) ,
408
+ _ => { } ,
409
+ }
410
+ write ! ( out, " = " ) ;
411
+ match & efn. receiver {
412
+ None => write ! ( out, "{}" , efn. ident) ,
413
+ Some ( base) => write ! ( out, "&{}::{}" , base. ident, efn. ident) ,
414
+ }
415
+ writeln ! ( out, ";" ) ;
358
416
write ! ( out, " " ) ;
359
417
if efn. throws {
360
418
writeln ! ( out, "::rust::Str::Repr throw$;" ) ;
@@ -377,7 +435,10 @@ fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
377
435
}
378
436
_ => { }
379
437
}
380
- write ! ( out, "{}$(" , efn. ident) ;
438
+ match & efn. receiver {
439
+ None => write ! ( out, "{}$(" , efn. ident) ,
440
+ Some ( _) => write ! ( out, "(__receiver$->*{}$)(" , efn. ident) ,
441
+ }
381
442
for ( i, arg) in efn. args . iter ( ) . enumerate ( ) {
382
443
if i > 0 {
383
444
write ! ( out, ", " ) ;
@@ -452,7 +513,11 @@ fn write_function_pointer_trampoline(
452
513
}
453
514
454
515
fn write_rust_function_decl ( out : & mut OutFile , efn : & ExternFn , types : & Types ) {
455
- let link_name = format ! ( "{}cxxbridge02${}" , out. namespace, efn. ident) ;
516
+ let receiver_type = match & efn. receiver {
517
+ Some ( base) => base. ident . to_string ( ) ,
518
+ None => "_" . to_string ( ) ,
519
+ } ;
520
+ let link_name = format ! ( "{}cxxbridge02${}${}" , out. namespace, receiver_type, efn. ident) ;
456
521
let indirect_call = false ;
457
522
write_rust_function_decl_impl ( out, & link_name, efn, types, indirect_call) ;
458
523
}
@@ -471,6 +536,10 @@ fn write_rust_function_decl_impl(
471
536
}
472
537
write ! ( out, "{}(" , link_name) ;
473
538
let mut needs_comma = false ;
539
+ if let Some ( base) = & sig. receiver {
540
+ write ! ( out, "{} &__receiver$" , base. ident) ;
541
+ needs_comma = true ;
542
+ }
474
543
for arg in & sig. args {
475
544
if needs_comma {
476
545
write ! ( out, ", " ) ;
@@ -500,20 +569,26 @@ fn write_rust_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
500
569
writeln ! ( out, "//{}" , line) ;
501
570
}
502
571
let local_name = efn. ident . to_string ( ) ;
503
- let invoke = format ! ( "{}cxxbridge02${}" , out. namespace, efn. ident) ;
572
+ let receiver_type = match & efn. receiver {
573
+ Some ( base) => base. ident . to_string ( ) ,
574
+ None => "_" . to_string ( ) ,
575
+ } ;
576
+ let invoke = format ! ( "{}cxxbridge02${}${}" , out. namespace, receiver_type, efn. ident) ;
504
577
let indirect_call = false ;
505
578
write_rust_function_shim_impl ( out, & local_name, efn, types, & invoke, indirect_call) ;
506
579
}
507
580
508
- fn write_rust_function_shim_impl (
581
+ fn write_rust_function_shim_decl (
509
582
out : & mut OutFile ,
510
583
local_name : & str ,
511
584
sig : & Signature ,
512
- types : & Types ,
513
- invoke : & str ,
585
+ receiver : Option < & Receiver > ,
514
586
indirect_call : bool ,
515
587
) {
516
588
write_return_type ( out, & sig. ret ) ;
589
+ if let Some ( base) = receiver {
590
+ write ! ( out, "{}::" , base. ident) ;
591
+ }
517
592
write ! ( out, "{}(" , local_name) ;
518
593
for ( i, arg) in sig. args . iter ( ) . enumerate ( ) {
519
594
if i > 0 {
@@ -532,6 +607,21 @@ fn write_rust_function_shim_impl(
532
607
if !sig. throws {
533
608
write ! ( out, " noexcept" ) ;
534
609
}
610
+ }
611
+
612
+ fn write_rust_function_shim_impl (
613
+ out : & mut OutFile ,
614
+ local_name : & str ,
615
+ sig : & Signature ,
616
+ types : & Types ,
617
+ invoke : & str ,
618
+ indirect_call : bool ,
619
+ ) {
620
+ if out. header && sig. receiver . is_some ( ) {
621
+ // We've already defined this inside the struct.
622
+ return ;
623
+ }
624
+ write_rust_function_shim_decl ( out, local_name, sig, sig. receiver . as_ref ( ) , indirect_call) ;
535
625
if out. header {
536
626
writeln ! ( out, ";" ) ;
537
627
} else {
@@ -570,8 +660,11 @@ fn write_rust_function_shim_impl(
570
660
write ! ( out, "::rust::Str::Repr error$ = " ) ;
571
661
}
572
662
write ! ( out, "{}(" , invoke) ;
663
+ if let Some ( _) = & sig. receiver {
664
+ write ! ( out, "*this" ) ;
665
+ }
573
666
for ( i, arg) in sig. args . iter ( ) . enumerate ( ) {
574
- if i > 0 {
667
+ if i > 0 || sig . receiver . is_some ( ) {
575
668
write ! ( out, ", " ) ;
576
669
}
577
670
match & arg. ty {
0 commit comments