Add support for nullable reference arguments
MODIFY
binding-generator/src/field.rs
binding-generator/src/field.rs
@@ -71,6 +71,7 @@ impl<'tu, 'ge> Field<'tu, 'ge> {
pub fn type_ref(&self) -> TypeRef<'tu, 'ge> {
let type_hint = match self.type_hint {
+ FieldTypeHint::ArgOverride(ArgumentOverride::Nullable) => TypeRefTypeHint::Nullable,
FieldTypeHint::ArgOverride(ArgumentOverride::Slice) => TypeRefTypeHint::Slice,
FieldTypeHint::ArgOverride(ArgumentOverride::NullableSlice) => TypeRefTypeHint::NullableSlice,
FieldTypeHint::Specialized(typ) => TypeRefTypeHint::Specialized(typ),

MODIFY
binding-generator/src/settings.rs
binding-generator/src/settings.rs
@@ -875,6 +875,7 @@ pub static IMPLEMENTED_GENERICS: Lazy<HashSet<&str>> = Lazy::new(|| hashset! {
#[derive(Clone, Copy, Debug)]
pub enum ArgumentOverride {
+ Nullable,
Slice,
NullableSlice,
LenForSlice(&'static str, usize),
@@ -943,6 +944,9 @@ pub static ARGUMENT_OVERRIDE: Lazy<HashMap<FuncId, HashMap<&str, ArgumentOverrid
"from_to" => ArgumentOverride::Slice,
"npairs" => ArgumentOverride::LenForSlice("from_to", 2),
},
+ FuncId::new("cv::createTrackbar", ["trackbarname", "winname", "value", "count", "onChange", "userdata"]) => hashmap! {
+ "value" => ArgumentOverride::Nullable,
+ },
});
pub static NO_SKIP_NAMESPACE_IN_LOCALNAME: Lazy<HashMap<&str, HashMap<&str, &str>>> = Lazy::new(|| hashmap! {

MODIFY
binding-generator/src/type_ref.rs
binding-generator/src/type_ref.rs
@@ -678,7 +678,7 @@ impl<'tu, 'ge> TypeRef<'tu, 'ge> {
}
pub fn is_nullable(&self) -> bool {
- matches!(self.type_hint, TypeRefTypeHint::NullableSlice)
+ matches!(self.type_hint, TypeRefTypeHint::NullableSlice | TypeRefTypeHint::Nullable)
}
pub fn as_class(&self) -> Option<Class<'tu, 'ge>> {
@@ -1190,12 +1190,12 @@ impl<'tu, 'ge> TypeRef<'tu, 'ge> {
format!("{name}.as_mut_ptr()", name=name)
};
return if self.is_nullable() {
- let null_ptr_name = if constness.with(self.constness()).is_const() {
- "null"
- } else {
- "null_mut"
- };
- format!("{name}.map_or(::core::ptr::{null_ptr_name}(), |{name}| {arr})", name=name, null_ptr_name=null_ptr_name, arr=arr)
+ format!(
+ "{name}.map_or({null_ptr}, |{name}| {arr})",
+ name=name,
+ null_ptr=constness.with(self.constness()).rust_null_ptr_full(),
+ arr=arr
+ )
} else {
arr
}
@@ -1215,6 +1215,20 @@ impl<'tu, 'ge> TypeRef<'tu, 'ge> {
);
}
}
+ if self.as_reference().is_some() || self.as_pointer().is_some() {
+ if self.is_nullable() {
+ let arg = if constness.with(self.constness()).is_const() {
+ format!("{name} as *_", name=name)
+ } else {
+ format!("{name} as *mut _", name=name)
+ }; return format!(
+ "{name}.map_or({null_ptr}, |{name}| {arg})",
+ name=name,
+ null_ptr=constness.with(self.constness()).rust_null_ptr_full(),
+ arg=arg,
+ )
+ }
+ }
name.to_string()
}

MODIFY
binding-generator/src/type_ref/renderer.rs
binding-generator/src/type_ref/renderer.rs
@@ -155,6 +155,14 @@ impl Constness {
}
}
+ pub fn rust_null_ptr_full(self) -> &'static str {
+ if self.is_const() {
+ "::core::ptr::null()"
+ } else {
+ "::core::ptr::null_mut()"
+ }
+ }
+
pub fn cpp_qual(self) -> &'static str {
if self.is_const() {
"const "
@@ -310,6 +318,14 @@ impl RustRenderer {
pub fn new(name_style: NameStyle, lifetime: Lifetime) -> Self {
Self { name_style, lifetime }
}
+
+ fn wrap_nullable<'a>(&self, type_ref: &TypeRef, typ: Cow<'a, str>) -> Cow<'a, str> {
+ if type_ref.is_nullable() {
+ format!("Option{fish}<{typ}>", fish=self.name_style.rust_turbo_fish_qual(), typ=typ).into()
+ } else {
+ typ
+ }
+ }
}
impl TypeRefRenderer<'_> for RustRenderer {
@@ -330,11 +346,7 @@ impl TypeRefRenderer<'_> for RustRenderer {
}
Kind::Array(elem, size) => {
let typ = type_ref.format_as_array(&elem.render(self.recurse()), size);
- if type_ref.is_nullable() {
- format!("Option{fish}<{typ}>", fish=self.name_style.rust_turbo_fish_qual(), typ=typ)
- } else {
- typ
- }.into()
+ self.wrap_nullable(&type_ref, typ.into())
}
Kind::StdVector(vec) => {
vec.rust_name(self.name_style).into_owned().into()
@@ -352,12 +364,13 @@ impl TypeRefRenderer<'_> for RustRenderer {
cnst=type_ref.constness().rust_qual(true),
).into()
} else {
- format!(
+ let typ = format!(
"&{lt: <}{cnst}{typ}",
cnst=type_ref.constness().rust_qual(false),
lt=self.lifetime,
typ=inner.render(self.recurse())
- ).into()
+ );
+ self.wrap_nullable(&type_ref, typ.into())
}
}
Kind::SmartPtr(ptr) => {

MODIFY
tests/callback.rs
tests/callback.rs
@@ -6,18 +6,34 @@ use opencv::{highgui, Result};
fn callback() -> Result<()> {
// only run under X11 on linux
if cfg!(target_os = "linux") && option_env!("DISPLAY").is_some() {
- highgui::named_window("test", 0)?;
+ {
+ highgui::named_window("test_1", 0)?;
let mut value = 50;
let cb_value = Arc::new(Mutex::new(0));
- highgui::create_trackbar("test_track", "test", &mut value, 100, Some(Box::new({
+ highgui::create_trackbar("test_track_1", "test_1", Some(&mut value), 100, Some(Box::new({
let cb_value = cb_value.clone();
move |s| {
*cb_value.lock().unwrap() = s;
}
})))?;
- highgui::set_trackbar_pos("test_track", "test", 10)?;
+ assert_eq!(value, 50);
+ highgui::set_trackbar_pos("test_track_1", "test_1", 10)?;
assert_eq!(value, 10);
assert_eq!(*cb_value.lock().unwrap(), 10);
}
+
+ {
+ highgui::named_window("test_2", 0)?;
+ let cb_value = Arc::new(Mutex::new(0));
+ highgui::create_trackbar("test_track_2", "test_2", None, 100, Some(Box::new({
+ let cb_value = cb_value.clone();
+ move |s| {
+ *cb_value.lock().unwrap() = s;
+ }
+ })))?;
+ highgui::set_trackbar_pos("test_track_2", "test_2", 10)?;
+ assert_eq!(*cb_value.lock().unwrap(), 10);
+ }
+ }
Ok(())
}

Add support for nullable reference arguments