已合并
docs(hicc): README与reference补充owned_ptr使用文档, 移除into_unique方案 #130
docs(hicc): README与reference补充owned_ptr使用文档, 移除into_unique方案 #130
已合并
hunting创建于 9月10日
共 13 个文件变更+622-32
@@ -360,7 +360,10 @@ impl FuncInfo {
360 360 
361 Some(Self {361 Some(Self {
362 is_dynamic_cast: matches!(sig.marker, Some(cpp::Marker::DynamicCast)),362 is_dynamic_cast: matches!(sig.marker, Some(cpp::Marker::DynamicCast)),
363- is_make_proxy: matches!(sig.marker, Some(cpp::Marker::MakeProxy { leading: true, .. })),363+ is_make_proxy: matches!(
364+ sig.marker,
365+ Some(cpp::Marker::MakeProxy { leading: true, .. })
366+ ),
364 is_embedded_proxy: false,367 is_embedded_proxy: false,
365 is_variadic: sig.variadic,368 is_variadic: sig.variadic,
366 is_ref_self,369 is_ref_self,
@@ -406,6 +409,15 @@ pub(super) struct Function<'a> {
406 409 
407impl<'a> Function<'a> {410impl<'a> Function<'a> {
408 pub fn try_from(f: &'a ImportFn) -> syn::Result<Self> {411 pub fn try_from(f: &'a ImportFn) -> syn::Result<Self> {
412+ Self::try_from_with(f, None)
413+ }
414+ 
415+ /// `self_alias`: impl/class 块内提升函数(带 member 属性)的 `Self` 占位符替身名。
416+ /// 仅自由函数导出路径(ExportLib::export)传入; 类成员方法的 `Self` 由类适配
417+ /// 作用域的 `typedef X Self;` 解析, 类管线经 `try_from` 传 None。
418+ /// 替换必须在签名解析前完成, 使后续按字节偏移的切片(ret_str/限定名/参数名)
419+ /// 与替换后的新串一致。
420+ pub fn try_from_with(f: &'a ImportFn, self_alias: Option<&str>) -> syn::Result<Self> {
409 let Some(attr) = Attr::get_attr("cpp", &f.attrs) else {421 let Some(attr) = Attr::get_attr("cpp", &f.attrs) else {
410 return Err(syn::Error::new(f.ident.span(), "not found #[cpp(...)]"));422 return Err(syn::Error::new(f.ident.span(), "not found #[cpp(...)]"));
411 };423 };
@@ -435,6 +447,11 @@ impl<'a> Function<'a> {
435 };447 };
436 let line = attr.span().start().line;448 let line = attr.span().start().line;
437 let input = input.trim();449 let input = input.trim();
450+ let input = match self_alias {
451+ Some(alias) => crate::utils::replace_ident_token(input, "Self", alias),
452+ None => input.to_string(),
453+ };
454+ let input = input.as_str();
438 // 嵌入形态: `@make_proxy<T>` 非首 token 时替换为 proxy 具体类型, 其余按普通函数导出455 // 嵌入形态: `@make_proxy<T>` 非首 token 时替换为 proxy 具体类型, 其余按普通函数导出
439 let raw = input;456 let raw = input;
440 let input = Self::substitute_embedded_proxy(input);457 let input = Self::substitute_embedded_proxy(input);
@@ -481,7 +498,10 @@ impl<'a> Function<'a> {
481 498 
482 /// `R T<..>::f(...)` 的 `T`(末段标识符, 去模板实参)499 /// `R T<..>::f(...)` 的 `T`(末段标识符, 去模板实参)
483 pub fn cpp_qualifier(&self) -> Option<String> {500 pub fn cpp_qualifier(&self) -> Option<String> {
484- self.sig.name.qualifier_bare_name(&self.input).map(str::to_string)501+ self.sig
502+ .name
503+ .qualifier_bare_name(&self.input)
504+ .map(str::to_string)
485 }505 }
486 506 
487 pub fn with_protected(mut self, protected: bool) -> Self {507 pub fn with_protected(mut self, protected: bool) -> Self {
@@ -600,7 +620,11 @@ impl<'a> Function<'a> {
600 let scope = self.scope();620 let scope = self.scope();
601 let line = self.line;621 let line = self.line;
602 622 
603- let ptr_scope = if self.cpp_info.is_member { "Self::" } else { "" };623+ let ptr_scope = if self.cpp_info.is_member {
624+ "Self::"
625+ } else {
626+ ""
627+ };
604 let name = self.qualified_name();628 let name = self.qualified_name();
605 let after_name = &self.input[self.sig.name.span.end..];629 let after_name = &self.input[self.sig.name.span.end..];
606 Ok(format!(630 Ok(format!(
@@ -786,10 +810,10 @@ impl<'a> Function<'a> {
786 if sig.qualifiers_span.end != self.input.len() {810 if sig.qualifiers_span.end != self.input.len() {
787 return Err(syn::Error::new(self.span, self.error_dynamic()));811 return Err(syn::Error::new(self.span, self.error_dynamic()));
788 }812 }
789- let path_of = |ty: &cpp::Type| -> Option<String> {813+ let path_of =
790- Some(ty.class_path()?.to_string(&self.input))814+ |ty: &cpp::Type| -> Option<String> { Some(ty.class_path()?.to_string(&self.input)) };
791- };815+ let ret =
792- let ret = path_of(&sig.ret).ok_or_else(|| syn::Error::new(self.span, self.error_dynamic()))?;816+ path_of(&sig.ret).ok_or_else(|| syn::Error::new(self.span, self.error_dynamic()))?;
793 let input = sig817 let input = sig
794 .params818 .params
795 .first()819 .first()
@@ -1,7 +1,7 @@
1use crate::{Attr, ImportClass, ImportFn, ImportLib};1use crate::{Attr, ImportClass, ImportFn, ImportLib};
2 2 
3-mod token;
4pub(crate) mod cpp;3pub(crate) mod cpp;
4+mod token;
5pub(crate) use function::Arg;5pub(crate) use function::Arg;
6use token::*;6use token::*;
7 7 
@@ -74,7 +74,9 @@ impl ImportLib {
74 let Some(member) = Attr::get_attr("member", &f.attrs) else {74 let Some(member) = Attr::get_attr("member", &f.attrs) else {
75 continue;75 continue;
76 };76 };
77- let (Ok(Some(cls)), Ok(Some(method))) = (member.value("class"), member.value("method")) else {77+ let (Ok(Some(cls)), Ok(Some(method))) =
78+ (member.value("class"), member.value("method"))
79+ else {
78 continue;80 continue;
79 };81 };
80 if cpp::strip_template_args(cls).trim() == class_ident {82 if cpp::strip_template_args(cls).trim() == class_ident {
@@ -267,11 +269,33 @@ impl ExportLib {
267 "#line {}\nEXPORT_METHODS_BEG({}) {{\n",269 "#line {}\nEXPORT_METHODS_BEG({}) {{\n",
268 self.line, self.link270 self.line, self.link
269 ));271 ));
272+ // impl/class 块内提升函数的 Self 替身 typedef: 注入导出表 struct 体内。
273+ // 成员 typedef 非数据成员, 不影响 const void* 平铺布局(rust 侧 #[repr(C)]
274+ // 字段对位不变); NSDMI 条目初始化处于 complete-class context, 可见该 typedef。
275+ codes.push_str(&self.self_typedefs());
270 276 
271 let statics = self.imported.collect_protected_statics()?;277 let statics = self.imported.collect_protected_statics()?;
272 for f in self.imported.funcs.iter() {278 for f in self.imported.funcs.iter() {
273 let is_protected = statics.iter().any(|(_, p)| p.ident == f.ident);279 let is_protected = statics.iter().any(|(_, p)| p.ident == f.ident);
274- let f = Function::try_from(f)?.with_protected(is_protected);280+ // 泛型类实例的 Self 无法解析: 条目以空指针占位, 保持导出表 ABI 对位
281+ // 与 build.rs 阶段 C++ 可编译性; Rust 侧由 generate() 宏级编译错误拦截。
282+ // 非 member 函数的裸 Self 维持既有失败路径, 不在此占位。
283+ let member_class = Attr::get_attr("member", &f.attrs)
284+ .and_then(|m| m.value("class").ok().flatten().map(str::to_string));
285+ let unresolvable = ImportLib::cpp_sig_has_self(f)
286+ && member_class
287+ .as_deref()
288+ .map(|c| self.imported.cpp_type_of(c).is_none())
289+ .unwrap_or(false);
290+ if unresolvable {
291+ codes.push_str("EXPORT_METHOD_IN(void, ExportMethods, (0));\n");
292+ continue;
293+ }
294+ let self_alias = member_class
295+ .as_deref()
296+ .filter(|c| self.imported.cpp_type_of(c).is_some())
297+ .map(crate::utils::self_alias_ident);
298+ let f = Function::try_from_with(f, self_alias.as_deref())?.with_protected(is_protected);
275 codes.push_str(&f.export_test()?);299 codes.push_str(&f.export_test()?);
276 codes.push_str(&f.export()?);300 codes.push_str(&f.export()?);
277 }301 }
@@ -279,6 +303,35 @@ impl ExportLib {
279 codes.push_str(&format!("#line {}\n}} EXPORT_METHODS_END();\n", self.line));303 codes.push_str(&format!("#line {}\n}} EXPORT_METHODS_END();\n", self.line));
280 Ok(codes)304 Ok(codes)
281 }305 }
306+ 
307+ /// 收集 cpp 串实际含整词 `Self` 占位符的提升函数(member 属性), 按类去重后
308+ /// 输出 `typedef {Cpp类型} {别名};` 行。无 Self 的 member 函数(如 hicc-std
309+ /// 类内提升)不发 typedef, 保证其生成物与既有输出一致。
310+ fn self_typedefs(&self) -> String {
311+ let mut codes = String::new();
312+ let mut seen: Vec<String> = vec![];
313+ for f in &self.imported.funcs {
314+ if !ImportLib::cpp_sig_has_self(f) {
315+ continue;
316+ }
317+ let Some(member) = Attr::get_attr("member", &f.attrs) else {
318+ continue;
319+ };
320+ let Ok(Some(class)) = member.value("class") else {
321+ continue;
322+ };
323+ let alias = crate::utils::self_alias_ident(class);
324+ if seen.contains(&alias) {
325+ continue;
326+ }
327+ let Some(cpp_ty) = self.imported.cpp_type_of(class) else {
328+ continue;
329+ };
330+ codes.push_str(&format!("typedef {} {};\n", cpp_ty, alias));
331+ seen.push(alias);
332+ }
333+ codes
334+ }
282}335}
283 336 
284#[cfg(test)]337#[cfg(test)]
@@ -970,3 +970,143 @@ fn make_proxy_embedded_multi_template_args_params_match_single() {
970 "模板实参数量不影响形参注入: {multi}"970 "模板实参数量不影响形参注入: {multi}"
971 );971 );
972}972}
973+ 
974+#[test]
975+fn impl_block_self_uses_unique_alias() {
976+ let lib = parse_lib(
977+ r#"
978+ #![link_name = "example"]
979+ #[cpp(class = "Foo")]
980+ class Foo {}
981+ impl Foo {
982+ #[cpp(func = "Self hicc::make_constructor<Self>(const Self&)")]
983+ pub fn make_clone(this: &Self) -> Self;
984+ }
985+ "#,
986+ );
987+ let codes = lib.export().unwrap();
988+ assert!(
989+ codes.contains("typedef Foo _hicc_self_Foo;"),
990+ "导出表 struct 体内应注入按类唯一的替身 typedef: {codes}"
991+ );
992+ assert!(
993+ codes.contains(
994+ "(_hicc_self_Foo (*)(const _hicc_self_Foo&))&hicc::make_constructor<_hicc_self_Foo>"
995+ ),
996+ "条目 C++ 签名中的 Self 应整词替换为替身: {codes}"
997+ );
998+ assert!(
999+ codes.contains("_hicc_self_Foo (* _"),
1000+ "取址测试函数同样使用替身: {codes}"
1001+ );
1002+ assert!(
1003+ !codes.contains("make_constructor<Self>") && !codes.contains("(Self (*)(const Self&))"),
1004+ "导出表内不应残留裸 Self: {codes}"
1005+ );
1006+ assert!(
1007+ codes.contains("typedef Foo Self;"),
1008+ "类适配区仍走类内 typedef Self 机制, 不受影响: {codes}"
1009+ );
1010+ assert!(
1011+ codes.contains(
1012+ "((_hicc_self_Foo (*)(const _hicc_self_Foo&))&hicc::make_constructor<_hicc_self_Foo>)"
1013+ ),
1014+ "条目 C++ 签名中的 Self 应整词替换为替身: {codes}"
1015+ );
1016+}
1017+ 
1018+#[test]
1019+fn impl_block_multiple_classes_get_distinct_aliases() {
1020+ let lib = parse_lib(
1021+ r#"
1022+ #![link_name = "example"]
1023+ #[cpp(class = "Foo")]
1024+ class Foo {}
1025+ #[cpp(class = "Bar")]
1026+ class Bar {}
1027+ impl Foo {
1028+ #[cpp(func = "Self hicc::make_constructor<Self>(const Self&)")]
1029+ pub fn make_foo(this: &Self) -> Self;
1030+ }
1031+ impl Bar {
1032+ #[cpp(func = "Self hicc::make_constructor<Self>(const Self&)")]
1033+ pub fn make_bar(this: &Self) -> Self;
1034+ }
1035+ "#,
1036+ );
1037+ let codes = lib.export().unwrap();
1038+ assert!(codes.contains("typedef Foo _hicc_self_Foo;"), "{codes}");
1039+ assert!(codes.contains("typedef Bar _hicc_self_Bar;"), "{codes}");
1040+ assert!(
1041+ !codes.contains("make_constructor<Self>"),
1042+ "多类并存时导出表内不得残留裸 Self: {codes}"
1043+ );
1044+}
1045+ 
1046+#[test]
1047+fn member_fn_without_self_token_keeps_cpp_string() {
1048+ let lib = parse_lib(
1049+ r#"
1050+ #![link_name = "example"]
1051+ #[cpp(class = "Foo")]
1052+ class Foo {}
1053+ impl Foo {
1054+ #[cpp(func = "Foo hicc::make_constructor<Foo>(int)")]
1055+ pub fn make(v: i32) -> Self;
1056+ }
1057+ "#,
1058+ );
1059+ let codes = lib.export().unwrap();
1060+ assert!(
1061+ codes.contains("(Foo (*)(int))&hicc::make_constructor<Foo>"),
1062+ "无 Self 占位符的 cpp 串应原样重构, 不受替身机制影响: {codes}"
1063+ );
1064+}
1065+ 
1066+#[test]
1067+fn generic_impl_self_uses_placeholder_entry() {
1068+ let lib = parse_lib(
1069+ r#"
1070+ #![link_name = "example"]
1071+ #[cpp(class = "template<class T> Foo<T>")]
1072+ class Foo<T> {}
1073+ impl Foo<i32> {
1074+ #[cpp(func = "Self hicc::make_constructor<Self>(const Self&)")]
1075+ pub fn make_clone(this: &Self) -> Self;
1076+ }
1077+ "#,
1078+ );
1079+ let codes = lib.export().unwrap();
1080+ assert!(
1081+ codes.contains("EXPORT_METHOD_IN(void, ExportMethods, (0));"),
1082+ "泛型实例条目以空指针占位, 保持导出表 ABI 对位: {codes}"
1083+ );
1084+ assert!(
1085+ !codes.contains("_hicc_self_"),
1086+ "泛型实例不发替身 typedef 也不替换别名(类适配区的 typedef Self 不受影响): {codes}"
1087+ );
1088+ assert!(
1089+ !codes.contains("_hicc_test_6"),
1090+ "占位条目不生成取址测试函数: {codes}"
1091+ );
1092+}
1093+ 
1094+#[test]
1095+fn generic_impl_with_concrete_cpp_ty_exports_normally() {
1096+ let lib = parse_lib(
1097+ r#"
1098+ #![link_name = "example"]
1099+ #[cpp(class = "template<class T> Foo<T>")]
1100+ class Foo<T> {}
1101+ impl Foo<i32> {
1102+ #[cpp(func = "Foo<int> hicc::make_constructor<Foo<int>>(const Foo<int>&)")]
1103+ pub fn make_clone(this: &Self) -> Self;
1104+ }
1105+ "#,
1106+ );
1107+ let codes = lib.export().unwrap();
1108+ assert!(
1109+ codes.contains("((Foo<int> (*)(const Foo<int>&))&hicc::make_constructor<Foo<int>>)"),
1110+ "直写具体类型的泛型 impl 条目正常发射: {codes}"
1111+ );
1112+}
@@ -116,6 +116,7 @@ impl ImportLib {
116 return Err(syn::Error::new(f.ident.span(), msg));116 return Err(syn::Error::new(f.ident.span(), msg));
117 }117 }
118 }118 }
119+ self.check_self_usages()?;
119 let mut codes = self120 let mut codes = self
120 .items121 .items
121 .iter()122 .iter()
@@ -441,6 +442,82 @@ impl ImportLib {
441 issues442 issues
442 }443 }
443 444 
445+ /// 函数 cpp 串是否含整词 `Self` 占位符。
446+ /// 提升函数(impl/class 块关联函数)的 cpp 属性恒为 `func` 键(method 仅用于
447+ /// 带 receiver 的类成员方法, 不进入提升路径)。
448+ pub(crate) fn cpp_sig_has_self(f: &ImportFn) -> bool {
449+ let Some(attr) = Attr::get_attr("cpp", &f.attrs) else {
450+ return false;
451+ };
452+ attr.value("func")
453+ .ok()
454+ .flatten()
455+ .is_some_and(|v| crate::utils::replace_ident_token(v, "Self", "") != v)
456+ }
457+ 
458+ /// member(class = ...) 字符串对应的 C++ 类型名: base 类名(去模板实参)命中
459+ /// DSL 声明类时取其 `#[cpp(class = ...)]` 值; 模板模式(以 template 开头)
460+ /// 无具体实例可 typedef, 返回 None 跳过; 未在 DSL 声明的类型按 member 原文
461+ /// 使用(由用户保证 C++ 可见性, 与 cpp 串直写具体类型的既有契约一致)。
462+ pub(crate) fn cpp_type_of(&self, class_str: &str) -> Option<String> {
463+ let base = class_str.split('<').next().unwrap_or(class_str);
464+ for c in &self.classes {
465+ if c.ident == base {
466+ let v = Attr::get_attr("cpp", &c.attrs)
467+ .and_then(|a| a.value("class").ok().flatten().map(|v| v.to_string()))
468+ .unwrap_or_else(|| c.ident.to_string());
469+ return if v.trim_start().starts_with("template") {
470+ None
471+ } else {
472+ Some(v)
473+ };
474+ }
475+ }
476+ Some(class_str.to_string())
477+ }
478+ 
479+ /// 泛型类(模板模式声明)实例的 impl 块函数在 cpp 串使用 `Self` 占位符:
480+ /// 导出表作用域无法解析出具体模板实例, 宏展开期即报 Rust 编译错误
481+ /// (指向 cpp 属性所在行, 先于 build.rs 的 C++ 编译), 指引在 cpp 串中
482+ /// 直写具体 C++ 类型(如 `Foo<int>`)。多个违规函数聚合为一个错误。
483+ pub(crate) fn check_self_usages(&self) -> parse::Result<()> {
484+ let mut errs: Option<syn::Error> = None;
485+ for f in &self.funcs {
486+ if !Self::cpp_sig_has_self(f) {
487+ continue;
488+ }
489+ let Some(member) = Attr::get_attr("member", &f.attrs) else {
490+ continue;
491+ };
492+ let Ok(Some(class)) = member.value("class") else {
493+ continue;
494+ };
495+ if self.cpp_type_of(class).is_some() {
496+ continue;
497+ }
498+ let span = Attr::get_attr("cpp", &f.attrs)
499+ .map(|a| a.span())
500+ .unwrap_or_else(|| f.ident.span());
501+ let e = syn::Error::new(
502+ span,
503+ format!(
504+ "`Self` placeholder in cpp signature is not supported for generic class `{class}`: write the concrete C++ type (e.g. `Foo<int>`) instead"
505+ ),
506+ );
507+ errs = Some(match errs {
508+ Some(mut prev) => {
509+ prev.combine(e);
510+ prev
511+ }
512+ None => e,
513+ });
514+ }
515+ match errs {
516+ Some(e) => Err(e),
517+ None => Ok(()),
518+ }
519+ }
520+ 
444 /// 在已解析的 DSL 类声明(classes)中, 按类名查找直接 trait。521 /// 在已解析的 DSL 类声明(classes)中, 按类名查找直接 trait。
445 fn derive_direct_intf(&self, class: &syn::Path) -> Option<&syn::Ident> {522 fn derive_direct_intf(&self, class: &syn::Path) -> Option<&syn::Ident> {
446 let name = class.segments.last()?.ident.clone();523 let name = class.segments.last()?.ident.clone();
@@ -1379,3 +1379,62 @@ fn lib_make_proxy_embedded_multi_template_args_bad_bound_errs() {
1379 };1379 };
1380 assert!(err.contains("not a direct or super trait"), "{err}");1380 assert!(err.contains("not a direct or super trait"), "{err}");
1381}1381}
1382+ 
1383+#[test]
1384+fn generic_impl_self_placeholder_is_compile_error() {
1385+ let lib: ImportLib = syn::parse_str(
1386+ r#"
1387+ #![link_name = "example"]
1388+ #[cpp(class = "template<class T> Foo<T>")]
1389+ class Foo<T> {}
1390+ impl Foo<i32> {
1391+ #[cpp(func = "Self hicc::make_constructor<Self>(const Self&)")]
1392+ pub fn make_clone(this: &Self) -> Self;
1393+ }
1394+ "#,
1395+ )
1396+ .unwrap();
1397+ let err = lib.generate().unwrap_err().to_string();
1398+ assert!(
1399+ err.contains("make_clone") || err.contains("Foo<i32>"),
1400+ "错误应含指引信息: {err}"
1401+ );
1402+ assert!(
1403+ err.contains("write the concrete C++ type"),
1404+ "错误应指引直写具体 C++ 类型: {err}"
1405+ );
1406+}
1407+ 
1408+#[test]
1409+fn generic_impl_concrete_cpp_ty_no_error() {
1410+ let lib: ImportLib = syn::parse_str(
1411+ r#"
1412+ #![link_name = "example"]
1413+ #[cpp(class = "template<class T> Foo<T>")]
1414+ class Foo<T> {}
1415+ impl Foo<i32> {
1416+ #[cpp(func = "Foo<int> hicc::make_constructor<Foo<int>>(const Foo<int>&)")]
1417+ pub fn make_clone(this: &Self) -> Self;
1418+ }
1419+ "#,
1420+ )
1421+ .unwrap();
1422+ lib.generate().unwrap();
1423+}
1424+ 
1425+#[test]
1426+fn non_generic_impl_self_no_error() {
1427+ let lib: ImportLib = syn::parse_str(
1428+ r#"
1429+ #![link_name = "example"]
1430+ #[cpp(class = "Foo")]
1431+ class Foo {}
1432+ impl Foo {
1433+ #[cpp(func = "Self hicc::make_constructor<Self>(const Self&)")]
1434+ pub fn make_clone(this: &Self) -> Self;
1435+ }
1436+ "#,
1437+ )
1438+ .unwrap();
1439+ lib.generate().unwrap();
1440+}
@@ -82,6 +82,54 @@ pub fn mangle_member_ident(class: &str, instance: Option<&str>, name: &str) -> s
82 }82 }
83}83}
84 84 
85+/// impl/class 块内提升为自由函数的关联函数, 其 `#[cpp(func/method)]` 串中的 `Self`
86+/// 占位符在导出表(自由函数)作用域的替身名: `_hicc_self_{class}`。
87+/// class 为 `#[member(class = ...)]` 字符串(已去空白); 非标识符字符净化为 `_`,
88+/// 保证不同泛型实例(`Foo<i32,i32>` 与 `Foo<i32,f64>`)互不冲突。
89+/// 配对机制: ExportLib::export 在导出表 struct 体内注入 `typedef {Cpp类型} {别名};`,
90+/// 类型本身(可能含逗号)只出现在 typedef 定义处, 不经过 C++ 预处理器宏参数切分。
91+pub fn self_alias_ident(class_str: &str) -> String {
92+ let sanitized: String = class_str
93+ .chars()
94+ .map(|c| {
95+ if c.is_alphanumeric() || c == '_' {
96+ c
97+ } else {
98+ '_'
99+ }
100+ })
101+ .collect();
102+ format!("_hicc_self_{}", sanitized)
103+}
104+ 
105+/// 整词替换标识符 `word`(前后均非 [A-Za-z0-9_]), 不误伤 `MySelf`/`SelfX` 等子串。
106+/// 多字节 UTF-8 序列整体拷贝, 不破坏非 ASCII 内容。
107+pub fn replace_ident_token(s: &str, word: &str, alias: &str) -> String {
108+ let b = s.as_bytes();
109+ let wb = word.as_bytes();
110+ let is_ident_ch = |c: u8| c.is_ascii_alphanumeric() || c == b'_';
111+ let mut out = String::with_capacity(s.len() + alias.len());
112+ let mut i = 0;
113+ while i < b.len() {
114+ if b[i..].starts_with(wb)
115+ && (i == 0 || !is_ident_ch(b[i - 1]))
116+ && (i + wb.len() == b.len() || !is_ident_ch(b[i + wb.len()]))
117+ {
118+ out.push_str(alias);
119+ i += wb.len();
120+ } else {
121+ let start = i;
122+ i += 1;
123+ // 连续拷贝 UTF-8 续字节, 保持多字节字符完整
124+ while i < b.len() && (b[i] & 0b1100_0000) == 0b1000_0000 {
125+ i += 1;
126+ }
127+ out.push_str(&s[start..i]);
128+ }
129+ }
130+ out
131+}
132+ 
85pub fn last_seg(ty: &syn::Type) -> Option<&syn::PathSegment> {133pub fn last_seg(ty: &syn::Type) -> Option<&syn::PathSegment> {
86 match ty {134 match ty {
87 syn::Type::Path(tp) => tp.path.segments.last(),135 syn::Type::Path(tp) => tp.path.segments.last(),
@@ -119,3 +167,40 @@ pub fn stable_hex(input: &str) -> String {
119 h.write(input.as_bytes());167 h.write(input.as_bytes());
120 format!("{:016x}", h.finish())168 format!("{:016x}", h.finish())
121}169}
170+ 
171+#[cfg(test)]
172+mod tests {
173+ use super::*;
174+ 
175+ #[test]
176+ fn self_alias_ident_sanitizes_generic_args() {
177+ assert_eq!(self_alias_ident("Foo"), "_hicc_self_Foo");
178+ assert_eq!(self_alias_ident("Foo<i32,i32>"), "_hicc_self_Foo_i32_i32_");
179+ assert_ne!(
180+ self_alias_ident("Foo<i32,i32>"),
181+ self_alias_ident("Foo<i32,f64>"),
182+ "不同泛型实例的别名必须互异"
183+ );
184+ }
185+ 
186+ #[test]
187+ fn replace_ident_token_whole_word_only() {
188+ assert_eq!(replace_ident_token("Self", "Self", "X"), "X");
189+ assert_eq!(replace_ident_token("const Self&", "Self", "X"), "const X&");
190+ assert_eq!(
191+ replace_ident_token("make_constructor<Self>", "Self", "X"),
192+ "make_constructor<X>"
193+ );
194+ assert_eq!(
195+ replace_ident_token("MySelf SelfX Self", "Self", "X"),
196+ "MySelf SelfX X",
197+ "标识符子串不得误伤"
198+ );
199+ assert_eq!(replace_ident_token("SelfSelf", "Self", "X"), "SelfSelf");
200+ assert_eq!(
201+ replace_ident_token("/* Self 中文 */ Self", "Self", "X"),
202+ "/* X 中文 */ X",
203+ "多字节 UTF-8 内容不受影响"
204+ );
205+ }
206+}
@@ -1,5 +1,3 @@
1-use hicc::AbiClass;
2- 
3hicc::cpp! {1hicc::cpp! {
4 2 
5class Foo {3class Foo {
@@ -31,7 +29,13 @@ hicc::import_class! {
31hicc::import_lib! {29hicc::import_lib! {
32 #![link_name = "example"]30 #![link_name = "example"]
33 31 
34- #[cpp(func = "Foo* Foo::new_instance()")]32+ // 将返回类型包装为hicc::owned_ptr<T>, Rust侧获得C++资源的所有权.
33+ cpp! {
34+ static hicc::owned_ptr<Foo> new_foo() {
35+ return Foo::new_instance();
36+ }
37+ }
38+ #[cpp(func = "hicc::owned_ptr<Foo> new_foo()")]
35 fn foo_new() -> Foo;39 fn foo_new() -> Foo;
36}40}
37 41 
@@ -40,9 +44,7 @@ fn main() {
40 44 
41 let mut foo = Foo::new();45 let mut foo = Foo::new();
42 foo.bar();46 foo.bar();
43- let mut foo = unsafe { foo.into_unique() };
44 foo.bar();47 foo.bar();
45- std::mem::drop(foo);
46 println!("exit");48 println!("exit");
47 49 
48 println!("=== [destroy] DONE ===");50 println!("=== [destroy] DONE ===");
@@ -30,7 +30,8 @@ hicc::cpp! {
30 // protected 构造 + protected 析构:30 // protected 构造 + protected 析构:
31 // - 构造: 只能经子类构造, @make_proxy 的 proxy 即子类, 天然可见;31 // - 构造: 只能经子类构造, @make_proxy 的 proxy 即子类, 天然可见;
32 // - 析构: 首 token 形态 @make_proxy 经 std::unique_ptr<T> 返回, 其 default_delete32 // - 析构: 首 token 形态 @make_proxy 经 std::unique_ptr<T> 返回, 其 default_delete
33- // 要求 ~T 可访问, 不兼容; 改用嵌入形态返回裸指针 + destroy 指定 protected 释放函数.33+ // 要求 ~T 可访问, 不兼容; 改用嵌入形态返回 hicc::owned_ptr<Guarded> 传递资源
34+ // 所有权 + destroy 指定 protected 释放函数.
34 struct Guarded {35 struct Guarded {
35 int tag;36 int tag;
36 virtual int vfn(int v) const {37 virtual int vfn(int v) const {
@@ -46,7 +47,7 @@ hicc::cpp! {
46 }47 }
47 };48 };
48 template <class P, class... A>49 template <class P, class... A>
49- static Guarded* new_guarded_raw(A&&... args) { return new P(std::forward<A>(args)...); }50+ static hicc::owned_ptr<Guarded> new_guarded(A&&... args) { return new P(std::forward<A>(args)...); }
50 51 
51 // 模板类: 同三种 protected 成员, 类型含模板参数52 // 模板类: 同三种 protected 成员, 类型含模板参数
52 template <typename T>53 template <typename T>
@@ -110,8 +111,9 @@ hicc::import_lib! {
110 #[cpp(class = "Guarded", ctor = "Guarded(int)", destroy = "Guarded::free", protected = "free")]111 #[cpp(class = "Guarded", ctor = "Guarded(int)", destroy = "Guarded::free", protected = "free")]
111 struct Guarded: GuardedTrait {}112 struct Guarded: GuardedTrait {}
112 113 
113- // 嵌入形态返回裸指针, 绕开 std::unique_ptr 对 ~T 的可访问性要求114+ // 嵌入形态返回 hicc::owned_ptr<Guarded>, C++ 侧适配并传递资源所有权,
114- #[cpp(func = "Guarded* new_guarded_raw<@make_proxy<Guarded>>(int)")]115+ // 绕开 std::unique_ptr 对 ~T 的可访问性要求
116+ #[cpp(func = "hicc::owned_ptr<Guarded> new_guarded<@make_proxy<Guarded>>(int)")]
115 fn new_guarded<I: GuardedTrait>(v: I, tag: i32) -> Guarded;117 fn new_guarded<I: GuardedTrait>(v: I, tag: i32) -> Guarded;
116 118 
117 #[interface]119 #[interface]
@@ -178,14 +180,12 @@ fn main() {
178 assert_eq!(p.nfn(1), 1);180 assert_eq!(p.nfn(1), 1);
179 assert!(p.as_rust::<RustBase>().is_some());181 assert!(p.as_rust::<RustBase>().is_some());
180 182 
181- // protected 构造/析构: 经 proxy 构造; 裸指针返回为借用语义, into_unique 接管183+ // protected 构造/析构: 经 proxy 构造; 工厂返回 owned_ptr 传递所有权,
182- // 所有权后 drop 经 Deleter<Guarded> → 桥 → protected free 释放184+ // drop 经 destroy 桥 → protected free 释放
183 {185 {
184 let g = new_guarded(RustGuarded, 7);186 let g = new_guarded(RustGuarded, 7);
185 assert_eq!(g.vfn(3), -3);187 assert_eq!(g.vfn(3), -3);
186 assert_eq!(g.as_super().vfn(3), 10);188 assert_eq!(g.as_super().vfn(3), 10);
187- let owned = unsafe { g.into_unique() };
188- drop(owned);
189 }189 }
190 190 
191 // 模板类: protected = "*" 全量191 // 模板类: protected = "*" 全量
@@ -123,6 +123,7 @@ fn main() {
123- **方法(有 `self`)**:以 `obj.fn_name(...)` 调用123- **方法(有 `self`)**:以 `obj.fn_name(...)` 调用
124- **泛型类**:支持 `class Generic<T> { ... }` 语法124- **泛型类**:支持 `class Generic<T> { ... }` 语法
125- **同名冲突**:不同 `class` 中的关联函数可同名,互不影响125- **同名冲突**:不同 `class` 中的关联函数可同名,互不影响
126+- **`Self` 占位符**:cpp 串中的 `Self` 仅**非泛型类**支持;泛型类实例(如 `impl Generic<int>`)的 cpp 串须直写具体 C++ 类型(如 `Generic<int>*`),使用 `Self` 会导致 Rust 编译错误(宏展开期报错,指向 cpp 属性所在行)
126 127 
127```rust128```rust
128hicc::cpp! {129hicc::cpp! {
@@ -492,14 +493,18 @@ impl Base {
492 493 
493名字在解析期校验:未知名字、类自身方法误入 `pure`、静态函数不在 `impl` 块内、`T::` 前缀不匹配均报错。模板类同样支持。494名字在解析期校验:未知名字、类自身方法误入 `pure`、静态函数不在 `impl` 块内、`T::` 前缀不匹配均报错。模板类同样支持。
494 495 
495-**构造与析构**:protected 构造函数对 `@make_proxy` 直接可用。protected 析构函数须经 `destroy = "Foo::free"` 释放(`free` 可列入 `protected`);此时首 token 形态 `T @make_proxy<T>(..)` 不适用(其 `std::unique_ptr<T>` 要求 `~T` 可访问),改用嵌入形态裸指针工厂 + `into_unique()` 接管所有权:496+**构造与析构**:protected 构造函数对 `@make_proxy` 直接可用。protected 析构函数须经 `destroy = "Foo::free"` 释放(`free` 可列入 `protected`);此时首 token 形态 `T @make_proxy<T>(..)` 不适用(其 `std::unique_ptr<T>` 要求 `~T` 可访问),改用嵌入形态工厂,并在 C++ 侧返回 `hicc::owned_ptr<Foo>` 传递资源所有权(推荐做法,参见上文「传递 C++ 资源所有权」):
496 497 
497```rust498```rust
498#[cpp(class = "Foo", ctor = "Foo(int)", destroy = "Foo::free", protected = "free")]499#[cpp(class = "Foo", ctor = "Foo(int)", destroy = "Foo::free", protected = "free")]
499struct Foo: FooTrait {}500struct Foo: FooTrait {}
500-#[cpp(func = "Foo* my_new<@make_proxy<Foo>>(int)")]501+ 
502+// C++ 侧适配函数返回 owned_ptr 传递所有权:
503+// template <class P, class... A>
504+// static hicc::owned_ptr<Foo> my_new(A&&... args) { return new P(std::forward<A>(args)...); }
505+#[cpp(func = "hicc::owned_ptr<Foo> my_new<@make_proxy<Foo>>(int)")]
501fn new_foo<I: FooTrait>(v: I, tag: i32) -> Foo;506fn new_foo<I: FooTrait>(v: I, tag: i32) -> Foo;
502-// let owned = unsafe { new_foo(impl, 7).into_unique() }; // drop → Foo::free → ~Foo507+// let foo = new_foo(impl, 7); // 拥有所有权, drop → Foo::free → ~Foo
503```508```
504 509 
505完整示例见 `hicc-examples/protected`(具体类 + 模板类,虚/非虚/静态 + protected 构造/析构)。510完整示例见 `hicc-examples/protected`(具体类 + 模板类,虚/非虚/静态 + protected 构造/析构)。
@@ -535,6 +540,65 @@ hicc::import_lib! {
535 540 
536工厂泛型 `bound` 可为直接接口或任一祖先(以类视角实参书写)。541工厂泛型 `bound` 可为直接接口或任一祖先(以类视角实参书写)。
537 542 
543+## 传递 C++ 资源所有权:`hicc::owned_ptr<T>`
544+ 
545+当 C++ 类的析构函数非公开(private/protected),必须经独立的静态函数释放资源时,用 `#[cpp(class = ..., destroy = ...)]` 声明释放函数;此时 C++ 侧资源创建函数的返回值应包装为 `hicc::owned_ptr<T>`(定义于 `<hicc/std/memory.hpp>`),标记返回的指针**拥有资源所有权**。Rust 侧接口的返回类型直接声明为映射的类类型,Rust 对象析构时自动调用 `destroy` 释放函数,避免资源泄露:
546+ 
547+```rust
548+hicc::cpp! {
549+ class Foo {
550+ ~Foo() {
551+ std::cout << "Foo::~Foo" << std::endl;
552+ }
553+ public:
554+ static Foo* new_instance() { return new Foo; }
555+ static void free_instance(Foo* foo) { delete foo; }
556+ void bar() const {
557+ std::cout << "Foo::bar" << std::endl;
558+ }
559+ };
560+}
561+ 
562+hicc::import_class! {
563+ #[cpp(class = "Foo", destroy = "Foo::free_instance")]
564+ class Foo {
565+ #[cpp(method = "void bar() const")]
566+ fn bar(&mut self);
567+ fn new() -> Self {
568+ foo_new()
569+ }
570+ }
571+}
572+ 
573+hicc::import_lib! {
574+ #![link_name = "example"]
575+ 
576+ // 将返回类型包装为hicc::owned_ptr<T>, Rust侧获得C++资源的所有权.
577+ cpp! {
578+ static hicc::owned_ptr<Foo> new_foo() {
579+ return Foo::new_instance();
580+ }
581+ }
582+ #[cpp(func = "hicc::owned_ptr<Foo> new_foo()")]
583+ fn foo_new() -> Foo;
584+}
585+ 
586+fn main() {
587+ let mut foo = Foo::new(); // C++ 侧 Foo::new_instance() 创建
588+ foo.bar();
589+} // foo 析构 → Foo::free_instance → ~Foo
590+```
591+ 
592+规则:
593+ 
594+| 位置 | 写法 |
595+|---|---|
596+| C++ 适配函数返回值 | `hicc::owned_ptr<T>`,标记所有权 |
597+| Rust 接口返回类型 | 映射的类类型(如 `Foo`),析构时经 `destroy` 自动释放 |
598+| C++ 适配函数参数 | **禁止**使用 `hicc::owned_ptr<T>`(仅用于返回值) |
599+ 
600+> `@make_proxy` 的 protected 析构场景同样推荐在 C++ 侧返回 `hicc::owned_ptr<T>` 传递所有权,参见上文「调用 C++ protected 成员」。完整示例参见 `examples/destroy`。
601+ 
538## 数据类型支持602## 数据类型支持
539 603 
540| 数据类型 | 支持 | 备注 |604| 数据类型 | 支持 | 备注 |
@@ -548,6 +612,7 @@ hicc::import_lib! {
548| `const T**` 多重指针 | ✅ | 程序员管理生命周期 |612| `const T**` 多重指针 | ✅ | 程序员管理生命周期 |
549| `T**` 多重指针 | ✅ | 程序员管理生命周期 |613| `T**` 多重指针 | ✅ | 程序员管理生命周期 |
550| `std::function<R(ArgTypes...)>` | ✅ | |614| `std::function<R(ArgTypes...)>` | ✅ | |
615+| `hicc::owned_ptr<T>` | ✅ | 仅用于返回值,Rust 侧获得资源所有权,析构经 `destroy` 释放 |
551 616 
552## 函数类型支持617## 函数类型支持
553 618 
@@ -638,6 +703,7 @@ build.flag("/GR-");
638| `examples/template-interface` | 泛型接口:参数少/多/命名不同/同形参多次绑定/部分实例化/`string` 同名别名/祖先链/工厂绑定祖先 |703| `examples/template-interface` | 泛型接口:参数少/多/命名不同/同形参多次绑定/部分实例化/`string` 同名别名/祖先链/工厂绑定祖先 |
639| `examples/scratch-super` | super 视图最小示例 |704| `examples/scratch-super` | super 视图最小示例 |
640| `examples/protected` | 调用 C++ protected 成员:虚/非虚/静态,具体类与模板类 |705| `examples/protected` | 调用 C++ protected 成员:虚/非虚/静态,具体类与模板类 |
706+| `examples/destroy` | `hicc::owned_ptr<T>` 传递资源所有权:私有析构类经 `destroy` 释放 |
641| `examples/no-exceptions` | `-fno-exceptions` 下编译:`hicc::Exception<T>` 退化直通、`import_class` 方法包装、`@make_proxy` 回调 |707| `examples/no-exceptions` | `-fno-exceptions` 下编译:`hicc::Exception<T>` 退化直通、`import_class` 方法包装、`@make_proxy` 回调 |
642| `examples/no-rtti` | `-fno-rtti -fno-exceptions` 下编译:首 token `@make_proxy` 六种形态 `as_super`/`as_rust` 有效、派生引用保留标记、嵌入形态/C++ 重包装/普通对象视为非 proxy、无泄漏 |708| `examples/no-rtti` | `-fno-rtti -fno-exceptions` 下编译:首 token `@make_proxy` 六种形态 `as_super`/`as_rust` 有效、派生引用保留标记、嵌入形态/C++ 重包装/普通对象视为非 proxy、无泄漏 |
643| `examples/placement_new` | 在 Rust 内存空间中构造 C++ 对象 |709| `examples/placement_new` | 在 Rust 内存空间中构造 C++ 对象 |
@@ -113,6 +113,48 @@ struct AbiValue<std::unique_ptr<T>> {
113 static output_type into_with(std::function<std::unique_ptr<T>()> fun) { return into(fun()); }113 static output_type into_with(std::function<std::unique_ptr<T>()> fun) { return into(fun()); }
114};114};
115 115 
116+// 对于部分类型其析构是非pub或者限制不能直接调用delete T,他们定义了Delete<T>的特化版本
117+// 但是资源创建函数返回的始终是T*,为了区分这个指针是否具有资源所有权,特意定义如下辅助类型
118+//
119+// 使用方式(样例参见hicc-examples/destroy):
120+// 1. C++类的析构函数非public时, 通过`#[cpp(class = ..., destroy = "T::free")]`声明释放函数;
121+// 2. C++侧资源创建函数将返回类型定义为owned_ptr<T>, 标记返回的指针拥有资源所有权;
122+// 3. Rust侧对应接口的返回类型直接声明为映射的类类型(如`fn new_foo() -> Foo`),
123+// Rust对象析构时自动调用destroy函数释放资源, 避免泄露.
124+//
125+// 对于使用者,只需要将C++返回类型定义为owned_ptr<T>即可保证Rust侧可正确释放其资源,避免泄露.
126+// 注: 它应该仅用于返回值,不应该用于任何函数的参数.
127+template<typename T>
128+struct owned_ptr {
129+ const T* ptr;
130+ owned_ptr(const T* p): ptr(p) {}
131+};
132+ 
133+template<typename T>
134+struct MethodsType<owned_ptr<T>> {
135+ typedef typename MethodsType<T>::type type;
136+};
137+ 
138+template<typename T>
139+struct AbiValue<owned_ptr<T>> {
140+ typedef AbiClass<T> input_type;
141+ typedef AbiClass<T> output_type;
142+ static owned_ptr<T> from(input_type val) {
143+ // 绝对不应该用于参数类型.
144+ return (const T*)val.get_obj();
145+ }
146+ static owned_ptr<T> from_with(std::function<input_type()> fun) {
147+ return from(fun());
148+ }
149+ static output_type into(owned_ptr<T> val) {
150+ return output_type(AbiClass<T>::destroy_methods(), (T*)val.ptr);
151+ }
152+ static output_type into_with(std::function<owned_ptr<T>()> fun) {
153+ return into(fun());
154+ }
155+};
156+ 
157+ 
116} // namespace hicc158} // namespace hicc
117 159 
118#endif160#endif
@@ -556,6 +556,8 @@ fn main() {
556**说明**:556**说明**:
557 557 
5581. C++类的私有析构函数需要利用`#[cpp(class = ..., destroy = ...)]`定义.5581. C++类的私有析构函数需要利用`#[cpp(class = ..., destroy = ...)]`定义.
559+1. C++侧资源创建函数的返回值应包装为`hicc::owned_ptr<T>`(定义于`hicc/std/memory.hpp`), 表示返回的指针拥有资源所有权; 对应Rust接口的返回类型直接声明为映射的类类型, Rust对象析构时自动调用`destroy`函数释放资源, 避免泄露.
560+1. `hicc::owned_ptr<T>`仅用于返回值, 不应该用于任何函数的参数.
559 561 
560## 读写C++变量562## 读写C++变量
561 563 
@@ -610,3 +612,25 @@ hicc::import_class! {
610 612 
6111. 如在`class`中定义,只能是静态函数,静态函数所在的类空间名是`SelfMethods`, 具体的C++类型可由`Self`引用.6131. 如在`class`中定义,只能是静态函数,静态函数所在的类空间名是`SelfMethods`, 具体的C++类型可由`Self`引用.
6122. 因为是成员函数,首参数必须是`Self`或其引用或其指针.6142. 因为是成员函数,首参数必须是`Self`或其引用或其指针.
615+ 
616+## impl块关联函数与`Self`占位符
617+ 
618+`import_lib!` 中 `impl` 块的关联函数会被提取为自由函数导出,其 `#[cpp(func = ...)]` 串中的 `Self` 由生成器整词替换为按类唯一的别名,并在导出表作用域注入 `typedef {C++类型} {别名};` 解析.
619+ 
620+```rust!
621+hicc::import_lib! {
622+ #![link_name = "example"]
623+ #[cpp(class = "Foo")]
624+ class Foo {}
625+ impl Foo {
626+ #[cpp(func = "Self hicc::make_constructor<Self>(const Self&)")]
627+ pub fn make_clone(this: &Self) -> Self;
628+ }
629+}
630+```
631+ 
632+**注意**:
633+ 
634+1. `Self` 占位符仅支持**非泛型类**;泛型类实例(如 `impl Foo<i32>`)在导出表作用域无法解析出具体模板实例.
635+2. 泛型场景请在 cpp 串中直写具体 C++ 类型(如 `Foo<int>`),使用 `Self` 会导致 Rust 编译错误(宏展开期报错,指向 cpp 属性所在行).
636+3. cpp 串直写具体类型时,若该类型未在 DSL 中声明,由使用者保证其在生成代码作用域可见(与既有契约一致).
@@ -17,6 +17,9 @@ pub trait AbiClass: Sized {
17 ///17 ///
18 /// 对应到`c++`接口返回指针的应用场景.业务需要主动释放指针分配的资源时调用.18 /// 对应到`c++`接口返回指针的应用场景.业务需要主动释放指针分配的资源时调用.
19 /// 需要确保此时`self`是资源的唯一引用者.19 /// 需要确保此时`self`是资源的唯一引用者.
20+ ///
21+ /// 注意: 不再推荐使用此接口接管资源所有权, 建议在`c++`侧将适配函数的返回值
22+ /// 包装为`hicc::owned_ptr<T>`传递所有权(参见`examples/destroy`样例).
20 unsafe fn into_unique(self) -> Self;23 unsafe fn into_unique(self) -> Self;
21 ///24 ///
22 /// 更新对象本身.25 /// 更新对象本身.
@@ -451,7 +451,11 @@
451/// `_hicc_Foo_new`、`_hicc_Generic_hicc_Pod_i32_create`),`_hicc_` 前缀451/// `_hicc_Foo_new`、`_hicc_Generic_hicc_Pod_i32_create`),`_hicc_` 前缀
452/// 预留内部命名空间,避免与用户自由函数冲突;452/// 预留内部命名空间,避免与用户自由函数冲突;
453/// 5. 泛型 `impl`(`impl<T> Foo<T>`)与 `trait impl` 一律透传;453/// 5. 泛型 `impl`(`impl<T> Foo<T>`)与 `trait impl` 一律透传;
454-/// 泛型类的**具体实例化**(`impl Generic<hicc::Pod<i32>>`)支持。454+/// 泛型类的**具体实例化**(`impl Generic<hicc::Pod<i32>>`)支持;
455+/// 6. cpp 串中的 `Self` 占位符仅**非泛型类**支持(导出表作用域注入
456+/// `typedef {C++类型} {别名};` 解析);泛型类实例无法解析出具体
457+/// 模板实例,cpp 串必须直写具体 C++ 类型(如样例的 `Generic<int>*`),
458+/// 使用 `Self` 会导致 Rust 编译错误(宏展开期报错,指向 cpp 属性所在行)。
455///459///
456/// 样例:460/// 样例:
457///461///
@@ -726,12 +730,19 @@ pub use hicc_macros::import_lib;
726/// 需要如下定义:730/// 需要如下定义:
727/// ```text731/// ```text
728/// hicc::import_class! {732/// hicc::import_class! {
729-/// #[cpp(class = "Foo", destroy = "Foo::free_intance")]733+/// #[cpp(class = "Foo", destroy = "Foo::free_instance")]
730/// class Foo {734/// class Foo {
731/// }735/// }
732/// }736/// }
733/// ```737/// ```
734///738///
739+/// 此时C++侧资源创建函数的返回值应包装为`hicc::owned_ptr<T>`(定义于`hicc/std/memory.hpp`),
740+/// 表示返回的指针拥有资源所有权; 对应`rust`接口的返回类型直接声明为映射的类类型,
741+/// `rust`对象析构时自动调用`destroy`函数释放资源, 避免泄露.
742+///
743+/// 注意: `hicc::owned_ptr<T>`仅用于返回值, 不应该用于任何函数的参数.
744+/// 完整样例参见`examples/destroy`.
745+///
735/// ## `interface` / `trait`关键字746/// ## `interface` / `trait`关键字
736///747///
737/// 接口(纯抽象类)映射为`rust`的`trait`.748/// 接口(纯抽象类)映射为`rust`的`trait`.
@@ -831,15 +842,19 @@ pub use hicc_macros::import_lib;
831/// 直接实例化`c++`本就不允许, 改走静态工厂(工厂为`protected`时列入`protected`即可).842/// 直接实例化`c++`本就不允许, 改走静态工厂(工厂为`protected`时列入`protected`即可).
832/// - `protected`析构函数: `destroy = "Foo::free"`的目标函数可列入`protected`(经桥调用).843/// - `protected`析构函数: `destroy = "Foo::free"`的目标函数可列入`protected`(经桥调用).
833/// 首 token 形态`T @make_proxy<T>(..)`经`std::unique_ptr<T>`返回, 其`default_delete`844/// 首 token 形态`T @make_proxy<T>(..)`经`std::unique_ptr<T>`返回, 其`default_delete`
834-/// 要求`~T`可访问, 不兼容; 改用嵌入形态返回裸指针(借用语义, `into_unique`接管后845+/// 要求`~T`可访问, 不兼容; 改用嵌入形态工厂, C++侧适配函数返回`hicc::owned_ptr<Foo>`
835-/// 经`Deleter`释放):846+/// 传递资源所有权(推荐做法, 参见`destroy`属性说明与`examples/destroy`样例):
836///847///
837/// ```text848/// ```text
838/// #[cpp(class = "Foo", ctor = "Foo(int)", destroy = "Foo::free", protected = "free")]849/// #[cpp(class = "Foo", ctor = "Foo(int)", destroy = "Foo::free", protected = "free")]
839/// struct Foo: FooTrait {}850/// struct Foo: FooTrait {}
840-/// #[cpp(func = "Foo* my_new<@make_proxy<Foo>>(int)")]851+///
852+/// // c++侧适配函数返回 owned_ptr 传递所有权:
853+/// // template <class P, class... A>
854+/// // static hicc::owned_ptr<Foo> my_new(A&&... args) { return new P(std::forward<A>(args)...); }
855+/// #[cpp(func = "hicc::owned_ptr<Foo> my_new<@make_proxy<Foo>>(int)")]
841/// fn new_foo<I: FooTrait>(v: I, tag: i32) -> Foo;856/// fn new_foo<I: FooTrait>(v: I, tag: i32) -> Foo;
842-/// // let owned = unsafe { new_foo(impl, 7).into_unique() }; // drop → Foo::free857+/// // let foo = new_foo(impl, 7); // 拥有所有权, drop → Foo::free → ~Foo
843/// ```858/// ```
844///859///
845/// ## `#[cpp(method = ...)]`860/// ## `#[cpp(method = ...)]`