#![allow(unused_variables, unused_mut)]
#![allow(unused_imports, unused_parens)]
use inflector::Inflector;
use clang::{Entity, EntityKind, EntityVisitResult, TypeKind};
use super::setting::*;
pub fn prepare_api_wrapper_code(ctx: &mut Context, e: &Entity) -> String {
let code_1 = traverse_ast(ctx, e);
code_1
}
pub fn prepare_spi_wrapper_code(ctx: &mut Context, e: &Entity) -> String {
ctx.cfg.module_flavor = ModuleFlavor::SpiTrait;
let code_0 = traverse_ast(ctx, e);
ctx.cfg = Config {
module_flavor: ModuleFlavor::VTableStruct,
prefer_pointer: PointerStyle::RawPointerConst,
prefer_param_cffi_type: true,
param_trim_prefix: false,
..ctx.cfg.clone()
};
ctx.methods
.insert("_".to_string(), Box::new(convert_spi_vtable_struct_));
let code_1 = traverse_ast(ctx, e);
ctx.cfg = Config {
module_flavor: ModuleFlavor::StaticTable,
prefer_pointer: PointerStyle::RawPointerConst,
prefer_param_cffi_type: true,
param_trim_prefix: false,
..ctx.cfg.clone()
};
ctx.methods
.insert("_".to_string(), Box::new(convert_spi_static_vtable_));
let code_2 = traverse_ast(ctx, e);
ctx.cfg = Config {
module_flavor: ModuleFlavor::ExternCFn,
prefer_pointer: PointerStyle::RawPointerConst,
prefer_param_cffi_type: true,
param_trim_prefix: false,
..ctx.cfg.clone()
};
ctx.methods
.insert("_".to_string(), Box::new(convert_spi_cfunc_));
let code_3 = traverse_ast(ctx, e);
let version = &ctx.cfg.version;
format!(
r#"/* generated by handle_module_spi */
use crate::{version}::bindings::*;
{code_0}
{code_1}
{code_2}
{code_3}
"#
)
}
pub fn traverse_ast(ctx: &mut Context, e: &Entity) -> String {
let mut lines = vec![];
e.visit_children(|c, _p| {
if c.get_kind() == EntityKind::ClassDecl {
let name = c.get_name().unwrap();
if name == ctx.cfg.source_class_name {
let list = c
.get_children()
.into_iter()
.filter(|e| e.get_kind() == EntityKind::Method && !e.is_static_method())
.map(|m| m)
.collect::<Vec<_>>();
let func_vec = list
.iter()
.map(|m| {
let params = m
.get_arguments()
.unwrap()
.iter()
.map(|a| {
let pt = a.get_type().unwrap();
convert_param_type(&ctx, a)
})
.collect::<Vec<_>>();
let func_name = m.get_name().unwrap();
if let Some(func_handler) = ctx.methods.get(&func_name) {
func_handler(ctx, m, ¶ms)
} else {
ctx.methods.get("_").unwrap()(ctx, m, ¶ms)
}
})
.collect::<Vec<_>>();
let module_handler = ctx.modules.get(&ctx.cfg.module_flavor).unwrap();
lines.push(module_handler(ctx, &c, &func_vec))
}
EntityVisitResult::Continue
} else {
if c.get_kind() == EntityKind::ParmDecl {
println!("{:?}", c);
}
if cfg!(feature = "sopt") {
EntityVisitResult::Recurse
} else {
EntityVisitResult::Continue
}
}
});
lines.join("")
}
pub fn handle_module_api_trait(ctx: &Context, e: &Entity, items: &ItemVec) -> String {
let version = &ctx.cfg.version;
let trait_name = &ctx.cfg.generate_trait_name;
let api_class = &ctx.cfg.source_class_name;
let spi_name = match ctx.cfg.source_class_name.as_str() {
"CThostFtdcMdApi" => "CThostFtdcMdSpi",
"CThostFtdcTraderApi" => "CThostFtdcTraderSpi",
_ => panic!("invalid target class name {}", &ctx.cfg.source_class_name),
};
let spi_file = &ctx.cfg.wrap_spi_trait.to_ascii_lowercase();
let header = format!(
r#"/* generated by handle_module_api */
use std::{{
cell::Cell,
ffi::{{CStr, CString}},
os::raw::c_char,
path::Path,
ptr::null_mut,
}};
use libloading::Library;
use crate::{version}::bindings::*;
use crate::{version}::{spi_file}::*;
"#,
);
let method_data = items
.iter()
.filter(|x| !x[0].is_empty())
.map(|x| x[0].as_str())
.collect::<Vec<_>>()
.join("\n");
let api_trait_code = format!(
r#"{header}
#[derive(Debug)]
pub struct {trait_name} {{
pub api_ptr: *mut {api_class},
pub spi_ptr: Cell<* mut {spi_name}Ext>,
pub dynlib: Option<Library>,
}}
unsafe impl Sync for {trait_name} {{}}
unsafe impl Send for {trait_name} {{}}
impl {trait_name} {{
{method_declare}
}}
"#,
method_declare = method_data,
);
api_trait_code
}
pub fn handle_module_spi_trait(ctx: &Context, e: &Entity, items: &ItemVec) -> String {
let spi_trait = &ctx.cfg.generate_trait_name;
let method_data = items
.iter()
.filter(|x| !x[0].is_empty())
.map(|x| x[0].as_str())
.collect::<Vec<_>>()
.join("\n");
let spi_trait_code = format!(
r#"
pub trait {spi_trait}: Send {{{method_code}
}}"#,
method_code = method_data,
);
spi_trait_code
}
pub fn handle_module_vtable_struct(ctx: &Context, e: &Entity, items: &ItemVec) -> String {
let trait_name = &ctx.cfg.generate_trait_name;
let method_data = items
.iter()
.filter(|x| !x[0].is_empty())
.map(|x| x[0].as_str())
.collect::<Vec<_>>()
.join("\n");
let vtable_func_code = format!(
r#"
#[repr(C)]
#[derive(Debug)]
pub struct {trait_name}VTable {{
{fn_declare_list}
}}"#,
fn_declare_list = method_data
);
vtable_func_code
}
pub fn handle_module_static_table(ctx: &Context, e: &Entity, items: &ItemVec) -> String {
let source_class = &ctx.cfg.source_class_name;
let trait_name = &ctx.cfg.generate_trait_name;
let method_data = items
.iter()
.filter(|x| !x[0].is_empty())
.map(|x| x[0].as_str())
.collect::<Vec<_>>()
.join("\n");
let static_table_code = format!(
r#"
static SPI_VTABLE: {trait_name}VTable = {trait_name}VTable {{
{fn_member_list}
}};
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct {source_class}Ext {{
vtable: *const {trait_name}VTable,
pub spi_ptr: *mut dyn {trait_name},
}}
impl {source_class}Ext {{
pub fn new(spi: *mut dyn {trait_name}) -> Self {{
Self {{
vtable: &SPI_VTABLE,
spi_ptr: spi,
}}
}}
}}
"#,
fn_member_list = method_data
);
static_table_code
}
pub fn handle_module_extern_cfn(ctx: &Context, e: &Entity, items: &ItemVec) -> String {
let method_data = items
.iter()
.filter(|x| !x[0].is_empty())
.map(|x| x[0].as_str())
.collect::<Vec<_>>()
.join("\n");
let spi_cfunc_code = format!(r#"{spi_funcs}"#, spi_funcs = method_data,);
spi_cfunc_code
}
pub fn handle_module_event_enum(ctx: &Context, e: &Entity, items: &ItemVec) -> String {
let spi_trait = &ctx.cfg.generate_trait_name;
let method_data = items
.iter()
.filter(|x| !x[0].is_empty())
.map(|x| x[0].as_str())
.collect::<Vec<_>>()
.join("\n");
let event_enum_code = format!(
r#"
#[derive(Clone, Debug)]
pub enum {spi_trait}Event {{
{event_enums}
}}
"#,
event_enums = method_data
);
event_enum_code
}
pub fn handle_module_event_struct(ctx: &Context, e: &Entity, items: &ItemVec) -> String {
let method_data = items
.iter()
.filter(|x| !x[0].is_empty())
.map(|x| x[0].as_str())
.collect::<Vec<_>>()
.join("\n");
method_data
}
pub fn _convert_api_registerspi_func(ctx: &Context, e: &Entity, params: &ParamVec) -> String {
let method_call = e.get_name().unwrap();
let method_name = match &ctx.cfg.method_to_snake {
true => rustify_method_name2(&method_call),
_ => method_call.clone(),
};
let comment = match &ctx.cfg.generate_comments {
true => e.get_comment().unwrap_or("".to_string()),
_ => "".to_string(),
};
let api_class = &ctx.cfg.source_class_name;
let arg_0_name = ¶ms[0].0;
let spi_name = match ctx.cfg.source_class_name.as_str() {
"CThostFtdcMdApi" => "CThostFtdcMdSpi",
"CThostFtdcTraderApi" => "CThostFtdcTraderSpi",
_ => panic!("invalid target class name {}", &ctx.cfg.source_class_name),
};
let self_text = match &ctx.cfg.prefer_self_mut_ref {
true => "&mut self",
_ => "&self",
};
let mut unsafe_code: String;
let mut args_code: String;
if ctx.cfg.wrap_api_struct {
unsafe_code = format!(
r#"
let spi_ptr = Box::into_raw(Box::new({spi_name}Ext::new({arg_0_name})));
let last_spi_ptr = self.spi_ptr.get();
unsafe {{
((*(*self.api_ptr).vtable_).{api_class}_RegisterSpi)(self.api_ptr, spi_ptr as _)
}}
self.spi_ptr.set(spi_ptr);
if !last_spi_ptr.is_null() {{
unsafe {{
let _ = Box::from_raw(last_spi_ptr); // 释放动态分配的内存
}}
}}"#,
spi_name = spi_name
);
args_code = format!(
"{self_text}, {arg_0_name}: *mut dyn {}",
&ctx.cfg.wrap_spi_trait
);
} else {
unsafe_code = format!(
r#"
unsafe {{
((*(*self).vtable_).{api_class}_RegisterSpi)(self as *mut {api_class}, {arg_0_name})
}}"#,
);
args_code = format!("&mut self, {arg_0_name}: *mut {spi_name}");
}
format!(
r#" {comment}
pub fn {method_name}({args_code}) {{{unsafe_code}
}}
"#
)
}
pub fn _convert_api_incomplete_array_func(ctx: &Context, e: &Entity, params: &ParamVec) -> String {
let method_call = e.get_name().unwrap();
let method_name = match &ctx.cfg.method_to_snake {
true => rustify_method_name2(&method_call),
_ => method_call.clone(),
};
let comment = match &ctx.cfg.generate_comments {
true => e.get_comment().unwrap_or("".to_string()),
_ => "".to_string(),
};
let (result_text, _) = convert_result_rust_type(
ctx,
e.get_result_type().unwrap().get_display_name().as_str(),
);
let self_text = match &ctx.cfg.prefer_self_mut_ref {
true => "&mut self",
_ => "&self",
};
let (self_p0, self_p1) = if ctx.cfg.wrap_api_struct {
("self.api_ptr".to_string(), "self.api_ptr".to_string())
} else {
(
"self".to_string(),
format!("self as *mut {}", ctx.cfg.source_class_name),
)
};
let api_class = &ctx.cfg.source_class_name;
let (arg_0_name, arg_0_type, param_0_call) = (¶ms[0]);
let args_text = format!("{self_text}, {arg_0_name}: {arg_0_type}");
let unsafe_code = if ctx.cfg.prefer_param_cffi_type {
format!(
r#"
unsafe {{
((*(*{self_p0}).vtable_).{api_class}_{method_call})({self_p1}, {param_0_call}, {arg_0_name}.len() as i32)
}}"#,
)
} else {
format!(
r#"
let cstrings: Vec<_> = {arg_0_name}.iter().map(|x| CString::new(x.clone()).unwrap()).collect();
let cstr_slice: Vec<*const i8> = cstrings.iter().map(|cstr| cstr.as_ptr()).collect();
unsafe {{
((*(*{self_p0}).vtable_).{api_class}_{method_call})({self_p1}, cstr_slice.as_ptr() as *mut *mut i8, {arg_0_name}.len() as i32)
}}"#,
)
};
format!(
r#" {comment}
pub fn {method_name}({args_text}){result_text}{{{unsafe_code}
}}
"#
)
}
pub fn _convert_api_char_s_func(ctx: &Context, e: &Entity, params: &ParamVec) -> String {
let method_call = e.get_name().unwrap();
let method_name = match &ctx.cfg.method_to_snake {
true => rustify_method_name2(&method_call),
_ => method_call.clone(),
};
let comment = match &ctx.cfg.generate_comments {
true => e.get_comment().unwrap_or("".to_string()),
_ => "".to_string(),
};
let api_class = &ctx.cfg.source_class_name;
let self_text = match &ctx.cfg.prefer_self_mut_ref {
true => "&mut self",
_ => "&self",
};
let (self_p0, self_p1) = if ctx.cfg.wrap_api_struct {
("self.api_ptr".to_string(), "self.api_ptr".to_string())
} else {
(
"self".to_string(),
format!("self as *mut {}", ctx.cfg.source_class_name),
)
};
let (ref arg0, ref type0, ref param0) = params[0];
let args_text = format!("{self_text}, {arg0}: {type0}");
let unsafe_code = if ctx.cfg.prefer_param_cffi_type {
format!(
r#"
unsafe {{
((*(*{self_p0}).vtable_).{api_class}_{method_call})(self.{self_p1}, {param0})
}}"#
)
} else {
format!(
r#"
unsafe {{
let {arg0} = CString::new({arg0}).unwrap();
((*(*{self_p0}).vtable_).{api_class}_{method_call})({self_p1}, {arg0}.as_ptr() as *mut i8)
}}"#
)
};
format!(
r#" {comment}
pub fn {method_name}({args_text}) {{{unsafe_code}
}}
"#
)
}
pub fn _convert_api_general_func(ctx: &Context, e: &Entity, params: &ParamVec) -> String {
let method_call = e.get_name().unwrap();
let method_name = match &ctx.cfg.method_to_snake {
true => rustify_method_name2(&method_call),
_ => method_call.clone(),
};
let comment = match &ctx.cfg.generate_comments {
true => e.get_comment().unwrap_or("".to_string()),
_ => "".to_string(),
};
let (result_text, result_type) = convert_result_rust_type(
ctx,
e.get_result_type().unwrap().get_display_name().as_str(),
);
let api_class = &ctx.cfg.source_class_name;
let self_text = match &ctx.cfg.prefer_self_mut_ref {
true => "&mut self",
_ => "&self",
};
let (self_p0, self_p1) = if ctx.cfg.wrap_api_struct {
("self.api_ptr".to_string(), "self.api_ptr".to_string())
} else {
(
"self".to_string(),
format!("self as *mut {}", ctx.cfg.source_class_name),
)
};
let mut arg_vec = params
.iter()
.map(|x| format!("{}: {}", x.0, x.1))
.collect::<Vec<String>>();
arg_vec.insert(0, self_text.to_string());
let args_text = arg_vec.join(", ");
let mut param_vec = params
.iter()
.map(|x| format!("{}", x.2))
.collect::<Vec<String>>();
param_vec.insert(0, self_p1.to_string());
let params_text = param_vec.join(", ");
let is_char_s_func =
if params.len() == 1 && (params[0].1 == "&std::ffi::CString" || params[0].1 == "&str") {
true
} else {
false
};
let unsafe_code = match (is_char_s_func, result_type) {
(true, TypeKind::Void) => match ctx.cfg.prefer_param_cffi_type {
true => {
let (ref arg0, _, ref param0) = params[0];
format!(
r#"
unsafe {{
((*(*{self_p0}).vtable_).{api_class}_{method_call})(self.{self_p1}, {param0})
}}"#
)
}
_ => {
let (ref arg0, _, ref param0) = params[0];
format!(
r#"
unsafe {{
let {arg0} = CString::new({arg0}).unwrap();
((*(*{self_p0}).vtable_).{api_class}_{method_call})(self.{self_p1}, {arg0}.as_ptr() as *mut i8)
}}"#
)
}
},
(false, TypeKind::CharS) => match ctx.cfg.prefer_param_cffi_type {
true => format!(
r#"
unsafe {{
((*(*{self_p0}).vtable_).{api_class}_{method_call})({self_p1})
}}"#
),
_ => format!(
r#"
unsafe {{
let cstr_ptr = ((*(*{self_p0}).vtable_).{api_class}_{method_call})({self_p1});
let c_str = CStr::from_ptr(cstr_ptr);
c_str.to_string_lossy().to_string()
}}"#
),
},
_ => {
format!(
r#"
unsafe {{
((*(*{self_p0}).vtable_).{api_class}_{method_call})({params_text})
}}"#
)
}
};
format!(
r#" {comment}
pub fn {method_name}({args_text}){result_text}{{{unsafe_code}
}}
"#
)
}
pub fn convert_api_trait_func_(ctx: &Context, e: &Entity, params: &ParamVec) -> Vec<String> {
let func_name = e.get_name().unwrap();
if func_name.contains("Subscribe") && params[0].1.contains("Vec") {
return vec![_convert_api_incomplete_array_func(ctx, e, params)];
}
let func_code = match func_name.as_str() {
"RegisterFront" | "RegisterNameServer" => _convert_api_char_s_func(ctx, e, params),
"RegisterSpi" => _convert_api_registerspi_func(ctx, e, params),
_ => _convert_api_general_func(ctx, e, params),
};
vec![func_code]
}
pub fn convert_spi_trait_func_(ctx: &Context, e: &Entity, params: &ParamVec) -> Vec<String> {
let method_call = e.get_name().unwrap();
let method_name = match ctx.cfg.method_to_snake {
true => rustify_method_name2(&method_call),
false => method_call.clone(),
};
let comment = match ctx.cfg.generate_comments {
true => e.get_comment().unwrap_or("".to_string()),
_ => "".to_string(),
};
let mut arg_vec = params
.iter()
.map(|x| format!("{}: {}", x.0, x.1))
.collect::<Vec<String>>();
if ctx.cfg.prefer_self_mut_ref {
arg_vec.insert(0, "&mut self".to_string());
} else {
arg_vec.insert(0, "&self".to_string());
}
let trait_method_code = format!(
r#"
{comment}
fn {method_name}({arg_list}) {{
}}"#,
arg_list = arg_vec.join(", "),
);
vec![trait_method_code]
}
pub fn convert_spi_vtable_struct_(ctx: &Context, e: &Entity, params: &ParamVec) -> Vec<String> {
let method_call = e.get_name().unwrap();
let method_name = match ctx.cfg.method_to_snake {
true => rustify_method_name2(&method_call),
false => method_call.clone(),
};
let mut arg_vec = params
.iter()
.map(|x| format!("{}: {}", x.0, x.1))
.collect::<Vec<String>>();
arg_vec.insert(0, format!("spi: *mut {}Ext", ctx.cfg.source_class_name));
let vtable_func_code = format!(
r#" {method_name}: unsafe extern "C" fn({}),"#,
arg_vec.join(", ")
);
vec![vtable_func_code]
}
pub fn convert_spi_static_vtable_(ctx: &Context, e: &Entity, params: &ParamVec) -> Vec<String> {
let method_call = e.get_name().unwrap();
let method_name = match ctx.cfg.method_to_snake {
true => rustify_method_name2(&method_call),
false => method_call.clone(),
};
let vtable_func_code = format!(r#" {method_name}: spi_{method_name},"#,);
vec![vtable_func_code]
}
pub fn convert_spi_cfunc_(ctx: &Context, e: &Entity, params: &ParamVec) -> Vec<String> {
let method_call = e.get_name().unwrap();
let method_name = match ctx.cfg.method_to_snake {
true => rustify_method_name2(&method_call),
false => method_call.clone(),
};
let self_ptr = format!("spi: *mut {}Ext", &ctx.cfg.source_class_name);
let mut arg_vec = params
.iter()
.map(|x| format!("{}: {}", x.0, x.1))
.collect::<Vec<_>>();
arg_vec.insert(0, self_ptr);
let params_ = params
.iter()
.map(|x| format!("{}", x.2))
.collect::<Vec<_>>()
.join(", ");
let spi_cfunc_code = format!(
r#"
extern "C" fn spi_{method_name}({}) {{
unsafe {{
(*(*spi).spi_ptr).{method_name}({params_})
}}
}}"#,
arg_vec.join(", ")
);
vec![spi_cfunc_code]
}
pub fn convert_spi_event_enum_(ctx: &Context, e: &Entity, params: &ParamVec) -> Vec<String> {
let trait_name = &ctx.cfg.wrap_spi_trait;
let method_call = e.get_name().unwrap();
let event_enum_entry = format!(" {method_call}({trait_name}{method_call}Event),");
vec![event_enum_entry]
}
pub fn convert_spi_event_struct_(ctx: &Context, e: &Entity, params: &ParamVec) -> Vec<String> {
let trait_name = &ctx.cfg.wrap_spi_trait;
let method_call = e.get_name().unwrap();
let (to_snake, trim_prefix) = (&ctx.cfg.param_to_snake, &ctx.cfg.param_trim_prefix);
let event_entries = params
.iter()
.map(|x| {
let pn = normalize_param_name2(&x.0, *to_snake, *trim_prefix);
format!(" pub {}: {},", pn, x.1)
})
.collect::<Vec<_>>()
.join("\n");
let v = format!(
r#"
#[derive(Clone, Debug)]
pub struct {trait_name}{method_call}Event {{
{event_entries}
}}"#,
);
vec![v]
}
pub fn convert_param_type(ctx: &Context, e: &Entity) -> (String, String, String) {
let tp = e.get_type().unwrap();
let tk = tp.get_kind();
let pn = e.get_name().unwrap();
let tn = tp.get_display_name();
match tk {
TypeKind::Int | TypeKind::Bool | TypeKind::Enum => {
let handler = ctx.params.get(&tk).unwrap();
handler(ctx, &pn, &tn, &tk)
}
TypeKind::Elaborated => {
let ct = tp.get_canonical_type();
let ctk = ct.get_kind();
let ctn = ct.get_display_name();
match ctk {
TypeKind::Enum => {
let handler = ctx.params.get(&TypeKind::Enum).unwrap();
handler(ctx, &pn, &tn, &ctk)
}
TypeKind::ConstantArray => convert_constant_array_type_(ctx, &pn, &tn, &ctk),
TypeKind::Pointer => {
let handler = ctx.params.get(&(TypeKind::Pointer)).unwrap();
handler(ctx, &pn, &ctn, &ctk)
}
_ => (pn.clone(), tn, pn),
}
}
TypeKind::Pointer => {
let pt = tp.get_pointee_type().unwrap();
let ptk = pt.get_kind();
let ptn = pt.get_display_name();
match ptk {
TypeKind::CharS => {
let handler = ctx.params.get(&ptk).unwrap();
handler(ctx, &pn, &tn, &ptk)
}
TypeKind::Pointer | TypeKind::Elaborated | TypeKind::Record => {
let handler = ctx.params.get(&(TypeKind::Pointer)).unwrap();
handler(ctx, &pn, &ptn, &ptk)
}
_ => panic!("_ => {}: {} {:?}", tn, pt.get_display_name(), pt.get_kind()),
}
}
TypeKind::IncompleteArray => {
let handler = ctx.params.get(&tk).unwrap();
handler(ctx, &pn, &tn, &tk)
}
_ => unimplemented!(),
}
}
pub fn convert_pointee_type(
ctx: &Context,
pn: &str,
tn: &str,
tk: &TypeKind,
) -> (String, String, String) {
let pn = normalize_param_name2(pn, ctx.cfg.param_to_snake, ctx.cfg.param_trim_prefix);
match (&ctx.cfg.prefer_pointer, &ctx.cfg.module_flavor) {
(PointerStyle::RawPointerMut, ModuleFlavor::SpiTrait) => {
(pn.clone(), format!("Option<&{}>", tn), pn)
}
(PointerStyle::RawPointerMut, ModuleFlavor::ExternCFn) => (
pn.clone(),
format!("*mut {}", tn),
format!("{}.as_ref()", pn),
),
(PointerStyle::RawPointerMut, ModuleFlavor::EventEnumStruct) => {
(pn.clone(), format!("Option<{}>", tn), format!("{}", pn))
}
(PointerStyle::RawPointerMut, ModuleFlavor::SpiFn) => (
pn.clone(),
format!("Option<&{}>", tn),
format!("{}.cloned()", pn),
),
(PointerStyle::RawPointerMut, _) => (pn.clone(), format!("*mut {}", tn), format!("{}", pn)),
(PointerStyle::RawPointerConst, ModuleFlavor::SpiTrait) => {
(pn.clone(), format!("Option<&{}>", tn), pn)
}
(PointerStyle::RawPointerConst, ModuleFlavor::ExternCFn) => (
pn.clone(),
format!("*const {}", tn),
format!("{}.as_ref()", pn),
),
(PointerStyle::RawPointerConst, ModuleFlavor::EventEnumStruct) => {
(pn.clone(), format!("Option<{}>", tn), format!("{}", &pn))
}
(PointerStyle::RawPointerConst, ModuleFlavor::SpiFn) => (
pn.clone(),
format!("Option<&{}>", tn),
format!("{}.cloned()", pn),
),
(PointerStyle::RawPointerConst, _) => (
pn.clone(),
format!("*const {}", tn),
format!("{} as *mut {}", &pn, tn),
),
(PointerStyle::MutRef, ModuleFlavor::SpiTrait) => (
pn.clone(),
format!("&{}mut {}", &ctx.cfg.life_time, tn),
format!("{}", &pn),
),
(PointerStyle::MutRef, ModuleFlavor::VTableStruct) => {
(pn.clone(), format!("*mut {}", tn), format!("{}", pn))
}
(PointerStyle::MutRef, ModuleFlavor::ExternCFn) => (
pn.clone(),
format!("*mut {}", tn),
format!("&{}mut *{}", &ctx.cfg.life_time, tn),
),
(PointerStyle::MutRef, ModuleFlavor::EventEnumStruct) => (
pn.clone(),
format!("&{} {}", &ctx.cfg.life_time, tn),
format!("{}", &pn),
),
(PointerStyle::MutRef, _) => (
pn.clone(),
format!("&{}mut {}", &ctx.cfg.life_time, tn),
format!("{} as *mut {}", &pn, tn),
),
(PointerStyle::Ref, ModuleFlavor::SpiTrait) => (
pn.clone(),
format!("&{} {}", &ctx.cfg.life_time, tn),
format!("{}", &pn),
),
(PointerStyle::Ref, ModuleFlavor::VTableStruct) => {
(pn.clone(), format!("*const {}", tn), format!("{}", pn))
}
(PointerStyle::Ref, ModuleFlavor::ExternCFn) => {
(pn.clone(), format!("*const {}", tn), format!("& *{}", &pn))
}
(PointerStyle::Ref, ModuleFlavor::EventEnumStruct) => (
pn.clone(),
format!("&{} {}", &ctx.cfg.life_time, tn),
format!("{}", &pn),
),
(PointerStyle::Ref, _) => (
pn.clone(),
format!("&{} {}", &ctx.cfg.life_time, tn),
format!("{} as *const {} *mut {}", &pn, tn, tn),
),
_ => panic!("invalid pointer style {:?}", &ctx.cfg.prefer_pointer),
}
}
pub fn convert_constant_array_type_(
ctx: &Context,
pn: &str,
tn: &str,
tk: &TypeKind,
) -> (String, String, String) {
let pn = normalize_param_name2(pn, ctx.cfg.param_to_snake, ctx.cfg.param_trim_prefix);
(
pn.clone(),
tn.to_string(),
format!("{}.as_ptr() as *mut i8", pn),
)
}
pub fn convert_base_type_(
ctx: &Context,
pn: &str,
tn: &str,
tk: &TypeKind,
) -> (String, String, String) {
let pn = normalize_param_name2(pn, ctx.cfg.param_to_snake, ctx.cfg.param_trim_prefix);
let type_text = match (tk, ctx.cfg.prefer_param_cffi_type) {
(TypeKind::Int, true) => "std::os::raw::c_int".to_string(),
(TypeKind::Int, false) => "i32".to_string(),
(TypeKind::Bool, _) => "bool".to_string(),
(TypeKind::Enum, _) => tn.to_string(),
_ => panic!("Unknown {:?}", tk),
};
(format!("{}", pn), type_text, format!("{}", pn))
}
pub fn convert_incomplete_array(
ctx: &Context,
pn: &str,
tn: &str,
tk: &TypeKind,
) -> (String, String, String) {
let pn = normalize_param_name2(pn, ctx.cfg.param_to_snake, ctx.cfg.param_trim_prefix);
let (type_text, param_call) = match &ctx.cfg.prefer_param_cffi_type {
true => (
format!("&Vec<std::ffi::CString>"),
format!(
"{}.iter().map(|cs| cs.as_ptr()).collect::<Vec<_>>().as_mut_ptr() as *mut *mut i8",
pn,
),
),
false => (
format!("&Vec<String>"),
format!(".as_ptr() as *mut *mut i8"),
),
};
(pn, type_text, param_call)
}
pub fn convert_char_s_type_(
ctx: &Context,
pn: &str,
tn: &str,
tk: &TypeKind,
) -> (String, String, String) {
let pn = normalize_param_name2(pn, ctx.cfg.param_to_snake, ctx.cfg.param_trim_prefix);
let (type_text, param_call) = match &ctx.cfg.prefer_param_cffi_type {
true => (
format!("&std::ffi::CString"),
format!("{}.as_ptr() as *mut i8", pn),
),
false => (format!("&str"), format!("{}.as_ptr() as *mut i8", pn)),
};
(pn, type_text, param_call)
}
pub fn convert_result_rust_type(ctx: &Context, result: &str) -> (String, TypeKind) {
let prefer_cffi_type = &ctx.cfg.prefer_param_cffi_type;
match (result, prefer_cffi_type) {
("void", _) => (" ".to_string(), TypeKind::Void),
("int", true) => (" -> std::os::raw::c_int ".to_string(), TypeKind::Int),
("int", false) => (" -> i32 ".to_string(), TypeKind::Int),
("const char *", true) => (
" -> *const std::os::raw::c_char ".to_string(),
TypeKind::CharS,
),
("const char *", false) => (" -> String ".to_string(), TypeKind::CharS),
_ => panic!("Unknown {:?}", result),
}
}
pub fn rustify_method_name2(method_name: &str) -> String {
method_name.replace("UnSub", "Unsub").to_snake_case()
}
pub fn normalize_param_name2(arg: &str, to_snake: bool, trim_prefix: bool) -> String {
match (to_snake, trim_prefix) {
(true, true) => strip_prefix_set(arg.to_snake_case().as_str()),
(true, false) => arg.to_snake_case(),
_ => arg.to_string(),
}
}
fn strip_prefix_set(input: &str) -> String {
let prefixes = ["psz_", "p_", "n_", "b_"];
for prefix in prefixes {
if let Some(stripped) = input.strip_prefix(prefix) {
return stripped.to_string();
}
}
input.into() }