use maplit::hashmap;
use once_cell::sync::Lazy;
use crate::{
CompiledInterpolation,
Constness,
ConstnessOverride,
Element,
EntityElement,
SmartPtr,
StrExt,
type_ref,
};
use super::RustNativeGeneratedElement;
impl RustNativeGeneratedElement for SmartPtr<'_, '_> {
fn element_safe_id(&self) -> String {
format!("{}-{}", self.rust_module(), self.rust_localalias())
}
fn gen_rust(&self, _opencv_version: &str) -> String {
static TPL: Lazy<CompiledInterpolation> = Lazy::new(
|| include_str!("tpl/smart_ptr/rust.tpl.rs").compile_interpolation()
);
static TRAIT_RAW_TPL: Lazy<CompiledInterpolation> = Lazy::new(
|| include_str!("tpl/smart_ptr/trait_raw.tpl.rs").compile_interpolation()
);
static BASE_CAST_TPL: Lazy<CompiledInterpolation> = Lazy::new(
|| include_str!("tpl/smart_ptr/base_cast.tpl.rs").compile_interpolation()
);
static CTOR_TPL: Lazy<CompiledInterpolation> = Lazy::new(
|| include_str!("tpl/smart_ptr/ctor.tpl.rs").compile_interpolation()
);
let type_ref = self.type_ref();
let pointee_type = self.pointee();
let mut inter_vars = hashmap! {
"rust_localalias" => self.rust_localalias(),
"rust_full" => self.rust_fullname(),
"rust_extern_const" => type_ref.rust_extern_with_const(ConstnessOverride::Yes(Constness::Const)),
"rust_extern_mut" => type_ref.rust_extern_with_const(ConstnessOverride::Yes(Constness::Mut)),
"inner_rust_full" => pointee_type.rust_full(),
};
let mut impls = String::new();
let mut gen_ctor = pointee_type.is_primitive();
if let Some(cls) = pointee_type.as_class() {
gen_ctor |= !cls.is_abstract();
if cls.is_trait() {
inter_vars.insert("base_rust_local", cls.rust_localname().into_owned().into());
inter_vars.insert("base_rust_full", cls.rust_trait_fullname().into_owned().into());
impls += &TRAIT_RAW_TPL.interpolate(&inter_vars);
let mut all_bases = cls.all_bases().into_iter()
.filter(|b| !b.is_excluded())
.collect::<Vec<_>>();
all_bases.sort_unstable_by(|a, b| a.cpp_fullname().cmp(&b.cpp_fullname()));
for base in all_bases {
inter_vars.insert("base_rust_local", base.rust_localname().into_owned().into());
inter_vars.insert("base_rust_full", base.rust_trait_fullname().into_owned().into());
inter_vars.insert("base_rust_full_ref", base.type_ref().rust_full().into_owned().into());
impls += &TRAIT_RAW_TPL.interpolate(&inter_vars);
if self.gen_env.is_used_in_smart_ptr(base.entity()) {
impls += &BASE_CAST_TPL.interpolate(&inter_vars);
}
}
}
};
if gen_ctor {
inter_vars.insert("ctor", CTOR_TPL.interpolate(&inter_vars).into());
} else {
inter_vars.insert("ctor", "".into());
}
inter_vars.insert("impls", impls.into());
TPL.interpolate(&inter_vars)
}
fn gen_cpp(&self) -> String {
static TPL: Lazy<CompiledInterpolation> = Lazy::new(
|| include_str!("tpl/smart_ptr/cpp.tpl.cpp").compile_interpolation()
);
static BASE_CAST_TPL: Lazy<CompiledInterpolation> = Lazy::new(
|| include_str!("tpl/smart_ptr/base_cast.tpl.cpp").compile_interpolation()
);
static CTOR_TPL: Lazy<CompiledInterpolation> = Lazy::new(
|| include_str!("tpl/smart_ptr/ctor.tpl.cpp").compile_interpolation()
);
let type_ref = self.type_ref();
let pointee_type = self.pointee();
let mut inner_cpp_extern = pointee_type.cpp_extern_return();
let mut extern_return_const_renderer = type_ref::CppExternReturnRenderer::new();
extern_return_const_renderer.constness_override = ConstnessOverride::Yes(Constness::Const);
let mut inner_cpp_extern_const = pointee_type.render(extern_return_const_renderer);
if !pointee_type.is_by_ptr() {
inner_cpp_extern.to_mut().push('*');
inner_cpp_extern_const.to_mut().push('*');
}
let mut const_renderer = type_ref::CppReferenceRenderer::new("", true);
const_renderer.constness_override = ConstnessOverride::Yes(Constness::Const);
let cpp_full_const = type_ref.render(const_renderer);
let mut inter_vars = hashmap! {
"rust_localalias" => self.rust_localalias(),
"cpp_extern" => type_ref.cpp_extern(),
"cpp_decl" => type_ref.cpp_arg_func_decl("instance").into(),
"cpp_full" => type_ref.cpp_full(),
"cpp_full_const" => cpp_full_const,
"inner_cpp_full" => pointee_type.cpp_full(),
"inner_cpp_extern" => inner_cpp_extern,
"inner_cpp_extern_const" => inner_cpp_extern_const,
};
let mut base_cast = String::new();
let pointee_primitive = pointee_type.is_primitive();
let mut gen_ctor = pointee_primitive;
if let Some(cls) = pointee_type.as_class() {
gen_ctor |= !cls.is_abstract();
if cls.is_trait() {
let mut all_bases = cls.all_bases().into_iter()
.filter(|b| !b.is_excluded() && self.gen_env.is_used_in_smart_ptr(b.entity()))
.collect::<Vec<_>>();
all_bases.sort_unstable_by(|a, b| a.cpp_fullname().cmp(&b.cpp_fullname()));
for base in all_bases {
inter_vars.insert("base_cpp_full", base.cpp_fullname().into_owned().into());
inter_vars.insert("base_rust_local", base.rust_localname().into_owned().into());
let new_base_cast = BASE_CAST_TPL.interpolate(&inter_vars);
if base_cast.is_empty() {
base_cast = new_base_cast;
} else {
base_cast += &new_base_cast;
}
}
}
}
if gen_ctor {
let inner_cpp_func_call = if pointee_primitive {
format!("new {typ}(val)", typ=pointee_type.cpp_full()).into()
} else {
let mut out = pointee_type.cpp_arg_func_call("val");
if out.starts_with('*') {
out.to_mut().drain(..1);
}
out
};
inter_vars.insert("inner_cpp_func_decl", pointee_type.cpp_arg_func_decl("val").into());
inter_vars.insert("inner_cpp_func_call", inner_cpp_func_call);
inter_vars.insert("ctor", CTOR_TPL.interpolate(&inter_vars).into());
} else {
inter_vars.insert("ctor", "".into());
};
inter_vars.insert("base_cast", base_cast.into());
TPL.interpolate(&inter_vars)
}
}