swift_bridge_ir/codegen/
generate_rust_tokens.rs1use std::collections::HashMap;
4
5use proc_macro2::TokenStream;
6use quote::ToTokens;
7use quote::{quote, quote_spanned};
8
9use self::vec::vec_of_opaque_rust_type::generate_vec_of_opaque_rust_type_functions;
10use crate::bridge_module_attributes::CfgAttr;
11use crate::parse::{HostLang, SharedTypeDeclaration, TypeDeclaration};
12use crate::SwiftBridgeModule;
13
14mod shared_enum;
15mod shared_struct;
16mod vec;
17
18impl ToTokens for SwiftBridgeModule {
19 fn to_tokens(&self, tokens: &mut TokenStream) {
20 let mod_name = &self.name;
21 let vis = &self.vis;
22 let swift_bridge_path = &self.swift_bridge_path;
23
24 let mut extern_rust_fn_tokens = vec![];
25
26 let mut structs_for_swift_classes = vec![];
27
28 let mut shared_struct_definitions = vec![];
29 let mut shared_enum_definitions = vec![];
30 let mut custom_type_definitions: HashMap<String, TokenStream> = HashMap::new();
31 let mut impl_fn_tokens: HashMap<String, Vec<TokenStream>> = HashMap::new();
32 let mut callbacks_support = vec![];
33 let mut freestanding_rust_call_swift_fn_tokens = vec![];
34 let mut extern_swift_fn_tokens = vec![];
35
36 for func in &self.functions {
37 match func.host_lang {
38 HostLang::Rust => {
39 extern_rust_fn_tokens.push(func.to_extern_c_function_tokens(
40 &self.swift_bridge_path,
41 &self.types,
42 &mut custom_type_definitions,
43 ));
44 }
45 HostLang::Swift => {
46 let tokens = func
47 .to_rust_fn_that_calls_a_swift_extern(&self.swift_bridge_path, &self.types);
48 callbacks_support
49 .push(func.callbacks_support(&self.swift_bridge_path, &self.types));
50
51 if let Some(ty) = func.associated_type.as_ref() {
52 match ty {
53 TypeDeclaration::Shared(_) => {
54 todo!()
57 }
58 TypeDeclaration::Opaque(ty) => {
59 impl_fn_tokens
60 .entry(ty.to_string())
61 .or_default()
62 .push(tokens);
63 }
64 };
65 } else {
66 freestanding_rust_call_swift_fn_tokens.push(tokens);
67 }
68
69 extern_swift_fn_tokens.push(func.to_extern_c_function_tokens(
70 &self.swift_bridge_path,
71 &self.types,
72 &mut custom_type_definitions,
73 ));
74 }
75 };
76 }
77
78 for ty in &self.types.types() {
79 match ty {
80 TypeDeclaration::Shared(SharedTypeDeclaration::Struct(shared_struct)) => {
81 if let Some(definition) = self.generate_shared_struct_tokens(shared_struct) {
82 shared_struct_definitions.push(definition);
83 }
84 }
85 TypeDeclaration::Shared(SharedTypeDeclaration::Enum(shared_enum)) => {
86 if let Some(definition) =
87 self.generate_shared_enum_tokens(shared_enum, &self.types)
88 {
89 shared_enum_definitions.push(definition);
90 }
91 }
92 TypeDeclaration::Opaque(ty) => {
93 if ty.attributes.declare_generic {
94 continue;
95 }
96
97 let link_name = ty.free_rust_opaque_type_ffi_name();
98 let free_mem_func_name = ty.free_rust_opaque_type_ident();
99 let this = &ty.ty;
100 let ty_name = &ty.ty;
101
102 match ty.host_lang {
103 HostLang::Rust => {
104 if ty.attributes.hashable {
105 let export_name = format!("__swift_bridge__${}$_hash", ty_name);
106 let function_name = syn::Ident::new(
107 &format!("__swift_bridge__{}__hash", ty_name),
108 ty.ty.span(),
109 );
110 let tokens = quote! {
111 #[export_name = #export_name]
112 pub extern "C" fn #function_name (
113 this: *const super::#ty_name,
114 ) -> u64 {
115 use std::hash::{Hash, Hasher};
116 use std::collections::hash_map::DefaultHasher;
117 let mut s = DefaultHasher::new();
118 (unsafe {&*this}).hash(&mut s);
119 s.finish()
120 }
121 };
122 extern_rust_fn_tokens.push(tokens);
123 }
124 if ty.attributes.equatable {
125 let export_name =
126 format!("__swift_bridge__${}$_partial_eq", ty_name);
127 let function_name = syn::Ident::new(
128 &format!("__swift_bridge__{}__partial_eq", ty_name),
129 ty.ty.span(),
130 );
131 let tokens = quote! {
132 #[export_name = #export_name]
133 pub extern "C" fn #function_name (
134 lhs: *const super::#ty_name,
135 rhs: *const super::#ty_name
136 ) -> bool {
137 unsafe { &*lhs == &*rhs }
138 }
139 };
140 extern_rust_fn_tokens.push(tokens);
141 }
142 if let Some(copy) = ty.attributes.copy {
143 let size = copy.size_bytes;
144
145 let generics = ty
146 .generics
147 .angle_bracketed_concrete_generics_tokens(&self.types);
148
149 let assert_size = quote_spanned! {ty.ty.span()=>
156 const _: () = {
157 let _: [u8; std::mem::size_of::<super::#ty_name #generics>()] = [0; #size];
158 fn _assert_copy() {
159 #swift_bridge_path::copy_support::assert_copy::<super::#ty_name #generics>();
160 }
161 };
162 };
163
164 let copy_ty_name = ty.ffi_copy_repr_ident();
165 let option_copy_ty_name = ty.ffi_option_copy_repr_ident();
166
167 let copy_ty = quote! {
168 #[repr(C)]
169 #[doc(hidden)]
170 pub struct #copy_ty_name([u8; #size]);
171 impl #copy_ty_name {
172 #[inline(always)]
173 fn into_rust_repr(self) -> super:: #ty_name #generics {
174 unsafe { std::mem::transmute(self) }
175 }
176 #[inline(always)]
177 fn from_rust_repr(repr: super:: #ty_name #generics) -> Self {
178 unsafe { std::mem::transmute(repr) }
179 }
180 }
181
182 #[repr(C)]
183 #[doc(hidden)]
184 pub struct #option_copy_ty_name {
185 is_some: bool,
186 val: std::mem::MaybeUninit<#copy_ty_name>
187 }
188 };
189
190 extern_rust_fn_tokens.push(assert_size);
191 extern_rust_fn_tokens.push(copy_ty);
192 }
193
194 if !ty.attributes.already_declared {
195 if ty.attributes.copy.is_none() {
196 let generics = ty
197 .generics
198 .angle_bracketed_concrete_generics_tokens(&self.types);
199
200 let free = quote! {
201 #[export_name = #link_name]
202 pub extern "C" fn #free_mem_func_name (this: *mut super::#this #generics) {
203 let this = unsafe { Box::from_raw(this) };
204 drop(this);
205 }
206 };
207
208 extern_rust_fn_tokens.push(free);
209
210 if ty.generics.len() == 0 {
214 let vec_functions =
215 generate_vec_of_opaque_rust_type_functions(ty_name);
216 extern_rust_fn_tokens.push(vec_functions);
217 }
218 }
219 }
220 }
221 HostLang::Swift => {
222 let ty_name = &ty.ty;
223
224 let impls = match impl_fn_tokens.get(&ty_name.to_string()) {
225 Some(impls) if impls.len() > 0 => {
226 quote! {
227 impl #ty_name {
228 #(#impls)*
229 }
230 }
231 }
232 _ => {
233 quote! {}
234 }
235 };
236
237 let struct_tokens = quote! {
238 #[repr(C)]
239 pub struct #ty_name(*mut std::ffi::c_void);
240
241 #impls
242
243 impl Drop for #ty_name {
244 fn drop (&mut self) {
245 unsafe { #free_mem_func_name(self.0) }
246 }
247 }
248 };
249 structs_for_swift_classes.push(struct_tokens);
250
251 let free = quote! {
252 #[link_name = #link_name]
253 fn #free_mem_func_name (this: *mut std::ffi::c_void);
254 };
255 extern_swift_fn_tokens.push(free);
256 }
257 };
258 }
259 }
260 }
261
262 let extern_swift_fn_tokens = if extern_swift_fn_tokens.len() > 0 {
263 generate_extern_c_block(extern_swift_fn_tokens)
264 } else {
265 quote! {}
266 };
267
268 let mut module_attributes = vec![];
269
270 for cfg in &self.cfg_attrs {
271 match cfg {
272 CfgAttr::Feature(feature_name) => {
273 module_attributes.push(quote! {
275 #[cfg(feature = #feature_name)]
276 });
277 }
278 };
279 }
280 let custom_type_definitions = custom_type_definitions.into_values();
281 let module_inner = quote! {
282 #(#shared_struct_definitions)*
283
284 #(#shared_enum_definitions)*
285
286 #(#custom_type_definitions)*
287
288 #(#extern_rust_fn_tokens)*
289
290 #(#freestanding_rust_call_swift_fn_tokens)*
291
292 #(#structs_for_swift_classes)*
293
294 #extern_swift_fn_tokens
295
296 #(#callbacks_support)*
297 };
298
299 let t = quote! {
300 #[allow(non_snake_case)]
301 #(#module_attributes)*
302 #vis mod #mod_name {
303 #module_inner
304 }
305 };
306 t.to_tokens(tokens);
307 }
308}
309
310fn generate_extern_c_block(extern_swift_fn_tokens: Vec<TokenStream>) -> TokenStream {
379 quote! {
380 #[allow(improper_ctypes)]
381 extern "C" {
382 #(#extern_swift_fn_tokens)*
383 }
384 }
385}
386
387#[cfg(test)]
388mod tests {
389 use quote::quote;
392
393 use crate::parse::SwiftBridgeModuleAndErrors;
394 use crate::test_utils::{assert_tokens_contain, assert_tokens_eq};
395
396 use super::*;
397
398 #[test]
400 fn freestanding_rust_function_no_args() {
401 let start = quote! {
402 mod foo {
403 extern "Rust" {
404 fn some_function ();
405 }
406 }
407 };
408 let expected = quote! {
409 #[allow(non_snake_case)]
410 mod foo {
411 #[export_name = "__swift_bridge__$some_function"]
412 pub extern "C" fn __swift_bridge__some_function () {
413 super::some_function()
414 }
415 }
416 };
417
418 assert_tokens_eq(&parse_ok(start).to_token_stream(), &expected);
419 }
420
421 #[test]
423 fn freestanding_swift_function_no_args() {
424 let start = quote! {
425 mod foo {
426 extern "Swift" {
427 fn some_function ();
428 }
429 }
430 };
431 let expected = quote! {
432 #[allow(non_snake_case)]
433 mod foo {
434 pub fn some_function() {
435 unsafe { __swift_bridge__some_function() }
436 }
437
438 #[allow(improper_ctypes)]
439 extern "C" {
440 #[link_name = "__swift_bridge__$some_function"]
441 fn __swift_bridge__some_function ();
442 }
443 }
444 };
445
446 assert_tokens_eq(&parse_ok(start).to_token_stream(), &expected);
447 }
448
449 #[test]
452 fn freestanding_swift_function_one_arg() {
453 let start = quote! {
454 mod foo {
455 extern "Swift" {
456 fn some_function (start: bool);
457 }
458 }
459 };
460 let expected = quote! {
461 #[allow(non_snake_case)]
462 mod foo {
463 pub fn some_function(start: bool) {
464 unsafe { __swift_bridge__some_function(start) }
465 }
466
467 #[allow(improper_ctypes)]
468 extern "C" {
469 #[link_name = "__swift_bridge__$some_function"]
470 fn __swift_bridge__some_function (start: bool);
471 }
472 }
473 };
474
475 assert_tokens_eq(&parse_ok(start).to_token_stream(), &expected);
476 }
477
478 #[test]
480 fn freestanding_rust_one_arg() {
481 let start = quote! {
482 mod foo {
483 extern "Rust" {
484 fn some_function (bar: u8);
485 }
486 }
487 };
488 let expected = quote! {
489 #[allow(non_snake_case)]
490 mod foo {
491 #[export_name = "__swift_bridge__$some_function"]
492 pub extern "C" fn __swift_bridge__some_function (bar: u8) {
493 super::some_function(bar)
494 }
495 }
496 };
497
498 assert_tokens_eq(&parse_ok(start).to_token_stream(), &expected);
499 }
500
501 #[test]
504 fn freestanding_rust_func_with_declared_swift_type_arg() {
505 let start = quote! {
506 mod foo {
507 extern "Rust" {
508 fn some_function (bar: MyType);
509 }
510
511 extern "Swift" {
512 type MyType;
513 }
514 }
515 };
516 let expected = quote! {
517 #[export_name = "__swift_bridge__$some_function"]
518 pub extern "C" fn __swift_bridge__some_function (
519 bar: MyType
520 ) {
521 super::some_function(
522 bar
523 )
524 }
525 };
526
527 assert_tokens_contain(&parse_ok(start).to_token_stream(), &expected);
528 }
529
530 #[test]
533 fn freestanding_rust_func_returns_opaque_swift_type() {
534 let start = quote! {
535 mod foo {
536 extern "Rust" {
537 fn some_function () -> MyType;
538 }
539
540 extern "Swift" {
541 type MyType;
542 }
543 }
544 };
545 let expected = quote! {
546 #[export_name = "__swift_bridge__$some_function"]
547 pub extern "C" fn __swift_bridge__some_function () -> MyType {
548 super::some_function()
549 }
550 };
551
552 assert_tokens_contain(&parse_ok(start).to_token_stream(), &expected);
553 }
554
555 #[test]
557 fn freestanding_rust_with_built_in_return_type() {
558 let start = quote! {
559 mod foo {
560 extern "Rust" {
561 fn some_function () -> u8;
562 }
563 }
564 };
565 let expected = quote! {
566 #[allow(non_snake_case)]
567 mod foo {
568 #[export_name = "__swift_bridge__$some_function"]
569 pub extern "C" fn __swift_bridge__some_function () -> u8 {
570 super::some_function()
571 }
572 }
573 };
574
575 assert_tokens_eq(&parse_ok(start).to_token_stream(), &expected);
576 }
577
578 #[test]
580 fn extern_rust_freestanding_function_rust_name() {
581 let start = quote! {
582 #[swift_bridge::bridge]
583 mod foo {
584 extern "Rust" {
585 type Foo;
586
587 #[swift_bridge(rust_name = "another_function")]
588 fn some_function () -> Foo;
589 }
590 }
591 };
592 let expected_func = quote! {
593 #[export_name = "__swift_bridge__$some_function"]
594 pub extern "C" fn __swift_bridge__some_function () -> *mut super::Foo {
595 Box::into_raw(Box::new({
596 let val: super::Foo = super::another_function();
597 val
598 })) as *mut super::Foo
599 }
600 };
601
602 assert_tokens_contain(&parse_ok(start).to_token_stream(), &expected_func);
603 }
604
605 #[test]
607 fn extern_rust_return_into() {
608 let start = quote! {
609 #[swift_bridge::bridge]
610 mod foo {
611 extern "Rust" {
612 type Foo;
613
614 #[swift_bridge(return_into)]
615 fn some_function () -> Foo;
616 }
617 }
618 };
619 let expected_func = quote! {
620 #[export_name = "__swift_bridge__$some_function"]
621 pub extern "C" fn __swift_bridge__some_function () -> *mut super::Foo {
622 Box::into_raw(Box::new({
623 let val: super::Foo = super::some_function().into();
624 val
625 })) as *mut super::Foo
626 }
627 };
628
629 assert_tokens_contain(&parse_ok(start).to_token_stream(), &expected_func);
630 }
631
632 #[test]
634 fn associated_fn_return_reference_to_bridged_type() {
635 let start = quote! {
636 #[swift_bridge::bridge]
637 mod foo {
638 extern "Rust" {
639 type Foo;
640 fn some_function () -> &'static Foo;
641 }
642 }
643 };
644 let expected_func = quote! {
645 #[export_name = "__swift_bridge__$some_function"]
646 pub extern "C" fn __swift_bridge__some_function () -> *const super::Foo {
647 super::some_function() as *const super::Foo
648 }
649 };
650
651 assert_tokens_contain(&parse_ok(start).to_token_stream(), &expected_func);
652 }
653
654 #[test]
656 fn method_return_reference_to_bridged_type() {
657 let start = quote! {
658 #[swift_bridge::bridge]
659 mod foo {
660 extern "Rust" {
661 type Foo;
662 fn some_function (&mut self) -> &mut Foo;
663 }
664 }
665 };
666 let expected_func = quote! {
667 #[export_name = "__swift_bridge__$Foo$some_function"]
668 pub extern "C" fn __swift_bridge__Foo_some_function (
669 this: *mut super::Foo
670 ) -> *mut super::Foo {
671 (unsafe { &mut * this }).some_function() as *mut super::Foo
672 }
673 };
674
675 assert_tokens_contain(&parse_ok(start).to_token_stream(), &expected_func);
676 }
677
678 #[test]
680 fn generates_struct_for_swift_type() {
681 let start = quote! {
682 #[swift_bridge::bridge]
683 mod foo {
684 extern "Swift" {
685 type Foo;
686 }
687 }
688 };
689 let expected = quote! {
690 #[repr(C)]
691 pub struct Foo(*mut std::ffi::c_void);
692
693 impl Drop for Foo {
694 fn drop (&mut self) {
695 unsafe { __swift_bridge__Foo__free(self.0) }
696 }
697 }
698
699 #[allow(improper_ctypes)]
700 extern "C" {
701 #[link_name = "__swift_bridge__$Foo$_free"]
702 fn __swift_bridge__Foo__free (this: *mut std::ffi::c_void);
703 }
704 };
705
706 assert_tokens_contain(&parse_ok(start).to_token_stream(), &expected);
707 }
708
709 #[test]
711 fn associated_rust_static_method_no_args() {
712 let start = quote! {
713 mod foo {
714 extern "Rust" {
715 type SomeType;
716
717 #[swift_bridge(associated_to = SomeType)]
718 fn new () -> SomeType;
719 }
720 }
721 };
722 let expected = quote! {
723 #[export_name = "__swift_bridge__$SomeType$new"]
724 pub extern "C" fn __swift_bridge__SomeType_new () -> *mut super::SomeType {
725 Box::into_raw(Box::new({
726 let val: super::SomeType = super::SomeType::new();
727 val
728 })) as *mut super::SomeType
729 }
730 };
731
732 assert_to_extern_c_function_tokens(start, &expected);
733 }
734
735 #[test]
737 fn swift_class_method_no_args() {
738 let start = quote! {
739 #[swift_bridge::bridge]
740 mod foo {
741 extern "Swift" {
742 type Foo;
743
744 #[swift_bridge(associated_to = Foo)]
745 fn new () -> Foo;
746 }
747 }
748 };
749 let expected = quote! {
750 #[repr(C)]
751 pub struct Foo(*mut std::ffi::c_void);
752
753 impl Foo {
754 pub fn new () -> Foo {
755 unsafe{ __swift_bridge__Foo_new() }
756 }
757 }
758
759 impl Drop for Foo {
760 fn drop (&mut self) {
761 unsafe { __swift_bridge__Foo__free(self.0) }
762 }
763 }
764
765 #[allow(improper_ctypes)]
766 extern "C" {
767 #[link_name = "__swift_bridge__$Foo$new"]
768 fn __swift_bridge__Foo_new() -> Foo;
769
770 #[link_name = "__swift_bridge__$Foo$_free"]
771 fn __swift_bridge__Foo__free (this: *mut std::ffi::c_void);
772 }
773 };
774
775 assert_tokens_contain(&parse_ok(start).to_token_stream(), &expected);
776 }
777
778 #[test]
780 fn associated_rust_static_method_one_arg() {
781 let start = quote! {
782 mod foo {
783 extern "Rust" {
784 type SomeType;
785
786 #[swift_bridge(associated_to = SomeType)]
787 fn new (foo: u8) -> u8;
788 }
789 }
790 };
791 let expected = quote! {
792 #[export_name = "__swift_bridge__$SomeType$new"]
793 pub extern "C" fn __swift_bridge__SomeType_new (foo: u8) -> u8 {
794 super::SomeType::new(foo)
795 }
796 };
797
798 assert_to_extern_c_function_tokens(start, &expected);
799 }
800
801 #[test]
803 fn associated_static_method_no_return_type() {
804 let start = quote! {
805 mod foo {
806 extern "Rust" {
807 type SomeType;
808
809 #[swift_bridge(associated_to = SomeType)]
810 fn new ();
811 }
812 }
813 };
814 let expected = quote! {
815 #[export_name = "__swift_bridge__$SomeType$new"]
816 pub extern "C" fn __swift_bridge__SomeType_new () {
817 super::SomeType::new()
818 }
819 };
820
821 assert_to_extern_c_function_tokens(start, &expected);
822 }
823
824 #[test]
826 fn associated_rust_method_no_args() {
827 let start = quote! {
828 mod foo {
829 extern "Rust" {
830 type MyType;
831 fn increment (&mut self);
832 }
833 }
834 };
835 let expected = quote! {
836 #[export_name = "__swift_bridge__$MyType$increment"]
837 pub extern "C" fn __swift_bridge__MyType_increment (
838 this: *mut super::MyType
839 ) {
840 (unsafe { &mut *this }).increment()
841 }
842 };
843
844 assert_to_extern_c_function_tokens(start, &expected);
845 }
846
847 #[test]
849 fn swift_instance_methods() {
850 let start = quote! {
851 #[swift_bridge::bridge]
852 mod foo {
853 extern "Swift" {
854 type Foo;
855
856 fn notify (&self);
857 fn message (self: &Foo);
858 fn call (&mut self, volume: u8);
859 }
860 }
861 };
862 let expected = quote! {
863 #[repr(C)]
864 pub struct Foo(*mut std::ffi::c_void);
865
866 impl Foo {
867 pub fn notify (&self) {
868 unsafe { __swift_bridge__Foo_notify(swift_bridge::PointerToSwiftType(self.0)) }
869 }
870
871 pub fn message (&self) {
872 unsafe { __swift_bridge__Foo_message(swift_bridge::PointerToSwiftType(self.0)) }
873 }
874
875 pub fn call (&mut self, volume: u8) {
876 unsafe { __swift_bridge__Foo_call(swift_bridge::PointerToSwiftType(self.0), volume) }
877 }
878 }
879
880 impl Drop for Foo {
881 fn drop (&mut self) {
882 unsafe { __swift_bridge__Foo__free(self.0) }
883 }
884 }
885
886 #[allow(improper_ctypes)]
887 extern "C" {
888 #[link_name = "__swift_bridge__$Foo$notify"]
889 fn __swift_bridge__Foo_notify(this: swift_bridge::PointerToSwiftType);
890
891 #[link_name = "__swift_bridge__$Foo$message"]
892 fn __swift_bridge__Foo_message(this: swift_bridge::PointerToSwiftType);
893
894 #[link_name = "__swift_bridge__$Foo$call"]
895 fn __swift_bridge__Foo_call(this: swift_bridge::PointerToSwiftType, volume: u8);
896
897 #[link_name = "__swift_bridge__$Foo$_free"]
898 fn __swift_bridge__Foo__free (this: *mut std::ffi::c_void);
899 }
900 };
901
902 assert_tokens_contain(&parse_ok(start).to_token_stream(), &expected);
903 }
904
905 #[test]
907 fn rust_associated_method_one_args() {
908 let start = quote! {
909 mod foo {
910 extern "Rust" {
911 type SomeType;
912 fn message (&self, val: u8);
913 }
914 }
915 };
916 let expected = quote! {
917 #[export_name = "__swift_bridge__$SomeType$message"]
918 pub extern "C" fn __swift_bridge__SomeType_message (
919 this: *mut super::SomeType,
920 val: u8
921 ) {
922 (unsafe { &*this }).message(val)
923 }
924 };
925
926 assert_to_extern_c_function_tokens(start, &expected);
927 }
928
929 #[test]
931 fn extern_rust_void_pointers() {
932 let start = quote! {
933 mod foo {
934 extern "Rust" {
935 fn void_pointers (arg1: *const c_void, arg2: *mut c_void) -> *const c_void;
936 }
937 }
938 };
939 let expected = quote! {
940 #[export_name = "__swift_bridge__$void_pointers"]
941 pub extern "C" fn __swift_bridge__void_pointers (
942 arg1: *const super::c_void,
943 arg2: *mut super::c_void
944 ) -> *const super::c_void {
945 super::void_pointers(arg1, arg2)
946 }
947 };
948
949 assert_to_extern_c_function_tokens(start, &expected);
950 }
951
952 #[test]
954 fn extern_swift_built_in_pointers() {
955 let start = quote! {
956 mod foo {
957 extern "Swift" {
958 fn built_in_pointers (arg1: *const u8, arg2: *mut i16) -> *const u32;
959 }
960 }
961 };
962 let expected = quote! {
963 pub fn built_in_pointers (arg1: *const u8, arg2: *mut i16) -> *const u32 {
964 unsafe { __swift_bridge__built_in_pointers(arg1, arg2) }
965 }
966
967 #[allow(improper_ctypes)]
968 extern "C" {
969 #[link_name = "__swift_bridge__$built_in_pointers"]
970 fn __swift_bridge__built_in_pointers (
971 arg1: *const u8,
972 arg2: *mut i16
973 ) -> *const u32;
974 }
975 };
976
977 assert_tokens_contain(&parse_ok(start).to_token_stream(), &expected);
978 }
979
980 #[test]
982 fn extern_swift_void_pointers() {
983 let start = quote! {
984 mod foo {
985 extern "Swift" {
986 fn void_pointers (arg1: *const c_void, arg2: *mut c_void) -> *const c_void;
987 }
988 }
989 };
990 let expected = quote! {
991 pub fn void_pointers (arg1: *const super::c_void, arg2: *mut super::c_void) -> *const super::c_void {
992 unsafe { __swift_bridge__void_pointers(arg1, arg2) }
993 }
994
995 #[allow(improper_ctypes)]
996 extern "C" {
997 #[link_name = "__swift_bridge__$void_pointers"]
998 fn __swift_bridge__void_pointers (
999 arg1: *const super::c_void,
1000 arg2: *mut super::c_void
1001 ) -> *const super::c_void;
1002 }
1003 };
1004
1005 assert_tokens_contain(&parse_ok(start).to_token_stream(), &expected);
1006 }
1007
1008 #[test]
1010 fn associated_method_drops_owned_self() {
1011 let start = quote! {
1012 mod foo {
1013 extern "Rust" {
1014 type SomeType;
1015 fn consume (self);
1016 }
1017 }
1018 };
1019 let expected = quote! {
1020 #[export_name = "__swift_bridge__$SomeType$consume"]
1021 pub extern "C" fn __swift_bridge__SomeType_consume (
1022 this: *mut super::SomeType
1023 ) {
1024 (* unsafe { Box::from_raw(this) }).consume()
1025 }
1026 };
1027
1028 assert_to_extern_c_function_tokens(start, &expected);
1029 }
1030
1031 fn parse_ok(tokens: TokenStream) -> SwiftBridgeModule {
1032 let module_and_errors: SwiftBridgeModuleAndErrors = syn::parse2(tokens).unwrap();
1033 module_and_errors.module
1034 }
1035
1036 fn assert_to_extern_c_function_tokens(module: TokenStream, expected_fn: &TokenStream) {
1037 let module = parse_ok(module);
1038 let function = &module.functions[0];
1039
1040 assert_tokens_eq(
1041 &function.to_extern_c_function_tokens(
1042 &module.swift_bridge_path,
1043 &module.types,
1044 &mut HashMap::new(),
1045 ),
1046 &expected_fn,
1047 );
1048 }
1049
1050 #[test]
1052 fn module_visibility() {
1053 let start = quote! {
1054 pub(super) mod foo {
1055 }
1056 };
1057 let expected = quote! {
1058 #[allow(non_snake_case)]
1059 pub(super) mod foo {
1060 }
1061 };
1062
1063 assert_tokens_eq(&parse_ok(start).to_token_stream(), &expected);
1064 }
1065}