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}
}
