Skip to content

Commit 9cafa3d

Browse files
committed
Added "delayed" generation of delegate signatures.
With this patch if a delegate is found during the construction of a method, its declaration is still emitted, after all the other types have been. This is implemented through an HashSet of forward declarations that is used as now for delegates, but can be expanded to include other item types in the future.
1 parent c0c873c commit 9cafa3d

10 files changed

+53
-3
lines changed

csbindgen/src/emitter.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::HashSet;
2+
13
use crate::alias_map::AliasMap;
24
use crate::builder::BindgenOptions;
35
use crate::type_meta::ExportSymbolNaming::{ExportName, NoMangle};
@@ -88,6 +90,7 @@ pub fn emit_csharp(
8890
let class_name = &options.csharp_class_name;
8991
let method_prefix = &options.csharp_method_prefix;
9092
let accessibility = &options.csharp_class_accessibility;
93+
let mut forward_decls: HashSet<String> = HashSet::new();
9194

9295
let mut dll_name = match options.csharp_if_symbol.as_str() {
9396
"" => format!(
@@ -126,6 +129,7 @@ pub fn emit_csharp(
126129
aliases,
127130
method_name,
128131
&"return".to_string(),
132+
&mut forward_decls,
129133
) {
130134
method_list_string.push_str(
131135
format!(" [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n")
@@ -143,6 +147,7 @@ pub fn emit_csharp(
143147
aliases,
144148
method_name,
145149
&p.name,
150+
&mut forward_decls,
146151
) {
147152
method_list_string.push_str(
148153
format!(" [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n")
@@ -164,7 +169,7 @@ pub fn emit_csharp(
164169
};
165170
let return_type = match &item.return_type {
166171
Some(x) => {
167-
x.to_csharp_string(options, aliases, false, method_name, &"return".to_string())
172+
x.to_csharp_string(options, aliases, false, method_name, &"return".to_string(), &mut forward_decls)
168173
}
169174
None => "void".to_string(),
170175
};
@@ -175,7 +180,7 @@ pub fn emit_csharp(
175180
.map(|p| {
176181
let mut type_name =
177182
p.rust_type
178-
.to_csharp_string(options, aliases, false, method_name, &p.name);
183+
.to_csharp_string(options, aliases, false, method_name, &p.name, &mut forward_decls);
179184
if type_name == "bool" {
180185
type_name = "[MarshalAs(UnmanagedType.U1)] bool".to_string();
181186
}
@@ -226,6 +231,7 @@ pub fn emit_csharp(
226231
true,
227232
&"".to_string(),
228233
&"".to_string(),
234+
&mut forward_decls,
229235
);
230236
let attr = if type_name == "bool" {
231237
"[MarshalAs(UnmanagedType.U1)] ".to_string()
@@ -304,6 +310,7 @@ pub fn emit_csharp(
304310
false,
305311
&"".to_string(),
306312
&"".to_string(),
313+
&mut forward_decls,
307314
);
308315

309316
// special case for string, char, ByteStr
@@ -347,6 +354,8 @@ pub fn emit_csharp(
347354
let class_string = if method_list_string.is_empty() && const_string.is_empty() {
348355
String::new()
349356
} else {
357+
let forward_decls_string = forward_decls.drain().collect::<Vec<_>>().join("\n");
358+
350359
format!(
351360
"{accessibility} static unsafe partial class {class_name}
352361
{{
@@ -355,6 +364,8 @@ pub fn emit_csharp(
355364
{const_string}
356365
357366
{method_list_string}
367+
368+
{forward_decls_string}
358369
}}"
359370
)
360371
};

csbindgen/src/type_meta.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::HashSet;
2+
13
use crate::{alias_map::AliasMap, builder::BindgenOptions};
24

35
pub fn escape_csharp_name(str: &str) -> String {
@@ -228,6 +230,7 @@ impl RustType {
228230
emit_from_struct: bool,
229231
method_name: &String,
230232
parameter_name: &String,
233+
forward_decls: &mut HashSet<String>,
231234
) -> String {
232235
fn convert_type_name(type_name: &str, options: &BindgenOptions) -> String {
233236
let temp_string: String;
@@ -308,6 +311,7 @@ impl RustType {
308311
emit_from_struct,
309312
method_name,
310313
parameter_name,
314+
forward_decls,
311315
)
312316
} else {
313317
convert_type_name(use_type.type_name.as_str(), options).to_string()
@@ -347,6 +351,7 @@ impl RustType {
347351
emit_from_struct,
348352
method_name,
349353
parameter_name,
354+
forward_decls,
350355
));
351356
sb.push_str(", ");
352357
}
@@ -358,6 +363,7 @@ impl RustType {
358363
emit_from_struct,
359364
method_name,
360365
parameter_name,
366+
forward_decls,
361367
));
362368
}
363369
None => {
@@ -366,7 +372,15 @@ impl RustType {
366372
};
367373
sb.push('>');
368374
} else {
369-
sb.push_str(build_method_delegate_name(method_name, parameter_name).as_str());
375+
let delegate_name = build_method_delegate_name(method_name, parameter_name);
376+
377+
sb.push_str(&delegate_name);
378+
379+
let decl = build_method_delegate_if_required(self, options, alias_map, method_name, parameter_name, forward_decls);
380+
381+
if let Some(decl) = decl {
382+
forward_decls.insert(format!(" [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n public {decl};"));
383+
}
370384
}
371385
}
372386
TypeKind::Option(inner) => {
@@ -379,6 +393,7 @@ impl RustType {
379393
emit_from_struct,
380394
method_name,
381395
parameter_name,
396+
forward_decls,
382397
)
383398
.as_str(),
384399
);
@@ -393,6 +408,7 @@ impl RustType {
393408
method_name: &String,
394409
parameter_name: &String,
395410
emit_inner: bool,
411+
forward_decls: &mut HashSet<String>,
396412
) -> bool {
397413
use PointerType::*;
398414
if let TypeKind::Pointer(p, inner) = &rust_type.type_kind {
@@ -405,6 +421,7 @@ impl RustType {
405421
emit_from_struct,
406422
method_name,
407423
parameter_name,
424+
forward_decls,
408425
)
409426
.as_str(),
410427
);
@@ -436,6 +453,7 @@ impl RustType {
436453
method_name,
437454
parameter_name,
438455
emit_inner,
456+
forward_decls,
439457
) {
440458
sb.push_str(type_csharp_string.as_str());
441459
}
@@ -452,6 +470,7 @@ impl RustType {
452470
method_name,
453471
parameter_name,
454472
emit_inner,
473+
forward_decls,
455474
) {
456475
if emit_inner {
457476
sb.push_str(type_csharp_string.as_str());
@@ -470,6 +489,7 @@ pub fn build_method_delegate_if_required(
470489
alias_map: &AliasMap,
471490
method_name: &String,
472491
parameter_name: &String,
492+
forward_decls: &mut HashSet<String>,
473493
) -> Option<String> {
474494
let emit_from_struct = false;
475495

@@ -487,6 +507,7 @@ pub fn build_method_delegate_if_required(
487507
emit_from_struct,
488508
method_name,
489509
parameter_name,
510+
forward_decls,
490511
),
491512
None => "void".to_string(),
492513
};
@@ -501,6 +522,7 @@ pub fn build_method_delegate_if_required(
501522
emit_from_struct,
502523
method_name,
503524
parameter_name,
525+
forward_decls,
504526
);
505527
let parameter_name = if p.name == "" {
506528
format!("arg{}", index + 1)
@@ -525,6 +547,7 @@ pub fn build_method_delegate_if_required(
525547
alias_map,
526548
method_name,
527549
parameter_name,
550+
forward_decls,
528551
),
529552
_ => None,
530553
}

dotnet-sandbox/NativeMethods.cs

+2
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ internal static unsafe partial class NativeMethods
181181
internal static extern void free_treat_as_empty_struct_context(TreatAsEmptyStruct* _src);
182182

183183

184+
185+
184186
}
185187

186188
[StructLayout(LayoutKind.Sequential)]

dotnet-sandbox/NestedModuleTests.cs

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ internal static unsafe partial class NestedModuleTests
2626
internal static extern int number_map(NumberEnum input);
2727

2828

29+
30+
2931
}
3032

3133
[StructLayout(LayoutKind.Sequential)]

dotnet-sandbox/bullet3_bindgen.cs

+2
Original file line numberDiff line numberDiff line change
@@ -1915,6 +1915,8 @@ internal static unsafe partial class LibBullet3
19151915
internal static extern void b3RotateVector(double* quat, double* vec, double* vecOut);
19161916

19171917

1918+
1919+
19181920
}
19191921

19201922
[StructLayout(LayoutKind.Sequential)]

dotnet-sandbox/libphysx_csbindgen.cs

+2
Original file line numberDiff line numberDiff line change
@@ -15540,6 +15540,8 @@ internal static unsafe partial class LibPhysx
1554015540
internal static extern PxPvdTransport* phys_PxDefaultPvdFileTransportCreate(byte* name);
1554115541

1554215542

15543+
15544+
1554315545
}
1554415546

1554515547
[StructLayout(LayoutKind.Sequential)]

dotnet-sandbox/libpng16_csbindgen.cs

+2
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,8 @@ internal static unsafe partial class LibPng16
938938
internal static extern int png_set_option(png_struct_def* png_ptr, int option, int onoff);
939939

940940

941+
942+
941943
}
942944

943945
[StructLayout(LayoutKind.Sequential)]

dotnet-sandbox/lz4_bindgen.cs

+2
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,8 @@ public static unsafe partial class LibLz4
997997
public static extern void LZ4F_resetDecompressionContext(LZ4F_dctx_s* dctx);
998998

999999

1000+
1001+
10001002
}
10011003

10021004
[StructLayout(LayoutKind.Sequential)]

dotnet-sandbox/quiche_bindgen.cs

+2
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,8 @@ internal static unsafe partial class LibQuiche
416416
internal static extern void quiche_h3_conn_free(quiche_h3_conn* conn);
417417

418418

419+
420+
419421
}
420422

421423
[StructLayout(LayoutKind.Sequential)]

dotnet-sandbox/zstd_bindgen.cs

+2
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,8 @@ internal static unsafe partial class LibZstd
626626
internal static extern nuint ZSTD_sizeof_DDict(ZSTD_DDict_s* ddict);
627627

628628

629+
630+
629631
}
630632

631633
[StructLayout(LayoutKind.Sequential)]

0 commit comments

Comments
 (0)