use std::fmt::Display;
use convert_case::{Case, Casing};
use crate::binding_types::{Arg, Function, RustWrapperType, WrapperType};
use crate::extern_module_translator::Exceptions;
use crate::swift::templates::TargetLanguageTypeName;
use crate::EXPORTED_SYMBOLS_PREFIX;
pub struct FunctionHelperVirtual {
pub function_name: String,
pub generated_args: String,
pub generated_function_body: Vec<String>,
pub generated_virtual_function_signature: String,
pub return_type: Option<WrapperType>,
pub arg_names: Vec<String>,
class_name: String,
}
impl FunctionHelperVirtual {
fn create_list_of_arguments_translated_to_cpp(function: &Function) -> Vec<String> {
let mut generated_args = function
.arguments
.iter()
.skip(1)
.map(|arg| match &arg.typ {
WrapperType {
rust_type: RustWrapperType::Primitive | RustWrapperType::FieldlessEnum,
..
} => format!("_ {}: {}", arg.arg_name, arg.typ.wrapper_name),
_ => format!("_ {}: UnsafeMutableRawPointer", arg.arg_name),
})
.collect::<Vec<String>>();
generated_args.insert(0, "_ _self: AnyObject".to_owned());
generated_args
}
fn create_function_signature(function: &Function) -> String {
function
.arguments
.iter()
.skip(1)
.map(|arg| format!("_ {}: {}", arg.arg_name, arg.typ.get_name()))
.collect::<Vec<String>>()
.join(", ")
}
fn create_function_body(function: &Function) -> Vec<String> {
function
.arguments
.iter()
.skip(1)
.map(|arg| {
let inner_type_name = arg.typ.get_name();
let arg_name = &arg.arg_name;
format!("{inner_type_name}({arg_name})")
})
.collect()
}
pub fn from_virtual_function(function: &Function, class_name: &str) -> Self {
let generated_args =
FunctionHelperVirtual::create_list_of_arguments_translated_to_cpp(function);
let generated_args = generated_args.join(", ");
let generated_virtual_function_signature =
FunctionHelperVirtual::create_function_signature(function);
let generated_function_body: Vec<String> =
FunctionHelperVirtual::create_function_body(function);
let function_name = function.name.to_string();
let arg_names = function
.arguments
.iter()
.map(|arg| arg.arg_name.to_string())
.collect();
FunctionHelperVirtual {
function_name,
generated_args,
generated_function_body,
generated_virtual_function_signature,
return_type: function.return_type.clone(),
arg_names,
class_name: class_name.to_owned(),
}
}
pub fn generate_virtual_declaration(self) -> String {
let FunctionHelperVirtual {
function_name,
generated_args: _,
generated_function_body: _,
generated_virtual_function_signature,
return_type,
..
} = self;
let function_name = function_name.to_case(Case::Camel);
let return_type_string = if let Some(wrapper) = return_type {
wrapper.get_name_for_abstract_method()
} else {
"Void".to_owned()
};
format!(" func {function_name}({generated_virtual_function_signature}) -> {return_type_string}\n")
}
pub fn generate_virtual_definition(self) -> String {
let FunctionHelperVirtual {
function_name,
generated_args,
generated_function_body,
generated_virtual_function_signature: _,
return_type,
arg_names: _,
class_name,
} = self;
let class_function_name = format!("{class_name}$");
let ffi_function_name =
format!("{EXPORTED_SYMBOLS_PREFIX}${class_function_name}{function_name}");
let generated_function_body = generated_function_body.join(", ");
let function_name = function_name.to_case(Case::Camel);
match return_type {
Some(WrapperType {
rust_type: RustWrapperType::Primitive | RustWrapperType::FieldlessEnum,
wrapper_name,
..
}) =>
format!(
"@_cdecl(\"{ffi_function_name}\") func {ffi_function_name}({generated_args}) -> {wrapper_name} {{
return (_self as! {class_name}).{function_name}({generated_function_body})\n}}\n"),
None => format!(
"@_cdecl(\"{ffi_function_name}\") func {ffi_function_name}({generated_args}) {{
(_self as! {class_name}).{function_name}({generated_function_body})\n}}\n"),
_ =>
format!(
"@_cdecl(\"{ffi_function_name}\") func {ffi_function_name}({generated_args}) -> UnsafeMutableRawPointer {{
return convertToOwnedType((_self as! {class_name}).{function_name}({generated_function_body}))\n}}\n"),
}
}
}
pub struct FunctionTranslator {
pub function_name: String,
pub generated_args: String,
pub generated_function_body: Vec<String>,
pub return_type: Option<WrapperType>,
class_name: Option<String>,
}
impl FunctionTranslator {
pub fn from_class_method(function: &Function, class_name: &str) -> Self {
FunctionTranslator::from_function(function, Some(class_name.to_owned()))
}
pub fn from_global_function(function: &Function) -> Self {
FunctionTranslator::from_function(function, None)
}
fn from_function(function: &Function, class_name: Option<String>) -> Self {
let generated_args: String = function
.arguments
.iter()
.skip(class_name.is_some() as usize)
.map(|arg| {
let arg_name = &arg.arg_name;
let return_type_string = arg.typ.get_name();
format!("_ {arg_name}: {return_type_string}")
})
.collect::<Vec<String>>()
.join(", ");
let generated_function_body: Vec<String> = function
.arguments
.iter()
.skip(class_name.is_some() as usize)
.map(map_function_argument)
.collect();
let function_name = function.name.to_string();
FunctionTranslator {
function_name,
generated_args,
generated_function_body,
return_type: function.return_type.clone(),
class_name,
}
}
fn primitive_exception_throw(enum_name: impl Display, exception: impl Display) -> String {
let variant_check = format!(" == {enum_name}_{exception}");
format!(
"
else if (result.unwrapErr(){variant_check}) {{
throw {enum_name}_{exception}Exception(result.unwrapErr())
}}"
)
}
fn non_primitive_exception_throw(enum_name: impl Display, exception: impl Display) -> String {
let variant_check = format!(" == {enum_name}Tag_{exception}");
format!(
"
else if (result.unwrapErr().getTag(){variant_check}) {{
throw {enum_name}_{exception}Exception(result.unwrapErr())
}}"
)
}
pub fn generate_definition(self) -> String {
let FunctionTranslator {
function_name,
generated_args,
mut generated_function_body,
return_type,
class_name,
} = self;
let class_function_name = if let Some(class_name) = &class_name {
format!("{class_name}$")
} else {
"".to_owned()
};
let ffi_function_name =
format!("{EXPORTED_SYMBOLS_PREFIX}${class_function_name}{function_name}");
let function_name = function_name.to_case(Case::Camel);
if class_name.is_some() {
generated_function_body.insert(0, "self._self".to_owned());
}
let generated_function_body = generated_function_body.join(", ");
if let Some(ref wrapper) = return_type {
if let Some(WrapperType {
wrapper_name,
rust_type: RustWrapperType::Result(_, err_type),
..
}) = &return_type
{
let exception_enum_name = &err_type.wrapper_name;
let exceptions_throws = match &err_type.rust_type {
RustWrapperType::Exceptions(Exceptions::Primitive(idents)) => idents
.iter()
.map(|exception| {
Self::primitive_exception_throw(exception_enum_name, exception)
})
.collect::<String>(),
RustWrapperType::Exceptions(Exceptions::NonPrimitive(idents)) => idents
.iter()
.map(|exception| {
Self::non_primitive_exception_throw(exception_enum_name, exception)
})
.collect::<String>(),
_ => panic!("Invalid wrapper type for exceptions wrapper"),
};
let return_type_string = wrapper.get_name();
format!("public func {function_name}({generated_args}) throws -> {return_type_string} {{
let result = {wrapper_name}({ffi_function_name}({generated_function_body}))
if (result.isOk()) {{
return result.unwrap()
}} {exceptions_throws}
else {{
fatalError(\"Unknown to ffi layer exception has been thrown\")
}}
}}\n"
)
} else {
let return_type_string = wrapper.get_name();
format!(
" public func {function_name}({generated_args}) -> {return_type_string} {{
return {return_type_string}({ffi_function_name}({generated_function_body}))
}}\n"
)
}
} else {
format!(
" public func {function_name}({generated_args}) {{
{ffi_function_name}({generated_function_body})
}}\n"
)
}
}
}
fn map_function_argument(arg: &Arg) -> String {
if arg.typ.reference_parameters.is_some()
&& arg.typ.rust_type != RustWrapperType::Primitive
&& arg.typ.rust_type != RustWrapperType::FieldlessEnum
&& arg.typ.rust_type != RustWrapperType::Trait
{
format!("{}.asRef()", arg.arg_name)
} else {
format!("convertToOwnedType({})", arg.arg_name.to_owned())
}
}