Skip to content

Commit 262198f

Browse files
committed
Support C++ constructor for shared type
1 parent 64e5e41 commit 262198f

File tree

10 files changed

+233
-101
lines changed

10 files changed

+233
-101
lines changed

gen/src/write.rs

Lines changed: 157 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,10 @@ fn write_struct<'a>(out: &mut OutFile<'a>, strct: &'a Struct, methods: &[&Extern
262262
write_doc(out, "", &strct.doc);
263263
writeln!(out, "struct {} final {{", strct.name.cxx);
264264

265+
if methods.iter().any(|method| method.sig.constructor) {
266+
writeln!(out, "{}() = default;", strct.name.cxx);
267+
}
268+
265269
for field in &strct.fields {
266270
write_doc(out, " ", &field.doc);
267271
write!(out, " ");
@@ -278,9 +282,12 @@ fn write_struct<'a>(out: &mut OutFile<'a>, strct: &'a Struct, methods: &[&Extern
278282
write_doc(out, " ", &method.doc);
279283
write!(out, " ");
280284
let sig = &method.sig;
281-
let local_name = method.name.cxx.to_string();
285+
let local_name = match (&method.self_type, sig.constructor) {
286+
(Some(self_type), true) => out.types.resolve(self_type).name.cxx.to_string(),
287+
_ => method.name.cxx.to_string(),
288+
};
282289
let indirect_call = false;
283-
if method.self_type.is_some() {
290+
if method.self_type.is_some() && !method.sig.constructor {
284291
write!(out, "static ");
285292
}
286293
write_rust_function_shim_decl(out, &local_name, sig, &None, indirect_call);
@@ -375,7 +382,7 @@ fn write_opaque_type<'a>(out: &mut OutFile<'a>, ety: &'a ExternType, methods: &[
375382
let sig = &method.sig;
376383
let local_name = method.name.cxx.to_string();
377384
let indirect_call = false;
378-
if method.self_type.is_some() {
385+
if method.self_type.is_some() && !method.sig.constructor {
379386
write!(out, "static ");
380387
}
381388
write_rust_function_shim_decl(out, &local_name, sig, &None, indirect_call);
@@ -754,51 +761,61 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
754761
if !efn.args.is_empty() || efn.receiver.is_some() {
755762
write!(out, ", ");
756763
}
757-
write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
764+
if efn.sig.constructor {
765+
write!(
766+
out,
767+
"{} ",
768+
out.types.resolve(efn.self_type.as_ref().unwrap()).name.cxx
769+
);
770+
} else {
771+
write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
772+
}
758773
write!(out, "*return$");
759774
}
760775
writeln!(out, ") noexcept {{");
761-
write!(out, " ");
762-
write_return_type(out, &efn.ret);
763-
match &efn.receiver {
764-
None => write!(out, "(*{}$)(", efn.name.rust),
765-
Some(receiver) => write!(
766-
out,
767-
"({}::*{}$)(",
768-
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
769-
efn.name.rust,
770-
),
771-
}
772-
for (i, arg) in efn.args.iter().enumerate() {
773-
if i > 0 {
774-
write!(out, ", ");
776+
if !efn.sig.constructor {
777+
write!(out, " ");
778+
write_return_type(out, &efn.ret);
779+
match &efn.receiver {
780+
None => write!(out, "(*{}$)(", efn.name.rust),
781+
Some(receiver) => write!(
782+
out,
783+
"({}::*{}$)(",
784+
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
785+
efn.name.rust,
786+
),
775787
}
776-
write_type(out, &arg.ty);
777-
}
778-
write!(out, ")");
779-
if let Some(receiver) = &efn.receiver {
780-
if !receiver.mutable {
781-
write!(out, " const");
788+
for (i, arg) in efn.args.iter().enumerate() {
789+
if i > 0 {
790+
write!(out, ", ");
791+
}
792+
write_type(out, &arg.ty);
782793
}
794+
write!(out, ")");
795+
if let Some(receiver) = &efn.receiver {
796+
if !receiver.mutable {
797+
write!(out, " const");
798+
}
799+
}
800+
write!(out, " = ");
801+
match (&efn.receiver, &efn.self_type) {
802+
(None, None) => write!(out, "{}", efn.name.to_fully_qualified()),
803+
(Some(receiver), None) => write!(
804+
out,
805+
"&{}::{}",
806+
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
807+
efn.name.cxx,
808+
),
809+
(None, Some(self_type)) => write!(
810+
out,
811+
"&{}::{}",
812+
out.types.resolve(self_type).name.to_fully_qualified(),
813+
efn.name.cxx,
814+
),
815+
_ => unreachable!("receiver and self_type are mutually exclusive"),
816+
}
817+
writeln!(out, ";");
783818
}
784-
write!(out, " = ");
785-
match (&efn.receiver, &efn.self_type) {
786-
(None, None) => write!(out, "{}", efn.name.to_fully_qualified()),
787-
(Some(receiver), None) => write!(
788-
out,
789-
"&{}::{}",
790-
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
791-
efn.name.cxx,
792-
),
793-
(None, Some(self_type)) => write!(
794-
out,
795-
"&{}::{}",
796-
out.types.resolve(self_type).name.to_fully_qualified(),
797-
efn.name.cxx,
798-
),
799-
_ => unreachable!("receiver and self_type are mutually exclusive"),
800-
}
801-
writeln!(out, ";");
802819
write!(out, " ");
803820
if efn.throws {
804821
out.builtin.ptr_len = true;
@@ -811,28 +828,38 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
811828
if indirect_return {
812829
out.include.new = true;
813830
write!(out, "new (return$) ");
814-
write_indirect_return_type(out, efn.ret.as_ref().unwrap());
831+
if efn.sig.constructor {
832+
write!(
833+
out,
834+
"{}",
835+
out.types.resolve(efn.self_type.as_ref().unwrap()).name.cxx
836+
);
837+
} else {
838+
write_indirect_return_type(out, efn.ret.as_ref().unwrap());
839+
}
815840
write!(out, "(");
816841
} else if efn.ret.is_some() {
817842
write!(out, "return ");
818843
}
819-
match &efn.ret {
820-
Some(Type::Ref(_)) => write!(out, "&"),
821-
Some(Type::Str(_)) if !indirect_return => {
822-
out.builtin.rust_str_repr = true;
823-
write!(out, "::rust::impl<::rust::Str>::repr(");
844+
if !efn.sig.constructor {
845+
match &efn.ret {
846+
Some(Type::Ref(_)) => write!(out, "&"),
847+
Some(Type::Str(_)) if !indirect_return => {
848+
out.builtin.rust_str_repr = true;
849+
write!(out, "::rust::impl<::rust::Str>::repr(");
850+
}
851+
Some(ty @ Type::SliceRef(_)) if !indirect_return => {
852+
out.builtin.rust_slice_repr = true;
853+
write!(out, "::rust::impl<");
854+
write_type(out, ty);
855+
write!(out, ">::repr(");
856+
}
857+
_ => {}
824858
}
825-
Some(ty @ Type::SliceRef(_)) if !indirect_return => {
826-
out.builtin.rust_slice_repr = true;
827-
write!(out, "::rust::impl<");
828-
write_type(out, ty);
829-
write!(out, ">::repr(");
859+
match &efn.receiver {
860+
None => write!(out, "{}$(", efn.name.rust),
861+
Some(_) => write!(out, "(self.*{}$)(", efn.name.rust),
830862
}
831-
_ => {}
832-
}
833-
match &efn.receiver {
834-
None => write!(out, "{}$(", efn.name.rust),
835-
Some(_) => write!(out, "(self.*{}$)(", efn.name.rust),
836863
}
837864
for (i, arg) in efn.args.iter().enumerate() {
838865
if i > 0 {
@@ -862,7 +889,9 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
862889
write!(out, "{}", arg.name.cxx);
863890
}
864891
}
865-
write!(out, ")");
892+
if !efn.sig.constructor {
893+
write!(out, ")");
894+
}
866895
match &efn.ret {
867896
Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
868897
Some(Type::UniquePtr(_)) => write!(out, ".release()"),
@@ -892,27 +921,36 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
892921
fn write_function_pointer_trampoline(out: &mut OutFile, efn: &ExternFn, var: &Pair, f: &Signature) {
893922
let r_trampoline = mangle::r_trampoline(efn, var, out.types);
894923
let indirect_call = true;
895-
write_rust_function_decl_impl(out, &r_trampoline, f, indirect_call);
924+
write_rust_function_decl_impl(out, &r_trampoline, f, &efn.self_type, indirect_call);
896925

897926
out.next_section();
898927
let c_trampoline = mangle::c_trampoline(efn, var, out.types).to_string();
899928
let doc = Doc::new();
900-
write_rust_function_shim_impl(out, &c_trampoline, f, &efn.self_type, &doc, &r_trampoline, indirect_call);
929+
write_rust_function_shim_impl(
930+
out,
931+
&c_trampoline,
932+
f,
933+
&efn.self_type,
934+
&doc,
935+
&r_trampoline,
936+
indirect_call,
937+
);
901938
}
902939

903940
fn write_rust_function_decl<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
904941
out.set_namespace(&efn.name.namespace);
905942
out.begin_block(Block::ExternC);
906943
let link_name = mangle::extern_fn(efn, out.types);
907944
let indirect_call = false;
908-
write_rust_function_decl_impl(out, &link_name, efn, indirect_call);
945+
write_rust_function_decl_impl(out, &link_name, efn, &efn.self_type, indirect_call);
909946
out.end_block(Block::ExternC);
910947
}
911948

912949
fn write_rust_function_decl_impl(
913950
out: &mut OutFile,
914951
link_name: &Symbol,
915952
sig: &Signature,
953+
self_type: &Option<Ident>,
916954
indirect_call: bool,
917955
) {
918956
out.next_section();
@@ -947,15 +985,23 @@ fn write_rust_function_decl_impl(
947985
if needs_comma {
948986
write!(out, ", ");
949987
}
950-
match sig.ret.as_ref().unwrap() {
951-
Type::Ref(ret) => {
952-
write_type_space(out, &ret.inner);
953-
if !ret.mutable {
954-
write!(out, "const ");
988+
if sig.constructor {
989+
write!(
990+
out,
991+
"{} ",
992+
out.types.resolve(self_type.as_ref().unwrap()).name.cxx
993+
);
994+
} else {
995+
match sig.ret.as_ref().unwrap() {
996+
Type::Ref(ret) => {
997+
write_type_space(out, &ret.inner);
998+
if !ret.mutable {
999+
write!(out, "const ");
1000+
}
1001+
write!(out, "*");
9551002
}
956-
write!(out, "*");
1003+
ret => write_type_space(out, ret),
9571004
}
958-
ret => write_type_space(out, ret),
9591005
}
9601006
write!(out, "*return$");
9611007
needs_comma = true;
@@ -982,7 +1028,15 @@ fn write_rust_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
9821028
let doc = &efn.doc;
9831029
let invoke = mangle::extern_fn(efn, out.types);
9841030
let indirect_call = false;
985-
write_rust_function_shim_impl(out, &local_name, efn, &efn.self_type, doc, &invoke, indirect_call);
1031+
write_rust_function_shim_impl(
1032+
out,
1033+
&local_name,
1034+
efn,
1035+
&efn.self_type,
1036+
doc,
1037+
&invoke,
1038+
indirect_call,
1039+
);
9861040
}
9871041

9881042
fn write_rust_function_shim_decl(
@@ -993,12 +1047,18 @@ fn write_rust_function_shim_decl(
9931047
indirect_call: bool,
9941048
) {
9951049
begin_function_definition(out);
996-
write_return_type(out, &sig.ret);
1050+
if !sig.constructor {
1051+
write_return_type(out, &sig.ret);
1052+
}
9971053
if let Some(self_type) = self_type {
998-
write!(out, "{}::{}(", out.types.resolve(self_type).name.cxx, local_name);
1054+
let cxx_name = &out.types.resolve(self_type).name.cxx;
1055+
if sig.constructor {
1056+
write!(out, "{}::{}(", cxx_name, cxx_name);
1057+
} else {
1058+
write!(out, "{}::{}(", cxx_name, local_name);
1059+
}
9991060
} else {
10001061
write!(out, "{}(", local_name);
1001-
10021062
}
10031063
for (i, arg) in sig.args.iter().enumerate() {
10041064
if i > 0 {
@@ -1059,20 +1119,22 @@ fn write_rust_function_shim_impl(
10591119
write!(out, " ");
10601120
let indirect_return = indirect_return(sig, out.types);
10611121
if indirect_return {
1062-
out.builtin.maybe_uninit = true;
1063-
write!(out, "::rust::MaybeUninit<");
1064-
match sig.ret.as_ref().unwrap() {
1065-
Type::Ref(ret) => {
1066-
write_type_space(out, &ret.inner);
1067-
if !ret.mutable {
1068-
write!(out, "const ");
1122+
if !sig.constructor {
1123+
out.builtin.maybe_uninit = true;
1124+
write!(out, "::rust::MaybeUninit<");
1125+
match sig.ret.as_ref().unwrap() {
1126+
Type::Ref(ret) => {
1127+
write_type_space(out, &ret.inner);
1128+
if !ret.mutable {
1129+
write!(out, "const ");
1130+
}
1131+
write!(out, "*");
10691132
}
1070-
write!(out, "*");
1133+
ret => write_type(out, ret),
10711134
}
1072-
ret => write_type(out, ret),
1135+
writeln!(out, "> return$;");
1136+
write!(out, " ");
10731137
}
1074-
writeln!(out, "> return$;");
1075-
write!(out, " ");
10761138
} else if let Some(ret) = &sig.ret {
10771139
write!(out, "return ");
10781140
match ret {
@@ -1128,7 +1190,11 @@ fn write_rust_function_shim_impl(
11281190
if needs_comma {
11291191
write!(out, ", ");
11301192
}
1131-
write!(out, "&return$.value");
1193+
if sig.constructor {
1194+
write!(out, "this");
1195+
} else {
1196+
write!(out, "&return$.value");
1197+
}
11321198
needs_comma = true;
11331199
}
11341200
if indirect_call {
@@ -1152,7 +1218,7 @@ fn write_rust_function_shim_impl(
11521218
writeln!(out, " throw ::rust::impl<::rust::Error>::error(error$);");
11531219
writeln!(out, " }}");
11541220
}
1155-
if indirect_return {
1221+
if indirect_return && !sig.constructor {
11561222
write!(out, " return ");
11571223
match sig.ret.as_ref().unwrap() {
11581224
Type::Ref(_) => write!(out, "*return$.value"),
@@ -1174,9 +1240,11 @@ fn write_return_type(out: &mut OutFile, ty: &Option<Type>) {
11741240
}
11751241

11761242
fn indirect_return(sig: &Signature, types: &Types) -> bool {
1177-
sig.ret
1178-
.as_ref()
1179-
.is_some_and(|ret| sig.throws || types.needs_indirect_abi(ret))
1243+
sig.constructor
1244+
|| sig
1245+
.ret
1246+
.as_ref()
1247+
.is_some_and(|ret| sig.throws || types.needs_indirect_abi(ret))
11801248
}
11811249

11821250
fn write_indirect_return_type(out: &mut OutFile, ty: &Type) {

0 commit comments

Comments
 (0)