Improve class simplicity detection
MODIFY
binding-generator/src/class.rs
binding-generator/src/class.rs
@@ -43,25 +43,31 @@ impl<'tu, 'ge> Class<'tu, 'ge> {
}
}
+ pub fn can_be_simple(&self) -> bool {
+ let cpp_refname = self.cpp_name(CppNameStyle::Reference);
+ if settings::IMPLEMENTED_GENERICS.contains(cpp_refname.as_ref())
+ || settings::IMPLEMENTED_CONST_GENERICS.contains(cpp_refname.as_ref())
+ {
+ return true;
+ }
+ self.has_fields()
+ && !self.has_descendants()
+ && !self.has_bases()
+ && !self
+ .for_each_field(|field| WalkAction::continue_until(!field.type_ref().is_copy()))
+ .is_interrupted()
+ }
+
pub fn kind(&self) -> Kind {
if settings::ELEMENT_EXCLUDE.contains(self.cpp_name(CppNameStyle::Reference).as_ref()) {
return Kind::Excluded;
}
match self.gen_env.get_export_config(self.entity).map(|c| c.simple) {
Some(true) => {
- let cant_be_simple = self
- .for_each_field(|field| {
- let type_ref = field.type_ref();
- let is_non_copy_field = type_ref.as_string().is_some()
- || type_ref.as_vector().is_some()
- || type_ref.as_class().map_or(false, |c| !c.is_simple());
- WalkAction::continue_until(is_non_copy_field || self.has_descendants())
- })
- .is_interrupted();
- if cant_be_simple {
- Kind::Boxed
- } else {
+ if self.can_be_simple() {
Kind::Simple
+ } else {
+ Kind::Boxed
}
}
Some(false) => Kind::Boxed,
@@ -69,7 +75,10 @@ impl<'tu, 'ge> Class<'tu, 'ge> {
if self.is_system() {
Kind::System
} else if let Some(kind) = self.gen_env.get_class_kind(self.entity) {
- kind
+ match kind {
+ Kind::Simple if !self.can_be_simple() => Kind::Boxed,
+ _ => kind,
+ }
} else {
Kind::Excluded
}
@@ -81,10 +90,6 @@ impl<'tu, 'ge> Class<'tu, 'ge> {
TypeRef::new(self.entity.get_type().expect("Can't get class type"), self.gen_env)
}
- pub fn detect_class_simplicity(&self) -> bool {
- !self.has_bases() && self.fields().into_iter().map(|f| f.type_ref()).all(|t| t.is_copy())
- }
-
pub fn as_template_specialization(&self) -> Option<Class<'tu, 'ge>> {
self.entity.get_template().map(|t| Class::new(t, self.gen_env))
}
@@ -143,10 +148,7 @@ impl<'tu, 'ge> Class<'tu, 'ge> {
self.entity
};
entity.walk_bases_while(|child| {
- out.push(Class::new(
- child.get_definition().expect("Can't get base class definition"),
- self.gen_env,
- ));
+ out.push(Class::new(Self::definition_entity(child), self.gen_env));
WalkAction::Continue
});
out
@@ -214,7 +216,9 @@ impl<'tu, 'ge> Class<'tu, 'ge> {
}
pub fn has_fields(&self) -> bool {
- self.entity.walk_fields_while(|_| WalkAction::Interrupt).is_interrupted()
+ Self::definition_entity(self.entity)
+ .walk_fields_while(|_| WalkAction::Interrupt)
+ .is_interrupted()
}
#[inline]
@@ -273,6 +277,12 @@ impl<'tu, 'ge> Class<'tu, 'ge> {
out
}
+ /// Returns an entity that defines current class, for specialized classes (Point_<int>) it's the template (Point_<T>), for
+ /// not fully defined classes it goes to its definition location.
+ fn definition_entity(entity: Entity<'tu>) -> Entity<'tu> {
+ entity.get_template().unwrap_or(entity).get_definition().unwrap_or(entity)
+ }
+
pub fn is_definition(&self) -> bool {
let class_loc = self.entity.get_location();
let def_loc = self.entity.get_definition().and_then(|d| d.get_location());

MODIFY
binding-generator/src/generator.rs
binding-generator/src/generator.rs
@@ -308,9 +308,7 @@ impl<'tu, 'r, V: GeneratorVisitor> OpenCvWalker<'tu, 'r, V> {
});
class_decl.walk_classes_while(|sub_cls| {
if !gen_env.get_export_config(sub_cls).is_some() {
- let cls = Class::new(sub_cls, gen_env);
- let is_simple = cls.detect_class_simplicity();
- gen_env.make_export_config(sub_cls).simple = is_simple;
+ gen_env.make_export_config(sub_cls).simple = Class::new(sub_cls, gen_env).can_be_simple();
}
Self::process_class(visitor, gen_env, sub_cls);
WalkAction::Continue

MODIFY
binding-generator/src/generator_env.rs
binding-generator/src/generator_env.rs
@@ -312,7 +312,7 @@ impl<'tu> GeneratorEnv<'tu> {
}
}
let cls = Class::new(entity, self);
- if cls.detect_class_simplicity() {
+ if cls.can_be_simple() {
return Some(ClassKind::Simple);
}
None

MODIFY
binding-generator/src/settings.rs
binding-generator/src/settings.rs
@@ -584,22 +584,12 @@ pub static ELEMENT_IGNORE: Lazy<HashSet<&str>> = Lazy::new(|| {
#[allow(clippy::type_complexity)]
pub static ELEMENT_EXPORT_TWEAK: Lazy<HashMap<&str, fn(&mut ExportConfig)>> = Lazy::new(|| {
hashmap! {
- "cv::dnn::ClassificationModel" => ExportConfig::make_boxed as _,
- "cv::dnn::DetectionModel" => ExportConfig::make_boxed as _,
- "cv::dnn::KeypointsModel" => ExportConfig::make_boxed as _, // marked as simple from OpenCV 4.5.2
- "cv::dnn::Model" => ExportConfig::make_boxed as _,
- "cv::dnn::SegmentationModel" => ExportConfig::make_boxed as _, // marked as simple from OpenCV 4.5.2
- "cv::dnn::TextDetectionModel" => ExportConfig::make_boxed as _, // inappropriately marked as simple
- "cv::dnn::TextDetectionModel_DB" => ExportConfig::make_boxed as _, // inappropriately marked as simple
- "cv::dnn::TextDetectionModel_EAST" => ExportConfig::make_boxed as _, // inappropriately marked as simple
- "cv::dnn::TextRecognitionModel" => ExportConfig::make_boxed as _, // inappropriately marked as simple
-
+ // missing exports
"VADisplay" => ExportConfig::make_export as _,
"VASurfaceID" => ExportConfig::make_export as _,
"cv::Mat_" => ExportConfig::make_export as _,
"cv::CvFeatureParams" => ExportConfig::make_export as _,
"cv::CvHaarEvaluator" => ExportConfig::make_export as _,
- "cv::CvHaarEvaluator::FeatureHaar" => ExportConfig::make_export as _, // no default constructor
"cv::DetectionROI" => ExportConfig::make_export as _,
"cv::FileNodeIterator::SeqReader" => ExportConfig::make_export as _,
"cv::QtFont" => ExportConfig::make_export as _,
@@ -652,6 +642,7 @@ pub static ELEMENT_EXPORT_TWEAK: Lazy<HashMap<&str, fn(&mut ExportConfig)>> = La
"cv::kinfu::Intr" => ExportConfig::make_simple as _,
"cv::videostab::MaskFrameSource" => ExportConfig::make_export as _,
"cv::ConfidenceMap" => ExportConfig::make_export as _,
+ "cv::linemod::QuantizedPyramid" => ExportConfig::make_export as _, // missing in 3.2
// gapi
"cv::GCompileArg" => ExportConfig::make_export as _,
@@ -668,9 +659,10 @@ pub static ELEMENT_EXPORT_TWEAK: Lazy<HashMap<&str, fn(&mut ExportConfig)>> = La
// override boxed
"cv::DetectionBasedTracker::ExtObject" => ExportConfig::make_boxed as _,
"cv::DetectionBasedTracker::IDetector" => ExportConfig::make_boxed as _,
- "cv::FileNode" => ExportConfig::make_boxed as _, // return references in methods, generally looks like not simple
+ "cv::KeyPoint" => ExportConfig::make_boxed as _, // has descendants in xfeatures2d
+ "cv::aruco::DetectorParameters" => ExportConfig::make_boxed as _, // used in Ptr
+ "cv::aruco::EstimateParameters" => ExportConfig::make_boxed as _, // used in Ptr
"cv::dnn::Net" => ExportConfig::make_boxed as _, // incorrectly marked as simple
- "cv::linemod::QuantizedPyramid" => ExportConfig::make_boxed as _, // missing export in 3.2
"cv::ocl::Device" => ExportConfig::make_boxed as _,
}
});

MODIFY
binding-generator/src/writer/rust_native/class.rs
binding-generator/src/writer/rust_native/class.rs
@@ -212,8 +212,8 @@ fn gen_rust_class(c: &Class, opencv_version: &str) -> String {
.collect::<Vec<_>>();
let fields = if is_simple {
- let mut out: Vec<_> = fields
- .iter()
+ fields
+ .into_iter()
.map(|f| {
let type_ref = f.type_ref();
let mut typ = type_ref.rust_name(NameStyle::ref_());
@@ -230,16 +230,7 @@ fn gen_rust_class(c: &Class, opencv_version: &str) -> String {
"type" => typ,
})
})
- .collect();
- if out.is_empty() {
- out.push(SIMPLE_FIELD_TPL.interpolate(&hashmap! {
- "doc_comment" => "",
- "visibility" => "",
- "name" => "__rust_private",
- "type" => "[u8; 0]",
- }))
- }
- out
+ .collect()
} else {
vec![]
};

MODIFY
binding-generator/src/writer/rust_native/smart_ptr.rs
binding-generator/src/writer/rust_native/smart_ptr.rs
@@ -196,7 +196,11 @@ impl SmartPtrExt for SmartPtr<'_, '_> {
fn method_new(rust_localalias: &str, smartptr_type: &TypeRef, pointee_type: &TypeRef) -> String {
let val = if pointee_type.is_copy() {
+ if pointee_type.as_simple_class().is_some() {
+ panic!("Ptr with simple class is not supported");
+ } else {
format!("new {typ}(val)", typ = pointee_type.cpp_name(CppNameStyle::Reference)).into()
+ }
} else {
Cow::Borrowed("val")
};

MODIFY
src/traits/opencv_type.rs
src/traits/opencv_type.rs
@@ -185,7 +185,7 @@ macro_rules! opencv_type_simple {
}
#[inline]
fn opencv_into_extern(self) -> Self::ExternSendMut {
- &mut *std::mem::ManuallyDrop::new(self) as _
+ unimplemented!("opencv_into_extern can't be used for simple class")
}
}
};

MODIFY
tests/marshalling.rs
tests/marshalling.rs
@@ -173,103 +173,40 @@ fn string_out_argument() -> Result<()> {
/// Setting and getting fields through Ptr
#[test]
fn field_access_on_ptr() -> Result<()> {
- #![cfg(any(ocvrs_has_module_aruco, ocvrs_has_module_aruco_detector))]
- #[cfg(not(ocvrs_has_module_aruco_detector))]
- use opencv::aruco::DetectorParameters;
- #[cfg(ocvrs_has_module_aruco_detector)]
- use opencv::aruco_detector::DetectorParameters;
-
- let mut ptr = DetectorParameters::create()?;
- let mut plain = DetectorParameters::default()?;
-
- assert_eq!(plain.adaptive_thresh_win_size_min(), ptr.adaptive_thresh_win_size_min());
- ptr.set_adaptive_thresh_win_size_min(4);
- assert_eq!(ptr.adaptive_thresh_win_size_min(), 4);
-
- assert_eq!(plain.adaptive_thresh_win_size_max(), ptr.adaptive_thresh_win_size_max());
- ptr.set_adaptive_thresh_win_size_max(24);
- assert_eq!(ptr.adaptive_thresh_win_size_max(), 24);
-
- assert_eq!(plain.adaptive_thresh_win_size_step(), ptr.adaptive_thresh_win_size_step());
- ptr.set_adaptive_thresh_win_size_step(11);
- assert_eq!(ptr.adaptive_thresh_win_size_step(), 11);
-
- assert_eq!(plain.adaptive_thresh_constant(), ptr.adaptive_thresh_constant());
- ptr.set_adaptive_thresh_constant(8.0);
- assert_eq!(ptr.adaptive_thresh_constant(), 8.0);
-
- assert_eq!(plain.min_marker_perimeter_rate(), ptr.min_marker_perimeter_rate());
- ptr.set_min_marker_perimeter_rate(1.0);
- assert_eq!(ptr.min_marker_perimeter_rate(), 1.0);
-
- assert_eq!(plain.max_marker_perimeter_rate(), ptr.max_marker_perimeter_rate());
- ptr.set_max_marker_perimeter_rate(5.0);
- assert_eq!(ptr.max_marker_perimeter_rate(), 5.0);
-
- assert_eq!(plain.min_corner_distance_rate(), ptr.min_corner_distance_rate());
- ptr.set_min_corner_distance_rate(1.0);
- assert_eq!(ptr.min_corner_distance_rate(), 1.0);
-
- assert_eq!(plain.min_distance_to_border(), ptr.min_distance_to_border());
- ptr.set_min_distance_to_border(4);
- assert_eq!(ptr.min_distance_to_border(), 4);
-
- assert_eq!(plain.min_marker_distance_rate(), ptr.min_marker_distance_rate());
- ptr.set_min_marker_distance_rate(1.0);
- assert_eq!(ptr.min_marker_distance_rate(), 1.0);
-
- assert_eq!(plain.corner_refinement_win_size(), ptr.corner_refinement_win_size());
- ptr.set_corner_refinement_win_size(6);
- assert_eq!(ptr.corner_refinement_win_size(), 6);
-
- assert_eq!(
- plain.corner_refinement_max_iterations(),
- ptr.corner_refinement_max_iterations()
- );
- ptr.set_corner_refinement_max_iterations(31);
- assert_eq!(ptr.corner_refinement_max_iterations(), 31);
-
- assert_eq!(plain.corner_refinement_min_accuracy(), ptr.corner_refinement_min_accuracy());
- ptr.set_corner_refinement_min_accuracy(1.0);
- assert_eq!(ptr.corner_refinement_min_accuracy(), 1.0);
-
- assert_eq!(plain.marker_border_bits(), ptr.marker_border_bits());
- ptr.set_marker_border_bits(2);
- assert_eq!(ptr.marker_border_bits(), 2);
-
- assert_eq!(
- plain.perspective_remove_ignored_margin_per_cell(),
- ptr.perspective_remove_ignored_margin_per_cell()
- );
- ptr.set_perspective_remove_ignored_margin_per_cell(1.0);
- assert_eq!(ptr.perspective_remove_ignored_margin_per_cell(), 1.0);
-
- assert_eq!(
- plain.max_erroneous_bits_in_border_rate(),
- ptr.max_erroneous_bits_in_border_rate()
- );
- ptr.set_max_erroneous_bits_in_border_rate(1.0);
- assert_eq!(ptr.max_erroneous_bits_in_border_rate(), 1.0);
-
- assert_eq!(plain.min_otsu_std_dev(), ptr.min_otsu_std_dev());
- ptr.set_min_otsu_std_dev(6.0);
- assert_eq!(ptr.min_otsu_std_dev(), 6.0);
-
- assert_eq!(plain.error_correction_rate(), ptr.error_correction_rate());
- ptr.set_error_correction_rate(1.0);
- assert_eq!(ptr.error_correction_rate(), 1.0);
-
- assert_eq!(
- plain.perspective_remove_pixel_per_cell(),
- ptr.perspective_remove_pixel_per_cell()
- );
- ptr.set_perspective_remove_pixel_per_cell(5);
- assert_eq!(ptr.perspective_remove_pixel_per_cell(), 5);
-
- plain.set_adaptive_thresh_constant(123.);
- assert_eq!(123., plain.adaptive_thresh_constant());
- plain.set_adaptive_thresh_constant(87.);
- assert_eq!(87., plain.adaptive_thresh_constant());
+ #![cfg(all(ocvrs_has_module_aruco, any(ocvrs_opencv_branch_34, ocvrs_opencv_branch_4)))]
+ use opencv::aruco::EstimateParameters;
+ // the location and parameters are wildly different between even the minor release in the OpenCV branches, so for now
+ // let's just limit to only those fields that are stable
+ // #[cfg(ocvrs_opencv_branch_34)]
+ // use opencv::aruco::PatternPos::CW_top_left_corner as LeftTop;
+ // #[cfg(ocvrs_opencv_branch_4)]
+ // use opencv::aruco::PatternPositionType::ARUCO_CW_TOP_LEFT_CORNER as LeftTop;
+ // #[cfg(ocvrs_opencv_branch_34)]
+ // use opencv::calib3d::SolvePnPMethod::{SOLVEPNP_EPNP, SOLVEPNP_MAX_COUNT};
+ // #[cfg(ocvrs_opencv_branch_4)]
+ // use opencv::calib3d::{SOLVEPNP_EPNP, SOLVEPNP_MAX_COUNT};
+ use opencv::core::Ptr;
+
+ let mut params = EstimateParameters::default()?;
+ assert_ne!(true, params.use_extrinsic_guess());
+ params.set_use_extrinsic_guess(true);
+ let params_ptr = Ptr::<EstimateParameters>::new(params);
+ assert_eq!(true, params_ptr.use_extrinsic_guess());
+
+ let plain = EstimateParameters::default()?;
+ let mut ptr = Ptr::<EstimateParameters>::new(EstimateParameters::default()?);
+
+ // assert_eq!(plain.pattern(), ptr.pattern());
+ // ptr.set_pattern(LeftTop);
+ // assert_eq!(LeftTop, ptr.pattern());
+
+ assert_eq!(plain.use_extrinsic_guess(), ptr.use_extrinsic_guess());
+ ptr.set_use_extrinsic_guess(true);
+ assert_eq!(true, ptr.use_extrinsic_guess());
+
+ // assert_eq!(plain.solve_pnp_method(), ptr.solve_pnp_method());
+ // ptr.set_solve_pnp_method(SOLVEPNP_MAX_COUNT);
+ // assert_eq!(ptr.solve_pnp_method(), SOLVEPNP_MAX_COUNT);
Ok(())
}

Improve class simplicity detection