use std::borrow::Cow;
use super::element::RustElement;
use super::type_ref::{NullabilityExt, TypeRefExt};
use crate::function::Function;
use crate::type_ref::{ExternDir, Nullability};
use crate::{NameStyle, StringExt, SupportedModule};
impl RustElement for Function<'_, '_> {
fn rust_module(&self) -> SupportedModule {
SupportedModule::Core
}
fn rust_name(&self, style: NameStyle) -> Cow<'_, str> {
let ret = self.return_type();
let args = self.arguments();
if let Some(userdata_idx) = args.iter().position(|a| a.is_user_data()) {
let mut args_str = String::with_capacity(args.len() * 16);
for (idx, arg) in args.iter().enumerate() {
if idx != userdata_idx {
args_str.extend_sep(", ", arg.type_ref().rust_extern(ExternDir::Contained).as_ref());
}
}
Nullability::Nullable.rust_wrap_nullable_decl(
format!(
"Box{fish}<dyn FnMut({args_str}) -> {ret} + Send + Sync + 'static>",
fish = style.rust_turbo_fish_qual(),
ret = ret.rust_extern(ExternDir::Contained),
)
.into(),
style,
)
} else {
self.rust_extern()
}
}
}
pub trait FunctionExt<'tu, 'ge> {
fn rust_extern(&self) -> Cow<'_, str>;
}
impl<'tu, 'ge> FunctionExt<'tu, 'ge> for Function<'tu, 'ge> {
fn rust_extern(&self) -> Cow<'_, str> {
let args = self.arguments();
let mut args_str = String::with_capacity(args.len() * 16);
for arg in &args {
args_str.extend_sep(", ", arg.type_ref().rust_extern(ExternDir::Contained).as_ref());
}
let ret = self.return_type();
Nullability::Nullable.rust_wrap_nullable_decl(
format!(
r#"unsafe extern "C" fn({args_str}) -> {ret}"#,
ret = ret.rust_extern(ExternDir::Contained)
)
.into(),
NameStyle::decl(),
)
}
}