Skip to content

Commit 04da8c2

Browse files
author
Guy Bedford
authored
gen-guest-c: flatten optional params into nullable pointers (#453)
1 parent 5362b21 commit 04da8c2

3 files changed

Lines changed: 82 additions & 34 deletions

File tree

crates/gen-guest-c/src/lib.rs

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -687,10 +687,34 @@ impl InterfaceGenerator<'_> {
687687
self.src.c_adapters(&c_sig.sig);
688688
self.src.c_adapters(" {\n");
689689

690+
// construct optional adapters from maybe pointers to real optional
691+
// structs internally
692+
let mut optional_adapters = String::from("");
693+
for (i, (_, param)) in c_sig.params.iter().enumerate() {
694+
let ty = &func.params[i].1;
695+
if let Type::Id(id) = ty {
696+
if let TypeDefKind::Option(option_ty) = &self.iface.types[*id].kind {
697+
let ty = self.type_string(ty);
698+
uwrite!(
699+
optional_adapters,
700+
"{ty} {param};
701+
{param}.is_some = maybe_{param} != NULL;"
702+
);
703+
if !self.is_empty_type(option_ty) {
704+
uwriteln!(
705+
optional_adapters,
706+
"if (maybe_{param}) {{
707+
{param}.val = *maybe_{param};
708+
}}",
709+
);
710+
}
711+
}
712+
}
713+
}
714+
690715
let mut f = FunctionBindgen::new(self, c_sig, &import_name);
691716
for (pointer, param) in f.sig.params.iter() {
692-
f.locals.insert(param).unwrap();
693-
717+
f.locals.insert(&param).unwrap();
694718
if *pointer {
695719
f.params.push(format!("*{}", param));
696720
} else {
@@ -700,6 +724,7 @@ impl InterfaceGenerator<'_> {
700724
for ptr in f.sig.retptrs.iter() {
701725
f.locals.insert(ptr).unwrap();
702726
}
727+
f.src.push_str(&optional_adapters);
703728
f.gen.iface.call(
704729
AbiVariant::GuestImport,
705730
LiftLower::LowerArgsLiftResults,
@@ -879,15 +904,29 @@ impl InterfaceGenerator<'_> {
879904
if i > 0 {
880905
self.src.h_fns(", ");
881906
}
882-
self.print_ty(SourceType::HFns, ty);
883-
self.src.h_fns(" ");
884907
let pointer = self.is_arg_by_pointer(ty);
908+
// optional param pointer flattening
909+
let optional_type = if let Type::Id(id) = ty {
910+
if let TypeDefKind::Option(option_ty) = &self.iface.types[*id].kind {
911+
Some(option_ty)
912+
} else {
913+
None
914+
}
915+
} else {
916+
None
917+
};
918+
let (print_ty, print_name) = if let Some(option_ty) = optional_type {
919+
(option_ty, format!("maybe_{}", name.to_snake_case()))
920+
} else {
921+
(ty, name.to_snake_case())
922+
};
923+
self.print_ty(SourceType::HFns, print_ty);
924+
self.src.h_fns(" ");
885925
if pointer {
886926
self.src.h_fns("*");
887927
}
888-
let name = name.to_snake_case();
889-
self.src.h_fns(&name);
890-
params.push((pointer, name));
928+
self.src.h_fns(&print_name);
929+
params.push((optional_type.is_none() && pointer, name.to_snake_case()));
891930
}
892931
let mut retptrs = Vec::new();
893932
let single_ret = ret.retptrs.len() == 1;
@@ -2101,13 +2140,28 @@ impl Bindgen for FunctionBindgen<'_, '_> {
21012140
if i > 0 {
21022141
args.push_str(", ");
21032142
}
2143+
let ty = &func.params[i].1;
21042144
if *byref {
21052145
let name = self.locals.tmp("arg");
2106-
let ty = self.gen.type_string(&func.params[i].1);
2146+
let ty = self.gen.type_string(ty);
21072147
uwriteln!(self.src, "{} {} = {};", ty, name, op);
21082148
args.push_str("&");
21092149
args.push_str(&name);
21102150
} else {
2151+
if !self.gen.in_import {
2152+
if let Type::Id(id) = ty {
2153+
if let TypeDefKind::Option(option_ty) =
2154+
&self.gen.iface.types[*id].kind
2155+
{
2156+
if self.gen.is_empty_type(option_ty) {
2157+
uwrite!(args, "{op}.is_some ? (void*)1 : NULL");
2158+
} else {
2159+
uwrite!(args, "{op}.is_some ? &({op}.val) : NULL");
2160+
}
2161+
continue;
2162+
}
2163+
}
2164+
}
21112165
args.push_str(op);
21122166
}
21132167
}

tests/runtime/flavorful/wasm.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void flavorful_test_imports() {
4141
flavorful_string_set(&b.val.err, "bar");
4242
c.tag = 0;
4343
flavorful_string_set(&c.val.f0, "baz");
44-
imports_f_list_in_variant1(&a, &b, &c);
44+
imports_f_list_in_variant1(&a.val, &b, &c);
4545
}
4646

4747
{
@@ -56,7 +56,7 @@ void flavorful_test_imports() {
5656
a.is_some = true;
5757
flavorful_string_set(&a.val, "input3");
5858
flavorful_string_t b;
59-
assert(imports_f_list_in_variant3(&a, &b));
59+
assert(imports_f_list_in_variant3(&a.val, &b));
6060
assert(memcmp(b.ptr, "output3", b.len) == 0);
6161
flavorful_string_free(&b);
6262
}
@@ -156,10 +156,10 @@ void flavorful_f_list_in_record4(flavorful_list_in_alias_t *a, flavorful_list_in
156156
flavorful_string_dup(&ret0->a, "result4");
157157
}
158158

159-
void flavorful_f_list_in_variant1(flavorful_list_in_variant1_v1_t *a, flavorful_list_in_variant1_v2_t *b, flavorful_list_in_variant1_v3_t *c) {
160-
assert(a->is_some);
161-
assert(memcmp(a->val.ptr, "foo", a->val.len) == 0);
162-
flavorful_list_in_variant1_v1_free(a);
159+
void flavorful_f_list_in_variant1(flavorful_string_t *maybe_a, flavorful_list_in_variant1_v2_t *b, flavorful_list_in_variant1_v3_t *c) {
160+
assert(maybe_a != NULL);
161+
assert(memcmp(maybe_a->ptr, "foo", maybe_a->len) == 0);
162+
flavorful_string_free(maybe_a);
163163

164164
assert(b->is_err);
165165
assert(memcmp(b->val.err.ptr, "bar", b->val.err.len) == 0);
@@ -175,11 +175,11 @@ bool flavorful_f_list_in_variant2(flavorful_string_t *ret0) {
175175
return true;
176176
}
177177

178-
bool flavorful_f_list_in_variant3(flavorful_list_in_variant3_t *a, flavorful_string_t *ret0) {
179-
assert(a->is_some);
180-
assert(memcmp(a->val.ptr, "input3", a->val.len) == 0);
181-
flavorful_list_in_variant3_free(a);
182-
flavorful_string_dup(ret0, "output3");
178+
bool flavorful_f_list_in_variant3(flavorful_string_t *maybe_a, flavorful_string_t *ret) {
179+
assert(maybe_a != NULL);
180+
assert(memcmp(maybe_a->ptr, "input3", maybe_a->len) == 0);
181+
flavorful_string_free(maybe_a);
182+
flavorful_string_dup(ret, "output3");
183183
return true;
184184
}
185185

tests/runtime/variants/wasm.c

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,12 @@
33

44
void variants_test_imports() {
55
{
6-
imports_option_float32_t a;
6+
float a = 1;
77
uint8_t r;
8-
a.is_some = true;
9-
a.val = 1;
108
assert(imports_roundtrip_option(&a, &r) && r == 1);
119
assert(r == 1);
12-
a.is_some = false;
13-
assert(!imports_roundtrip_option(&a, &r));
14-
a.is_some = true;
15-
a.val = 2;
10+
assert(!imports_roundtrip_option(NULL, &r));
11+
a = 2;
1612
assert(imports_roundtrip_option(&a, &r) && r == 2);
1713
}
1814

@@ -120,12 +116,10 @@ void variants_test_imports() {
120116
}
121117

122118
{
123-
imports_option_typedef_t a;
124-
a.is_some = false;
125119
bool b = false;
126120
imports_result_typedef_t c;
127121
c.is_err = true;
128-
imports_variant_typedefs(&a, b, &c);
122+
imports_variant_typedefs(NULL, b, &c);
129123
}
130124

131125
{
@@ -139,11 +133,11 @@ void variants_test_imports() {
139133
}
140134
}
141135

142-
bool variants_roundtrip_option(variants_option_float32_t *a, uint8_t *ret0) {
143-
if (a->is_some) {
144-
*ret0 = a->val;
136+
bool variants_roundtrip_option(float *a, uint8_t *ret0) {
137+
if (a) {
138+
*ret0 = *a;
145139
}
146-
return a->is_some;
140+
return a != NULL;
147141
}
148142

149143
bool variants_roundtrip_result(variants_result_u32_float32_t *a, double *ok, uint8_t *err) {
@@ -172,6 +166,6 @@ void variants_variant_zeros(variants_zeros_t *a, variants_zeros_t *b) {
172166
*b = *a;
173167
}
174168

175-
void variants_variant_typedefs(variants_option_typedef_t *a, variants_bool_typedef_t b, variants_result_typedef_t *c) {
169+
void variants_variant_typedefs(uint32_t *a, variants_bool_typedef_t b, variants_result_typedef_t *c) {
176170
}
177171

0 commit comments

Comments
 (0)