go build main.go ! stdout . ! stderr . -- main.go -- package main import ( "p/b" ) func main() { f() } func f() { typ := indexedPageType{newIndexedType(nil)} page := newPage(typ.indexedType) page.Data() } func newPage(typ *indexedType) Page { values := typ.NewValues(nil, nil) return &indexedPage{ typ: typ, values: values.Int32(), columnIndex: ^0, } } type Type interface { NewPage(columnIndex, numValues int, data b.Values) Page NewValues(values []byte, offsets []uint32) b.Values } type Page interface { Type() Type Data() b.Values } type indexedPage struct { typ *indexedType values []int32 columnIndex int16 } func (page *indexedPage) Type() Type { return indexedPageType{page.typ} } func (page *indexedPage) Data() b.Values { return b.Int32Values(page.values) } type indexedType struct { Type } func newIndexedType(typ Type) *indexedType { return &indexedType{Type: typ} } type indexedPageType struct{ *indexedType } func (t indexedPageType) NewValues(values []byte, _ []uint32) b.Values { return b.Int32ValuesFromBytes(values) } -- go.mod -- module p go 1.24 -- internal/a/a.go -- package a import "unsafe" type slice struct { ptr unsafe.Pointer len int cap int } func Slice[To, From any](data []From) []To { // This function could use unsafe.Slice but it would drop the capacity // information, so instead we implement the type conversion. var zf From var zt To var s = slice{ ptr: unsafe.Pointer(unsafe.SliceData(data)), len: int((uintptr(len(data)) * unsafe.Sizeof(zf)) / unsafe.Sizeof(zt)), cap: int((uintptr(cap(data)) * unsafe.Sizeof(zf)) / unsafe.Sizeof(zt)), } return *(*[]To)(unsafe.Pointer(&s)) } -- b/b.go -- package b import "p/internal/a" type Kind int32 const Int32 Kind = iota + 2 type Values struct { kind Kind size int32 data []byte offsets []uint32 } func (v *Values) Int32() []int32 { return a.Slice[int32](v.data) } func makeValues[T any](kind Kind, values []T) Values { return Values{kind: kind, data: a.Slice[byte](values)} } func Int32Values(values []int32) Values { return makeValues(Int32, values) } func Int32ValuesFromBytes(values []byte) Values { return Values{kind: Int32, data: values} }