Skip to content

Commit e5f37a9

Browse files
committed
Fix passing Option<Ptr<T>>
1 parent 55a254b commit e5f37a9

File tree

8 files changed

+124
-22
lines changed

8 files changed

+124
-22
lines changed

binding-generator/src/writer/rust_native/smart_ptr.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ impl RustNativeGeneratedElement for SmartPtr<'_, '_> {
147147
let rust_as_raw_mut = type_ref.rust_as_raw_name(Constness::Mut);
148148

149149
let ctor = if gen_ctor(&pointee_kind) {
150-
let extern_new = method_new(smartptr_class.clone(), type_ref, pointee_type.as_ref().clone()).identifier();
150+
let extern_new = method_new(smartptr_class.clone(), type_ref.clone(), pointee_type.as_ref().clone()).identifier();
151151
CTOR_TPL.interpolate(&HashMap::from([
152152
("inner_rust_full", inner_rust_full.as_ref()),
153153
("extern_new", &extern_new),
@@ -156,13 +156,15 @@ impl RustNativeGeneratedElement for SmartPtr<'_, '_> {
156156
"".to_string()
157157
};
158158

159+
let extern_new_null = method_new_null(smartptr_class.clone(), type_ref).identifier();
159160
let extern_delete = FuncDesc::method_delete(smartptr_class).identifier();
160161
TPL.interpolate(&HashMap::from([
161162
("rust_localalias", rust_localalias.as_ref()),
162163
("rust_as_raw_const", &rust_as_raw_const),
163164
("rust_as_raw_mut", &rust_as_raw_mut),
164165
("rust_full", &rust_full),
165166
("inner_rust_full", &inner_rust_full),
167+
("extern_new_null", &extern_new_null),
166168
("extern_delete", &extern_delete),
167169
("extern_get_inner_ptr", &extern_get_inner_ptr),
168170
("extern_get_inner_ptr_mut", &extern_get_inner_ptr_mut),
@@ -197,6 +199,7 @@ fn extern_functions<'tu, 'ge>(ptr: &SmartPtr<'tu, 'ge>) -> Vec<Func<'tu, 'ge>> {
197199
smartptr_class.clone(),
198200
pointee_type.as_ref().clone().with_inherent_constness(Constness::Mut),
199201
));
202+
out.push(method_new_null(smartptr_class.clone(), type_ref.clone()));
200203
out.push(FuncDesc::method_delete(smartptr_class.clone()));
201204
if let Some(cls) = pointee_kind.as_class().filter(|cls| cls.kind().is_trait()) {
202205
for base in all_bases(&cls) {
@@ -297,6 +300,21 @@ fn method_new<'tu, 'ge>(
297300
)
298301
}
299302

303+
fn method_new_null<'tu, 'ge>(smartptr_class: Class<'tu, 'ge>, smartptr_type_ref: TypeRef<'tu, 'ge>) -> Func<'tu, 'ge> {
304+
Func::new_desc(
305+
FuncDesc::new(
306+
FuncKind::Constructor(smartptr_class),
307+
Constness::Const,
308+
ReturnKind::InfallibleNaked,
309+
"new_null",
310+
"<unused>",
311+
[],
312+
smartptr_type_ref,
313+
)
314+
.cpp_body(FuncCppBody::ManualCallReturn("return new {{ret_type}}();".into())),
315+
)
316+
}
317+
300318
fn method_cast_to_base<'tu, 'ge>(
301319
smartptr_class: Class<'tu, 'ge>,
302320
base_type_ref: TypeRef<'tu, 'ge>,

binding-generator/src/writer/rust_native/tpl/smart_ptr/rust.tpl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
pub type {{rust_localalias}} = {{rust_full}};
33

44
ptr_extern! { {{inner_rust_full}},
5-
{{extern_delete}}, {{extern_get_inner_ptr}}, {{extern_get_inner_ptr_mut}}
5+
{{extern_new_null}}, {{extern_delete}}, {{extern_get_inner_ptr}}, {{extern_get_inner_ptr_mut}}
66
}
77

88
{{ctor}}

binding-generator/src/writer/rust_native/type_ref.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ impl TypeRefExt for TypeRef<'_, '_> {
7373
RenderLane::Primitive(PrimitiveRenderLane::from_cpp_non_canonical(cpp, self.clone()))
7474
}
7575
TypeRefKind::Function(f) => RenderLane::Function(FunctionRenderLane::from_non_canonical_func(self.clone(), f)),
76-
TypeRefKind::StdVector(_) | TypeRefKind::SmartPtr(_) | TypeRefKind::StdTuple(_) => {
77-
RenderLane::CppPassByVoidPtr(CppPassByVoidPtrRenderLane::from_non_canonical(self.clone()))
78-
}
76+
TypeRefKind::StdVector(_) | TypeRefKind::SmartPtr(_) | TypeRefKind::StdTuple(_) => RenderLane::CppPassByVoidPtr(
77+
CppPassByVoidPtrRenderLane::from_non_canonical_indirection(self.clone(), Indirection::None),
78+
),
7979
TypeRefKind::Array(elem, None) => {
8080
if matches!(self.type_hint(), TypeRefTypeHint::Slice) && elem.kind().is_void() {
8181
RenderLane::VoidSlice(VoidSliceRenderLane::from_canonical(canonical.into_owned()))
@@ -90,7 +90,10 @@ impl TypeRefExt for TypeRef<'_, '_> {
9090
)),
9191
TypeRefKind::RValueReference(inner) => {
9292
if inner.kind().extern_pass_kind().is_by_void_ptr() {
93-
RenderLane::CppPassByVoidPtr(CppPassByVoidPtrRenderLane::from_non_canonical(self.clone()))
93+
RenderLane::CppPassByVoidPtr(CppPassByVoidPtrRenderLane::from_non_canonical_indirection(
94+
self.clone(),
95+
Indirection::None,
96+
))
9497
} else {
9598
RenderLane::ByMove(ByMoveRenderLane::from_non_canonical(self.clone()))
9699
}
@@ -130,9 +133,9 @@ impl TypeRefExt for TypeRef<'_, '_> {
130133
enm,
131134
indirection,
132135
)),
133-
kind if kind.extern_pass_kind().is_by_void_ptr() => {
134-
RenderLane::CppPassByVoidPtr(CppPassByVoidPtrRenderLane::from_non_canonical(self.clone()))
135-
}
136+
kind if kind.extern_pass_kind().is_by_void_ptr() => RenderLane::CppPassByVoidPtr(
137+
CppPassByVoidPtrRenderLane::from_non_canonical_indirection(self.clone(), indirection),
138+
),
136139
_ => RenderLane::Indirect(IndirectRenderLane::from_non_canonical_indirection(self.clone(), indirection)),
137140
}
138141
}

binding-generator/src/writer/rust_native/type_ref/render_lane/cpp_pass_by_void_ptr.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
use std::borrow::Cow;
22
use std::borrow::Cow::{Borrowed, Owned};
33

4-
use super::{rust_arg_func_decl, rust_self_func_decl, RenderLaneTrait};
4+
use super::{rust_arg_func_decl, rust_self_func_decl, FunctionProps, Indirection, RenderLaneTrait};
55
use crate::type_ref::{Constness, ExternDir, FishStyle, TypeRef};
6-
use crate::writer::rust_native::type_ref::{Lifetime, NullabilityExt, TypeRefExt};
6+
use crate::writer::rust_native::type_ref::{Lifetime, TypeRefExt};
77
use crate::{CowMapBorrowedExt, CppNameStyle, NameStyle};
88

99
pub struct CppPassByVoidPtrRenderLane<'tu, 'ge> {
1010
non_canonical: TypeRef<'tu, 'ge>,
11+
indirection: Indirection,
1112
}
1213

1314
impl<'tu, 'ge> CppPassByVoidPtrRenderLane<'tu, 'ge> {
14-
pub fn from_non_canonical(non_canonical: TypeRef<'tu, 'ge>) -> Self {
15-
Self { non_canonical }
15+
pub fn from_non_canonical_indirection(non_canonical: TypeRef<'tu, 'ge>, indirection: Indirection) -> Self {
16+
Self {
17+
non_canonical,
18+
indirection,
19+
}
1620
}
1721
}
1822

@@ -33,6 +37,22 @@ impl RenderLaneTrait for CppPassByVoidPtrRenderLane<'_, '_> {
3337
)
3438
}
3539

40+
fn rust_arg_pre_call(&self, name: &str, function_props: &FunctionProps) -> String {
41+
let is_nullable = self.non_canonical.type_hint().nullability().is_nullable();
42+
if is_nullable && self.non_canonical.source().kind().as_smart_ptr().is_some() {
43+
let ref_spec = match self.indirection {
44+
Indirection::Pointer | Indirection::Reference => "ref ",
45+
Indirection::None => "",
46+
};
47+
format!(
48+
"smart_ptr_option_arg!({safety}{ref_spec}{name})",
49+
safety = function_props.safety.rust_block_safety_qual()
50+
)
51+
} else {
52+
"".to_string()
53+
}
54+
}
55+
3656
fn rust_arg_func_call(&self, name: &str) -> String {
3757
rust_arg_func_call(&self.non_canonical, name)
3858
}
@@ -71,12 +91,8 @@ impl RenderLaneTrait for CppPassByVoidPtrRenderLane<'_, '_> {
7191
}
7292

7393
fn rust_arg_func_call(type_ref: &TypeRef, name: &str) -> String {
74-
let src_typ = type_ref.source();
75-
let constness = type_ref.constness();
76-
let by_ptr = format!("{name}.{as_raw}()", as_raw = src_typ.rust_as_raw_name(constness));
77-
type_ref
78-
.type_hint()
79-
.nullability()
80-
.rust_wrap_nullable_func_call(name, by_ptr.into(), constness)
81-
.into_owned()
94+
format!(
95+
"{name}.{as_raw}()",
96+
as_raw = type_ref.source().rust_as_raw_name(type_ref.constness())
97+
)
8298
}

src/manual/core/ptr.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ where
3535
unsafe { Self::from_raw(Self::extern_new(val.opencv_into_extern())) }
3636
}
3737

38+
/// Create a new `Ptr` which points to `NULL`
39+
///
40+
/// Not generally useful, mostly for internal use.
41+
pub unsafe fn new_null() -> Self {
42+
unsafe { Self::from_raw(Self::extern_new_null()) }
43+
}
44+
3845
/// Get raw pointer to the inner object
3946
pub fn inner_as_raw(&self) -> *const c_void {
4047
unsafe { self.extern_inner_as_ptr() }

src/manual/core/ptr/ptr_extern.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use crate::{extern_receive, extern_send};
55

66
#[doc(hidden)]
77
pub trait PtrExtern {
8+
#[doc(hidden)]
9+
unsafe fn extern_new_null() -> *mut c_void;
810
#[doc(hidden)]
911
unsafe fn extern_delete(&mut self);
1012
#[doc(hidden)]
@@ -24,8 +26,13 @@ pub trait PtrExternCtor<T: OpenCVTypeExternContainerMove> {
2426
#[doc(hidden)]
2527
#[macro_export]
2628
macro_rules! ptr_extern {
27-
($type: ty, $extern_delete: ident, $extern_inner_as_ptr: ident, $extern_inner_as_ptr_mut: ident $(,)?) => {
29+
($type: ty, $extern_new_null: ident, $extern_delete: ident, $extern_inner_as_ptr: ident, $extern_inner_as_ptr_mut: ident $(,)?) => {
2830
impl $crate::core::PtrExtern for $crate::core::Ptr<$type> {
31+
#[inline]
32+
unsafe fn extern_new_null() -> *mut ::std::ffi::c_void {
33+
$crate::sys::$extern_new_null()
34+
}
35+
2936
#[inline]
3037
unsafe fn extern_delete(&mut self) {
3138
$crate::sys::$extern_delete(self.as_raw_mut())

src/templ.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,31 @@ macro_rules! string_array_arg_mut {
9797
};
9898
}
9999

100+
macro_rules! smart_ptr_option_arg {
101+
(unsafe ref $name: ident) => {
102+
let null = if $name.is_none() {
103+
Some(unsafe { $crate::core::Ptr::new_null() })
104+
} else {
105+
None
106+
};
107+
let $name = $name.or(null.as_ref()).expect("Nullability should have been checked");
108+
};
109+
(unsafe $name: ident) => {
110+
let $name = $name.unwrap_or_else(|| unsafe { $crate::core::Ptr::new_null() });
111+
};
112+
(ref $name: ident) => {
113+
let null = if $name.is_none() {
114+
Some($crate::core::Ptr::new_null())
115+
} else {
116+
None
117+
};
118+
let $name = $name.or(null.as_ref()).expect("Nullability should have been checked");
119+
};
120+
($name: ident) => {
121+
let $name = $name.unwrap_or_else(|| $crate::core::Ptr::new_null());
122+
};
123+
}
124+
100125
macro_rules! return_send {
101126
(via $name: ident) => {
102127
let mut $name = ::std::mem::MaybeUninit::uninit();

tests/marshalling.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,29 @@ fn string_array() -> Result<()> {
279279
assert_eq!("b", parser.get_str("a", true)?);
280280
Ok(())
281281
}
282+
283+
#[test]
284+
fn smart_ptr_optional() -> Result<()> {
285+
#![cfg(ocvrs_has_module_calib3d)]
286+
287+
use opencv::calib3d;
288+
use opencv::core::{Point2f, Size, Vector};
289+
290+
let mut centers = Vector::<Point2f>::new();
291+
for i in 0..4 {
292+
for j in 0..4 {
293+
centers.push((i as f32 * 100.0, j as f32 * 100.0).into());
294+
}
295+
}
296+
297+
let mut out_centers = Vector::<Point2f>::new();
298+
let r = calib3d::find_circles_grid_1(
299+
&centers,
300+
Size::new(4, 4),
301+
&mut out_centers,
302+
calib3d::CALIB_CB_SYMMETRIC_GRID,
303+
None,
304+
);
305+
assert!(matches!(r, Ok(true)));
306+
Ok(())
307+
}

0 commit comments

Comments
 (0)