Skip to content

Commit 5475a75

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 cd9346d commit 5475a75

File tree

2 files changed

+36
-3
lines changed

2 files changed

+36
-3
lines changed

csbindgen/src/emitter.rs

+12-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::*;
@@ -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
}
@@ -227,6 +232,7 @@ pub fn emit_csharp(
227232
true,
228233
&"".to_string(),
229234
&"".to_string(),
235+
&mut forward_decls,
230236
);
231237
let attr = if type_name == "bool" {
232238
"[MarshalAs(UnmanagedType.U1)] ".to_string()
@@ -305,6 +311,7 @@ pub fn emit_csharp(
305311
false,
306312
&"".to_string(),
307313
&"".to_string(),
314+
&mut forward_decls,
308315
);
309316

310317
// special case for string, char, ByteStr
@@ -361,6 +368,8 @@ pub fn emit_csharp(
361368
imported_namespaces.push_str_ln(format!("using {name};").as_str());
362369
}
363370

371+
let forward_decls_string = forward_decls.drain().collect::<Vec<_>>().join("\n");
372+
364373
let result = format!(
365374
"{file_header}
366375
using System;
@@ -376,6 +385,7 @@ namespace {namespace}
376385
{const_string}
377386
378387
{method_list_string}
388+
{forward_decls_string}
379389
}}
380390
381391
{structs_string}

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 {
@@ -220,6 +222,7 @@ impl RustType {
220222
emit_from_struct: bool,
221223
method_name: &String,
222224
parameter_name: &String,
225+
forward_decls: &mut HashSet<String>,
223226
) -> String {
224227
fn convert_type_name(type_name: &str, options: &BindgenOptions) -> String {
225228
let temp_string: String;
@@ -300,6 +303,7 @@ impl RustType {
300303
emit_from_struct,
301304
method_name,
302305
parameter_name,
306+
forward_decls,
303307
)
304308
} else {
305309
convert_type_name(use_type.type_name.as_str(), options).to_string()
@@ -339,6 +343,7 @@ impl RustType {
339343
emit_from_struct,
340344
method_name,
341345
parameter_name,
346+
forward_decls,
342347
));
343348
sb.push_str(", ");
344349
}
@@ -350,6 +355,7 @@ impl RustType {
350355
emit_from_struct,
351356
method_name,
352357
parameter_name,
358+
forward_decls,
353359
));
354360
}
355361
None => {
@@ -358,7 +364,15 @@ impl RustType {
358364
};
359365
sb.push('>');
360366
} else {
361-
sb.push_str(build_method_delegate_name(method_name, parameter_name).as_str());
367+
let delegate_name = build_method_delegate_name(method_name, parameter_name);
368+
369+
sb.push_str(&delegate_name);
370+
371+
let decl = build_method_delegate_if_required(self, options, alias_map, method_name, parameter_name, forward_decls);
372+
373+
if let Some(decl) = decl {
374+
forward_decls.insert(format!(" [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n public {decl};"));
375+
}
362376
}
363377
}
364378
TypeKind::Option(inner) => {
@@ -371,6 +385,7 @@ impl RustType {
371385
emit_from_struct,
372386
method_name,
373387
parameter_name,
388+
forward_decls,
374389
)
375390
.as_str(),
376391
);
@@ -385,6 +400,7 @@ impl RustType {
385400
method_name: &String,
386401
parameter_name: &String,
387402
emit_inner: bool,
403+
forward_decls: &mut HashSet<String>,
388404
) -> bool {
389405
use PointerType::*;
390406
if let TypeKind::Pointer(p, inner) = &rust_type.type_kind {
@@ -397,6 +413,7 @@ impl RustType {
397413
emit_from_struct,
398414
method_name,
399415
parameter_name,
416+
forward_decls,
400417
)
401418
.as_str(),
402419
);
@@ -428,6 +445,7 @@ impl RustType {
428445
method_name,
429446
parameter_name,
430447
emit_inner,
448+
forward_decls,
431449
) {
432450
sb.push_str(type_csharp_string.as_str());
433451
}
@@ -444,6 +462,7 @@ impl RustType {
444462
method_name,
445463
parameter_name,
446464
emit_inner,
465+
forward_decls,
447466
) {
448467
if emit_inner {
449468
sb.push_str(type_csharp_string.as_str());
@@ -462,6 +481,7 @@ pub fn build_method_delegate_if_required(
462481
alias_map: &AliasMap,
463482
method_name: &String,
464483
parameter_name: &String,
484+
forward_decls: &mut HashSet<String>,
465485
) -> Option<String> {
466486
let emit_from_struct = false;
467487

@@ -479,6 +499,7 @@ pub fn build_method_delegate_if_required(
479499
emit_from_struct,
480500
method_name,
481501
parameter_name,
502+
forward_decls,
482503
),
483504
None => "void".to_string(),
484505
};
@@ -493,6 +514,7 @@ pub fn build_method_delegate_if_required(
493514
emit_from_struct,
494515
method_name,
495516
parameter_name,
517+
forward_decls,
496518
);
497519
let parameter_name = if p.name == "" {
498520
format!("arg{}", index + 1)
@@ -517,6 +539,7 @@ pub fn build_method_delegate_if_required(
517539
alias_map,
518540
method_name,
519541
parameter_name,
542+
forward_decls,
520543
),
521544
_ => None,
522545
}

0 commit comments

Comments
 (0)