Make sure to use pointers instead of references where it's appropriate
MODIFY
binding-generator/src/bin/settings-cleanup.rs
binding-generator/src/bin/settings-cleanup.rs
use std::{
+ cell::RefCell,
collections::HashSet,
env,
+ fmt,
+ mem,
path::{Path, PathBuf},
};
@@ -13,6 +16,7 @@ use opencv_binding_generator::{
EntityWalker,
EntityWalkerVisitor,
Func,
+ FuncId,
Generator,
GeneratorEnv,
opencv_module_from_path,
@@ -21,25 +25,29 @@ use opencv_binding_generator::{
struct FunctionFinder<'tu, 'f> {
pub gen_env: GeneratorEnv<'tu>,
- pub func_rename_unused: &'f mut HashSet<&'static str>,
- pub func_cfg_attr_unused: &'f mut HashSet<&'static str>,
- pub func_unsafe_unused: &'f mut HashSet<&'static str>,
- pub func_manual_unused: &'f mut HashSet<&'static str>,
- pub func_specialize_unused: &'f mut HashSet<&'static str>,
- pub argument_override_unused: &'f mut HashSet<String>, // fixme, doesn't seem to work perfectly (shows cv::mixChannels, but it's def used)
+ pub func_rename_unused: RefCell<&'f mut HashSet<&'static str>>,
+ pub func_cfg_attr_unused: RefCell<&'f mut HashSet<&'static str>>,
+ pub func_unsafe_unused: RefCell<&'f mut HashSet<FuncId<'static>>>,
+ pub func_manual_unused: RefCell<&'f mut HashSet<&'static str>>,
+ pub func_specialize_unused: RefCell<&'f mut HashSet<&'static str>>,
+ pub argument_override_unused: RefCell<&'f mut HashSet<String>>, // fixme, doesn't seem to work perfectly (shows cv::mixChannels, but it's def used)
}
impl<'tu, 'f> FunctionFinder<'tu, 'f> {
- pub fn update_used_func_identifier(&mut self, identifier: &str) {
- self.func_rename_unused.remove(identifier);
- self.func_cfg_attr_unused.remove(identifier);
- self.func_unsafe_unused.remove(identifier);
- self.func_manual_unused.remove(identifier);
- self.func_specialize_unused.remove(identifier);
- }
+ pub fn update_used_func(&self, f: &Func) {
+ let identifier = f.identifier();
+ let func_id = f.func_id();
+ let cpp_fullname = f.cpp_fullname();
- pub fn update_used_func_cpp_fullname(&mut self, cpp_fullname: &str) {
- self.argument_override_unused.remove(cpp_fullname);
+ self.func_rename_unused.borrow_mut().remove(identifier.as_ref());
+ self.func_cfg_attr_unused.borrow_mut().remove(identifier.as_ref());
+ {
+ let static_func_id: FuncId<'static> = unsafe { mem::transmute(func_id) };
+ self.func_unsafe_unused.borrow_mut().remove(&static_func_id);
+ }
+ self.func_manual_unused.borrow_mut().remove(identifier.as_ref());
+ self.func_specialize_unused.borrow_mut().remove(identifier.as_ref());
+ self.argument_override_unused.borrow_mut().remove(cpp_fullname.as_ref());
}
}
@@ -69,12 +77,8 @@ impl<'tu> EntityWalkerVisitor<'tu> for FunctionFinder<'tu, '_> {
}
true
});
- let methods = methods.into_iter()
- .map(|m| (m.identifier().into_owned(), m.cpp_fullname().into_owned()))
- .collect::<Vec<_>>();
- for (identifier, cpp_fullname) in methods {
- self.update_used_func_identifier(&identifier);
- self.update_used_func_cpp_fullname(&cpp_fullname);
+ for f in methods {
+ self.update_used_func(&f);
}
entity.walk_classes_while(|child| {
self.visit_entity(child)
@@ -84,8 +88,7 @@ impl<'tu> EntityWalkerVisitor<'tu> for FunctionFinder<'tu, '_> {
}
EntityKind::FunctionDecl => {
let f = Func::new(entity, &self.gen_env);
- let identifier = f.identifier().into_owned();
- self.update_used_func_identifier(&identifier);
+ self.update_used_func(&f);
true
}
_ => true
@@ -93,10 +96,10 @@ impl<'tu> EntityWalkerVisitor<'tu> for FunctionFinder<'tu, '_> {
}
}
-fn show<S: AsRef<str>>(c: impl IntoIterator<Item=S>) {
+fn show<S: fmt::Display>(c: impl IntoIterator<Item=S>) {
let v = c.into_iter().collect::<Vec<_>>();
let mut sorted = v.iter()
- .map(|s| s.as_ref())
+ .map(|s| s.to_string())
.collect::<Vec<_>>();
sorted.sort_unstable();
for f in sorted {
@@ -140,12 +143,12 @@ fn main() {
let walker = EntityWalker::new(root_entity);
walker.walk_opencv_entities(FunctionFinder {
gen_env,
- func_rename_unused: &mut func_rename_unused,
- func_cfg_attr_unused: &mut func_cfg_attr_unused,
- func_unsafe_unused: &mut func_unsafe_unused,
- func_manual_unused: &mut func_manual_unused,
- func_specialize_unused: &mut func_specialize_unused,
- argument_override_unused: &mut argument_override_unused,
+ func_rename_unused: RefCell::new(&mut func_rename_unused),
+ func_cfg_attr_unused: RefCell::new(&mut func_cfg_attr_unused),
+ func_unsafe_unused: RefCell::new(&mut func_unsafe_unused),
+ func_manual_unused: RefCell::new(&mut func_manual_unused),
+ func_specialize_unused: RefCell::new(&mut func_specialize_unused),
+ argument_override_unused: RefCell::new(&mut argument_override_unused),
});
});
}

MODIFY
binding-generator/src/field.rs
binding-generator/src/field.rs
@@ -75,6 +75,7 @@ impl<'tu, 'ge> Field<'tu, 'ge> {
FieldTypeHint::ArgOverride(ArgumentOverride::Slice) => TypeRefTypeHint::Slice,
FieldTypeHint::ArgOverride(ArgumentOverride::NullableSlice) => TypeRefTypeHint::NullableSlice,
FieldTypeHint::Specialized(typ) => TypeRefTypeHint::Specialized(typ),
+ FieldTypeHint::FieldSetter => TypeRefTypeHint::PrimitiveRefAsPointer,
_ => TypeRefTypeHint::None,
};
TypeRef::new_ext(self.entity.get_type().expect("Can't get type"), type_hint, Some(self.entity), self.gen_env)
@@ -127,7 +128,7 @@ impl<'tu, 'ge> Field<'tu, 'ge> {
let type_ref = self.type_ref();
let leafname = self.cpp_localname();
(leafname == "userdata" || leafname == "userData" || leafname == "cookie" || leafname == "unnamed")
- && type_ref.as_pointer().map_or(false, |inner| inner.is_void())
+ && type_ref.is_void_ptr()
}
pub fn as_slice_len(&self) -> Option<(&'static str, usize)> {

MODIFY
binding-generator/src/func.rs
binding-generator/src/func.rs
@@ -146,6 +146,12 @@ impl<'f> FuncId<'f> {
}
}
+impl fmt::Display for FuncId<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}({})", self.name, self.args.join(", "))
+ }
+}
+
#[derive(Clone)]
pub struct Func<'tu, 'ge> {
entity: Entity<'tu>,
@@ -340,6 +346,11 @@ impl<'tu, 'ge> Func<'tu, 'ge> {
|| settings::FORCE_INFALLIBLE.contains(&self.func_id())
}
+ pub fn is_unsafe(&self) -> bool {
+ settings::FUNC_UNSAFE.contains(&self.func_id())
+ || self.arguments().into_iter().any(|a| a.type_ref().is_pass_by_ptr() && !a.is_user_data())
+ }
+
pub fn is_default_constructor(&self) -> bool {
self.entity.is_default_constructor() && !self.has_arguments()
}
@@ -372,7 +383,7 @@ impl<'tu, 'ge> Func<'tu, 'ge> {
Kind::Function | Kind::InstanceMethod(..) | Kind::StaticMethod(..)
| Kind::ConversionMethod(..) | Kind::GenericInstanceMethod(..) | Kind::GenericFunction
| Kind::FunctionOperator(..) | Kind::InstanceOperator(..) => {
- let mut out = TypeRef::new(self.entity.get_result_type().expect("Can't get return type"), self.gen_env);
+ let mut out = TypeRef::new_ext(self.entity.get_result_type().expect("Can't get return type"), TypeRefTypeHint::PrimitiveRefAsPointer, None, self.gen_env);
if let Some(spec) = self.as_specialized() {
if out.is_generic() {
let spec_type = spec.get(out.base().cpp_full().as_ref())
@@ -392,7 +403,9 @@ impl<'tu, 'ge> Func<'tu, 'ge> {
if self.type_hint == FunctionTypeHint::FieldSetter {
TypeRef::new(self.gen_env.resolve_type("void").expect("Can't resolve void type"), self.gen_env)
} else {
- Field::new(self.entity, self.gen_env).type_ref()
+ let mut out = Field::new(self.entity, self.gen_env).type_ref();
+ out.set_type_hint(TypeRefTypeHint::PrimitiveRefAsPointer);
+ out
}
}
}
@@ -510,7 +523,11 @@ impl<'tu, 'ge> Func<'tu, 'ge> {
}
pub fn func_id(&self) -> FuncId {
- FuncId::from_entity(self.entity)
+ let mut out = FuncId::from_entity(self.entity);
+ if self.as_field_setter().is_some() {
+ out.args.push("val".into());
+ }
+ out
}
}

MODIFY
binding-generator/src/lib.rs
binding-generator/src/lib.rs
@@ -37,7 +37,7 @@ pub use element::{DefaultElement, Element, EntityElement, is_opencv_path, opencv
pub use entity::EntityExt;
pub use enumeration::Enum;
use field::{Field, FieldTypeHint};
-pub use func::{Func, FunctionTypeHint};
+pub use func::{Func, FuncId, FunctionTypeHint};
use function::Function;
#[allow(unused)]
use generator::{dbg_clang_entity, dbg_clang_type};

MODIFY
binding-generator/src/settings.rs
binding-generator/src/settings.rs
@@ -687,57 +687,36 @@ pub static ELEMENT_EXPORT_TWEAK: Lazy<HashMap<&str, fn (&mut ExportConfig)>> = L
});
/// set of functions that should have unsafe in their declaration, element is Func.identifier()
-pub static FUNC_UNSAFE: Lazy<HashSet<&str>> = Lazy::new(|| hashset! {
+pub static FUNC_UNSAFE: Lazy<HashSet<FuncId>> = Lazy::new(|| hashset! {
// allocates uninitialized memory
- "cv_Mat_Mat_Size_int",
- "cv_Mat_Mat_const_vector_int_R_int",
- "cv_Mat_Mat_int_const_intX_int",
- "cv_Mat_Mat_int_int_int",
- "cv_Mat_create_Size_int",
- "cv_Mat_create_const_vector_int_R_int",
- "cv_Mat_create_int_const_intX_int",
- "cv_Mat_create_int_int_int",
- "cv_UMat_UMat_Size_int_UMatUsageFlags",
- "cv_UMat_UMat_int_const_intX_int_UMatUsageFlags",
- "cv_UMat_UMat_int_int_int_UMatUsageFlags",
- "cv_UMat_create_Size_int_UMatUsageFlags",
- "cv_UMat_create_const_vector_int_R_int_UMatUsageFlags",
- "cv_UMat_create_int_const_intX_int_UMatUsageFlags",
- "cv_UMat_create_int_int_int_UMatUsageFlags",
- "cv__OutputArray_createSameSize_const_const__InputArrayR_int",
- "cv__OutputArray_create_const_Size_int_int_bool_int",
- "cv__OutputArray_create_const_int_const_intX_int_int_bool_int",
- "cv__OutputArray_create_const_int_int_int_int_bool_int",
- // allows passing arbitrary data
- "cv_Mat_Mat_Size_int_voidX_size_t",
- "cv_Mat_Mat_const_vector_int_R_int_voidX_const_size_tX",
- "cv_Mat_Mat_int_const_intX_int_voidX_const_size_tX",
- "cv_Mat_Mat_int_int_int_voidX_size_t",
- "cv_Mat_setPropData_unsigned_charX",
- "cv_UMatData_setPropData_unsigned_charX",
- "cv_cuda_GpuMat_GpuMat_int_int_int_voidX_size_t",
- "cv_cuda_GpuMat_GpuMat_Size_int_voidX_size_t",
- // no bounds checking
- "cv_Mat_ptr_const_const_intX",
- "cv_Mat_ptr_const_int",
- "cv_Mat_ptr_const_intX",
- "cv_Mat_ptr_const_int_int",
- "cv_Mat_ptr_const_int_int_int",
- "cv_Mat_ptr_int",
- "cv_Mat_ptr_int_int",
- "cv_Mat_ptr_int_int_int",
+ FuncId::new("cv::Mat::Mat", ["size", "type"]),
+ FuncId::new("cv::Mat::Mat", ["sizes", "type"]),
+ FuncId::new("cv::Mat::Mat", ["ndims", "sizes", "type"]),
+ FuncId::new("cv::Mat::Mat", ["rows", "cols", "type"]),
+ FuncId::new("cv::Mat::create", ["size", "type"]),
+ FuncId::new("cv::Mat::create", ["sizes", "type"]),
+ FuncId::new("cv::Mat::create", ["ndims", "sizes", "type"]),
+ FuncId::new("cv::Mat::create", ["rows", "cols", "type"]),
+ FuncId::new("cv::UMat::UMat", ["size", "type", "usageFlags"]),
+ FuncId::new("cv::UMat::UMat", ["ndims", "sizes", "type", "usageFlags"]),
+ FuncId::new("cv::UMat::UMat", ["rows", "cols", "type", "usageFlags"]),
+ FuncId::new("cv::UMat::create", ["size", "type", "usageFlags"]),
+ FuncId::new("cv::UMat::create", ["size", "type", "usageFlags"]),
+ FuncId::new("cv::UMat::create", ["ndims", "sizes", "type", "usageFlags"]),
+ FuncId::new("cv::UMat::create", ["sizes", "type", "usageFlags"]),
+ FuncId::new("cv::UMat::create", ["rows", "cols", "type", "usageFlags"]),
+ FuncId::new("cv::_OutputArray::createSameSize", ["arr", "mtype"]),
// pointer to internal data
- "cv_dnn_Dict_ptr_const_StringR",
- "cv_dnn_Dict_ptr_const_const_StringR",
+ FuncId::new("cv::dnn::Dict::ptr", ["key"]),
// takes reference and stores it for the lifetime of an object (fixme: add lifetime management)
- "cv_cuda_GpuMat_GpuMat_AllocatorX",
- "cv_cuda_GpuMat_GpuMat_Size_int_AllocatorX",
- "cv_cuda_GpuMat_GpuMat_Size_int_Scalar_AllocatorX",
- "cv_cuda_GpuMat_GpuMat_const__InputArrayR_AllocatorX",
- "cv_cuda_GpuMat_GpuMat_int_int_int_AllocatorX",
- "cv_cuda_GpuMat_GpuMat_int_int_int_Scalar_AllocatorX",
- "cv_cuda_GpuMat_setPropAllocator_AllocatorX",
- "cv_cuda_GpuMat_setDefaultAllocator_AllocatorX", // fixme, should take 'static
+ FuncId::new("cv::cuda::GpuMat::GpuMat", ["allocator"]),
+ FuncId::new("cv::cuda::GpuMat::GpuMat", ["size", "type", "allocator"]),
+ FuncId::new("cv::cuda::GpuMat::GpuMat", ["size", "type", "s", "allocator"]),
+ FuncId::new("cv::cuda::GpuMat::GpuMat", ["arr", "allocator"]),
+ FuncId::new("cv::cuda::GpuMat::GpuMat", ["rows", "cols", "type", "allocator"]),
+ FuncId::new("cv::cuda::GpuMat::GpuMat", ["rows", "cols", "type", "s", "allocator"]),
+ FuncId::new("cv::cuda::GpuMat::allocator", ["val"]),
+ FuncId::new("cv::cuda::GpuMat::setDefaultAllocator", ["allocator"]), // fixme, should take 'static
});
pub static IMPLEMENTED_FUNCTION_LIKE_MACROS: Lazy<HashSet<&str>> = Lazy::new(|| hashset! {

MODIFY
binding-generator/src/type_ref.rs
binding-generator/src/type_ref.rs
@@ -88,6 +88,7 @@ pub enum TypeRefTypeHint<'tu> {
Nullable,
Slice,
NullableSlice,
+ PrimitiveRefAsPointer,
Specialized(Type<'tu>),
}
@@ -632,6 +633,10 @@ impl<'tu, 'ge> TypeRef<'tu, 'ge> {
matches!(self.canonical().kind(), Kind::Primitive("bool", _))
}
+ pub fn is_void_ptr(&self) -> bool {
+ self.as_pointer().map_or(false, |inner| inner.is_void())
+ }
+
pub fn as_pointer(&self) -> Option<TypeRef<'tu, 'ge>> {
if let Kind::Pointer(out) = self.canonical().kind() {
Some(out)
@@ -795,6 +800,20 @@ impl<'tu, 'ge> TypeRef<'tu, 'ge> {
settings::DATA_TYPES.contains(self.cpp_full().as_ref())
}
+ pub fn can_pass_by_ptr(&self) -> bool {
+ if let Some(inner) = self.as_pointer() {
+ if inner.is_primitive() && !self.as_string().is_some() {
+ return true;
+ }
+ }
+ false
+ }
+
+ pub fn is_pass_by_ptr(&self) -> bool {
+ self.is_void_ptr() ||
+ matches!(self.type_hint, TypeRefTypeHint::PrimitiveRefAsPointer) && self.can_pass_by_ptr()
+ }
+
pub fn template_specialization_args(&self) -> Vec<TemplateArg<'tu, 'ge>> {
match self.type_ref.get_kind() {
TypeKind::Typedef => {
@@ -900,7 +919,7 @@ impl<'tu, 'ge> TypeRef<'tu, 'ge> {
}
pub fn rust_name(&self, name_style: NameStyle, lifetime: Lifetime) -> Cow<str> {
- self.render(RustRenderer::new(name_style, lifetime))
+ self.render(RustRenderer::new(name_style, lifetime, self.is_pass_by_ptr()))
}
pub fn rust_local(&self) -> Cow<str> {
@@ -1077,7 +1096,7 @@ impl<'tu, 'ge> TypeRef<'tu, 'ge> {
unsafety_call=unsafety_call,
typ=self.rust_return_func_decl(FishStyle::Turbo, is_static_func),
).into()
- } else if self.as_pointer().map_or(false, |i| !i.is_void()) || self.as_fixed_array().is_some() {
+ } else if self.as_pointer().map_or(false, |i| !i.is_void()) && !self.is_pass_by_ptr() || self.as_fixed_array().is_some() {
let ptr_call = if self.constness().is_const() { "ref" } else { "mut" };
let error_handling = if is_infallible {
".expect(\"Function returned null pointer\")"

MODIFY
binding-generator/src/type_ref/renderer.rs
binding-generator/src/type_ref/renderer.rs
@@ -320,11 +320,12 @@ fn render_rust_tpl_decl<'a>(renderer: impl TypeRefRenderer<'a>, type_ref: &TypeR
pub struct RustRenderer {
pub name_style: NameStyle,
pub lifetime: Lifetime,
+ pub primitive_ref_as_ptr: bool,
}
impl RustRenderer {
- pub fn new(name_style: NameStyle, lifetime: Lifetime) -> Self {
- Self { name_style, lifetime }
+ pub fn new(name_style: NameStyle, lifetime: Lifetime, primitive_ref_as_ptr: bool) -> Self {
+ Self { name_style, lifetime, primitive_ref_as_ptr }
}
fn wrap_nullable<'a>(&self, type_ref: &TypeRef, typ: Cow<'a, str>) -> Cow<'a, str> {
@@ -365,13 +366,19 @@ impl TypeRefRenderer<'_> for RustRenderer {
// because some functions can potentially save the pointer to the value, but it will be destroyed after function call
inner.render(self.recurse()).into_owned().into()
}
- Kind::Pointer(inner) | Kind::Reference(inner) => {
- if inner.is_void() {
+ Kind::Pointer(inner) if self.primitive_ref_as_ptr || inner.is_void() => {
+ let typ = if inner.is_void() {
+ "c_void".into()
+ } else {
+ inner.render(self.recurse())
+ };
format!(
- "*{cnst}c_void",
+ "*{cnst}{typ}",
cnst=type_ref.constness().rust_qual(true),
+ typ=typ
).into()
- } else {
+ }
+ Kind::Pointer(inner) | Kind::Reference(inner) => {
let typ = format!(
"&{lt: <}{cnst}{typ}",
cnst=type_ref.constness().rust_qual(false),
@@ -380,7 +387,6 @@ impl TypeRefRenderer<'_> for RustRenderer {
);
self.wrap_nullable(type_ref, typ.into())
}
- }
Kind::SmartPtr(ptr) => {
ptr.rust_name(self.name_style).into_owned().into()
}
@@ -425,6 +431,7 @@ impl TypeRefRenderer<'_> for RustRenderer {
Self {
name_style: self.name_style,
lifetime: self.lifetime.next().expect("Too many lifetimes"),
+ primitive_ref_as_ptr: self.primitive_ref_as_ptr,
}
}
}

MODIFY
binding-generator/src/writer/rust_native/func.rs
binding-generator/src/writer/rust_native/func.rs
@@ -91,7 +91,7 @@ fn gen_rust_with_name(f: &Func, name: &str, opencv_version: &str) -> String {
"pub "
};
let identifier = f.identifier();
- let is_safe = !settings::FUNC_UNSAFE.contains(identifier.as_ref());
+ let is_safe = !f.is_unsafe();
let is_static_func = matches!(f.kind(), Kind::StaticMethod(..) | Kind::Function);
let return_type = f.return_type();
let return_type_func_decl = if is_infallible {

MODIFY
src/manual/core/mat.rs
src/manual/core/mat.rs
@@ -21,13 +21,13 @@ use crate::{
mod mat_;
#[inline(always)]
-unsafe fn convert_ptr<T>(r: &u8) -> &T {
- &*(r as *const u8 as *const T)
+unsafe fn convert_ptr<'r, T>(r: *const u8) -> &'r T {
+ &*(r as *const T)
}
#[inline(always)]
-unsafe fn convert_ptr_mut<T>(r: &mut u8) -> &mut T {
- &mut *(r as *mut u8 as *mut T)
+unsafe fn convert_ptr_mut<'r, T>(r: *mut u8) -> &'r mut T {
+ &mut *(r as *mut T)
}
#[inline]
@@ -535,8 +535,7 @@ impl Deref for MatSize {
#[inline]
fn deref(&self) -> &Self::Target {
- let ptr = self.to_ri32() as *const i32;
- unsafe { slice::from_raw_parts(ptr, self.dims() as usize) }
+ unsafe { slice::from_raw_parts(self.to_xconst_i32(), self.dims() as usize) }
}
}

Make sure to use pointers instead of references where it's appropriate