callback complete

This commit is contained in:
neuecc 2023-03-05 15:30:41 +09:00
parent b986cbefff
commit 12af43c76c
6 changed files with 157 additions and 39 deletions

View File

@ -14,6 +14,28 @@ mod lz4;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
mod lz4_ffi; mod lz4_ffi;
#[no_mangle]
pub extern "C" fn callback_test(cb: extern "C" fn(a: i32) -> i32) -> i32 {
cb(100)
}
#[no_mangle]
pub extern "C" fn nullable_callback_test(cb: Option<extern "C" fn(a: i32) -> i32>) -> i32 {
match cb {
Some(f) => f(100),
None => -1,
}
}
#[no_mangle]
pub extern "C" fn callback_test2() -> extern "C" fn(a: i32) -> i32 {
callback
}
extern "C" fn callback(a: i32) -> i32 {
a * a
}
#[no_mangle] #[no_mangle]
#[allow(improper_ctypes_definitions)] #[allow(improper_ctypes_definitions)]
pub extern "C" fn ignore_nop() -> (i32, i32) { pub extern "C" fn ignore_nop() -> (i32, i32) {
@ -31,12 +53,6 @@ pub extern "C" fn my_add(x: i32, y: i32) -> i32 {
x + y x + y
} }
#[no_mangle]
pub extern "C" fn callback_test(cb: extern fn(a: i32) -> i32) -> i32 {
// Fn
cb(100)
}
#[no_mangle] #[no_mangle]
pub extern "C" fn create_counter_context() -> *mut c_void { pub extern "C" fn create_counter_context() -> *mut c_void {
let ctx = Box::new(CounterContext { let ctx = Box::new(CounterContext {

View File

@ -25,7 +25,7 @@ pub fn emit_rust_method(list: &Vec<ExternMethod>, options: &BindgenOptions) -> S
format!( format!(
" {}: {}", " {}: {}",
p.name, p.name,
p.rust_type.to_string(method_type_path) p.rust_type.to_rust_string(method_type_path)
) )
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
@ -33,7 +33,7 @@ pub fn emit_rust_method(list: &Vec<ExternMethod>, options: &BindgenOptions) -> S
let return_line = match &item.return_type { let return_line = match &item.return_type {
None => "".to_string(), None => "".to_string(),
Some(v) => format!(" -> {}", v.to_string(method_type_path)), Some(v) => format!(" -> {}", v.to_rust_string(method_type_path)),
}; };
let parameter_only_names = item let parameter_only_names = item

View File

@ -1,8 +1,6 @@
use crate::{builder::BindgenOptions, type_meta::*}; use crate::{builder::BindgenOptions, type_meta::*};
use std::{ use std::collections::{HashMap, HashSet};
collections::{HashMap, HashSet}, use syn::{ForeignItem, Item, Pat, ReturnType};
};
use syn::{ForeignItem, Item, Pat, ReturnType};
enum FnItem { enum FnItem {
ForeignItem(syn::ForeignItemFn), ForeignItem(syn::ForeignItemFn),
@ -120,8 +118,8 @@ pub fn collect_type_alias(ast: &syn::File) -> Vec<(String, RustType)> {
name, name,
RustType { RustType {
type_name: alias.to_string(), type_name: alias.to_string(),
type_kind: TypeKind::Normal type_kind: TypeKind::Normal,
} },
)); ));
} }
} }
@ -217,22 +215,46 @@ fn parse_type(t: &syn::Type) -> RustType {
if let syn::Type::Path(path) = &*t.elem { if let syn::Type::Path(path) = &*t.elem {
return RustType { return RustType {
type_name: path.path.segments.last().unwrap().ident.to_string(), type_name: path.path.segments.last().unwrap().ident.to_string(),
type_kind: TypeKind::Pointer(if has_const { PointerType::ConstPointer } else { PointerType::MutPointer }) type_kind: TypeKind::Pointer(if has_const {
PointerType::ConstPointer
} else {
PointerType::MutPointer
}),
}; };
} else if let syn::Type::Ptr(t) = &*t.elem { } else if let syn::Type::Ptr(t) = &*t.elem {
if let syn::Type::Path(path) = &*t.elem { if let syn::Type::Path(path) = &*t.elem {
return RustType { return RustType {
type_name: path.path.segments.last().unwrap().ident.to_string(), type_name: path.path.segments.last().unwrap().ident.to_string(),
type_kind: TypeKind::Pointer(if has_const { PointerType::ConstPointerPointer } else { PointerType::MutPointerPointer }) type_kind: TypeKind::Pointer(if has_const {
PointerType::ConstPointerPointer
} else {
PointerType::MutPointerPointer
}),
}; };
} }
} }
} }
syn::Type::Path(t) => { syn::Type::Path(t) => {
return RustType{ let last_segment = t.path.segments.last().unwrap();
type_name:t.path.segments.last().unwrap().ident.to_string(), if let syn::PathArguments::AngleBracketed(x) = &last_segment.arguments {
type_kind: TypeKind::Normal // generics, only supports Option<> for null function pointer
} if last_segment.ident.to_string() == "Option" {
if let Some(x) = x.args.first() {
if let syn::GenericArgument::Type(t) = x {
let rust_type = parse_type(t);
return RustType {
type_name: "Option".to_string(),
type_kind: TypeKind::Option(Box::new(rust_type)),
};
}
}
}
} else {
return RustType {
type_name: last_segment.ident.to_string(),
type_kind: TypeKind::Normal,
};
}
} }
syn::Type::Array(t) => { syn::Type::Array(t) => {
let mut digits = "".to_string(); let mut digits = "".to_string();
@ -256,8 +278,29 @@ fn parse_type(t: &syn::Type) -> RustType {
}; };
}; };
} }
syn::Type::BareFn(_) => { syn::Type::BareFn(t) => {
//todo!(); let mut parameters = Vec::new();
for arg in t.inputs.iter() {
let rust_type = parse_type(&arg.ty);
let name = if let Some((ident, _)) = &arg.name {
ident.to_string()
} else {
"".to_string()
};
parameters.push(Parameter { name, rust_type });
}
let ret = match &t.output {
syn::ReturnType::Default => None,
syn::ReturnType::Type(_, t) => Some(Box::new(parse_type(&t))),
};
return RustType {
type_name: "extern \"C\" fn".to_string(),
type_kind: TypeKind::Function(parameters, ret),
};
} }
_ => {} _ => {}
}; };

