Skip to content

Commit

Permalink
Add BoxedRef to allow returning Boxed objects retaining lifetime conn…
Browse files Browse the repository at this point in the history
…ection to the origin object
  • Loading branch information
twistedfall committed Dec 1, 2023
1 parent 026e827 commit 7e94842
Show file tree
Hide file tree
Showing 19 changed files with 700 additions and 337 deletions.
7 changes: 2 additions & 5 deletions binding-generator/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,10 +407,8 @@ impl<'tu, 'ge> Class<'tu, 'ge> {
out.extend(fields.flat_map(|fld| {
iter::from_fn({
let doc_comment = Rc::from(fld.doc_comment());
let fld_type_ref = fld
.type_ref()
.into_owned()
.with_type_hint(TypeRefTypeHint::PrimitiveRefAsPointer);
let mut fld_type_ref = fld.type_ref().into_owned();
fld_type_ref.set_type_hint(TypeRefTypeHint::PrimitiveRefAsPointer);
let fld_type_ref_return_as_naked = fld_type_ref.return_as_naked();
let fld_const = fld.constness();
let passed_by_ref = fld_type_ref.can_return_as_direct_reference();
Expand Down Expand Up @@ -502,7 +500,6 @@ impl<'tu, 'ge> Class<'tu, 'ge> {
arguments: Rc::new([Field::new_desc(FieldDesc {
cpp_fullname: "val".into(),
type_ref: fld_type_ref.with_inherent_constness(Constness::Const),
type_ref_type_hint: TypeRefTypeHint::None,
default_value: fld.default_value().map(|v| v.into()),
})]),
return_kind: ReturnKind::InfallibleNaked,
Expand Down
23 changes: 19 additions & 4 deletions binding-generator/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,21 @@ impl<'tu, 'ge> Field<'tu, 'ge> {
Self::Desc(Rc::new(desc))
}

pub(crate) fn to_desc(&self) -> Rc<FieldDesc<'tu, 'ge>> {
match self {
Self::Clang { type_ref_type_hint, .. } => Rc::new(FieldDesc {
cpp_fullname: self.cpp_name(CppNameStyle::Reference).into(),
type_ref: self.type_ref().into_owned().with_type_hint(type_ref_type_hint.clone()), // fixme, add an option to avoid inheriting type_ref
default_value: self.default_value().map(Rc::from),
}),
Self::Desc(desc) => Rc::clone(desc),
}
}

pub fn type_ref_type_hint(&self) -> &TypeRefTypeHint {
match self {
Self::Clang { type_ref_type_hint, .. } => type_ref_type_hint,
Self::Desc(desc) => &desc.type_ref_type_hint,
Self::Desc(desc) => desc.type_ref.type_hint(),
}
}

Expand All @@ -56,7 +67,7 @@ impl<'tu, 'ge> Field<'tu, 'ge> {
type_ref_type_hint: old_type_ref_type_hint,
..
} => *old_type_ref_type_hint = type_ref_type_hint,
Self::Desc(desc) => Rc::make_mut(desc).type_ref_type_hint = type_ref_type_hint,
Self::Desc(desc) => Rc::make_mut(desc).type_ref.set_type_hint(type_ref_type_hint),
}
}

Expand Down Expand Up @@ -92,6 +103,12 @@ impl<'tu, 'ge> Field<'tu, 'ge> {
}
}

pub fn with_type_ref(&self, type_ref: TypeRef<'tu, 'ge>) -> Self {
let mut desc = self.to_desc();
Rc::make_mut(&mut desc).type_ref = type_ref;
Self::Desc(desc)
}

pub fn constness(&self) -> Constness {
let type_ref = self.type_ref();
match type_ref.canonical().kind().as_ref() {
Expand Down Expand Up @@ -254,7 +271,6 @@ impl fmt::Debug for Field<'_, '_> {
pub struct FieldDesc<'tu, 'ge> {
pub cpp_fullname: Rc<str>,
pub type_ref: TypeRef<'tu, 'ge>,
pub type_ref_type_hint: TypeRefTypeHint,
pub default_value: Option<Rc<str>>,
}

Expand All @@ -263,7 +279,6 @@ impl<'tu, 'ge> FieldDesc<'tu, 'ge> {
Self {
cpp_fullname: name.into(),
type_ref,
type_ref_type_hint: TypeRefTypeHint::None,
default_value: None,
}
}
Expand Down
114 changes: 56 additions & 58 deletions binding-generator/src/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ impl<'tu, 'ge> Func<'tu, 'ge> {
Field::new_desc(FieldDesc {
cpp_fullname: arg.cpp_name(CppNameStyle::Reference).into(),
type_ref,
type_ref_type_hint: TypeRefTypeHint::None,
default_value: arg.default_value().map(|v| v.into()),
})
},
Expand All @@ -126,15 +125,16 @@ impl<'tu, 'ge> Func<'tu, 'ge> {
.map(|s| s().cpp_name(CppNameStyle::Reference).into_owned())
.join(", ");
let mut desc = self.to_desc(InheritConfig::empty().kind().arguments().return_type_ref());
desc.kind = kind;
desc.type_hint = FuncTypeHint::Specialized;
desc.arguments = arguments;
desc.return_type_ref = specialized(&return_type_ref).unwrap_or(return_type_ref);
desc.cpp_body = FuncCppBody::ManualCall(format!("{{{{name}}}}<{generic}>({{{{args}}}})").into());
Self::new_desc(desc)
let desc_mut = Rc::make_mut(&mut desc);
desc_mut.kind = kind;
desc_mut.type_hint = FuncTypeHint::Specialized;
desc_mut.arguments = arguments;
desc_mut.return_type_ref = specialized(&return_type_ref).unwrap_or(return_type_ref);
desc_mut.cpp_body = FuncCppBody::ManualCall(format!("{{{{name}}}}<{generic}>({{{{args}}}})").into());
Self::Desc(desc)
}

pub(crate) fn to_desc(&self, skip_config: InheritConfig) -> FuncDesc<'tu, 'ge> {
pub(crate) fn to_desc(&self, skip_config: InheritConfig) -> Rc<FuncDesc<'tu, 'ge>> {
match self {
Func::Clang { .. } => {
let kind = if skip_config.kind {
Expand Down Expand Up @@ -167,7 +167,7 @@ impl<'tu, 'ge> Func<'tu, 'ge> {
} else {
self.file_line_name().location
};
FuncDesc {
Rc::new(FuncDesc {
kind,
type_hint: FuncTypeHint::None,
constness: self.constness(),
Expand All @@ -183,7 +183,7 @@ impl<'tu, 'ge> Func<'tu, 'ge> {
cpp_body: FuncCppBody::Auto,
rust_body: FuncRustBody::Auto,
rust_extern_definition: FuncRustExtern::Auto,
}
})
}
Func::Desc(desc) => {
let kind = if skip_config.kind {
Expand All @@ -201,23 +201,12 @@ impl<'tu, 'ge> Func<'tu, 'ge> {
} else {
desc.def_loc.clone()
};
FuncDesc {
kind,
type_hint: FuncTypeHint::None,
constness: desc.constness,
return_kind: desc.return_kind,
cpp_name: Rc::clone(&desc.cpp_name),
rust_custom_leafname: desc.rust_custom_leafname.as_ref().map(Rc::clone),
rust_module: Rc::clone(&desc.rust_module),
doc_comment: Rc::clone(&desc.doc_comment),
def_loc,
rust_generic_decls: Rc::new([]),
arguments: Rc::clone(&desc.arguments),
return_type_ref,
cpp_body: FuncCppBody::Auto,
rust_body: FuncRustBody::Auto,
rust_extern_definition: FuncRustExtern::Auto,
}
let mut desc = Rc::clone(desc);
let desc_mut = Rc::make_mut(&mut desc);
desc_mut.kind = kind;
desc_mut.return_type_ref = return_type_ref;
desc_mut.def_loc = def_loc;
desc
}
}
}
Expand Down Expand Up @@ -249,8 +238,8 @@ impl<'tu, 'ge> Func<'tu, 'ge> {
Func::Clang { .. } => {
if inherit_config.any_enabled() {
let mut desc = self.to_desc(inherit_config);
transfer(&mut desc, ancestor, inherit_config);
Self::new_desc(desc);
transfer(Rc::make_mut(&mut desc), ancestor, inherit_config);
*self = Func::Desc(desc);
}
}
Func::Desc(desc) => transfer(Rc::make_mut(desc), ancestor, inherit_config),
Expand Down Expand Up @@ -434,38 +423,47 @@ impl<'tu, 'ge> Func<'tu, 'ge> {

pub fn return_type_ref(&self) -> TypeRef<'tu, 'ge> {
match self {
&Self::Clang { entity, gen_env, .. } => match self.kind().as_ref() {
FuncKind::Constructor(cls) => cls.type_ref(),
// `operator =` returns a reference to the `self` value and it's quite cumbersome to handle correctly
FuncKind::InstanceOperator(_, OperatorKind::Set) => TypeRefDesc::void(),
FuncKind::Function
| FuncKind::InstanceMethod(..)
| FuncKind::StaticMethod(..)
| FuncKind::FieldAccessor(..)
| FuncKind::ConversionMethod(..)
| FuncKind::GenericInstanceMethod(..)
| FuncKind::GenericFunction
| FuncKind::FunctionOperator(..)
| FuncKind::InstanceOperator(..) => {
let mut out = TypeRef::new_ext(
entity.get_result_type().expect("Can't get return type"),
TypeRefTypeHint::PrimitiveRefAsPointer,
None,
gen_env,
);
if let Some(type_hint) = settings::ARGUMENT_OVERRIDE
.get(&self.func_id())
.and_then(|x| x.get(RETURN_HINT))
{
out = out.with_type_hint(type_hint.clone())
&Self::Clang { entity, gen_env, .. } => {
let mut out = match self.kind().as_ref() {
FuncKind::Constructor(cls) => cls.type_ref(),
// `operator =` returns a reference to the `self` value and it's quite cumbersome to handle correctly
FuncKind::InstanceOperator(_, OperatorKind::Set) => TypeRefDesc::void(),
FuncKind::Function
| FuncKind::InstanceMethod(..)
| FuncKind::StaticMethod(..)
| FuncKind::FieldAccessor(..)
| FuncKind::ConversionMethod(..)
| FuncKind::GenericInstanceMethod(..)
| FuncKind::GenericFunction
| FuncKind::FunctionOperator(..)
| FuncKind::InstanceOperator(..) => {
let out = TypeRef::new_ext(
entity.get_result_type().expect("Can't get return type"),
TypeRefTypeHint::PrimitiveRefAsPointer,
None,
gen_env,
);
out.as_reference().unwrap_or(out)
}
if let Some(type_ref) = out.as_reference() {
type_ref
} else {
out
};
if let Some(type_hint) = settings::ARGUMENT_OVERRIDE
.get(&self.func_id())
.and_then(|x| x.get(RETURN_HINT))
{
out.set_type_hint(type_hint.clone());
// if we're returning a BoxedRef then assign its mutability to the mutability of the borrowed argument
if let TypeRefTypeHint::BoxedAsRef(borrow_arg_name, _) = type_hint {
let args = self.arguments();
let borrow_arg = args
.iter()
.find(|arg| arg.cpp_name(CppNameStyle::Declaration) == *borrow_arg_name);
if let Some(borrow_arg) = borrow_arg {
out.set_inherent_constness(borrow_arg.type_ref().constness());
}
}
}
},
out
}
Self::Desc(desc) => desc.return_type_ref.clone(),
}
}
Expand Down
26 changes: 16 additions & 10 deletions binding-generator/src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ pub trait TypeRefRenderer<'a> {
type Recursed: TypeRefRenderer<'a> + Sized;

fn render<'t>(self, type_ref: &'t TypeRef) -> Cow<'t, str>;
fn recurse(&self) -> Self::Recursed;
fn recurse(self) -> Self::Recursed;
fn recursed(&self) -> Self::Recursed;
}

#[derive(Debug)]
Expand Down Expand Up @@ -47,11 +48,8 @@ impl<'a> TypeRefRenderer<'a> for CppRenderer<'_> {
if self.name.is_empty() {
format!("{cnst}{typ}**", typ = inner.render(self.recurse()))
} else {
format!(
"{cnst}{typ}(*{name})[{size}]",
typ = inner.render(self.recurse()),
name = self.name
)
let name = self.name;
format!("{cnst}{typ}(*{name})[{size}]", typ = inner.render(self.recurse()))
}
} else {
format!("{typ}*{space_name}", typ = inner.render(self.recurse()))
Expand All @@ -72,7 +70,7 @@ impl<'a> TypeRefRenderer<'a> for CppRenderer<'_> {
// fixme: hack to keep backwards compatible behavior after tuple rendering changes
// ideal fix would be to use CppName::Reference in the recurse() function globally
// but it changes the function identifier generation
let mut renderer = self.recurse();
let mut renderer = self.recursed();
renderer.name_style = CppNameStyle::Reference;
tref.render(renderer)
})
Expand Down Expand Up @@ -138,7 +136,11 @@ impl<'a> TypeRefRenderer<'a> for CppRenderer<'_> {
.into()
}

fn recurse(&self) -> Self {
fn recurse(self) -> Self {
self.recursed()
}

fn recursed(&self) -> Self::Recursed {
Self {
name_style: self.name_style,
name: "",
Expand All @@ -164,7 +166,11 @@ impl<'a> TypeRefRenderer<'a> for CppExternReturnRenderer {
self.recurse().render(over.as_ref().unwrap_or(type_ref)).into_owned().into()
}

fn recurse(&self) -> Self::Recursed {
fn recurse(self) -> Self::Recursed {
self.recursed()
}

fn recursed(&self) -> Self::Recursed {
CppRenderer::new(CppNameStyle::Reference, "", true)
}
}
Expand All @@ -175,7 +181,7 @@ fn render_cpp_tpl<'a>(renderer: impl TypeRefRenderer<'a>, type_ref: &TypeRef) ->
let generic_types = generic_types
.iter()
.filter_map(|t| match t {
TemplateArg::Typename(type_ref) => Some(type_ref.render(renderer.recurse())),
TemplateArg::Typename(type_ref) => Some(type_ref.render(renderer.recursed())),
TemplateArg::Constant(literal) => Some(literal.into()),
TemplateArg::Unknown => None,
})
Expand Down
13 changes: 13 additions & 0 deletions binding-generator/src/settings/argument_override.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::collections::HashMap;
use once_cell::sync::Lazy;

use crate::type_ref::TypeRefTypeHint;
use crate::writer::rust_native::type_ref::Lifetime;
use crate::FuncId;

pub const RETURN_HINT: &str = "return";
Expand Down Expand Up @@ -37,6 +38,18 @@ pub static ARGUMENT_OVERRIDE: Lazy<HashMap<FuncId, HashMap<&str, TypeRefTypeHint
FuncId::new_mut("cv::Mat::Mat", ["ndims", "sizes", "type", "data", "steps"]),
HashMap::from([("steps", TypeRefTypeHint::NullableSlice)]),
),
(
FuncId::new_mut("cv::Mat::Mat", ["m", "roi"]),
HashMap::from([(RETURN_HINT, TypeRefTypeHint::BoxedAsRef("m", Lifetime::Elided))]),
),
(
FuncId::new_mut("cv::Mat::Mat", ["m"]),
HashMap::from([(RETURN_HINT, TypeRefTypeHint::BoxedAsRef("m", Lifetime::Elided))]),
),
(
FuncId::new_mut("cv::Mat::Mat", ["m", "rowRange", "colRange"]),
HashMap::from([(RETURN_HINT, TypeRefTypeHint::BoxedAsRef("m", Lifetime::Custom("boxed")))]),
),
(
FuncId::new_mut(
"cv::createTrackbar",
Expand Down
1 change: 1 addition & 0 deletions binding-generator/src/settings/func_exclude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub static FUNC_EXCLUDE: Lazy<HashSet<&str>> = Lazy::new(|| {
"cv_setUseCollection_bool",
"cv_useCollection",
"cv_vconcat_const_MatX_size_t_const__OutputArrayR", // duplicate of cv_vconcat_VectorOfMat_Mat, but with pointers
"cv_Mat_Mat_MatRR", // Mat::copy that takes arg by value
// ### cudaimgproc ###
"cv_cuda_histEven_const__InputArrayR_GpuMatXX_intXX_intXX_intXX_StreamR", // slice of boxed objects
"cv_cuda_histRange_const__InputArrayR_GpuMatXX_const_GpuMatXX_StreamR", // slice of boxed objects
Expand Down
Loading

0 comments on commit 7e94842

Please sign in to comment.