opencv-binding-generator 0.55.0

Binding generator for opencv crate
Documentation
use std::borrow::Cow;
use std::collections::HashSet;

use maplit::hashmap;
use once_cell::sync::Lazy;

use crate::type_ref::{Constness, FishStyle};
use crate::{CompiledInterpolation, CppNameStyle, FunctionTypeHint, IteratorExt, NameStyle, StrExt, Tuple, TypeRef};

use super::element::{DefaultRustNativeElement, RustElement};
use super::func::disambiguate_single_name;
use super::func_desc::{ClassDesc, CppFuncDesc, FuncDescCppCall, FuncDescKind};
use super::type_ref::TypeRefExt;
use super::RustNativeGeneratedElement;

impl RustElement for Tuple<'_, '_> {
	fn rust_module(&self) -> Cow<str> {
		DefaultRustNativeElement::rust_module(self)
	}

	fn rust_name(&self, style: NameStyle) -> Cow<str> {
		DefaultRustNativeElement::rust_name(self, style)
	}

	fn rust_leafname(&self, fish_style: FishStyle) -> Cow<str> {
		format!(
			"Tuple{fish}<{inner}>",
			fish = fish_style.rust_qual(),
			inner = self.rust_inner()
		)
		.into()
	}

	fn rendered_doc_comment_with_prefix(&self, prefix: &str, opencv_version: &str) -> String {
		DefaultRustNativeElement::rendered_doc_comment_with_prefix(self, prefix, opencv_version)
	}
}

impl RustNativeGeneratedElement for Tuple<'_, '_> {
	fn element_safe_id(&self) -> String {
		format!("{}-{}", self.rust_element_module(), self.rust_localalias())
	}

	fn gen_rust(&self, _opencv_version: &str) -> String {
		static RUST_TPL: Lazy<CompiledInterpolation> = Lazy::new(|| include_str!("tpl/tuple/rust.tpl.rs").compile_interpolation());

		let rust_localalias = self.rust_localalias();

		let mut rets = disambiguate_single_name("arg");

		let getters = self
			.elements()
			.into_iter()
			.enumerate()
			.map(|(i, typ)| {
				let ret_name = rets.next().expect("Endless iterator");
				format!(
					"{num} = {ret_name}: {typ}, get_{num} via cv_{alias}_get_{num}",
					num = i,
					ret_name = ret_name,
					typ = typ.rust_name(NameStyle::ref_()),
					alias = rust_localalias,
				)
			})
			.join(",\n");

		RUST_TPL.interpolate(&hashmap! {
			"rust_localalias" => rust_localalias,
			"rust_full" => self.rust_name(NameStyle::ref_()),
			"inner_rust_full" => self.rust_inner().into(),
			"getters" => getters.into(),
		})
	}

	fn gen_cpp(&self) -> String {
		static CPP_TPL: Lazy<CompiledInterpolation> = Lazy::new(|| include_str!("tpl/tuple/cpp.tpl.cpp").compile_interpolation());

		let type_ref = self.type_ref();

		let rust_localalias = self.rust_localalias();
		let elements = self.elements();
		let tuple_desc = ClassDesc {
			is_boxed: true,
			cpp_name_ref: type_ref.cpp_name(CppNameStyle::Reference).into_owned(),
		};
		let void = self.gen_env.resolve_typeref("void");
		let mut methods = vec![
			method_new(&rust_localalias, &type_ref, self.tuple_type, &elements),
			method_delete(&rust_localalias, &tuple_desc, &void),
		];

		for (i, typ) in elements.into_iter().enumerate() {
			methods.push(method_get(&rust_localalias, &tuple_desc, &typ, i));
		}

		CPP_TPL.interpolate(&hashmap! {
			"methods" => methods.join(""),
		})
	}
}

pub trait TupleExt {
	fn rust_localalias(&self) -> Cow<str>;
	fn rust_inner(&self) -> String;
	fn rust_element_module(&self) -> Cow<str>;
}

impl TupleExt for Tuple<'_, '_> {
	fn rust_localalias(&self) -> Cow<str> {
		format!(
			"TupleOf{typ}",
			typ = self
				.elements()
				.into_iter()
				.map(|e| e.rust_safe_id(true).into_owned())
				.join("_")
		)
		.into()
	}

	fn rust_inner(&self) -> String {
		let mut out = "(".to_string();
		out.push_str(
			&self
				.elements()
				.into_iter()
				.map(|e| e.rust_name(NameStyle::ref_()).into_owned())
				.join(", "),
		);
		out.push(')');
		out
	}

	fn rust_element_module(&self) -> Cow<str> {
		let mut elem_modules = self
			.elements()
			.into_iter()
			.map(|elem_type| elem_type.rust_module().into_owned())
			.collect::<HashSet<_>>()
			.into_iter()
			.filter(|m| m != "core")
			.collect::<Vec<_>>();
		if let Some(module) = elem_modules.pop() {
			if elem_modules.is_empty() {
				module.into()
			} else {
				panic!("Too many element modules: {module:?} + {elem_modules:?}")
			}
		} else {
			self.rust_module()
		}
	}
}

fn method_new(rust_localalias: &str, tuple_typeref: &TypeRef, tuple_type: &str, elements: &[TypeRef]) -> String {
	let arguments = disambiguate_single_name("arg")
		.zip(elements.iter())
		.map(|(arg_name, type_ref)| (arg_name, type_ref.clone()))
		.collect();
	CppFuncDesc {
		extern_name: format!("cv_{rust_localalias}_new").into(),
		constness: Constness::Const,
		is_infallible: true,
		is_naked_return: true,
		return_type: tuple_typeref.clone(),
		kind: FuncDescKind::Function,
		type_hint: FunctionTypeHint::None,
		call: FuncDescCppCall::Manual(
			format!("std::make_{tuple_type}({{{{args}}}})").compile_interpolation(),
		),
		debug: "".to_string(),
		arguments,
	}
	.gen_cpp()
}

fn method_delete(rust_localalias: &str, tuple_desc: &ClassDesc, void: &TypeRef) -> String {
	CppFuncDesc {
		extern_name: format!("cv_{rust_localalias}_delete").into(),
		constness: Constness::Mut,
		is_infallible: true,
		is_naked_return: true,
		return_type: void.clone(),
		kind: FuncDescKind::InstanceMethod(tuple_desc.clone()),
		type_hint: FunctionTypeHint::None,
		call: FuncDescCppCall::Manual("delete instance".compile_interpolation()),
		debug: "".to_string(),
		arguments: vec![],
	}
	.gen_cpp()
}

fn method_get(rust_localalias: &str, tuple_desc: &ClassDesc, element_type: &TypeRef, num: usize) -> String {
	CppFuncDesc {
		extern_name: format!("cv_{rust_localalias}_get_{num}").into(),
		constness: Constness::Const,
		is_infallible: true,
		is_naked_return: false,
		return_type: element_type.clone(),
		kind: FuncDescKind::InstanceMethod(tuple_desc.clone()),
		type_hint: FunctionTypeHint::None,
		call: FuncDescCppCall::Manual(format!("std::get<{num}>(*instance)").compile_interpolation()),
		debug: "".to_string(),
		arguments: vec![],
	}
	.gen_cpp()
}