Skip to content

supported nested delegate functions #108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 30 additions & 40 deletions csbindgen/src/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ pub fn emit_csharp(
}

let mut method_list_string = String::new();
let mut delegate_list = Vec::new();
for item in methods {
let mut method_name = &item.method_name;
let method_name_temp: String;
Expand All @@ -119,40 +120,6 @@ pub fn emit_csharp(
method_name = &method_name_temp;
}

if let Some(x) = &item.return_type {
if let Some(delegate_method) = build_method_delegate_if_required(
x,
options,
aliases,
method_name,
&"return".to_string(),
) {
method_list_string.push_str(
format!(" [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n")
.as_str(),
);
method_list_string
.push_str(format!(" {accessibility} {delegate_method};\n\n").as_str());
}
}

for p in item.parameters.iter() {
if let Some(delegate_method) = build_method_delegate_if_required(
&p.rust_type,
options,
aliases,
method_name,
&p.name,
) {
method_list_string.push_str(
format!(" [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n")
.as_str(),
);
method_list_string
.push_str(format!(" {accessibility} {delegate_method};\n\n").as_str());
}
}

let entry_point = match &item.export_naming {
NoMangle => &item.method_name,
ExportName(export_name) => export_name,
Expand All @@ -163,19 +130,29 @@ pub fn emit_csharp(
x => format!("{x}{entry_point}"),
};
let return_type = match &item.return_type {
Some(x) => {
x.to_csharp_string(options, aliases, false, method_name, &"return".to_string())
}
Some(x) => x.to_csharp_string(
options,
aliases,
&mut delegate_list,
false,
method_name,
&"return".to_string(),
),
None => "void".to_string(),
};

let parameters = item
.parameters
.iter()
.map(|p| {
let mut type_name =
p.rust_type
.to_csharp_string(options, aliases, false, method_name, &p.name);
let mut type_name = p.rust_type.to_csharp_string(
options,
aliases,
&mut delegate_list,
false,
method_name,
&p.name,
);
if type_name == "bool" {
type_name = "[MarshalAs(UnmanagedType.U1)] bool".to_string();
}
Expand Down Expand Up @@ -223,6 +200,7 @@ pub fn emit_csharp(
let type_name = field.rust_type.to_csharp_string(
options,
aliases,
&mut delegate_list,
true,
&"".to_string(),
&"".to_string(),
Expand Down Expand Up @@ -301,6 +279,7 @@ pub fn emit_csharp(
let mut type_name = item.rust_type.to_csharp_string(
options,
aliases,
&mut delegate_list,
false,
&"".to_string(),
&"".to_string(),
Expand Down Expand Up @@ -343,6 +322,15 @@ pub fn emit_csharp(
}
}

let mut delegate_list_string = String::new();
delegate_list.sort();
delegate_list.dedup();
for delegate in delegate_list {
delegate_list_string
.push_str(" [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n");
delegate_list_string.push_str(format!(" {accessibility} {delegate};\n\n").as_str());
}

// use empty string if the generated class is empty.
let class_string = if method_list_string.is_empty() && const_string.is_empty() {
String::new()
Expand All @@ -354,6 +342,8 @@ pub fn emit_csharp(

{const_string}

{delegate_list_string}

{method_list_string}
}}"
)
Expand Down
100 changes: 58 additions & 42 deletions csbindgen/src/type_meta.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{alias_map::AliasMap, builder::BindgenOptions};
use std::collections::HashMap;

pub fn escape_csharp_name(str: &str) -> String {
match str {
Expand Down Expand Up @@ -225,6 +226,7 @@ impl RustType {
&self,
options: &BindgenOptions,
alias_map: &AliasMap,
delegate_list: &mut Vec<String>,
emit_from_struct: bool,
method_name: &String,
parameter_name: &String,
Expand Down Expand Up @@ -305,6 +307,7 @@ impl RustType {
use_type.to_csharp_string(
options,
alias_map,
delegate_list,
emit_from_struct,
method_name,
parameter_name,
Expand Down Expand Up @@ -344,6 +347,7 @@ impl RustType {
sb.push_str(&p.rust_type.to_csharp_string(
options,
alias_map,
delegate_list,
emit_from_struct,
method_name,
parameter_name,
Expand All @@ -355,6 +359,7 @@ impl RustType {
sb.push_str(&x.to_csharp_string(
options,
alias_map,
delegate_list,
emit_from_struct,
method_name,
parameter_name,
Expand All @@ -366,6 +371,14 @@ impl RustType {
};
sb.push('>');
} else {
build_method_delegate(
self,
options,
alias_map,
delegate_list,
method_name,
parameter_name,
);
sb.push_str(build_method_delegate_name(method_name, parameter_name).as_str());
}
}
Expand All @@ -376,6 +389,7 @@ impl RustType {
.to_csharp_string(
options,
alias_map,
delegate_list,
emit_from_struct,
method_name,
parameter_name,
Expand All @@ -389,6 +403,7 @@ impl RustType {
rust_type: &RustType,
options: &BindgenOptions,
alias_map: &AliasMap,
delegate_list: &mut Vec<String>,
emit_from_struct: bool,
method_name: &String,
parameter_name: &String,
Expand All @@ -402,6 +417,7 @@ impl RustType {
.to_csharp_string(
options,
alias_map,
delegate_list,
emit_from_struct,
method_name,
parameter_name,
Expand Down Expand Up @@ -432,6 +448,7 @@ impl RustType {
&use_type,
options,
alias_map,
delegate_list,
emit_from_struct,
method_name,
parameter_name,
Expand All @@ -448,6 +465,7 @@ impl RustType {
&self,
options,
alias_map,
delegate_list,
emit_from_struct,
method_name,
parameter_name,
Expand All @@ -464,69 +482,67 @@ impl RustType {
}
}

pub fn build_method_delegate_if_required(
pub fn build_method_delegate(
me: &RustType,
options: &BindgenOptions,
alias_map: &AliasMap,
delegate_list: &mut Vec<String>,
method_name: &String,
parameter_name: &String,
) -> Option<String> {
) {
let emit_from_struct = false;

match &me.type_kind {
TypeKind::Function(parameters, return_type) => {
if emit_from_struct && !options.csharp_use_function_pointer {
None
} else if options.csharp_use_function_pointer {
None
} else {
let return_type_name = match return_type {
Some(x) => x.to_csharp_string(
let return_type_name = match return_type {
Some(x) => x.to_csharp_string(
options,
alias_map,
delegate_list,
emit_from_struct,
&build_method_delegate_name(method_name, parameter_name),
&x.type_name,
),
None => "void".to_string(),
};

let joined_param = parameters
.iter()
.enumerate()
.map(|(index, p)| {
let cs = p.rust_type.to_csharp_string(
options,
alias_map,
delegate_list,
emit_from_struct,
method_name,
parameter_name,
),
None => "void".to_string(),
};
&build_method_delegate_name(method_name, parameter_name),
&p.name,
);
let parameter_name = if p.name == "" {
format!("arg{}", index + 1)
} else {
p.name.clone()
};

let joined_param = parameters
.iter()
.enumerate()
.map(|(index, p)| {
let cs = p.rust_type.to_csharp_string(
options,
alias_map,
emit_from_struct,
method_name,
parameter_name,
);
let parameter_name = if p.name == "" {
format!("arg{}", index + 1)
} else {
p.name.clone()
};

format!("{} {}", cs, escape_csharp_name(parameter_name.as_str()))
})
.collect::<Vec<_>>()
.join(", ");
format!("{} {}", cs, escape_csharp_name(parameter_name.as_str()))
})
.collect::<Vec<_>>()
.join(", ");

let delegate_name = build_method_delegate_name(method_name, parameter_name);
let delegate_code =
format!("delegate {return_type_name} {delegate_name}({joined_param})");
Some(delegate_code)
}
let delegate_name = build_method_delegate_name(method_name, parameter_name);
let delegate_code =
format!("delegate {return_type_name} {delegate_name}({joined_param})");
delegate_list.push(delegate_code);
}
TypeKind::Option(inner) => build_method_delegate_if_required(
TypeKind::Option(inner) => build_method_delegate(
inner,
options,
alias_map,
delegate_list,
method_name,
parameter_name,
),
_ => None,
_ => (),
}
}

Expand Down