View File

@ -1,4 +1,4 @@
use std::collections::HashMap; use std::{collections::HashMap};
use crate::builder::BindgenOptions; use crate::builder::BindgenOptions;
@ -51,8 +51,9 @@ pub struct RustType {
pub enum TypeKind { pub enum TypeKind {
Normal, Normal,
Pointer(PointerType), Pointer(PointerType),
FixedArray(String, Option<PointerType>), // digits FixedArray(String, Option<PointerType>), // digits
Function(Vec<RustType>, Option<Box<RustType>>), // parameter, return Function(Vec<Parameter>, Option<Box<RustType>>), // parameter, return
Option(Box<RustType>),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -71,7 +72,7 @@ pub struct RustStruct {
} }
impl RustType { impl RustType {
pub fn to_string(&self, type_path: &str) -> String { pub fn to_rust_string(&self, type_path: &str) -> String {
let mut sb = String::new(); let mut sb = String::new();
fn emit_pointer(sb: &mut String, p: &PointerType) { fn emit_pointer(sb: &mut String, p: &PointerType) {
@ -118,8 +119,25 @@ impl RustType {
sb.push_str(digits.as_str()); sb.push_str(digits.as_str());
sb.push(']'); sb.push(']');
} }
Function(x, y) => { Function(parameters, return_type) => {
todo!(); emit_type_name(&mut sb); // extern fn
sb.push('(');
let params = parameters
.iter()
.map(|x| format!("{}: {}", x.escape_name(), x.rust_type.to_rust_string(type_path)))
.collect::<Vec<_>>()
.join(", ");
sb.push_str(params.as_str());
sb.push(')');
if let Some(t) = return_type {
sb.push_str(" -> ");
sb.push_str(t.to_rust_string(type_path).as_str());
}
},
Option(inner) => {
sb.push_str("Option<");
sb.push_str(inner.to_rust_string(type_path).as_str());
sb.push('>');
} }
}; };
@ -180,7 +198,7 @@ impl RustType {
let mut sb = String::new(); let mut sb = String::new();
match self.type_kind { match &self.type_kind {
TypeKind::FixedArray(_, _) => { TypeKind::FixedArray(_, _) => {
sb.push_str("fixed "); sb.push_str("fixed ");
@ -194,6 +212,27 @@ impl RustType {
sb.push_str(type_name.as_str()); sb.push_str(type_name.as_str());
} }
TypeKind::Function(parameters, return_type) => {
sb.push_str("delegate* unmanaged[Cdecl]");
sb.push('<');
for p in parameters {
sb.push_str(&p.rust_type.to_csharp_string(options, alias_map));
sb.push_str(", ");
}
match return_type {
Some(x) => {
sb.push_str(&x.to_csharp_string(options, alias_map));
}
None => {
sb.push_str("void");
}
};
sb.push('>');
},
TypeKind::Option(inner) =>{
// function pointer can not annotate ? so emit inner only
sb.push_str(inner.to_csharp_string(options, alias_map).as_str());
},
_ => { _ => {
sb.push_str(convert_type_name(use_type.type_name.as_str(), options).as_str()); sb.push_str(convert_type_name(use_type.type_name.as_str(), options).as_str());
@ -229,6 +268,6 @@ impl RustType {
impl std::fmt::Display for RustType { impl std::fmt::Display for RustType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_string("")) write!(f, "{}", self.to_rust_string(""))
} }
} }

View File

@ -13,16 +13,24 @@ using System.Text;
unsafe unsafe
{ {
// LibRust.call_bindgen(); [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
static int Method(int x) => x * x;
var tako = LibRust.callback_test(&Method);
var n = LibRust.nullable_callback_test(null);
Console.WriteLine(n);
var ctx = LibRust.create_counter_context(); //var ctx = LibRust.create_counter_context();
LibRust.insert_counter_context(ctx, 10); //LibRust.insert_counter_context(ctx, 10);
LibRust.insert_counter_context(ctx, 20); //LibRust.insert_counter_context(ctx, 20);
LibRust.insert_counter_context(ctx, 20); //LibRust.insert_counter_context(ctx, 20);
LibRust.insert_counter_context(ctx, 30); //LibRust.insert_counter_context(ctx, 30);
LibRust.insert_counter_context(ctx, 99); //LibRust.insert_counter_context(ctx, 99);
LibRust.delete_counter_context(ctx); //LibRust.delete_counter_context(ctx);
//var cString = LibRust.alloc_c_string(); //var cString = LibRust.alloc_c_string();
//var u8String = LibRust.alloc_u8_string(); //var u8String = LibRust.alloc_u8_string();

View File

@ -11,6 +11,18 @@ namespace CsBindgen
{ {
const string __DllName = "csbindgen_tests"; const string __DllName = "csbindgen_tests";
[DllImport(__DllName, EntryPoint = "callback_test", CallingConvention = CallingConvention.Cdecl)]
public static extern int callback_test(delegate* unmanaged[Cdecl]<int, int> cb);
[DllImport(__DllName, EntryPoint = "nullable_callback_test", CallingConvention = CallingConvention.Cdecl)]
public static extern int nullable_callback_test(delegate* unmanaged[Cdecl]<int, int> cb);
[DllImport(__DllName, EntryPoint = "callback_test2", CallingConvention = CallingConvention.Cdecl)]
public static extern delegate* unmanaged[Cdecl]<int, int> callback_test2();
[DllImport(__DllName, EntryPoint = "callback", CallingConvention = CallingConvention.Cdecl)]
public static extern int callback(int a);
[DllImport(__DllName, EntryPoint = "nop", CallingConvention = CallingConvention.Cdecl)] [DllImport(__DllName, EntryPoint = "nop", CallingConvention = CallingConvention.Cdecl)]
public static extern void nop(); public static extern void nop();