Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cm, wit/bindgen: add HostLayout field to generated structs #177

Merged
merged 10 commits into from
Sep 24, 2024
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),

### Added

- Generated structs and structs in package `cm` now include a [`HostLayout` field](https://github.com/golang/go/issues/66408) in order to conform with the [relaxed types proposal](https://github.com/golang/go/issues/66984) for `GOARCH=wasm32`. The `cm.HostLayout` type is an alias for `structs.HostLayout` on Go 1.23 or later, and a polyfill for Go 1.22 or earlier.
- [#163](https://github.com/bytecodealliance/wasm-tools-go/issues/163): added `cm.F32ToU64()` and `cm.U64ToF32()` for flattening `f32` and `u64` types in the Canonical ABI.
- Test data from [bytecodealliance/wit-bindgen/tests/codegen](https://github.com/bytecodealliance/wit-bindgen/tree/main/tests/codegen)
- Test data from [bytecodealliance/wit-bindgen/tests/codegen](https://github.com/bytecodealliance/wit-bindgen/tree/main/tests/codegen).

### Fixed

Expand Down
11 changes: 11 additions & 0 deletions cm/hostlayout_go122.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//go:build !go1.23

package cm

// HostLayout marks a struct as using host memory layout.
// See [structs.HostLayout] in Go 1.23 or later.
type HostLayout struct {
_ hostLayout // prevent accidental conversion with plain struct{}
}

type hostLayout struct{}
9 changes: 9 additions & 0 deletions cm/hostlayout_go123.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//go:build go1.23

package cm

import "structs"

// HostLayout marks a struct as using host memory layout.
// See [structs.HostLayout] in Go 1.23 or later.
type HostLayout = structs.HostLayout
4 changes: 4 additions & 0 deletions cm/layout_test.go → cm/hostlayout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

func TestFieldAlignment(t *testing.T) {
var v1 struct {
_ HostLayout
_ bool
_ [0][7]byte
u64 uint64
Expand All @@ -22,6 +23,7 @@ func TestFieldAlignment(t *testing.T) {
}

var v2 struct {
_ HostLayout
_ bool
_ [0][7]byte
_ [0][51]float64
Expand All @@ -40,6 +42,7 @@ func TestFieldAlignment(t *testing.T) {

// size 1
var v3 struct {
_ HostLayout
_ struct{}
b bool // offset 0
}
Expand All @@ -52,6 +55,7 @@ func TestFieldAlignment(t *testing.T) {

// size 0
var v4 struct {
_ HostLayout
_ [0]uint32
b bool // offset 0!
}
Expand Down
1 change: 1 addition & 0 deletions cm/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func ToList[S ~[]T, T any](s S) List[T] {
// It is intended to be embedded in a [List], so embedding types maintain
// the methods defined on this type.
type list[T any] struct {
_ HostLayout
data *T
len uint
}
Expand Down
1 change: 1 addition & 0 deletions cm/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func Some[T any](v T) Option[T] {
// The first byte is a bool representing none or some,
// followed by storage for the associated type T.
type option[T any] struct {
_ HostLayout
isSome bool
some T
}
Expand Down
1 change: 1 addition & 0 deletions cm/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type Result[Shape, OK, Err any] struct{ result[Shape, OK, Err] }

// result represents the internal representation of a Component Model result type.
type result[Shape, OK, Err any] struct {
_ HostLayout
isErr bool
_ [0]OK
_ [0]Err
Expand Down
1 change: 1 addition & 0 deletions cm/result_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ func TestIssue95Struct(t *testing.T) {
type (
// structResult Result[structVariant, stringStruct, structVariant]
stringStruct struct {
_ HostLayout
// i int
s string
}
Expand Down
15 changes: 15 additions & 0 deletions cm/tuple.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package cm
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple[T0, T1 any] struct {
_ HostLayout
F0 T0
F1 T1
}
Expand All @@ -12,6 +13,7 @@ type Tuple[T0, T1 any] struct {
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple3[T0, T1, T2 any] struct {
_ HostLayout
F0 T0
F1 T1
F2 T2
Expand All @@ -21,6 +23,7 @@ type Tuple3[T0, T1, T2 any] struct {
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple4[T0, T1, T2, T3 any] struct {
_ HostLayout
F0 T0
F1 T1
F2 T2
Expand All @@ -31,6 +34,7 @@ type Tuple4[T0, T1, T2, T3 any] struct {
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple5[T0, T1, T2, T3, T4 any] struct {
_ HostLayout
F0 T0
F1 T1
F2 T2
Expand All @@ -42,6 +46,7 @@ type Tuple5[T0, T1, T2, T3, T4 any] struct {
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple6[T0, T1, T2, T3, T4, T5 any] struct {
_ HostLayout
F0 T0
F1 T1
F2 T2
Expand All @@ -54,6 +59,7 @@ type Tuple6[T0, T1, T2, T3, T4, T5 any] struct {
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple7[T0, T1, T2, T3, T4, T5, T6 any] struct {
_ HostLayout
F0 T0
F1 T1
F2 T2
Expand All @@ -67,6 +73,7 @@ type Tuple7[T0, T1, T2, T3, T4, T5, T6 any] struct {
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple8[T0, T1, T2, T3, T4, T5, T6, T7 any] struct {
_ HostLayout
F0 T0
F1 T1
F2 T2
Expand All @@ -81,6 +88,7 @@ type Tuple8[T0, T1, T2, T3, T4, T5, T6, T7 any] struct {
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple9[T0, T1, T2, T3, T4, T5, T6, T7, T8 any] struct {
_ HostLayout
F0 T0
F1 T1
F2 T2
Expand All @@ -96,6 +104,7 @@ type Tuple9[T0, T1, T2, T3, T4, T5, T6, T7, T8 any] struct {
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple10[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any] struct {
_ HostLayout
F0 T0
F1 T1
F2 T2
Expand All @@ -112,6 +121,7 @@ type Tuple10[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any] struct {
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple11[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any] struct {
_ HostLayout
F0 T0
F1 T1
F2 T2
Expand All @@ -129,6 +139,7 @@ type Tuple11[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any] struct {
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple12[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any] struct {
_ HostLayout
F0 T0
F1 T1
F2 T2
Expand All @@ -147,6 +158,7 @@ type Tuple12[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any] struct {
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple13[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any] struct {
_ HostLayout
F0 T0
F1 T1
F2 T2
Expand All @@ -166,6 +178,7 @@ type Tuple13[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any] struct {
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple14[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any] struct {
_ HostLayout
F0 T0
F1 T1
F2 T2
Expand All @@ -186,6 +199,7 @@ type Tuple14[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any] str
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple15[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any] struct {
_ HostLayout
F0 T0
F1 T1
F2 T2
Expand All @@ -207,6 +221,7 @@ type Tuple15[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any
//
// [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples
type Tuple16[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any] struct {
_ HostLayout
F0 T0
F1 T1
F2 T2
Expand Down
15 changes: 8 additions & 7 deletions cm/tuple_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import (
)

func TestTuple(t *testing.T) {
_ = Tuple[string, bool]{"hello", false}
_ = Tuple3[string, bool, uint8]{"hello", false, 1}
_ = Tuple4[string, bool, uint8, uint16]{"hello", false, 1, 32000}
_ = Tuple5[string, bool, uint8, uint16, uint32]{"hello", false, 1, 32000, 1_000_000}
_ = Tuple6[string, bool, uint8, uint16, uint32, uint64]{"hello", false, 1, 32000, 1_000_000, 5_000_000_000}
_ = Tuple7[string, bool, uint8, uint16, uint32, uint64, float32]{"hello", false, math.MaxUint8, math.MaxUint16, math.MaxUint32, math.MaxUint64, math.MaxFloat32}
_ = Tuple8[string, bool, uint8, uint16, uint32, uint64, float32, float64]{"hello", false, math.MaxUint8, math.MaxUint16, math.MaxUint32, math.MaxUint64, math.MaxFloat32, math.MaxFloat64}
var HL HostLayout
_ = Tuple[string, bool]{HL, "hello", false}
_ = Tuple3[string, bool, uint8]{HL, "hello", false, 1}
_ = Tuple4[string, bool, uint8, uint16]{HL, "hello", false, 1, 32000}
_ = Tuple5[string, bool, uint8, uint16, uint32]{HL, "hello", false, 1, 32000, 1_000_000}
_ = Tuple6[string, bool, uint8, uint16, uint32, uint64]{HL, "hello", false, 1, 32000, 1_000_000, 5_000_000_000}
_ = Tuple7[string, bool, uint8, uint16, uint32, uint64, float32]{HL, "hello", false, math.MaxUint8, math.MaxUint16, math.MaxUint32, math.MaxUint64, math.MaxFloat32}
_ = Tuple8[string, bool, uint8, uint16, uint32, uint64, float32, float64]{HL, "hello", false, math.MaxUint8, math.MaxUint16, math.MaxUint32, math.MaxUint64, math.MaxFloat32, math.MaxFloat64}
}
1 change: 1 addition & 0 deletions cm/variant.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func Case[T any, V ~struct{ variant[Tag, Shape, Align] }, Tag Discriminant, Shap
// variant is the internal representation of a Component Model variant.
// Shape and Align must be non-zero sized types.
type variant[Tag Discriminant, Shape, Align any] struct {
_ HostLayout
tag Tag
_ [0]Align
data Shape // [unsafe.Sizeof(*(*Shape)(unsafe.Pointer(nil)))]byte
Expand Down
2 changes: 2 additions & 0 deletions testdata/example/non-flat-params.wit
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ interface corner-case {
u17-void: func(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8, h: u8, i: u8, j: u8, k: u8, l: u8, m: u8, n: u8, o: u8, p: u8, q: u8);
u17-u8-u8: func(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8, h: u8, i: u8, j: u8, k: u8, l: u8, m: u8, n: u8, o: u8, p: u8, q: u8) -> (r0: u8, r1: u8);
}

reserved-names: func(%bool: u8, int8: u8, uint8: u8, int16: u8, uint16: u8, int32: u8, uint32: u8, %f32: u8, %f64: u8, %string: u8, %record: u8, struct: u8, %world: u8, %interface: u8, %option: u8, %package: u8, %result: u8) -> (r0: u8, r1: u8);
}

world imports {
Expand Down
84 changes: 84 additions & 0 deletions testdata/example/non-flat-params.wit.json
Original file line number Diff line number Diff line change
Expand Up @@ -1641,6 +1641,90 @@
"type": "u8"
}
]
},
"reserved-names": {
"name": "reserved-names",
"kind": "freestanding",
"params": [
{
"name": "bool",
"type": "u8"
},
{
"name": "int8",
"type": "u8"
},
{
"name": "uint8",
"type": "u8"
},
{
"name": "int16",
"type": "u8"
},
{
"name": "uint16",
"type": "u8"
},
{
"name": "int32",
"type": "u8"
},
{
"name": "uint32",
"type": "u8"
},
{
"name": "f32",
"type": "u8"
},
{
"name": "f64",
"type": "u8"
},
{
"name": "string",
"type": "u8"
},
{
"name": "record",
"type": "u8"
},
{
"name": "struct",
"type": "u8"
},
{
"name": "world",
"type": "u8"
},
{
"name": "interface",
"type": "u8"
},
{
"name": "option",
"type": "u8"
},
{
"name": "package",
"type": "u8"
},
{
"name": "result",
"type": "u8"
}
],
"results": [
{
"name": "r0",
"type": "u8"
},
{
"name": "r1",
"type": "u8"
}
]
}
},
"package": 0
Expand Down
1 change: 1 addition & 0 deletions testdata/example/non-flat-params.wit.json.golden.wit
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ interface corner-case {
u16-x17-u8: func(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8, h: u8, i: u8, j: u8, k: u8, l: u8, m: u8, n: u8, o: u8, p: u8) -> (a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8, h: u8, i: u8, j: u8, k: u8, l: u8, m: u8, n: u8, o: u8, p: u8, q: u8);
u17-void: func(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8, h: u8, i: u8, j: u8, k: u8, l: u8, m: u8, n: u8, o: u8, p: u8, q: u8);
u17-u8-u8: func(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8, h: u8, i: u8, j: u8, k: u8, l: u8, m: u8, n: u8, o: u8, p: u8, q: u8) -> (r0: u8, r1: u8);
reserved-names: func(%bool: u8, int8: u8, uint8: u8, int16: u8, uint16: u8, int32: u8, uint32: u8, %f32: u8, %f64: u8, %string: u8, %record: u8, struct: u8, %world: u8, %interface: u8, %option: u8, %package: u8, %result: u8) -> (r0: u8, r1: u8);
}

world imports {
Expand Down
7 changes: 5 additions & 2 deletions wit/bindgen/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,9 @@ func (g *generator) primitiveRep(p wit.Primitive) string {
func (g *generator) recordRep(file *gen.File, dir wit.Direction, r *wit.Record, goName string) string {
exported := len(goName) == 0 || token.IsExported(goName)
var b strings.Builder
b.WriteString("struct {")
cm := file.Import(g.opts.cmPackage)
b.WriteString("struct {\n")
stringio.Write(&b, "_ ", cm, ".HostLayout")
for i, f := range r.Fields {
if i == 0 || i > 0 && f.Docs.Contents != "" {
b.WriteRune('\n')
Expand Down Expand Up @@ -1728,7 +1730,8 @@ func (g *generator) defineImportedFunction(_ wit.Ident, f *wit.Function, decl fu
if i > 0 {
b.WriteString(", ")
}
b.WriteString(p.name)
// compound parameter struct field names are identical to parameter names
stringio.Write(&b, p.name, ": ", p.name)
}
b.WriteString(" }\n")
} else if len(callParams) > 0 {
Expand Down
Loading