Sort out const attribute generation
MODIFY
binding-generator/src/return_type_wrapper.rs
binding-generator/src/return_type_wrapper.rs
@@ -15,19 +15,28 @@ pub enum DefinitionLocation {
#[derive(Debug)]
pub struct ReturnTypeWrapper<'tu> {
type_ref: TypeRef<'tu>,
- gen_env: &'tu GeneratorEnv<'tu>,
+ const_hint: Option<bool>,
definition_location: DefinitionLocation,
+ gen_env: &'tu GeneratorEnv<'tu>,
}
impl<'tu> ReturnTypeWrapper<'tu> {
- pub fn new(type_ref: TypeRef<'tu>, gen_env: &'tu GeneratorEnv<'tu>, definition_location: DefinitionLocation) -> Self {
- Self { type_ref, gen_env, definition_location }
+ pub fn new(type_ref: TypeRef<'tu>, definition_location: DefinitionLocation, gen_env: &'tu GeneratorEnv<'tu>) -> Self {
+ Self::new_ext(type_ref, None, definition_location, gen_env)
+ }
+
+ pub fn new_ext(type_ref: TypeRef<'tu>, const_hint: Option<bool>, definition_location: DefinitionLocation, gen_env: &'tu GeneratorEnv<'tu>) -> Self {
+ Self { type_ref, const_hint, definition_location, gen_env }
}
pub fn type_ref(&self) -> &TypeRef<'tu> {
&self.type_ref
}
+ pub fn const_hint(&self) -> Option<bool> {
+ self.const_hint
+ }
+
pub fn definition_location(&self) -> Cow<str> {
match &self.definition_location {
DefinitionLocation::Module => {

MODIFY
binding-generator/src/settings.rs
binding-generator/src/settings.rs
@@ -15,22 +15,22 @@ pub static FUNC_RENAME: Lazy<HashMap<&str, &str>> = Lazy::new(|| hashmap! {
"cv_aruco_getPredefinedDictionary_int" => "+_i32",
// ### bioinspired ###
- "cv_bioinspired_Retina_create_Size_bool_int_bool_float_float" => "+_ext",
+ "cv_bioinspired_Retina_create_Size_const_bool_int_const_bool_const_float_const_float" => "+_ext",
"cv_bioinspired_Retina_getMagnoRAW_const__OutputArrayR" => "+_to",
"cv_bioinspired_Retina_getParvoRAW_const__OutputArrayR" => "+_to",
- "cv_bioinspired_Retina_setup_FileStorageR_bool" => "+_from_storage",
- "cv_bioinspired_Retina_setup_String_bool" => "+_from_file",
+ "cv_bioinspired_Retina_setup_FileStorageR_const_bool" => "+_from_storage",
+ "cv_bioinspired_Retina_setup_String_const_bool" => "+_from_file",
"cv_bioinspired_Retina_write_const_FileStorageR" => "+_to_storage",
- "cv_bioinspired_TransientAreasSegmentationModule_setup_FileStorageR_bool" => "+_from_storage",
- "cv_bioinspired_TransientAreasSegmentationModule_setup_String_bool" => "+_from_file",
+ "cv_bioinspired_TransientAreasSegmentationModule_setup_FileStorageR_const_bool" => "+_from_storage",
+ "cv_bioinspired_TransientAreasSegmentationModule_setup_String_const_bool" => "+_from_file",
"cv_bioinspired_TransientAreasSegmentationModule_write_const_FileStorageR" => "+_to_storage",
- "cv_bioinspired_createRetina_OCL_Size_bool_int_bool_float_float" => "+_ext", // 3.2 only
+ "cv_bioinspired_createRetina_OCL_Size_const_bool_int_const_bool_const_float_const_float" => "+_ext", // 3.2 only
// ### calib3d ###
"cv_LMSolver_create_const_Ptr_Callback_R_int_double" => "+_ext",
"cv_findEssentialMat_const__InputArrayR_const__InputArrayR_const__InputArrayR_int_double_double_const__OutputArrayR" => "+_matrix",
"cv_findFundamentalMat_const__InputArrayR_const__InputArrayR_const__OutputArrayR_int_double_double" => "+_mask",
- "cv_findHomography_const__InputArrayR_const__InputArrayR_int_double_const__OutputArrayR_int_double" => "+_ext",
+ "cv_findHomography_const__InputArrayR_const__InputArrayR_int_double_const__OutputArrayR_const_int_const_double" => "+_ext",
"cv_fisheye_initUndistortRectifyMap_const__InputArrayR_const__InputArrayR_const__InputArrayR_const__InputArrayR_const_SizeR_int_const__OutputArrayR_const__OutputArrayR" => "fisheye_+",
"cv_fisheye_projectPoints_const__InputArrayR_const__OutputArrayR_const_Affine3dR_const__InputArrayR_const__InputArrayR_double_const__OutputArrayR" => "fisheye_+",
"cv_fisheye_projectPoints_const__InputArrayR_const__OutputArrayR_const__InputArrayR_const__InputArrayR_const__InputArrayR_const__InputArrayR_double_const__OutputArrayR" => "fisheye_+_vec",
@@ -211,7 +211,7 @@ pub static FUNC_RENAME: Lazy<HashMap<&str, &str>> = Lazy::new(|| hashmap! {
"cv_cuda_GpuMat_GpuMat_int_int_int_voidX_size_t" => "+_rows_cols_with_data",
"cv_cuda_GpuMat_download_const_const__OutputArrayR_StreamR" => "+_async",
"cv_cuda_GpuMat_upload_const__InputArrayR_StreamR" => "+_async",
- "cv_directx_getTypeFromD3DFORMAT_int" => "get_type_from_d3d_format",
+ "cv_directx_getTypeFromD3DFORMAT_const_int" => "get_type_from_d3d_format",
"cv_divide_const__InputArrayR_const__InputArrayR_const__OutputArrayR_double_int" => "+2",
"cv_getNumberOfCPUs" => "get_number_of_cpus",
"cv_hconcat_const__InputArrayR_const__InputArrayR_const__OutputArrayR" => "+2",
@@ -349,12 +349,12 @@ pub static FUNC_RENAME: Lazy<HashMap<&str, &str>> = Lazy::new(|| hashmap! {
"cv_dnn_Layer_finalize_const_vector_Mat_R" => "+_mat",
"cv_dnn_Layer_finalize_const_vector_Mat_R_vector_Mat_R" => "+_mat_to",
"cv_dnn_Layer_forward_vector_MatX_R_vector_Mat_R_vector_Mat_R" => "+_mat",
- "cv_dnn_NMSBoxes_const_vector_Rect2d_R_const_vector_float_R_float_float_vector_int_R_float_int" => "+_f64",
+ "cv_dnn_NMSBoxes_const_vector_Rect2d_R_const_vector_float_R_const_float_const_float_vector_int_R_const_float_const_int" => "+_f64",
"cv_dnn_Net_connect_String_String" => "+_first_second",
"cv_dnn_Net_forward_const_StringR" => "+_single",
"cv_dnn_Net_forward_const__OutputArrayR_const_StringR" => "+_layer",
"cv_dnn_Net_getMemoryConsumption_const_const_vector_MatShape_R_vector_int_R_vector_size_t_R_vector_size_t_R" => "+_for_layers",
- "cv_dnn_Net_getMemoryConsumption_const_int_const_vector_MatShape_R_size_tR_size_tR" => "+_for_layer",
+ "cv_dnn_Net_getMemoryConsumption_const_const_int_const_vector_MatShape_R_size_tR_size_tR" => "+_for_layer",
"cv_dnn_blobFromImage_const__InputArrayR_const__OutputArrayR_double_const_SizeR_const_ScalarR_bool_bool_int" => "+_to",
"cv_dnn_blobFromImages_const__InputArrayR_const__OutputArrayR_double_Size_const_ScalarR_bool_bool_int" => "+_to",
"cv_dnn_readNetFromCaffe_const_charX_size_t_const_charX_size_t" => "+_str",
@@ -746,10 +746,10 @@ pub static FUNC_MANUAL: Lazy<HashMap<&str, CompiledInterpolation>> = Lazy::new(|
pub static FUNC_SPECIALIZE: Lazy<HashMap<&str, Vec<HashMap<&str, &str>>>> = Lazy::new(|| hashmap! {
"cv_dnn_Dict_set_const_StringR_const_TR" => vec![
- hashmap! { "T" => "cv::String" },
- hashmap! { "T" => "cv::dnn::DictValue" },
- hashmap! { "T" => "double" },
- hashmap! { "T" => "int64_t" },
+ hashmap! { "const T" => "cv::String" },
+ hashmap! { "const T" => "cv::dnn::DictValue" },
+ hashmap! { "const T" => "double" },
+ hashmap! { "const T" => "int64_t" },
],
"cv_dnn_DictValue_get_const_int" => vec![
hashmap! { "T" => "cv::String" },

MODIFY
binding-generator/src/smart_ptr.rs
binding-generator/src/smart_ptr.rs
@@ -7,12 +7,10 @@ use clang::Entity;
use crate::{
DefaultElement,
- DefinitionLocation,
DependentType,
Element,
EntityElement,
GeneratorEnv,
- ReturnTypeWrapper,
type_ref::TemplateArg,
TypeRef,
};
@@ -42,18 +40,15 @@ impl<'tu> SmartPtr<'tu> {
}
pub fn dependent_types<D: DependentType<'tu>>(&self) -> Vec<D> {
- let canon = self.type_ref().canonical_clang();
- let mut out = vec![
- D::from_return_type_wrapper(ReturnTypeWrapper::new(canon.clone(), self.gen_env, DefinitionLocation::Module))
- ];
if self.pointee().as_typedef().is_some() {
- out.extend(canon.dependent_types())
+ self.type_ref().canonical_clang().dependent_types()
+ } else {
+ vec![]
}
- out
}
pub fn rust_localalias(&self) -> Cow<str> {
- format!("PtrOf{typ}", typ=self.pointee().rust_safe_id()).into()
+ format!("PtrOf{typ}", typ=self.pointee().rust_safe_id_ext(false)).into()
}
pub fn rust_fullalias(&self) -> Cow<str> {

MODIFY
binding-generator/src/type_ref.rs
binding-generator/src/type_ref.rs
@@ -159,29 +159,6 @@ pub enum Kind<'tu> {
Ignored,
}
-impl Kind<'_> {
- pub fn is_constified(&self) -> bool {
- match self {
- Kind::Pointer(inner) | Kind::Reference(inner) | Kind::Array(inner, ..) => {
- match inner.kind() {
- // avoid specifying "const" twice for "const Type**"
- Kind::Pointer(..) | Kind::Reference(..) => {
- !inner.is_const()
- }
- _ => {
- true
- }
- }
- }
- Kind::Primitive(..) | Kind::StdVector(..) | Kind::SmartPtr(..)
- | Kind::Class(..) | Kind::Enum(..) | Kind::Function(..)
- | Kind::Typedef(..) | Kind::Generic(..) | Kind::Ignored => {
- false
- }
- }
- }
-}
-
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TypeRefTypeHint<'tu> {
None,
@@ -531,22 +508,22 @@ impl<'tu> TypeRef<'tu> {
}
pub fn is_const(&self) -> bool {
- self.type_ref.is_const_qualified() || match self.kind() {
+ self.is_clang_const() || match self.kind() {
Kind::Primitive(..) | Kind::Generic(..) | Kind::Enum(..)
| Kind::Class(..) | Kind::Function(..) | Kind::Ignored => {
false
}
Kind::Array(elem, ..) => {
- elem.is_const()
+ elem.is_clang_const()
}
Kind::StdVector(vec) => {
- vec.element_type().is_const()
+ vec.element_type().is_clang_const()
}
Kind::Pointer(inner) | Kind::Reference(inner) => {
- inner.is_const()
+ inner.is_clang_const()
}
Kind::SmartPtr(ptr) => {
- ptr.pointee().is_const()
+ ptr.pointee().is_clang_const()
}
Kind::Typedef(decl) => {
decl.underlying_type_ref().is_const()
@@ -554,6 +531,19 @@ impl<'tu> TypeRef<'tu> {
}
}
+ pub fn is_clang_const(&self) -> bool {
+ self.type_ref.is_const_qualified()
+ }
+
+ fn get_const_hint(&self, type_ref: &TypeRef) -> Option<bool> {
+ let is_const = self.is_const();
+ if is_const && !type_ref.is_clang_const() {
+ Some(is_const)
+ } else {
+ None
+ }
+ }
+
pub fn is_primitive(&self) -> bool {
match self.canonical().kind() {
Kind::Primitive(..) => {
@@ -586,7 +576,7 @@ impl<'tu> TypeRef<'tu> {
inner.is_std_string()
}
Kind::Pointer(inner) => {
- inner.is_std_string() && !inner.is_const()
+ inner.is_std_string() && !inner.is_recursive_const()
}
_ => {
false
@@ -603,7 +593,7 @@ impl<'tu> TypeRef<'tu> {
inner.is_cv_string()
}
Kind::Pointer(inner) => {
- inner.is_cv_string() && !inner.is_const()
+ inner.is_cv_string() && !inner.is_recursive_const()
}
_ => {
false
@@ -613,11 +603,9 @@ impl<'tu> TypeRef<'tu> {
pub fn is_char_ptr_string(&self) -> bool {
match self.canonical().kind() {
- Kind::Pointer(inner) => {
- inner.cpp_full() == "char"
- }
- Kind::Array(inner, ..) => {
- inner.cpp_full() == "char"
+ Kind::Pointer(inner) | Kind::Array(inner, ..) => {
+ let inner_cpp_full = inner.cpp_full();
+ inner_cpp_full == "char" || inner_cpp_full == "const char"
}
_ => {
false
@@ -885,7 +873,7 @@ impl<'tu> TypeRef<'tu> {
}
fn is_output(&self) -> bool {
- !self.is_const() && (self.as_reference().is_some() || self.as_pointer().map_or(false, |t| t.is_string()))
+ !self.is_recursive_const() && (self.as_reference().is_some() || self.as_pointer().map_or(false, |t| t.is_string()))
}
pub fn is_data_type(&self) -> bool {
@@ -904,6 +892,18 @@ impl<'tu> TypeRef<'tu> {
}
}
+ pub fn rust_clang_const_qual(&self, pointer: bool) -> &'static str {
+ if self.is_clang_const() {
+ if pointer {
+ "const "
+ } else {
+ ""
+ }
+ } else {
+ "mut "
+ }
+ }
+
pub fn cpp_const_qual(&self) -> &'static str {
if self.is_const() {
"const "
@@ -912,6 +912,14 @@ impl<'tu> TypeRef<'tu> {
}
}
+ pub fn cpp_clang_const_qual(&self) -> &'static str {
+ if self.is_clang_const() {
+ "const "
+ } else {
+ ""
+ }
+ }
+
pub fn template_specialization_args(&self) -> Vec<TemplateArg<'tu>> {
match self.type_ref.get_kind() {
TypeKind::Typedef => {
@@ -942,9 +950,13 @@ impl<'tu> TypeRef<'tu> {
}
pub fn rust_safe_id(&self) -> Cow<str> {
+ self.rust_safe_id_ext(true)
+ }
+
+ pub fn rust_safe_id_ext(&self, add_const: bool) -> Cow<str> {
let mut out = String::with_capacity(64);
let kind = self.kind();
- if kind.is_constified() && self.is_const() {
+ if add_const && self.is_clang_const() {
out.push_str("const_");
}
out.push_str(&match kind {
@@ -1152,7 +1164,7 @@ impl<'tu> TypeRef<'tu> {
}
}
Kind::Reference(inner) => {
- if !((inner.as_simple_class().is_some() || inner.is_enum()) && inner.is_const()) {
+ if !((inner.as_simple_class().is_some() || inner.is_enum()) && inner.is_clang_const()) {
1 + inner.rust_lifetime_count()
} else {
0
@@ -1321,7 +1333,7 @@ impl<'tu> TypeRef<'tu> {
if is_function_infallible {
flags.push("nofail")
}
- if !self.is_const() {
+ if !self.is_recursive_const() {
flags.push("mut")
}
let mut flags = flags.join(" ");
@@ -1382,7 +1394,7 @@ impl<'tu> TypeRef<'tu> {
if self.is_string() {
return if self.is_output() {
format!("&mut {name}_via", name=name)
- } else if self.is_const() || is_const {
+ } else if self.is_recursive_const() || is_const {
format!("{name}.opencv_as_extern()", name=name)
} else {
format!("{name}.opencv_as_extern_mut()", name=name)
@@ -1397,9 +1409,9 @@ impl<'tu> TypeRef<'tu> {
if self.is_by_ptr() {
let typ = self.source();
return if self.is_const() || is_const {
- format!("{name}.as_raw_{rust_safe_id}()", name=name, rust_safe_id=typ.rust_safe_id())
+ format!("{name}.as_raw_{rust_safe_id}()", name=name, rust_safe_id=typ.rust_safe_id_ext(false))
} else {
- format!("{name}.as_raw_mut_{rust_safe_id}()", name=name, rust_safe_id=typ.rust_safe_id())
+ format!("{name}.as_raw_mut_{rust_safe_id}()", name=name, rust_safe_id=typ.rust_safe_id_ext(false))
};
}
if self.as_variable_array().is_some() || self.as_abstract_class_ptr().is_some() {
@@ -1419,8 +1431,8 @@ impl<'tu> TypeRef<'tu> {
return format!(
"{name} as *{cnst} _ as *{cnst} *{const_inner} _",
name=name,
- cnst=self.rust_const_qual(true),
- const_inner=inner.rust_const_qual(true)
+ cnst=self.rust_clang_const_qual(true),
+ const_inner=inner.rust_clang_const_qual(true)
);
}
}
@@ -1481,20 +1493,63 @@ impl<'tu> TypeRef<'tu> {
match self.source().kind() {
Kind::StdVector(vec) => {
out = vec.dependent_types();
+ out.reserve(2);
+ if let Some(Dir::In(str_type)) = vec.element_type().as_string() {
+ // We need to generate return wrappers for std::vector<cv::String>, but it has several issues:
+ // * we can't use get_canonical_type() because it resolves into compiler dependent inner type like
+ // std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>
+ // * we can't generate both vector<cv::String> and vector<std::string> because for OpenCV 4
+ // cv::String is an typedef to std::string and it would lead to duplicate definition error
+ // That's why we try to resolve both types and check if they are the same, if they are we only generate
+ // vector<std::string> if not - both.
+ let vec_cv_string = self.gen_env.resolve_type("std::vector<cv::String>").expect("Can't resolve std::vector<cv::String>");
+ let vec_std_string = self.gen_env.resolve_type("std::vector<std::string>").expect("Can't resolve std::vector<std::string>");
+ let vec_type_ref = if vec_cv_string.get_canonical_type() == vec_std_string.get_canonical_type() {
+ TypeRef::new(vec_std_string, self.gen_env)
+ } else {
+ vec.type_ref()
+ };
+ let const_hint = self.get_const_hint(&vec_type_ref);
+ out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new_ext(
+ vec_type_ref,
+ const_hint,
+ DefinitionLocation::Module,
+ self.gen_env,
+ )));
// implement workaround for race when type with std::string gets generated first
// we only want vector<cv::String> because it's more compatible across OpenCV versions
- if vec.element_type().is_std_string() {
+ if str_type == StrType::StdString {
let tref = TypeRef::new(
- self.gen_env.resolve_type("std::vector<cv::String>").expect("Can't resolve std::vector<cv::String>"),
+ vec_cv_string,
self.gen_env,
);
out.push(D::from_vector(tref.as_vector().expect("Not possible unless something is terribly broken")));
} else {
out.push(D::from_vector(vec))
}
+ } else {
+ let vec_type_ref = vec.type_ref().canonical_clang();
+ let const_hint = self.get_const_hint(&vec_type_ref);
+ out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new_ext(
+ vec_type_ref,
+ const_hint,
+ DefinitionLocation::Module,
+ self.gen_env,
+ )));
+ out.push(D::from_vector(vec));
+ }
},
Kind::SmartPtr(ptr) => {
out = ptr.dependent_types();
+ out.reserve(2);
+ let ptr_type_ref = ptr.type_ref().canonical_clang();
+ let const_hint = self.get_const_hint(&ptr_type_ref);
+ out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new_ext(
+ ptr_type_ref,
+ const_hint,
+ DefinitionLocation::Module,
+ self.gen_env,
+ )));
out.push(D::from_smart_ptr(ptr))
},
Kind::Typedef(typedef) => {
@@ -1512,9 +1567,16 @@ impl<'tu> TypeRef<'tu> {
DefinitionLocation::Type => DefinitionLocation::Custom(self.rust_module().into_owned()),
dl => dl
};
- out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new(type_ref, self.gen_env, def_location)));
+ out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new(type_ref, def_location, self.gen_env)));
} else {
- out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new(self.canonical_clang(), self.gen_env, def_location)));
+ let type_ref = self.canonical_clang();
+ let const_hint = self.get_const_hint(&type_ref);
+ out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new_ext(
+ type_ref,
+ const_hint,
+ def_location,
+ self.gen_env,
+ )));
if self.as_abstract_class_ptr().is_some() {
out.push(D::from_abstract_ref_wrapper(AbstractRefWrapper::new(self.clone(), self.gen_env)))
}
@@ -1533,11 +1595,6 @@ impl<'tu> TypeRef<'tu> {
}
fn cpp_type_ref(&self, form: CppForm) -> Cow<str> {
- let mut out = String::with_capacity(64);
- let kind = self.kind();
- if kind.is_constified() {
- out.push_str(self.cpp_const_qual());
- }
let name = match form {
CppForm::Reference(name, _) => name,
_ => "",
@@ -1546,10 +1603,20 @@ impl<'tu> TypeRef<'tu> {
CppForm::Declaration(extern_types) => extern_types,
CppForm::Reference(_, extern_types) => extern_types,
};
- let space_name = if name.is_empty() { "".to_string() } else { format!(" {}", name) };
- out.push_str(&match self.kind() {
+ let cnst = self.cpp_clang_const_qual();
+ let (space_name, space_const_name) = if name.is_empty() {
+ ("".to_string(), "".to_string())
+ } else {
+ (format!(" {}", name), format!(" {}{}", cnst, name))
+ };
+ match self.kind() {
Kind::Primitive(_, cpp) => {
- cpp.to_string() + &space_name
+ format!(
+ "{cnst}{typ}{name}",
+ cnst=cnst,
+ typ=cpp.to_string(),
+ name=space_name,
+ )
}
Kind::Array(inner, size) => {
if let Some(size) = size {
@@ -1569,21 +1636,31 @@ impl<'tu> TypeRef<'tu> {
}
Kind::StdVector(vec) => {
format!(
- "{vec_type}<{elem_type}>{name}",
+ "{cnst}{vec_type}<{elem_type}>{name}",
+ cnst=cnst,
vec_type=vec.cpp_name(form.is_full()),
elem_type=vec.element_type().cpp_type_ref(form.recurse()),
name=space_name,
)
}
Kind::Reference(inner) if !extern_types => {
- format!("{typ}&{name}", typ=inner.cpp_type_ref(form.recurse()), name=space_name)
+ format!(
+ "{typ}&{name}",
+ typ=inner.cpp_type_ref(form.recurse()),
+ name=space_const_name,
+ )
}
Kind::Pointer(inner) | Kind::Reference(inner) => {
- format!("{typ}*{name}", typ=inner.cpp_type_ref(form.recurse()), name=space_name)
+ format!(
+ "{typ}*{name}",
+ typ=inner.cpp_type_ref(form.recurse()),
+ name=space_const_name,
+ )
}
Kind::SmartPtr(ptr) => {
format!(
- "{ptr_type}<{inner_type}>{name}",
+ "{cnst}{ptr_type}<{inner_type}>{name}",
+ cnst=cnst,
ptr_type=ptr.cpp_name(form.is_full()),
inner_type=ptr.pointee().cpp_type_ref(form.recurse()),
name=space_name,
@@ -1594,30 +1671,56 @@ impl<'tu> TypeRef<'tu> {
if !self.is_std_string() { // fixme prevents emission of std::string<char>
out += &self.cpp_tpl_decl(form);
}
- out + &space_name
+ format!(
+ "{cnst}{typ}{name}",
+ cnst=cnst,
+ typ=out,
+ name=space_name,
+ )
}
Kind::Enum(enm) => {
- enm.cpp_name(form.is_full()).into_owned() + &space_name
+ format!(
+ "{cnst}{typ}{name}",
+ cnst=cnst,
+ typ=enm.cpp_name(form.is_full()),
+ name=space_name,
+ )
}
Kind::Typedef(tdef) => {
let underlying_type = tdef.underlying_type_ref();
- if underlying_type.as_reference().is_some() { // references can't be used in lvalue position
- underlying_type.cpp_type_ref(form.recurse()).into_owned() + &space_name
+ let typ = if underlying_type.as_reference().is_some() { // references can't be used in lvalue position
+ underlying_type.cpp_type_ref(form.recurse())
} else {
- tdef.cpp_name(form.is_full()).into_owned() + &space_name
- }
+ tdef.cpp_name(form.is_full())
+ };
+ format!(
+ "{cnst}{typ}{name}",
+ cnst=cnst,
+ typ=typ,
+ name=space_name,
+ )
}
Kind::Generic(generic_name) => {
- generic_name + &space_name
+ format!(
+ "{cnst}{typ}{name}",
+ cnst=cnst,
+ typ=generic_name,
+ name=space_name,
+ )
}
Kind::Function(func) => {
- func.cpp_name(form.is_full()).into_owned() + &space_name
+ let mut typ = func.cpp_name(form.is_full());
+ if typ.contains("(*)") {
+ typ.to_mut().replacen_in_place("(*)", 1, &format!("(*{name})", name=name));
+ typ.into_owned()
+ } else {
+ format!("{typ}{name}", typ=typ, name=space_name)
+ }
}
Kind::Ignored => {
- "<ignored>".to_string() + &space_name
+ format!("<ignored>{name}", name=space_name)
}
- });
- out.into()
+ }.into()
}
pub fn cpp_local(&self) -> Cow<str> {
@@ -1678,13 +1781,13 @@ impl<'tu> TypeRef<'tu> {
if self.as_pointer().is_some() || self.as_reference().is_some() {
format!("{typ}{name}", typ=self.cpp_full(), name=space_name).into()
} else {
- format!("{cnst}{typ}*{name}", cnst=self.cpp_const_qual(), typ=self.cpp_full(), name=space_name).into()
+ format!("{typ}*{name}", typ=self.cpp_full(), name=space_name).into()
}
} else if self.is_string() {
if self.is_output() {
- format!("{cnst}void*{name}", cnst=self.cpp_const_qual(), name=space_name).into()
+ format!("{cnst}void*{name}", cnst=self.cpp_recursive_const_qual(), name=space_name).into()
} else {
- format!("{cnst}char*{name}", cnst=self.cpp_const_qual(), name=space_name).into()
+ format!("{cnst}char*{name}", cnst=self.cpp_recursive_const_qual(), name=space_name).into()
}
} else {
self.cpp_full_with_name(name)
@@ -1705,19 +1808,9 @@ impl<'tu> TypeRef<'tu> {
}
pub fn cpp_arg_func_decl(&self, name: &str) -> String {
- if self.is_output() && self.is_string() {
+ if self.is_output() && self.is_string() || self.as_simple_class().is_some() {
return format!("{typ}* {name}", typ=self.cpp_extern(), name=name);
}
- if self.as_function().is_some() {
- let mut typ: String = self.cpp_extern().into_owned();
- if typ.contains("(*)") {
- typ.replace_in_place("(*)", &format!("(*{name})", name=name));
- return typ;
- }
- }
- if self.as_simple_class().is_some() {
- return format!("const {typ}* {name}", typ=self.cpp_extern(), name=name)
- }
self.cpp_extern_with_name(name).into_owned()
}
@@ -1805,6 +1898,9 @@ impl fmt::Debug for TypeRef<'_> {
if self.is_const() {
props.push("const");
}
+ if self.is_clang_const() {
+ props.push("clang_const");
+ }
if self.is_primitive() {
props.push("primitive");
}
@@ -1839,7 +1935,7 @@ impl fmt::Debug for TypeRef<'_> {
props.push("by_ptr");
}
if self.is_output() {
- props.push("output_ref");
+ props.push("output_string");
}
if self.is_generic() {
props.push("generic");

MODIFY
binding-generator/src/vector.rs
binding-generator/src/vector.rs
@@ -53,50 +53,31 @@ impl<'tu> Vector<'tu> {
let element_type = self.element_type();
let is_data_type = self.is_data_type(&element_type);
let mut out = element_type.dependent_types_with_mode(DependentTypeMode::ForReturn(DefinitionLocation::Type));
- out.reserve(2 + if is_data_type { 3 } else { 0 });
+ out.reserve(1 + if is_data_type { 3 } else { 0 });
if element_type.is_string() {
out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new(
TypeRef::new(self.gen_env.resolve_type(&element_type.cpp_extern_return()).expect("Can't resolve string cpp_extern_return()"), self.gen_env),
- self.gen_env,
DefinitionLocation::Custom(element_type.rust_module().into_owned()),
- )));
- // We need to generate return wrappers for std::vector<cv::String>, but it has several issues:
- // * we can't use get_canonical_type() because it resolves into compiler dependent inner type like
- // std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>
- // * we can't generate both vector<cv::String> and vector<std::string> because for OpenCV 4
- // cv::String is an typedef to std::string and it would lead to duplicate definition error
- // That's why we try to resolve both types and check if they are the same, if they are we only generate
- // vector<std::string> if not - both.
- let vec_cv_string = self.gen_env.resolve_type("std::vector<cv::String>").expect("Can't resolve std::vector<cv::String>");
- let vec_std_string = self.gen_env.resolve_type("std::vector<std::string>").expect("Can't resolve std::vector<std::string>");
- if vec_cv_string.get_canonical_type() == vec_std_string.get_canonical_type() {
- out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new(
- TypeRef::new(vec_std_string, self.gen_env),
self.gen_env,
- DefinitionLocation::Module,
)));
} else {
- out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new(self.type_ref(), self.gen_env, DefinitionLocation::Module)));
- }
- } else {
- out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new(element_type.canonical_clang(), self.gen_env, DefinitionLocation::Type)));
- out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new(self.type_ref().canonical_clang(), self.gen_env, DefinitionLocation::Module)));
+ out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new(element_type.canonical_clang(), DefinitionLocation::Type, self.gen_env)));
}
if is_data_type {
out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new(
TypeRef::new(self.gen_env.resolve_type("cv::_InputArray").expect("Can't resolve _InputArray"), self.gen_env),
- self.gen_env,
DefinitionLocation::Custom(element_type.rust_module().into_owned()),
+ self.gen_env,
)));
out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new(
TypeRef::new(self.gen_env.resolve_type("cv::_OutputArray").expect("Can't resolve _OutputArray"), self.gen_env),
- self.gen_env,
DefinitionLocation::Custom(element_type.rust_module().into_owned()),
+ self.gen_env,
)));
out.push(D::from_return_type_wrapper(ReturnTypeWrapper::new(
TypeRef::new(self.gen_env.resolve_type("cv::_InputOutputArray").expect("Can't resolve _InputOutputArray"), self.gen_env),
- self.gen_env,
DefinitionLocation::Custom(element_type.rust_module().into_owned()),
+ self.gen_env,
)));
}
out

MODIFY
binding-generator/src/writer/rust_native/func.rs
binding-generator/src/writer/rust_native/func.rs
@@ -270,7 +270,7 @@ fn cpp_method_return<'f>(f: &'f Func) -> Cow<'f, str> {
} else if return_type.is_char_ptr_string() {
"return Ok(ocvrs_create_string(ret));".into()
} else {
- "return Ok(ret);".into()
+ format!("return Ok<{typ}>(ret);", typ=return_type.cpp_extern_return()).into()
}
}

MODIFY
binding-generator/src/writer/rust_native/return_type_wrapper.rs
binding-generator/src/writer/rust_native/return_type_wrapper.rs
+use std::borrow::Cow;
+
use maplit::hashmap;
use once_cell::sync::Lazy;
@@ -6,17 +8,26 @@ use crate::{
ReturnTypeWrapper,
StrExt,
StringExt,
+ TypeRef,
};
use super::RustNativeGeneratedElement;
+fn cpp_extern_return<'t>(type_ref: &'t TypeRef, const_hint: Option<bool>) -> Cow<'t, str> {
+ let mut out = type_ref.cpp_extern_return();
+ if const_hint.unwrap_or(false) && !type_ref.is_const() {
+ out.to_mut().insert_str(0, "const ");
+ }
+ out
+}
+
impl RustNativeGeneratedElement for ReturnTypeWrapper<'_> {
fn element_order(&self) -> u8 {
10
}
fn element_safe_id(&self) -> String {
- let mut name = self.type_ref().cpp_extern_return().into_owned();
+ let mut name = cpp_extern_return(self.type_ref(), self.const_hint()).into_owned();
name.cleanup_name();
format!("{}-{}", self.definition_location(), name)
}
@@ -29,7 +40,7 @@ impl RustNativeGeneratedElement for ReturnTypeWrapper<'_> {
);
CPP_TPL.interpolate(&hashmap! {
- "cpp_full" => self.type_ref().cpp_extern_return(),
+ "cpp_full" => cpp_extern_return(self.type_ref(), self.const_hint()),
})
}
}

MODIFY
src_cpp/common.hpp
src_cpp/common.hpp
#define OCVRS_TYPE(...) __VA_ARGS__
#define CODE_CATCH(return_type, exc_type, code, msg) \
-catch (exc_type& e) { \
- return_type ret; \
- memset(&ret, 0x00, sizeof(ret)); \
- ret.error_code = code; \
- ret.error_msg = ocvrs_create_string(e.what()); \
- return ret; \
+catch (exc_type) { \
+ return Err<return_type>(code, msg); \
}
#define OCVRS_CATCH(return_type) \
-catch (cv::Exception& e) { \
- return_type ret; \
- memset(&ret, 0x00, sizeof(ret)); \
- ret.error_code = e.code; \
- ret.error_msg = ocvrs_create_string(e.what()); \
- return ret; \
-} catch (...) { \
- return_type ret; \
- memset(&ret, 0x00, sizeof(ret)); \
- ret.error_code = -99999; \
- ret.error_msg = ocvrs_create_string("unspecified error in OpenCV guts"); \
- return ret; \
-}
+CODE_CATCH(OCVRS_TYPE(return_type), cv::Exception& e, e.code, e.what()) \
+CODE_CATCH(OCVRS_TYPE(return_type), ..., -99999, "unspecified error in OpenCV guts")
+
+#define VEC_CATCH(return_type) \
+CODE_CATCH(OCVRS_TYPE(return_type), std::out_of_range, cv::Error::Code::StsOutOfRange, "index out of bounds")
-#define VEC_CATCH(return_type) CODE_CATCH(return_type, std::out_of_range, cv::Error::Code::StsOutOfRange, "index out of bounds")
+// defined in src/templ.rs
+extern "C" void* ocvrs_create_string(const char*);
template<typename T> struct Result {
int error_code;
@@ -55,5 +44,11 @@ inline Result_void Ok() {
return Result_void { .error_code = 0, .error_msg = 0 };
}
-// defined in src/templ.rs
-extern "C" void* ocvrs_create_string(const char*);
+template<typename T> inline T Err(int code, const char* msg) {
+ unsigned char ret_buf[sizeof(T)] = {};
+ T ret = *reinterpret_cast<T*>(&ret_buf);
+ ret.error_code = code;
+ ret.error_msg = ocvrs_create_string(msg);
+ return ret;
+}
+

Sort out const attribute generation