use std::collections::HashSet;
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
use syn::token::Comma;
use syn::{parse_quote, Abi, Field, Item, ItemEnum, ItemForeignMod, ItemMod, Type, Variant};
use crate::utils::BuildContext;
use crate::DROP_FUNCTION_SYMBOL_NAME;
use crate::{
binding_types::*,
cpp::{generate_cpp_file, swig_generator::generate_swig_based_on_wrappers},
enum_helpers::*,
extern_functions_utils::*,
extern_module_translator::ExternModuleTranslator,
swift::{generate_c_externs_file, generate_swift_file},
EXPORTED_SYMBOLS_PREFIX,
};
pub struct GeneratedFilesContent {
pub cpp_header: String,
pub swift_header: String,
pub cpp_externs: String,
pub swig_interface: String,
}
#[derive(Debug, Clone)]
pub struct CargoFeature {
val: String,
}
impl CargoFeature {
pub fn new<T>(val: &T) -> Self
where
T: AsRef<str> + ?Sized,
{
Self {
val: val.as_ref().to_uppercase().replace('-', "_"),
}
}
}
impl PartialEq for CargoFeature {
fn eq(&self, other: &Self) -> bool {
self.val == other.val
}
}
pub struct BindingModule {
extern_module_translator: ExternModuleTranslator,
wrappers_impls: TokenStream,
extern_functions: Vec<ExternFunction>,
}
impl BindingModule {
pub fn translate_module(module: ItemMod, context: &BuildContext) -> anyhow::Result<Self> {
let enums: HashSet<ItemEnum> = get_enums_from_module(&module, context)?
.into_iter()
.collect();
let module_name = &module.ident;
let mut extern_module_translator = ExternModuleTranslator::new(enums.clone());
if let Some(ext_rust_module) = BindingModule::get_extern_mod_from_module(&module, "Rust") {
extern_module_translator.parse_items_in_extern_rust_module(ext_rust_module, context)?;
}
if let Some(ext_trait_module) = BindingModule::get_extern_mod_from_module(&module, "Traits")
{
extern_module_translator.translate_trait_external_modules(ext_trait_module, context)?;
}
if let Some(ext_exception_trait_module) =
BindingModule::get_extern_mod_from_module(&module, "ExceptionTrait")
{
extern_module_translator
.translate_exception_trait_external_module(ext_exception_trait_module, context)?;
}
let mut result = BindingModule {
extern_module_translator,
wrappers_impls: Default::default(),
extern_functions: Default::default(),
};
result.create_wrappers_for_custom_types();
result.create_complex_enum_getters(&enums);
result.create_wrappers_for_exception_trait();
result.create_wrappers_for_traits();
result.create_wrappers_for_global_functions();
result.create_wrappers_for_results(enums)?;
result.create_wrappers_for_builtins()?;
result.create_wrappers_for_clones();
result.create_wrappers_for_strings()?;
result.wrappers_impls.extend(
result
.extern_functions
.iter()
.map(|extern_function| extern_function.tokens.clone()),
);
let wrappers_impls = &result.wrappers_impls;
result.wrappers_impls = quote!( mod #module_name { #![allow(warnings, unused)] use super::*; #wrappers_impls } );
Ok(result)
}
pub fn generate_binding_files(&self) -> GeneratedFilesContent {
GeneratedFilesContent {
cpp_header: generate_cpp_file(&self.extern_module_translator, &self.extern_functions),
swift_header: generate_swift_file(&self.extern_module_translator),
cpp_externs: generate_c_externs_file(
&self.extern_module_translator,
&self.extern_functions,
),
swig_interface: generate_swig_based_on_wrappers(&self.extern_module_translator),
}
}
pub fn get_tokens(&self) -> TokenStream {
self.wrappers_impls.clone()
}
fn get_extern_mod_from_module<'a>(
module: &'a ItemMod,
extern_lang: &str,
) -> Option<&'a ItemForeignMod> {
module.content.as_ref().and_then(|(_, items)| {
items.iter().find_map(|module_item| match module_item {
Item::ForeignMod(
rust_module @ ItemForeignMod {
abi:
Abi {
name: Some(lang), ..
},
..
},
) if lang.value() == extern_lang => Some(rust_module),
_ => None,
})
})
}
fn register_extern_function(&mut self, function: ExternFunction) {
self.extern_functions.push(function);
}
fn create_complex_enum_getters(&mut self, enums: &HashSet<ItemEnum>) {
enums
.iter()
.filter(|enum_item| !is_primitive_enum(enum_item))
.for_each(|ce| self.complex_enum_getter(ce));
}
fn complex_enum_getter(&mut self, complex_enum: &ItemEnum) {
let enum_ident = &complex_enum.ident;
let variant_wrapper_structs = complex_enum
.variants
.iter()
.map(|v| self.create_variant_struct_wrapper(v, complex_enum))
.collect::<TokenStream>();
let many_fields_variants_wrapper_getters =
self.create_and_register_many_fields_variants_wrapper_getters(complex_enum);
let single_field_variants_getters =
self.create_and_register_single_field_variants_wrapper_getters(complex_enum);
if complex_enum
.variants
.iter()
.any(|v| !is_ignored_variant(v) && !is_unit_variant(v))
{
let enum_impl_block = quote! {
impl #enum_ident {
#many_fields_variants_wrapper_getters
#single_field_variants_getters
}
};
self.wrappers_impls.extend(variant_wrapper_structs);
self.wrappers_impls.extend(enum_impl_block);
}
}
fn create_and_register_many_fields_variants_wrapper_getters(
&mut self,
complex_enum: &ItemEnum,
) -> TokenStream {
let enum_ident = &complex_enum.ident;
complex_enum
.variants
.iter()
.filter(|v| is_many_fields_variant(v))
.map(|v| {
let getter_name = variant_getter_ident(v);
let wrapper_name = variant_wrapper_ident(enum_ident, &v.ident);
self.register_variant_getter_extern_function(complex_enum, v);
quote! {fn #getter_name(&self) -> #wrapper_name {
#wrapper_name(self.clone())
}}
})
.collect::<TokenStream>()
}
fn create_and_register_single_field_variants_wrapper_getters(
&mut self,
complex_enum: &ItemEnum,
) -> TokenStream {
complex_enum
.variants
.iter()
.filter(|v| is_single_field_variant(v))
.filter_map(|v| {
let field = &get_fields(v).unwrap()[0];
let variant_ident = &v.ident;
match &field_type(field) {
FieldType::Type(field_type) => {
let return_type: Ident = syn::parse_str(field_type).unwrap();
let fn_ident = variant_getter_ident(v);
let field_retrieve = if is_primitive_field(field) {
quote! {*field}
} else {
quote! {field.clone()}
};
let field_match = if let Some(name) = field_name(field) {
let name = syn::parse_str::<Ident>(&name).unwrap();
quote! {{#name: field}}
} else {
quote! {(field)}
};
self.register_variant_getter_extern_function(complex_enum, v);
Some(quote! {
fn #fn_ident(&self) -> #return_type {
match &self {
Self::#variant_ident #field_match => #field_retrieve,
_ => panic!(),
}
}
})
}
FieldType::Ignored => None,
}
})
.collect::<TokenStream>()
}
fn create_variant_struct_wrapper(
&mut self,
variant: &Variant,
enum_item: &ItemEnum,
) -> TokenStream {
let enum_ident = &enum_item.ident;
let wrapper_ident = variant_wrapper_ident(enum_ident, &variant.ident);
let struct_tokens = quote! {#[derive(Clone)] pub struct #wrapper_ident(#enum_ident);};
get_fields(variant)
.map(|fields| {
if fields.len() > 1 {
let field_getters =
self.create_and_register_variant_fields_getters(fields, enum_item, variant);
self.register_drop_function_for_variant_wrapper(wrapper_ident.to_string());
self.register_clone_function_for_variant_wrapper(wrapper_ident.to_string());
quote! {
#struct_tokens
impl #wrapper_ident {
#field_getters
}
}
} else {
quote! {}
}
})
.unwrap_or_default()
}
fn register_drop_function_for_variant_wrapper(&mut self, wrapper_name: String) {
let ext_fun = create_drop_extern_function(WrapperType {
original_type_name: syn::parse_str(&wrapper_name).unwrap(),
wrapper_name,
rust_type: RustWrapperType::Custom,
reference_parameters: None,
});
self.register_extern_function(ext_fun);
}
fn register_clone_function_for_variant_wrapper(&mut self, wrapper_name: String) {
let ext_fun = create_clone_extern_function(WrapperType {
original_type_name: syn::parse_str(&wrapper_name).unwrap(),
wrapper_name,
rust_type: RustWrapperType::Custom,
reference_parameters: None,
});
self.register_extern_function(ext_fun);
}
fn create_and_register_variant_fields_getters(
&mut self,
fields: &syn::punctuated::Punctuated<syn::Field, Comma>,
enum_item: &ItemEnum,
variant: &Variant,
) -> TokenStream {
fields
.iter()
.enumerate()
.map(|(idx, field)| {
let field_type = field_type(field).unwrap_type();
let return_type: TokenStream = field_type.parse().unwrap();
let fn_ident = field_getter_ident(field, idx);
let (fields_match, field_name) = if let Some(field_name) = &field.ident {
(quote! {{#field_name, ..}}, field_name.clone())
} else {
let fields_match = (0..fields.len())
.map(|idx| format!("_{idx}"))
.collect::<Vec<_>>()
.join(", ")
.parse::<TokenStream>()
.unwrap();
(
quote! {(#fields_match)},
Ident::new(&format!("_{idx}"), Span::call_site()),
)
};
self.register_field_getter_extern_function(enum_item, variant, field, idx);
let variant_ident = &variant.ident;
let enum_ident = &enum_item.ident;
quote! {
fn #fn_ident(&self) -> #return_type {
match &self.0 {
#enum_ident::#variant_ident #fields_match => (*#field_name).clone(),
_ => panic!(),
}
}
}
})
.collect::<TokenStream>()
}
fn register_field_getter_extern_function(
&mut self,
enum_item: &ItemEnum,
variant: &Variant,
field: &Field,
field_idx: usize,
) {
let function = create_field_getter_function(enum_item, variant, field, field_idx);
let extern_function = create_extern_function_for_custom_type(
variant_wrapper_ident(&enum_item.ident, &variant.ident)
.to_string()
.as_str(),
&function,
);
self.register_extern_function(extern_function);
}
fn register_variant_getter_extern_function(&mut self, enum_item: &ItemEnum, variant: &Variant) {
let function = create_variant_getter_function(enum_item, variant);
if let Some(function) = function {
let extern_function = create_extern_function_for_custom_type(
enum_item.ident.to_string().as_str(),
&function,
);
self.register_extern_function(extern_function);
}
}
fn create_wrappers_for_custom_types(&mut self) {
self.extern_module_translator
.user_custom_types
.iter()
.flat_map(|(custom_type, functions)| match custom_type {
WrapperType {
original_type_name: _,
wrapper_name,
rust_type:
RustWrapperType::Custom | RustWrapperType::ArcMutex | RustWrapperType::Arc,
..
} => functions
.iter()
.map(|function| create_extern_function_for_custom_type(wrapper_name, function))
.collect(),
_ => vec![],
})
.collect::<Vec<_>>()
.into_iter()
.for_each(|f| self.register_extern_function(f));
}
fn create_wrappers_for_results(&mut self, enums: HashSet<ItemEnum>) -> anyhow::Result<()> {
self.extern_module_translator
.rust_types_wrappers.clone()
.unordered_iter()
.map(|wrapper| match wrapper {
WrapperType {
original_type_name,
wrapper_name,
rust_type: RustWrapperType::Result(ok_wrapper_type, exceptions_wrapper_type),
..
} => {
let mut local_extern_mod_translator = ExternModuleTranslator::new(enums.clone());
let ok_type = &ok_wrapper_type.original_type_name;
let exc_type = &exceptions_wrapper_type.original_type_name;
let from_ok_extern_function = from_ok_extern_function(wrapper, ok_wrapper_type);
let from_err_extern_function = from_err_extern_function(wrapper, exceptions_wrapper_type);
let (_, is_ok_function) = local_extern_mod_translator
.translate_function(&parse_quote! { fn is_ok(self: &#original_type_name) -> bool; })?;
let is_ok_extern_function = create_extern_function_for_custom_type(
wrapper_name,
&is_ok_function,
);
let (_, unwrap_unchecked_function) = local_extern_mod_translator
.translate_function(
&parse_quote! { fn unwrap(self: #original_type_name) -> #ok_type; },
)?;
let unwrap_unchecked_extern_function = create_extern_function_for_custom_type(
wrapper_name,
&unwrap_unchecked_function,
);
let (_, unwrap_err_unchecked_function) = local_extern_mod_translator
.translate_function(
&parse_quote! { fn unwrap_err_unchecked(self: #original_type_name) -> #exc_type; },
)?;
let unwrap_err_unchecked_extern_function = create_extern_function_for_custom_type(
wrapper_name,
&unwrap_err_unchecked_function,
);
Ok(vec![
from_ok_extern_function,
from_err_extern_function,
is_ok_extern_function,
unwrap_unchecked_extern_function,
unwrap_err_unchecked_extern_function,
])
},
_ => Ok(vec![])
})
.collect::<anyhow::Result<Vec<_>>>()?
.into_iter()
.flatten()
.for_each(|f| self.register_extern_function(f));
Ok(())
}
fn create_option_extern_functions(
wrapper: &WrapperType,
inner_type: &WrapperType,
original_type_name: &Type,
wrapper_name: &str,
local_extern_mod_translator: &mut ExternModuleTranslator,
) -> anyhow::Result<Vec<ExternFunction>> {
let inner_type = &inner_type.original_type_name;
let (_, new_function) = local_extern_mod_translator.translate_function(
&parse_quote! { fn from(val: #inner_type) -> #original_type_name; },
)?;
let wrapper_without_generics = WrapperType {
original_type_name: syn::parse_str("Option").unwrap(),
..wrapper.clone()
};
let from_extern_function = create_extern_associated_function_for_custom_type(
wrapper_without_generics,
&new_function,
);
let (_, new_function) = local_extern_mod_translator
.translate_function(&parse_quote! { fn default() -> #original_type_name; })?;
let wrapper_without_generics = WrapperType {
original_type_name: syn::parse_str("Option").unwrap(),
..wrapper.clone()
};
let default_extern_function = create_extern_associated_function_for_custom_type(
wrapper_without_generics,
&new_function,
);
let (_, is_some_function) = local_extern_mod_translator.translate_function(
&parse_quote! { fn is_some(self: &#original_type_name) -> bool; },
)?;
let is_ok_extern_function =
create_extern_function_for_custom_type(wrapper_name, &is_some_function);
let (_, unwrap_unchecked_function) = local_extern_mod_translator.translate_function(
&parse_quote! { fn unwrap(self: #original_type_name) -> #inner_type; },
)?;
let unwrap_unchecked_extern_function =
create_extern_function_for_custom_type(wrapper_name, &unwrap_unchecked_function);
Ok(vec![
from_extern_function,
default_extern_function,
is_ok_extern_function,
unwrap_unchecked_extern_function,
])
}
fn create_vector_extern_functions(
wrapper: &WrapperType,
inner_type: &WrapperType,
original_type_name: &Type,
wrapper_name: &str,
local_extern_mod_translator: &mut ExternModuleTranslator,
) -> anyhow::Result<Vec<ExternFunction>> {
let inner_type_original = &inner_type.original_type_name;
let (_, new_function) = local_extern_mod_translator
.translate_function(&parse_quote! { fn new() -> #original_type_name; })?;
let wrapper_without_generics = WrapperType {
original_type_name: syn::parse_str("Vec").unwrap(),
..wrapper.clone()
};
let new_extern_function = create_extern_associated_function_for_custom_type(
wrapper_without_generics,
&new_function,
);
let get_extern_function =
create_get_from_vec_extern_function(wrapper.clone(), inner_type.clone());
let (_, push_function) = local_extern_mod_translator.translate_function(
&parse_quote! { fn push(self: &#original_type_name, obj: #inner_type_original); },
)?;
let push_extern_function =
create_extern_function_for_custom_type(wrapper_name, &push_function);
let (_, as_mut_ptr_function) = local_extern_mod_translator
.translate_function(&parse_quote! { fn as_mut_ptr(self: &#original_type_name) -> *mut #inner_type_original; })?;
let as_mut_ptr_extern_function =
create_extern_function_for_custom_type(wrapper_name, &as_mut_ptr_function);
let (_, len_function) = local_extern_mod_translator
.translate_function(&parse_quote! { fn len(self: &#original_type_name) -> usize; })?;
let len_extern_function =
create_extern_function_for_custom_type(wrapper_name, &len_function);
Ok(vec![
new_extern_function,
get_extern_function,
push_extern_function,
len_extern_function,
as_mut_ptr_extern_function,
])
}
fn create_wrappers_for_builtins(&mut self) -> anyhow::Result<()> {
self.extern_module_translator
.rust_types_wrappers
.clone()
.unordered_iter()
.map(|wrapper| match wrapper {
WrapperType {
original_type_name,
wrapper_name,
rust_type: RustWrapperType::Option(inner_type),
..
} => BindingModule::create_option_extern_functions(
wrapper,
inner_type,
original_type_name,
wrapper_name,
&mut self.extern_module_translator,
),
WrapperType {
original_type_name,
wrapper_name,
rust_type: RustWrapperType::Vector(inner_type),
..
} => BindingModule::create_vector_extern_functions(
wrapper,
inner_type,
original_type_name,
wrapper_name,
&mut self.extern_module_translator,
),
_ => Ok(vec![]),
})
.collect::<anyhow::Result<Vec<_>>>()?
.into_iter()
.flatten()
.for_each(|f| self.register_extern_function(f));
Ok(())
}
fn create_wrappers_for_traits(&mut self) {
let drop_native_ref: TokenStream = quote! {
extern "C" {
#[link_name = #DROP_FUNCTION_SYMBOL_NAME]
fn drop_native_ref(input: *mut std::ffi::c_void);
}
};
self.wrappers_impls.extend(drop_native_ref);
let limit_lifetime: TokenStream = quote! {
fn limit_lifetime<'a, T: ?Sized>(r: &'static T, _: &'a ()) -> &'a T {
r
}
};
self.wrappers_impls.extend(limit_lifetime);
let limit_lifetime_mut: TokenStream = quote! {
fn limit_lifetime_mut<'a, T: ?Sized>(r: &'static mut T, _: &'a mut ()) -> &'a mut T {
r
}
};
self.wrappers_impls.extend(limit_lifetime_mut);
for (custom_type, functions) in &self.extern_module_translator.user_traits {
if custom_type.rust_type == RustWrapperType::Trait {
let wrapper_name = Ident::new(&custom_type.wrapper_name, Span::call_site());
let generated_functions =
generate_trait_methods(functions.iter(), &custom_type.wrapper_name);
let generated_wrapper_impl: TokenStream = quote! {
pub struct #wrapper_name(std::sync::atomic::AtomicPtr<std::ffi::c_void>);
impl super::#wrapper_name for #wrapper_name {
#(#generated_functions)*
}
impl #wrapper_name {
fn new(inner: *mut std::ffi::c_void) -> Self {
Self(std::sync::atomic::AtomicPtr::new(inner))
}
}
impl Drop for #wrapper_name {
fn drop(&mut self) {
unsafe { drop_native_ref(self.0.load(std::sync::atomic::Ordering::Relaxed)) }
}
}
};
self.wrappers_impls.extend(generated_wrapper_impl);
let extern_link_functions = functions.iter().map(|function| {
let function_name = &function.name;
let export_function_name =
format!("{EXPORTED_SYMBOLS_PREFIX}${wrapper_name}${function_name}");
let function_name = Ident::new(
&format!("{EXPORTED_SYMBOLS_PREFIX}{wrapper_name}_{function_name}"),
Span::call_site(),
);
let return_type = match &function.return_type {
Some(WrapperType {
original_type_name,
rust_type: RustWrapperType::Primitive | RustWrapperType::FieldlessEnum,
..
}) => original_type_name.clone(),
Some(WrapperType {
original_type_name, ..
}) => parse_quote! { *mut #original_type_name },
_ => parse_quote! { () },
};
let mut args = prepare_extern_function_signature(function);
if let Some(self_arg) = args.first_mut() {
*self_arg = parse_quote! {_self: *mut std::ffi::c_void}
}
quote! {
extern "C" {
#[link_name = #export_function_name]
fn #function_name(#args) -> #return_type;
}
}
});
self.wrappers_impls.extend(extern_link_functions);
}
}
}
fn create_wrappers_for_exception_trait(&mut self) {
let exception_types_names_iter = self
.extern_module_translator
.rust_types_wrappers
.unordered_iter()
.filter_map(|wrapper| {
if matches!(wrapper.rust_type, RustWrapperType::Exceptions(_)) {
Some(wrapper.wrapper_name.clone())
} else {
None
}
})
.collect::<Vec<String>>();
self.extern_module_translator
.exception_trait_methods
.iter()
.flat_map(|function| {
exception_types_names_iter
.clone()
.iter()
.map(|wrapper_name| {
create_extern_function_for_exception_trait_method(wrapper_name, function)
})
.collect::<Vec<_>>()
})
.collect::<Vec<_>>()
.into_iter()
.for_each(|f| self.register_extern_function(f));
}
fn create_wrappers_for_global_functions(&mut self) {
self.extern_module_translator
.global_functions
.iter()
.map(create_extern_global_function)
.collect::<Vec<_>>()
.into_iter()
.for_each(|f| self.register_extern_function(f));
}
fn create_wrappers_for_strings(&mut self) -> anyhow::Result<()> {
let wrapper = WrapperType {
original_type_name: syn::parse_str("String").unwrap(),
wrapper_name: "RustString".to_owned(),
rust_type: RustWrapperType::String,
reference_parameters: Some(ReferenceParameters::shared()),
};
let original_type_name = &wrapper.original_type_name;
let wrapper_name = &wrapper.wrapper_name;
let (_, new_function) = self
.extern_module_translator
.translate_function(&parse_quote! { fn new() -> #original_type_name; })?;
let new_extern_function =
create_extern_associated_function_for_custom_type(wrapper.clone(), &new_function);
let from_c_str_extern_function = create_from_c_str_extern_function(wrapper.clone());
let (_, as_mut_ptr_function) = self.extern_module_translator.translate_function(
&parse_quote! { fn as_mut_ptr(self: &#original_type_name) -> &mut u8; },
)?;
let as_mut_ptr_extern_function =
create_extern_function_for_custom_type(wrapper_name, &as_mut_ptr_function);
let (_, len_function) = self
.extern_module_translator
.translate_function(&parse_quote! { fn len(self: &#original_type_name) -> usize; })?;
let len_extern_function =
create_extern_function_for_custom_type(wrapper_name, &len_function);
let clone_extern_function = create_clone_extern_function(wrapper.clone());
let drop_extern_function = create_drop_extern_function(wrapper.clone());
[
new_extern_function,
from_c_str_extern_function,
as_mut_ptr_extern_function,
len_extern_function,
clone_extern_function,
drop_extern_function,
]
.into_iter()
.for_each(|f| self.register_extern_function(f));
Ok(())
}
fn create_wrappers_for_clones(&mut self) {
self.extern_module_translator
.rust_types_wrappers
.unordered_iter()
.flat_map(|wrapper| match wrapper.rust_type {
RustWrapperType::Trait
| RustWrapperType::String
| RustWrapperType::Primitive
| RustWrapperType::FieldlessEnum
| RustWrapperType::ExceptionTrait
| RustWrapperType::Exceptions(_) => vec![],
_ => vec![
create_clone_extern_function(wrapper.clone()),
create_drop_extern_function(wrapper.clone()),
],
})
.collect::<Vec<_>>()
.into_iter()
.for_each(|f| self.register_extern_function(f));
}
}