blob: 82aeb736075a29e5a38b9034af31d0ece091b5b9 [file] [log] [blame]
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fidl
import (
"errors"
"math"
"reflect"
"strconv"
"strings"
"sync"
"syscall/zx"
"syscall/zx/fidl/internal/unsafevalue"
"unicode/utf8"
"unsafe"
)
type strictness bool
const (
isFlexible strictness = false
isStrict strictness = true
)
type resourceness bool
const (
isResourceType resourceness = true
isValueType resourceness = false
)
// MustCreateMarshaler is like CreateMarshaler but panics if the sample struct
// cannot be used to create a marshaler. It simplifies safe initialization of
// global variables holding marshalers.
func MustCreateMarshaler(sample interface{}) Marshaler {
m, err := CreateMarshaler(sample)
if err != nil {
panic(err)
}
return m
}
// CreateMarshaler creates a marshaler from a sample struct.
func CreateMarshaler(sample interface{}) (Marshaler, error) {
typ := reflect.TypeOf(sample)
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
if typ.Kind() == reflect.Struct {
return createMarshaler(typ)
}
return nil, errors.New("unable to create marshaler for " + nicefmt(typ))
}
// CreateMarshaler creates a lazy marshaler from a sample struct. This lazy
// marshaler initializes its actual delegate marshaler on first use, rather
// than on creation. As a result, there is no validation on creation, and
// instead the lazy marshaler will panic on first use if a marshaler
// cannot be created of the sample provided.
func CreateLazyMarshaler(sample interface{}) Marshaler {
return &lazyMarshaler{
sample: sample,
}
}
type lazyMarshaler struct {
once sync.Once
sample interface{}
delegate Marshaler
}
// Assert that lazyMarshaler implements the Marshaler interface.
var _ Marshaler = &lazyMarshaler{}
func (m *lazyMarshaler) init() {
m.delegate = MustCreateMarshaler(m.sample)
}
func (m *lazyMarshaler) getMarshalSize(ctx MarshalerContext) int {
m.once.Do(m.init)
return m.delegate.getMarshalSize(ctx)
}
func (m *lazyMarshaler) getUnmarshalSize(ctx MarshalerContext) int {
m.once.Do(m.init)
return m.delegate.getUnmarshalSize(ctx)
}
func (m *lazyMarshaler) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
m.once.Do(m.init)
return m.delegate.marshal(ctx, v, out, offset, depth)
}
func (m *lazyMarshaler) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
m.once.Do(m.init)
return m.delegate.unmarshal(ctx, in, offset, depth, v)
}
// Marshal marshals (or encodes) a message into the data and handles slices.
func Marshal(ctx MarshalerContext, message Message, data []byte, handleDispositions []zx.HandleDisposition) (int, int, error) {
// By construction, we know that message is a pointer to a struct since
// we only generate pointer receiver methods for top-level messages.
// Should one implement the interface differently, and call into this
// code, it would fail in an obscure way withing reflection. Just don't do
// that.
var (
v = unsafevalue.ValueOf(message)
m = message.Marshaler()
)
// Now, let's get the value of s, marshal the header into a starting
// buffer, and then marshal the rest of the payload in s.
out := &encoder{buffer: data[:0], handleDispositions: handleDispositions[:0]}
offset, err := out.newObject(m.getMarshalSize(ctx), 0)
if err != nil {
return 0, 0, err
}
if err := m.marshal(ctx, v, out, offset, 1); err != nil {
return 0, 0, err
}
return len(out.buffer), len(out.handleDispositions), nil
}
// UnmarshalBuffer unmarshals (or decodes) into message using the data and handle slices.
// Unlike Unmarshal, it does not check that the entire message is consumed.
func UnmarshalBuffer(ctx MarshalerContext, data []byte, handleInfos []zx.HandleInfo, message Message) (int, int, error) {
// By construction, we know that message is a pointer to a struct since
// we only generate pointer receiver methods for top-level messages.
// Should one implement the interface differently, and call into this
// code, it would fail in an obscure way withing reflection. Just don't do
// that.
var (
v = unsafevalue.ValueOf(message)
m = message.Marshaler()
)
// Get the payload's value and unmarshal it.
in := &decoder{
buffer: data,
handleInfos: handleInfos,
}
offset, err := in.newObject(m.getUnmarshalSize(ctx), 0)
if err != nil {
return 0, 0, err
}
if err := m.unmarshal(ctx, in, offset, 1, v); err != nil {
return 0, 0, err
}
return in.nextObject, len(handleInfos) - len(in.handleInfos), nil
}
// Unmarshal unmarshals (or decodes) into message using the data and handle slices.
func Unmarshal(ctx MarshalerContext, data []byte, handleInfos []zx.HandleInfo, message Message) error {
var hasSucceeded bool
defer func() {
if !hasSucceeded {
for _, handleInfo := range handleInfos {
handleClose(&handleInfo.Handle)
}
}
}()
b, h, err := UnmarshalBuffer(ctx, data, handleInfos, message)
if err != nil {
return err
}
if b != len(data) {
return newExpectError(ErrTooManyBytesInMessage, b, len(data))
}
if h != len(handleInfos) {
return newExpectError(ErrTooManyHandles, h, len(handleInfos))
}
hasSucceeded = true
return nil
}
const tagSizeV2 = "fidl_size_v2"
const tagAlignmentV2 = "fidl_alignment_v2"
const tagOffsetV2 = "fidl_offset_v2"
const tagHandleRights = "fidl_handle_rights"
const tagHandleSubtype = "fidl_handle_subtype"
const tagOrdinal = "fidl_ordinal"
const tagBounds = "fidl_bounds"
const tagMarshalerKind = "fidl"
const tagIsResource = "fidl_resource"
// These rights come from FTP-028
// (all requests and interfaces have the same handle rights)
const ProtocolRights = zx.RightTransfer | zx.RightWait | zx.RightInspect | zx.RightWrite | zx.RightRead | zx.RightSignal | zx.RightSignalPeer
type tagKind int
const (
_ = iota
structTag tagKind = iota
xunionTag
strictXunionTag
tableTag
)
type bounds []int
func (b bounds) pop() (int, []int) {
if len(b) == 0 {
return math.MaxInt32, nil
}
return b[0], b[1:]
}
func nicefmt(typ reflect.Type) string {
typKindName := typ.Kind().String()
if typName := typ.Name(); len(typName) != 0 {
return typName + " (" + typKindName + ")"
}
return typKindName
}
// Extracts a list of fields for struct, union, table types that can be used
// for iterating.
// This skips the initial tag field.
func dataFields(typ reflect.Type) []reflect.StructField {
if typ.Kind() != reflect.Struct {
panic("expected struct")
}
if name := typ.Field(0).Name; name != "_" && !strings.HasPrefix(name, "I_") {
panic("expected first field to be a metadata field")
}
fields := make([]reflect.StructField, typ.NumField()-1)
for i := range fields {
fields[i] = typ.Field(i + 1)
}
return fields
}
// Identifies the fields in a union that store unknown data, and that therefore
// do not need to have a field marshaler created
func isUnknownDataField(fieldName string) bool {
return fieldName == "I_unknownData"
}
// Returns true if the go type has the same layout as the FIDL wire format.
func matchesWireFormatLayout(marshaler Marshaler, typ reflect.Type) bool {
switch marshaler := marshaler.(type) {
case *mBool:
// Need to validate 0, 1.
return false
case *mInt8, *mInt16, *mInt32, *mInt64, *mUint8, *mUint16, *mUint32, *mUint64:
return true
case *mEnumOfInt8, *mEnumOfInt16, *mEnumOfInt32, *mEnumOfInt64:
// Need to validate.
return false
case *mEnumOfUint8, *mEnumOfUint16, *mEnumOfUint32, *mEnumOfUint64:
// Need to validate.
return false
case *mBitsOfUint8, *mBitsOfUint16, *mBitsOfUint32, *mBitsOfUint64:
// Need to validate.
return false
case *mFloat32:
// Need to validate.
return false
case *mFloat64:
// Need to validate.
return false
case *mArray:
return matchesWireFormatLayout(marshaler.Marshaler, typ.Elem())
case *mStruct:
// Note: In some cases, go structs may be different size than wire format
// structs but otherwise identical. It may be possible to change this
// logic to allow a partial copy in the future.
if marshaler.useUnsafeCopy {
return true
}
if marshaler.sizeV2 != int(typ.Size()) {
return false
}
if marshaler.alignmentV2 != typ.Align() {
return false
}
var endOfLast uintptr
for i, rField := range dataFields(typ) {
field := marshaler.fields[i]
if field.offset != rField.Offset {
return false
}
if endOfLast != field.offset {
// There is padding.
return false
}
if !matchesWireFormatLayout(field.Marshaler, rField.Type) {
return false
}
endOfLast = field.offset + rField.Type.Size()
}
if endOfLast != typ.Size() {
return false
}
return true
case *mEmptyStruct:
// Note: empty struct is 0 or 1 bytes at different times in go.
return false
case *mHandle, *mProtocol:
// Note: In the future, we might instead consider treating handles
// like uint32 and decoding in a subsequent step.
return false
case *mXUnion, *mOptXUnion, *mTable, *mVector, *mOptVector, *mString, *mOptString, *mPointer:
return false
default:
panic("unhandledType " + reflect.TypeOf(marshaler).Name() + " for " + typ.String())
}
}
type creator struct {
interns map[reflect.Type]Marshaler
}
func createMarshaler(typ reflect.Type) (Marshaler, error) {
c := &creator{
interns: map[reflect.Type]Marshaler{},
}
return c.createMarshalerForStruct(typ)
}
func (c *creator) createMarshalerForStruct(typ reflect.Type) (Marshaler, error) {
if seen, ok := c.interns[typ]; ok {
return seen, nil
}
// field 0 holds the tag
tagField := typ.Field(0)
marshalerKind, err := readKindTag(tagField)
if err != nil {
return nil, err
}
var (
kind = marshalerKind
fields []mField
ordinals []uint64
wireOffsetsV2 []int
presenceOffsets []uintptr
)
df := dataFields(typ)
var out Marshaler
switch kind {
case structTag:
if len(df) == 0 {
return &mEmptyStruct{}, nil
}
out = &mStruct{}
case xunionTag, strictXunionTag:
out = &mXUnion{}
case tableTag:
out = &mTable{}
default:
return nil, errors.New("unknown kind tag on " + nicefmt(typ))
}
c.interns[typ] = out
// - structs, unions, and xunions have fields one after the other;
// - tables have a field, followed by a bool presence indicator, etc.
for index, field := range df {
if (kind == xunionTag || kind == tableTag) && isUnknownDataField(field.Name) {
continue
}
if kind == tableTag && index%2 == 0 {
// Presence field
if field.Type.Kind() != reflect.Bool {
return nil, errors.New("incorrect presence field on " + nicefmt(typ))
}
presenceOffsets = append(presenceOffsets, field.Offset)
continue
}
fieldBounds := readBoundsTag(field)
handleRights, handleSubtype, err := readHandleRightsAndSubtype(field)
if err != nil {
return nil, err
}
switch kind {
case structTag:
offsetV2, err := readIntTag(field, tagOffsetV2)
if err != nil {
return nil, err
}
wireOffsetsV2 = append(wireOffsetsV2, offsetV2)
case xunionTag, strictXunionTag, tableTag:
ordinal := readOrdinalTag(field)
ordinals = append(ordinals, uint64(ordinal))
default:
}
fieldMarshaler, err := c.createMarshalerForField(field.Type, fieldBounds, handleRights, handleSubtype)
if err != nil {
return nil, err
}
fields = append(fields, mField{fieldMarshaler, field.Index[0], field.Offset})
}
sizeV2, err := readIntTag(tagField, tagSizeV2)
if err != nil {
return nil, errors.New("error creating marshaller for " + typ.String() + ": " + err.Error())
}
alignmentV2, err := readIntTag(tagField, tagAlignmentV2)
if err != nil {
return nil, errors.New("error creating marshaller for " + typ.String() + ": " + err.Error())
}
switch m := out.(type) {
case *mStruct:
var structFields []mFieldWithWireOffset
for i := 0; i < len(fields); i++ {
structFields = append(structFields, mFieldWithWireOffset{
mField: fields[i],
wireOffsetV2: wireOffsetsV2[i],
})
}
m.fields = structFields
m.sizeV2 = sizeV2
m.alignmentV2 = alignmentV2
m.useUnsafeCopy = matchesWireFormatLayout(m, typ)
if m.useUnsafeCopy {
m.fields = nil
}
return m, nil
case *mXUnion:
strictness := strictness(kind == strictXunionTag)
isResource, err := readBoolTag(tagField, tagIsResource)
if err != nil {
return nil, errors.New("error creating marshaller for " + typ.String() + ": " + err.Error())
}
ordinalToFields := make(map[uint64]mField)
for i := 0; i < len(fields); i++ {
ordinalToFields[ordinals[i]] = fields[i]
}
m.typ = typ
m.fields = ordinalToFields
m.ordinals = ordinals
m.sizeV2 = sizeV2
m.alignmentV2 = alignmentV2
m.strictness = strictness
m.resourceness = resourceness(isResource)
return m, nil
case *mTable:
isResource, err := readBoolTag(tagField, tagIsResource)
if err != nil {
return nil, errors.New("error creating marshaller for " + typ.String() + ": " + err.Error())
}
m.fields = fields
m.presenceOffsets = presenceOffsets
m.size = sizeV2
m.alignment = alignmentV2
m.ordinals = ordinals
m.resourceness = resourceness(isResource)
return m, nil
default:
return nil, errors.New("unknown kind tag on " + nicefmt(typ))
}
}
func readKindTag(field reflect.StructField) (tagKind, error) {
content, ok := field.Tag.Lookup(tagMarshalerKind)
if !ok {
return 0, errors.New(tagMarshalerKind + " not found on field " + field.Name)
}
switch content {
case "s":
return structTag, nil
case "x":
return xunionTag, nil
case "x!":
return strictXunionTag, nil
case "t":
return tableTag, nil
default:
return 0, errors.New("unknown kind tag: " + content)
}
}
func readHandleRightsAndSubtype(field reflect.StructField) (zx.Rights, zx.ObjType, error) {
if !containsHandleType(field.Type) {
// Skip non-handle field types and don't return an error.
return zx.RightSameRights, zx.ObjTypeNone, nil
}
// Read handle rights
val, ok := field.Tag.Lookup(tagHandleRights)
if !ok {
return zx.RightSameRights, zx.ObjTypeNone, ErrUnspecifiedHandleRights
}
rights, err := strconv.ParseInt(val, 0, 64)
if err != nil {
return zx.RightSameRights, zx.ObjTypeNone, err
}
convertedRights := zx.Rights(rights)
// Read handle subtype
val, ok = field.Tag.Lookup(tagHandleSubtype)
if !ok {
return zx.RightSameRights, zx.ObjTypeNone, ErrUnspecifiedHandleType
}
subtype, err := strconv.ParseInt(val, 0, 64)
if err != nil {
return zx.RightSameRights, zx.ObjTypeNone, err
}
convertedSubtype := zx.ObjType(subtype)
return convertedRights, convertedSubtype, nil
}
func containsHandleType(typ reflect.Type) bool {
// Protocols and requests are technically handle types but their rights /
// subtypes are handled elsewhere.
if typ.ConvertibleTo(proxyType) || typ.ConvertibleTo(interfaceRequestType) {
return false
}
if isHandleType(typ) {
return true
}
if typ.Kind() == reflect.Slice || typ.Kind() == reflect.Array || typ.Kind() == reflect.Ptr {
return containsHandleType(typ.Elem())
}
return false
}
func readOrdinalTag(field reflect.StructField) int {
ordinal, err := readIntTag(field, tagOrdinal)
if err != nil {
return math.MaxInt32
}
return ordinal
}
func readBoundsTag(field reflect.StructField) bounds {
content, ok := field.Tag.Lookup(tagBounds)
if !ok {
return nil
}
var nums []int
for _, elem := range strings.Split(content, ",") {
var (
num = math.MaxInt32
err error
)
if len(elem) != 0 {
num, err = strconv.Atoi(elem)
if err != nil {
panic(elem + ": " + err.Error())
}
}
nums = append(nums, num)
}
return bounds(nums)
}
func readBoolTag(field reflect.StructField, tagKey string) (bool, error) {
content, ok := field.Tag.Lookup(tagKey)
if !ok {
return false, errors.New(tagKey + " not found on field " + field.Name)
}
res, err := strconv.ParseBool(content)
if err != nil {
return false, errors.New("error parsing bool body from tag " + tagKey + " " + err.Error())
}
return res, nil
}
func readIntTag(field reflect.StructField, tagKey string) (int, error) {
content, ok := field.Tag.Lookup(tagKey)
if !ok {
return 0, errors.New(tagKey + " not found on field " + field.Name)
}
res, err := strconv.ParseInt(content, 0, 64)
if err != nil {
return 0, errors.New("error parsing int body from tag " + tagKey + " " + err.Error())
}
return int(res), nil
}
func readHandleRightsTag(field reflect.StructField) (zx.Rights, error) {
val, ok := field.Tag.Lookup(tagHandleRights)
if !ok {
return zx.RightSameRights, nil
}
rights, err := strconv.ParseInt(val, 0, 64)
if err != nil {
return zx.RightSameRights, err
}
convertedRights := zx.Rights(rights)
return convertedRights, nil
}
func toInt8Map(values reflect.Value) map[int8]struct{} {
m := make(map[int8]struct{})
for i := 0; i < values.Len(); i++ {
value := values.Index(i)
m[int8(value.Int())] = struct{}{}
}
return m
}
func toInt16Map(values reflect.Value) map[int16]struct{} {
m := make(map[int16]struct{})
for i := 0; i < values.Len(); i++ {
value := values.Index(i)
m[int16(value.Int())] = struct{}{}
}
return m
}
func toInt32Map(values reflect.Value) map[int32]struct{} {
m := make(map[int32]struct{})
for i := 0; i < values.Len(); i++ {
value := values.Index(i)
m[int32(value.Int())] = struct{}{}
}
return m
}
func toInt64Map(values reflect.Value) map[int64]struct{} {
m := make(map[int64]struct{})
for i := 0; i < values.Len(); i++ {
value := values.Index(i)
m[int64(value.Int())] = struct{}{}
}
return m
}
func toUint8Map(values reflect.Value) map[uint8]struct{} {
m := make(map[uint8]struct{})
for i := 0; i < values.Len(); i++ {
value := values.Index(i)
m[uint8(value.Uint())] = struct{}{}
}
return m
}
func toUint16Map(values reflect.Value) map[uint16]struct{} {
m := make(map[uint16]struct{})
for i := 0; i < values.Len(); i++ {
value := values.Index(i)
m[uint16(value.Uint())] = struct{}{}
}
return m
}
func toUint32Map(values reflect.Value) map[uint32]struct{} {
m := make(map[uint32]struct{})
for i := 0; i < values.Len(); i++ {
value := values.Index(i)
m[uint32(value.Uint())] = struct{}{}
}
return m
}
func toUint64Map(values reflect.Value) map[uint64]struct{} {
m := make(map[uint64]struct{})
for i := 0; i < values.Len(); i++ {
value := values.Index(i)
m[uint64(value.Uint())] = struct{}{}
}
return m
}
func (c *creator) createMarshalerForField(typ reflect.Type, bounds bounds, handleRights zx.Rights, handleSubtype zx.ObjType) (Marshaler, error) {
if isHandleType(typ) {
nullable, _ := bounds.pop()
return &mHandle{nullable: nullable != 0, rights: handleRights, subtype: handleSubtype}, nil
}
if typ.ConvertibleTo(proxyType) || typ.ConvertibleTo(interfaceRequestType) {
nullable, _ := bounds.pop()
return &mProtocol{
nullable: nullable != 0,
rights: ProtocolRights,
subtype: zx.ObjTypeChannel}, nil
}
if m, ok := typ.MethodByName("I_EnumValues"); ok {
values := m.Func.Call([]reflect.Value{reflect.Zero(typ)})[0]
var isStrict bool
if m, ok := typ.MethodByName("I_EnumIsStrict"); ok {
isStrict = m.Func.Call([]reflect.Value{reflect.Zero(typ)})[0].Interface().(bool)
} else {
return nil, errors.New("unable to create field marshaler for enum of " + nicefmt(typ) + ", missing I_EnumIsStrict method")
}
switch typ.Kind() {
case reflect.Int8:
return &mEnumOfInt8{
isStrict: isStrict,
values: toInt8Map(values),
}, nil
case reflect.Int16:
return &mEnumOfInt16{
isStrict: isStrict,
values: toInt16Map(values),
}, nil
case reflect.Int32:
return &mEnumOfInt32{
isStrict: isStrict,
values: toInt32Map(values),
}, nil
case reflect.Int64:
return &mEnumOfInt64{
isStrict: isStrict,
values: toInt64Map(values),
}, nil
case reflect.Uint8:
return &mEnumOfUint8{
isStrict: isStrict,
values: toUint8Map(values),
}, nil
case reflect.Uint16:
return &mEnumOfUint16{
isStrict: isStrict,
values: toUint16Map(values),
}, nil
case reflect.Uint32:
return &mEnumOfUint32{
isStrict: isStrict,
values: toUint32Map(values),
}, nil
case reflect.Uint64:
return &mEnumOfUint64{
isStrict: isStrict,
values: toUint64Map(values),
}, nil
default:
return nil, errors.New("unable to create field marshaler for enum of " + nicefmt(typ))
}
}
if m, ok := typ.MethodByName("I_BitsMask"); ok {
mask := m.Func.Call([]reflect.Value{reflect.Zero(typ)})[0]
var isStrict bool
if m, ok := typ.MethodByName("I_BitsIsStrict"); ok {
isStrict = m.Func.Call([]reflect.Value{reflect.Zero(typ)})[0].Interface().(bool)
} else {
return nil, errors.New("unable to create field marshaler for bits of " + nicefmt(typ) + ", missing I_BitsIsStrict method")
}
switch typ.Kind() {
case reflect.Uint8:
return &mBitsOfUint8{
isStrict: isStrict,
mask: uint8(mask.Uint()),
}, nil
case reflect.Uint16:
return &mBitsOfUint16{
isStrict: isStrict,
mask: uint16(mask.Uint()),
}, nil
case reflect.Uint32:
return &mBitsOfUint32{
isStrict: isStrict,
mask: uint32(mask.Uint()),
}, nil
case reflect.Uint64:
return &mBitsOfUint64{
isStrict: isStrict,
mask: uint64(mask.Uint()),
}, nil
default:
return nil, errors.New("unable to create field marshaler for bits of " + nicefmt(typ))
}
}
switch typ.Kind() {
case reflect.Bool:
return &mBool{}, nil
case reflect.Int8:
return &mInt8{}, nil
case reflect.Int16:
return &mInt16{}, nil
case reflect.Int32:
return &mInt32{}, nil
case reflect.Int64:
return &mInt64{}, nil
case reflect.Uint8:
return &mUint8{}, nil
case reflect.Uint16:
return &mUint16{}, nil
case reflect.Uint32:
return &mUint32{}, nil
case reflect.Uint64:
return &mUint64{}, nil
case reflect.Float32:
return &mFloat32{}, nil
case reflect.Float64:
return &mFloat64{}, nil
case reflect.String:
maxSize, _ := bounds.pop()
s := mString(maxSize)
return &s, nil
case reflect.Array:
elemMarshaler, err := c.createMarshalerForField(typ.Elem(), bounds, handleRights, handleSubtype)
if err != nil {
return nil, err
}
return &mArray{
Marshaler: elemMarshaler,
size: typ.Len(),
rtElemSize: typ.Elem().Size(),
}, nil
case reflect.Slice:
maxSize, remainder := bounds.pop()
elemTyp := typ.Elem()
elemMarshaler, err := c.createMarshalerForField(elemTyp, remainder, handleRights, handleSubtype)
if err != nil {
return nil, err
}
return &mVector{
Marshaler: elemMarshaler,
maxSize: maxSize,
elemTyp: elemTyp,
useUnsafeCopy: matchesWireFormatLayout(elemMarshaler, elemTyp),
}, nil
case reflect.Struct:
return c.createMarshalerForStruct(typ)
case reflect.Ptr:
return c.createOptMarshalerForField(typ.Elem(), bounds, handleRights, handleSubtype)
default:
return nil, errors.New("unable to create field marshaler for " + nicefmt(typ))
}
}
func (c *creator) createOptMarshalerForField(typ reflect.Type, bounds bounds, handleRights zx.Rights, handleSubtype zx.ObjType) (Marshaler, error) {
m, err := c.createMarshalerForField(typ, bounds, handleRights, handleSubtype)
if err != nil {
return nil, err
}
switch m := m.(type) {
case *mString:
o := mOptString(*m)
return &o, nil
case *mEmptyStruct:
return &mPointer{
Marshaler: m,
elemTyp: typ,
}, nil
case *mStruct:
return &mPointer{
Marshaler: m,
elemTyp: typ,
}, nil
case *mVector:
return &mOptVector{
mVector: m,
sliceTyp: typ,
}, nil
case *mXUnion:
return &mOptXUnion{
mXUnion: m,
typ: typ,
}, nil
default:
return nil, errors.New("unable to create optional field marshaler for " + nicefmt(typ))
}
}
// Message is implemented by any value that represents a FIDL message.
type Message interface {
Marshaler() Marshaler
}
type Marshaler interface {
// Marshal and unmarshal sizes can be different because they can be context dependent.
// e.g. it is possible to write a new format but still read the old format
getMarshalSize(ctx MarshalerContext) int
getUnmarshalSize(ctx MarshalerContext) int
marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error
unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error
}
// Assert various encoders implement the Marshaler interface.
var _ = []Marshaler{
(*mString)(nil),
(*mOptString)(nil),
(*mBool)(nil),
(*mInt8)(nil),
(*mInt16)(nil),
(*mInt32)(nil),
(*mInt64)(nil),
(*mUint8)(nil),
(*mUint16)(nil),
(*mUint32)(nil),
(*mUint64)(nil),
(*mFloat32)(nil),
(*mFloat64)(nil),
(*mEmptyStruct)(nil),
(*mStruct)(nil),
(*mXUnion)(nil),
(*mOptXUnion)(nil),
(*mTable)(nil),
(*mPointer)(nil),
(*mArray)(nil),
(*mVector)(nil),
(*mOptVector)(nil),
(*mEnumOfInt8)(nil),
(*mEnumOfInt16)(nil),
(*mEnumOfInt32)(nil),
(*mEnumOfInt64)(nil),
(*mEnumOfUint8)(nil),
(*mEnumOfUint16)(nil),
(*mEnumOfUint32)(nil),
(*mEnumOfUint64)(nil),
(*mBitsOfUint8)(nil),
(*mBitsOfUint16)(nil),
(*mBitsOfUint32)(nil),
(*mBitsOfUint64)(nil),
}
type mField struct {
Marshaler
index int
offset uintptr
}
type mFieldWithWireOffset struct {
mField
wireOffsetV2 int
}
type mStruct struct {
fields []mFieldWithWireOffset
sizeV2, alignmentV2 int
useUnsafeCopy bool
}
func (m *mStruct) getMarshalSize(ctx MarshalerContext) int {
return m.sizeV2
}
func (m *mStruct) getUnmarshalSize(ctx MarshalerContext) int {
return m.sizeV2
}
func (m *mStruct) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if m.useUnsafeCopy {
// Directly copy the object's memory to the buffer.
sh := reflect.SliceHeader{
Data: uintptr(unsafe.Pointer(v.UnsafeAddr())),
Len: m.sizeV2,
Cap: m.sizeV2,
}
s := *(*[]uint8)(unsafe.Pointer(&sh))
copy(out.buffer[offset:], s)
return nil
}
for _, field := range m.fields {
fieldOffset := offset + field.wireOffsetV2
if err := field.Marshaler.marshal(ctx, v.StructFieldOffset(field.offset), out, fieldOffset, depth); err != nil {
return err
}
}
return nil
}
func (m *mStruct) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
if m.useUnsafeCopy {
size := m.getUnmarshalSize(ctx)
// Directly copy from the buffer to the object's memory.
if len(in.buffer) < offset+size {
return ErrPayloadTooSmall
}
sh := reflect.SliceHeader{
Data: uintptr(unsafe.Pointer(v.UnsafeAddr())),
Len: size,
Cap: size,
}
s := *(*[]uint8)(unsafe.Pointer(&sh))
copy(s, in.buffer[offset:])
return nil
}
endOfLastWire := 0
for _, field := range m.fields {
wireOffset := field.wireOffsetV2
fieldOffset := offset + wireOffset
for i := offset + endOfLastWire; i < fieldOffset; i++ {
if in.buffer[i] != 0 {
return newValueError(ErrNonZeroPadding, in.buffer[i])
}
}
endOfLastWire = wireOffset + field.getUnmarshalSize(ctx)
if err := field.Marshaler.unmarshal(ctx, in, fieldOffset, depth, v.StructFieldOffset(field.offset)); err != nil {
return err
}
}
for i := offset + endOfLastWire; i < offset+m.getUnmarshalSize(ctx); i++ {
if in.buffer[i] != 0 {
return newValueError(ErrNonZeroPadding, in.buffer[i])
}
}
return nil
}
type mEmptyStruct struct{}
func (_ *mEmptyStruct) getMarshalSize(ctx MarshalerContext) int {
return 1
}
func (_ *mEmptyStruct) getUnmarshalSize(ctx MarshalerContext) int {
return 1
}
func (_ *mEmptyStruct) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
out.writeUint8(offset, 0)
return nil
}
func (_ *mEmptyStruct) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
if structByte := in.readUint8(offset); structByte != 0 {
return newValueError(ErrInvalidEmptyStruct, structByte)
}
return nil
}
// closeHandles closes all the handles in the provided slice, ignoring any
// errors (best effort)
func closeHandles(handles []zx.HandleInfo) {
for i := range handles {
_ = handleClose(&handles[i].Handle)
}
}
type mXUnion struct {
typ reflect.Type
fields map[uint64]mField
ordinals []uint64
sizeV2, alignmentV2 int
strictness
resourceness
}
func (m *mXUnion) getMarshalSize(ctx MarshalerContext) int {
return m.sizeV2
}
func (m *mXUnion) getUnmarshalSize(ctx MarshalerContext) int {
return m.sizeV2
}
func (m *mXUnion) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
var ordinal uint64
ordinal = v.StructFieldOffset(0).Uint64()
if ordinal == 0 {
return newValueError(ErrInvalidXUnionTag, ordinal)
}
field, ok := m.fields[ordinal]
out.writeUint64(offset, ordinal)
if !ok {
if m.strictness == isStrict {
return newValueError(ErrInvalidXUnionTag, ordinal)
}
fld, fldOk := m.typ.FieldByName("I_unknownData")
if !fldOk {
return errorf("internal error (no unknown field found in flexible union to encode)")
}
rawUnknownData := v.StructFieldOffset(fld.Offset).Interface()
unknownData, ok := rawUnknownData.(UnknownData)
if !ok {
return errorf("internal error (unexpected union I_unknownData type {})", rawUnknownData)
}
if len(unknownData.Handles) > 0 && m.resourceness == isValueType {
closeHandles(unknownData.Handles)
return ErrValueTypeHandles
}
err := marshalEnvelopeUnknown(
ctx,
out,
offset+8,
depth,
unknownData,
)
if err != nil {
return err
}
return nil
}
// Field.
if err := marshalEnvelopePresent(ctx, field, v.StructFieldOffset(field.offset), out, offset+8, depth); err != nil {
return err
}
return nil
}
func (m *mXUnion) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
return m.unmarshalWithOptSpecified(ctx, in, offset, depth, v, nil)
}
func (m *mXUnion) unmarshalWithOptSpecified(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value, typ reflect.Type) error {
// Can this envelope be optional? If it can, the type must be provided
// in order to reflectively create a pointer container.
optAllowed := typ != nil
ordinal := in.readUint64(offset)
// ordinal=0 indicates that there MUST be no envelope.
if ordinal == 0 {
h, err := unmarshalEnvelopeHeader(ctx, in, offset+8)
if err != nil {
return err
}
if !optAllowed && !h.isPresent(ctx) {
return newValueError(ErrUnexpectedNullRef, ordinal)
}
if !optAllowed || h.isPresent(ctx) {
return newValueError(ErrInvalidXUnionTag, ordinal)
}
return nil
}
// If we reach here, ordinal != 0.
field, ok := m.fields[ordinal]
if !ok {
v.StructFieldOffset(0).SetUint64(ordinal)
unknownDataItem, err := unmarshalEnvelopeUnknown(ctx, in, offset+8, depth)
if err != nil {
return err
}
if m.strictness == isStrict {
closeHandles(unknownDataItem.Handles)
return newValueError(ErrInvalidXUnionTag, ordinal)
}
if len(unknownDataItem.Handles) > 0 && m.resourceness == isValueType {
closeHandles(unknownDataItem.Handles)
return ErrValueTypeHandles
}
fld, ok := m.typ.FieldByName("I_unknownData")
if !ok {
return errorf("internal error (no unknown field found in flexible union to decode into)")
}
v.StructFieldOffset(fld.Offset).SetInterface(unknownDataItem)
return nil
}
if optAllowed {
v.PointerSetNew(m.typ)
v = v.PointerElem()
}
ordinalOrFieldIndex := ordinal
v.StructFieldOffset(0).SetUint64(ordinalOrFieldIndex)
var mode unmarshalEnvelopeMode
if optAllowed {
mode = knownMayBeAbsent
} else {
mode = knownMustBePresent
}
isPresent, err := unmarshalEnvelope(ctx, field.Marshaler, in, offset+8, depth, v.StructFieldOffset(field.offset), mode)
if err != nil {
return err
}
if !isPresent {
v.PointerSetNil()
}
return nil
}
type mOptXUnion struct {
*mXUnion
typ reflect.Type
}
func (m *mOptXUnion) getMarshalSize(ctx MarshalerContext) int {
return m.mXUnion.getMarshalSize(ctx)
}
func (m *mOptXUnion) getUnmarshalSize(ctx MarshalerContext) int {
return m.mXUnion.getUnmarshalSize(ctx)
}
func (m *mOptXUnion) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if v.PointerIsNil() {
out.writeUint64(offset, 0) // ordinal + padding
marshalEnvelopeAbsent(ctx, out, offset+8)
return nil
} else {
return m.mXUnion.marshal(ctx, v.PointerElem(), out, offset, depth)
}
}
func (m *mOptXUnion) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
return m.unmarshalWithOptSpecified(ctx, in, offset, depth, v, m.typ)
}
// This assumes that I_unknownData in tables is always the first non-zero
// sized member.
const unknownTableDataOffset = 0
type mTable struct {
typ reflect.Type
fields []mField
presenceOffsets []uintptr
ordinals []uint64
size, alignment int
resourceness
}
func (m *mTable) getMarshalSize(ctx MarshalerContext) int {
return m.size
}
func (m *mTable) getUnmarshalSize(ctx MarshalerContext) int {
return m.size
}
func envelopeSize(ctx MarshalerContext) int {
return 8
}
type envelopeState int
const (
emptyEnvelope envelopeState = iota
inlineEnvelope
outOfLineEnvelope
)
type envelopeHeader struct {
byteValue []byte
byteCount uint32
handleCount uint32
state envelopeState
}
func (h envelopeHeader) isPresent(ctx MarshalerContext) bool {
return h.state != emptyEnvelope
}
func marshalEnvelopePresent(ctx MarshalerContext, m Marshaler, v unsafevalue.Value, out *encoder, offset int, depth int) error {
numHandleDispositions := len(out.handleDispositions)
if m.getMarshalSize(ctx) <= 4 {
if err := m.marshal(ctx, v, out, offset, depth+1); err != nil {
return err
}
numHandleDispositions = len(out.handleDispositions) - numHandleDispositions
out.writeUint16(offset+4, uint16(numHandleDispositions))
out.writeUint16(offset+6, 1)
return nil
}
numBytes := len(out.buffer)
outOfLineOffset, err := out.newObject(m.getMarshalSize(ctx), depth)
if err != nil {
return err
}
if err := m.marshal(ctx, v, out, outOfLineOffset, depth+1); err != nil {
return err
}
numHandleDispositions = len(out.handleDispositions) - numHandleDispositions
numBytes = len(out.buffer) - numBytes
out.writeUint32(offset, uint32(numBytes))
out.writeUint16(offset+4, uint16(numHandleDispositions))
out.writeUint16(offset+6, 0)
return nil
}
func marshalEnvelopeAbsent(ctx MarshalerContext, out *encoder, offset int) {
out.writeUint64(offset, 0) // zero envelope
}
func marshalEnvelopeUnknown(ctx MarshalerContext, out *encoder, offset int, depth int, unknownData UnknownData) error {
for _, info := range unknownData.Handles {
out.handleDispositions = append(out.handleDispositions, zx.HandleDisposition{
Operation: zx.HandleOpMove,
Handle: info.Handle,
Type: info.Type,
Rights: info.Rights,
Result: zx.ErrOk,
})
}
if len(unknownData.Bytes) <= 4 {
copy(out.buffer[offset:], unknownData.Bytes)
out.writeUint16(offset+4, uint16(len(unknownData.Handles)))
out.writeUint16(offset+6, 1)
return nil
}
outOfLineOffset, err := out.newObject(len(unknownData.Bytes), depth)
if err != nil {
return err
}
copy(out.buffer[outOfLineOffset:], unknownData.Bytes)
out.writeUint32(offset, uint32(len(unknownData.Bytes)))
out.writeUint16(offset+4, uint16(len(unknownData.Handles)))
out.writeUint16(offset+6, 0)
return nil
}
type unmarshalEnvelopeMode int
const (
_ unmarshalEnvelopeMode = iota
// knownMayBeAbsent indicates that the content of the envelope is known,
// and that it may be absent, i.e. encountering an empty envelope is
// expected
knownMayBeAbsent
// knownMustBePresent indicates that the content of the envelope is known,
// and that it must be present, i.e. encountering an empty envelope
// should be considered a failure
knownMustBePresent
)
func unmarshalEnvelopeHeader(ctx MarshalerContext, in *decoder, offset int) (envelopeHeader, error) {
var h envelopeHeader
inlineIndicator := in.readUint16(offset + 6)
switch inlineIndicator {
case 1:
h = envelopeHeader{
byteValue: in.buffer[offset : offset+4],
handleCount: uint32(in.readUint16(offset + 4)),
state: inlineEnvelope,
}
case 0:
h = envelopeHeader{
byteCount: in.readUint32(offset),
handleCount: uint32(in.readUint16(offset + 4)),
}
if h.byteCount == 0 && h.handleCount == 0 {
h.state = emptyEnvelope
} else {
h.state = outOfLineEnvelope
}
if h.byteCount%8 != 0 {
return h, newValueError(ErrInvalidNumBytesInEnvelope, h.byteCount)
}
default:
return h, newValueError(ErrBadInlineIndicatorEncoding, h)
}
return h, nil
}
func unmarshalEnvelopeUnknown(ctx MarshalerContext, in *decoder, offset int, depth int) (UnknownData, error) {
header, err := unmarshalEnvelopeHeader(ctx, in, offset)
if err != nil {
return UnknownData{}, err
}
var unknownHandles []zx.HandleInfo
if header.handleCount > uint32(len(in.handleInfos)) {
return UnknownData{}, newValueError(ErrTooManyHandles, header)
}
if header.handleCount != 0 {
// Slice the end off first; in Go, slicing the head is a more conservative
// operation than slicing the tail because the tail is allowed to reach
// into capacity, but the head may only use length. Slicing the head first
// allows the compiler to elide bounds checks on all the subsequent code.
//
// Even slicing from zero incurs a bounds check, hence the above check.
usedHandles := in.handleInfos[header.handleCount:]
// The compiler's bounds check elimination is not smart enough to avoid
// bounds checks in the loop body without this local variable.
unknownHandles = in.handleInfos[:header.handleCount]
in.handleInfos = usedHandles
}
if header.state == inlineEnvelope {
unknownBytes := in.buffer[offset:][:4]
return UnknownData{Bytes: unknownBytes, Handles: unknownHandles}, nil
}
start, err := in.newObject(int(header.byteCount), depth)
if err != nil {
return UnknownData{}, err
}
unknownBytes := in.buffer[start:][:header.byteCount]
return UnknownData{Bytes: unknownBytes, Handles: unknownHandles}, nil
}
func unmarshalEnvelopeContent(ctx MarshalerContext, header envelopeHeader, m Marshaler, in *decoder, depth int, v unsafevalue.Value, mode unmarshalEnvelopeMode) (bool, error) {
if header.state == inlineEnvelope {
// Inline envelope.
var innerDecoderHandleInfos []zx.HandleInfo
if header.handleCount != 0 {
if header.handleCount != 1 {
return false, newValueError(ErrInvalidNumHandlesInEnvelope, header.handleCount)
}
if len(in.handleInfos) > 0 {
innerDecoderHandleInfos = []zx.HandleInfo{in.handleInfos[0]}
in.handleInfos = in.handleInfos[1:]
}
}
for _, elem := range header.byteValue[m.getUnmarshalSize(ctx):] {
if elem != 0 {
return false, newValueError(ErrNonZeroPadding, elem)
}
}
d := decoder{
buffer: header.byteValue,
handleInfos: innerDecoderHandleInfos,
}
if err := m.unmarshal(ctx, &d, 0, depth+1, v); err != nil {
return false, err
}
return true, nil
}
outOfLineOffset, err := in.newObject(m.getUnmarshalSize(ctx), depth)
if err != nil {
return false, err
}
if err := m.unmarshal(ctx, in, outOfLineOffset, depth+1, v); err != nil {
return false, err
}
return true, nil
}
func unmarshalEnvelope(ctx MarshalerContext, m Marshaler, in *decoder, offset int, depth int, v unsafevalue.Value, mode unmarshalEnvelopeMode) (bool, error) {
startingFrom := in.nextObject
unclaimedHandles := uint32(len(in.handleInfos))
header, err := unmarshalEnvelopeHeader(ctx, in, offset)
if err != nil {
return false, err
}
if m.getUnmarshalSize(ctx) > 4 && header.state == inlineEnvelope {
return false, newExpectError(ErrInvalidInlineBitValueInEnvelope, header.state, outOfLineEnvelope)
}
if m.getUnmarshalSize(ctx) <= 4 && header.state == outOfLineEnvelope {
return false, newExpectError(ErrInvalidInlineBitValueInEnvelope, header.state, inlineEnvelope)
}
if !header.isPresent(ctx) {
if mode == knownMustBePresent {
return false, newValueError(ErrUnexpectedNullRef, v)
}
return false, nil
}
success, err := unmarshalEnvelopeContent(ctx, header, m, in, depth, v, mode)
if err != nil {
return false, err
}
consumedHandles := unclaimedHandles - uint32(len(in.handleInfos))
consumedBytes := in.nextObject - startingFrom
if header.handleCount != consumedHandles {
return false, newExpectError(ErrInvalidNumHandlesInEnvelope, header.handleCount, consumedHandles)
}
if header.byteCount != uint32(consumedBytes) {
return false, newExpectError(ErrInvalidNumBytesInEnvelope, header.byteCount, consumedBytes)
}
return success, nil
}
// closeUnknownFieldHandles closes all of the handles in the provided map,
// ignoring any errors (best effort).
func closeUnknownFieldHandles(unknownFields map[uint64]UnknownData) {
for _, data := range unknownFields {
closeHandles(data.Handles)
}
}
func (m *mTable) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
var (
maxOrdinal uint64
numKnown = len(m.ordinals)
fieldPresent = make([]bool, numKnown)
unknownData map[uint64]UnknownData
)
rawUnknownData := v.StructFieldOffset(unknownTableDataOffset).Interface()
if rawUnknownData != nil {
var ok bool
unknownData, ok = rawUnknownData.(map[uint64]UnknownData)
if !ok {
return errorf("internal error (unexpected table I_unknownData type {})", rawUnknownData)
}
// Determining max ordinal from unknown ordinals.
for unknownOrdinal := range unknownData {
if maxOrdinal < unknownOrdinal {
maxOrdinal = unknownOrdinal
}
}
}
if m.resourceness == isValueType {
for _, data := range unknownData {
if len(data.Handles) > 0 {
closeUnknownFieldHandles(unknownData)
return ErrValueTypeHandles
}
}
}
// Determining max ordinal from known ordinals.
for index := 0; index < numKnown; index++ {
fieldPresent[index] = v.StructFieldOffset(m.presenceOffsets[index]).Bool()
if fieldPresent[index] {
if fieldOrdinal := m.ordinals[index]; maxOrdinal < fieldOrdinal {
maxOrdinal = fieldOrdinal
}
}
}
// Vector of envelopes header.
out.writeUint64(offset, maxOrdinal)
out.writeUint64(offset+8, allocPresent)
// Early exit on empty table.
if maxOrdinal == 0 {
return nil
}
// Encode in the out-of-line object.
outOfLineOffset, err := out.newObject(int(maxOrdinal)*envelopeSize(ctx), depth)
if err != nil {
return err
}
// Envelopes.
var (
ordinal uint64 = 1
index = 0
)
envelopeOffset := outOfLineOffset
for ordinal <= maxOrdinal {
fieldKnown := index < numKnown && ordinal == m.ordinals[index]
if fieldKnown && fieldPresent[index] {
if fieldPresent[index] {
if err := marshalEnvelopePresent(ctx, m.fields[index], v.StructFieldOffset(m.fields[index].offset), out, envelopeOffset, depth+1); err != nil {
return err
}
} else {
// This else clause is redundant with the else clause in the top level if statement but
// saves a map lookup in the common case (all fields are known)
marshalEnvelopeAbsent(ctx, out, envelopeOffset)
}
} else if unknownField, ok := unknownData[ordinal]; ok {
err := marshalEnvelopeUnknown(
ctx,
out,
envelopeOffset,
depth+1,
unknownField,
)
if err != nil {
return err
}
} else {
marshalEnvelopeAbsent(ctx, out, envelopeOffset)
}
ordinal++
envelopeOffset += 8
if fieldKnown {
index++
}
}
return nil
}
func (m *mTable) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
mou := in.readUint64(offset)
// The wire format requires vector counts to fit in uint32.
if mou > uint64(^uint32(0)) {
return newValueError(ErrUnexpectedOrdinal, v)
}
maxOrdinal := mou
switch allocPtr := in.readUint64(offset + 8); allocPtr {
case allocPresent:
// good
case noAlloc:
return newValueError(ErrUnexpectedNullRef, v)
default:
return newValueError(ErrBadRefEncoding, v)
}
// Early exit on empty table.
if maxOrdinal == 0 {
return nil
}
// Envelopes.
var (
numKnown = len(m.ordinals)
ordinal uint64 = 1
index = 0
unknownData map[uint64]UnknownData
)
outOfLineOffset, err := in.newObject(int(maxOrdinal)*envelopeSize(ctx), depth)
if err != nil {
return err
}
envelopeOffset := outOfLineOffset
for ordinal <= maxOrdinal {
fieldKnown := index < numKnown && ordinal == m.ordinals[index]
if fieldKnown {
if isPresent, err := unmarshalEnvelope(ctx, m.fields[index], in, envelopeOffset, depth+1, v.StructFieldOffset(m.fields[index].offset), knownMayBeAbsent); err != nil {
return err
} else if isPresent {
v.StructFieldOffset(m.presenceOffsets[index]).SetBool(true)
}
} else {
unknownDataItem, err := unmarshalEnvelopeUnknown(ctx, in, envelopeOffset, depth+1)
if err != nil {
return err
}
if len(unknownDataItem.Bytes) > 0 || len(unknownDataItem.Handles) > 0 {
if unknownData == nil {
unknownData = make(map[uint64]UnknownData)
v.StructFieldOffset(unknownTableDataOffset).SetInterface(unknownData)
}
unknownData[ordinal] = unknownDataItem
}
}
ordinal++
envelopeOffset += envelopeSize(ctx)
if fieldKnown {
index++
}
}
if m.resourceness == isValueType {
for _, data := range unknownData {
if len(data.Handles) > 0 {
closeUnknownFieldHandles(unknownData)
return ErrValueTypeHandles
}
}
}
return nil
}
type mPointer struct {
Marshaler
elemTyp reflect.Type
}
func (m *mPointer) getMarshalSize(ctx MarshalerContext) int {
return 8
}
func (m *mPointer) getUnmarshalSize(ctx MarshalerContext) int {
return 8
}
func (m *mPointer) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
// Nil?
if v.PointerIsNil() {
out.writeUint64(offset, noAlloc)
return nil
}
// Write out allocation marker.
out.writeUint64(offset, allocPresent)
// Set up the out-of-line space.
outOfLineOffset, err := out.newObject(align(m.Marshaler.getMarshalSize(ctx), 8), depth)
if err != nil {
return err
}
// Marshal field.
if err := m.Marshaler.marshal(ctx, v.PointerElem(), out, outOfLineOffset, depth+1); err != nil {
return err
}
return nil
}
func (m *mPointer) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
// Nil?
switch ptr := in.readUint64(offset); ptr {
case noAlloc:
v.PointerSetNil()
return nil
case allocPresent:
// good
default:
return newValueError(ErrBadRefEncoding, v)
}
// Create the new struct.
v.PointerSetNew(m.elemTyp)
// Set up the out-of-line space and the head.
outOfLineOffset, err := in.newObject(m.Marshaler.getUnmarshalSize(ctx), depth)
if err != nil {
return err
}
// Unmarshal field.
if err := m.Marshaler.unmarshal(ctx, in, outOfLineOffset, depth+1, v.PointerElem()); err != nil {
return err
}
return nil
}
type mArray struct {
Marshaler
rtElemSize uintptr
size int
}
func (m *mArray) getMarshalSize(ctx MarshalerContext) int {
return m.size * m.Marshaler.getMarshalSize(ctx)
}
func (m *mArray) getUnmarshalSize(ctx MarshalerContext) int {
return m.size * m.Marshaler.getUnmarshalSize(ctx)
}
func (m *mArray) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
elemSize := m.Marshaler.getMarshalSize(ctx)
for i, len := 0, m.size; i < len; i++ {
if err := m.Marshaler.marshal(ctx, v.ArrayIndex(m.rtElemSize, i), out, offset+i*elemSize, depth); err != nil {
return err
}
}
return nil
}
func (m *mArray) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
elemSize := m.Marshaler.getUnmarshalSize(ctx)
for i, len := 0, m.size; i < len; i++ {
if err := m.Marshaler.unmarshal(ctx, in, offset+i*elemSize, depth, v.ArrayIndex(m.rtElemSize, i)); err != nil {
return err
}
}
return nil
}
type mVector struct {
Marshaler
maxSize int
elemTyp reflect.Type
useUnsafeCopy bool
}
func (m *mVector) getMarshalSize(ctx MarshalerContext) int {
return 16
}
func (m *mVector) getUnmarshalSize(ctx MarshalerContext) int {
return 16
}
func (m *mVector) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
// Bounds check.
vLen := v.SliceLen()
if m.maxSize < vLen {
return newExpectError(ErrVectorTooLong, m.maxSize, vLen)
}
// Vector header.
out.writeUint64(offset, uint64(vLen))
out.writeUint64(offset+8, allocPresent)
// Early exit if the vector is empty.
if vLen == 0 {
return nil
}
// Encode in the out-of-line object.
outOfLineOffset, err := out.newObject(vLen*m.Marshaler.getMarshalSize(ctx), depth)
if err != nil {
return err
}
// Marshal elements.
wireElemSize := m.Marshaler.getMarshalSize(ctx)
if m.useUnsafeCopy {
var bytes []byte
sh := (*reflect.SliceHeader)(unsafe.Pointer(&bytes))
sh.Data = (*reflect.SliceHeader)(unsafe.Pointer(v.UnsafeAddr())).Data
sh.Len = vLen * wireElemSize
sh.Cap = vLen * wireElemSize
copy(out.buffer[outOfLineOffset:], bytes)
} else {
elemTypSize := m.elemTyp.Size()
for i := 0; i < vLen; i++ {
if err := m.Marshaler.marshal(ctx, v.SliceIndex(elemTypSize, i), out, outOfLineOffset+i*wireElemSize, depth+1); err != nil {
return err
}
}
}
return nil
}
func (m *mVector) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
size := in.readUint64(offset)
ptr := in.readUint64(offset + 8)
switch ptr {
case noAlloc:
return newValueError(ErrUnexpectedNullRef, v)
case allocPresent:
return m.unmarshalWithUncheckedSize(ctx, in, depth, v, int(size))
default:
return newValueError(ErrBadRefEncoding, v)
}
}
func (m *mVector) unmarshalWithUncheckedSize(ctx MarshalerContext, in *decoder, depth int, v unsafevalue.Value, size int) error {
if size < 0 || m.maxSize < size {
return newExpectError(ErrVectorTooLong, m.maxSize, size)
}
// Unmarshal in the out-of-line object.
elemSize := m.Marshaler.getUnmarshalSize(ctx)
outOfLineOffset, err := in.newObject(size*elemSize, depth)
if err != nil {
return err
}
// Unmarshal elements.
if m.useUnsafeCopy {
// Copy the data as bytes, then construct a slice header with the appropriate size
// for the slice type (if it is not bytes).
s := make([]byte, size*m.Marshaler.getUnmarshalSize(ctx))
copy(s, in.buffer[outOfLineOffset:])
sh := (*reflect.SliceHeader)(unsafe.Pointer(v.UnsafeAddr()))
sh.Data = (*reflect.SliceHeader)(unsafe.Pointer(&s)).Data
sh.Len = size
sh.Cap = size
} else {
elemTypSize := m.elemTyp.Size()
v.SliceSetMakeSlice(m.elemTyp, size, size)
for i := 0; i < size; i++ {
if err := m.Marshaler.unmarshal(ctx, in, outOfLineOffset+i*elemSize, depth+1, v.SliceIndex(elemTypSize, i)); err != nil {
return err
}
}
}
return nil
}
type mOptVector struct {
*mVector
sliceTyp reflect.Type
}
func (m *mOptVector) getMarshalSize(ctx MarshalerContext) int {
return 16
}
func (m *mOptVector) getUnmarshalSize(ctx MarshalerContext) int {
return 16
}
func (m *mOptVector) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if v.PointerIsNil() {
out.writeUint64(offset, 0)
out.writeUint64(offset+8, noAlloc)
return nil
}
return m.mVector.marshal(ctx, v.PointerElem(), out, offset, depth)
}
func (m *mOptVector) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
size := in.readUint64(offset)
ptr := in.readUint64(offset + 8)
switch ptr {
case noAlloc:
if size > 0 {
return newValueError(ErrUnexpectedNullRef, ptr)
}
v.PointerSetNil()
return nil
case allocPresent:
v.PointerSetNew(m.sliceTyp)
return m.mVector.unmarshalWithUncheckedSize(ctx, in, depth, v.PointerElem(), int(size))
default:
return newValueError(ErrBadRefEncoding, v)
}
}
type mBool struct{}
func (m *mBool) getMarshalSize(ctx MarshalerContext) int {
return 1
}
func (m *mBool) getUnmarshalSize(ctx MarshalerContext) int {
return 1
}
func (m *mBool) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if v.Bool() {
out.writeUint8(offset, 1)
} else {
out.writeUint8(offset, 0)
}
return nil
}
func (m *mBool) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
b := in.readUint8(offset)
switch b {
case 0, 1:
v.SetBool(b == 1)
return nil
default:
return newValueError(ErrInvalidBoolValue, b)
}
}
type mInt8 struct{}
func (m *mInt8) getMarshalSize(ctx MarshalerContext) int {
return 1
}
func (m *mInt8) getUnmarshalSize(ctx MarshalerContext) int {
return 1
}
func (m *mInt8) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
out.writeUint8(offset, uint8(v.Int8()))
return nil
}
func (m *mInt8) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
v.SetInt8(int8(in.readUint8(offset)))
return nil
}
type mInt16 struct{}
func (m *mInt16) getMarshalSize(ctx MarshalerContext) int {
return 2
}
func (m *mInt16) getUnmarshalSize(ctx MarshalerContext) int {
return 2
}
func (m *mInt16) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
out.writeUint16(offset, uint16(v.Int16()))
return nil
}
func (m *mInt16) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
v.SetInt16(int16(in.readUint16(offset)))
return nil
}
type mInt32 struct{}
func (m *mInt32) getMarshalSize(ctx MarshalerContext) int {
return 4
}
func (m *mInt32) getUnmarshalSize(ctx MarshalerContext) int {
return 4
}
func (m *mInt32) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
out.writeUint32(offset, uint32(v.Int32()))
return nil
}
func (m *mInt32) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
v.SetInt32(int32(in.readUint32(offset)))
return nil
}
type mInt64 struct{}
func (m *mInt64) getMarshalSize(ctx MarshalerContext) int {
return 8
}
func (m *mInt64) getUnmarshalSize(ctx MarshalerContext) int {
return 8
}
func (m *mInt64) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
out.writeUint64(offset, uint64(v.Int64()))
return nil
}
func (m *mInt64) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
v.SetInt64(int64(in.readUint64(offset)))
return nil
}
type mUint8 struct{}
func (m *mUint8) getMarshalSize(ctx MarshalerContext) int {
return 1
}
func (m *mUint8) getUnmarshalSize(ctx MarshalerContext) int {
return 1
}
func (m *mUint8) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
out.writeUint8(offset, v.Uint8())
return nil
}
func (m *mUint8) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
v.SetUint8(in.readUint8(offset))
return nil
}
type mUint16 struct{}
func (m *mUint16) getMarshalSize(ctx MarshalerContext) int {
return 2
}
func (m *mUint16) getUnmarshalSize(ctx MarshalerContext) int {
return 2
}
func (m *mUint16) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
out.writeUint16(offset, v.Uint16())
return nil
}
func (m *mUint16) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
v.SetUint16(in.readUint16(offset))
return nil
}
type mUint32 struct{}
func (m *mUint32) getMarshalSize(ctx MarshalerContext) int {
return 4
}
func (m *mUint32) getUnmarshalSize(ctx MarshalerContext) int {
return 4
}
func (m *mUint32) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
out.writeUint32(offset, v.Uint32())
return nil
}
func (m *mUint32) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
v.SetUint32(in.readUint32(offset))
return nil
}
type mUint64 struct{}
func (m *mUint64) getMarshalSize(ctx MarshalerContext) int {
return 8
}
func (m *mUint64) getUnmarshalSize(ctx MarshalerContext) int {
return 8
}
func (m *mUint64) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
out.writeUint64(offset, v.Uint64())
return nil
}
func (m *mUint64) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
v.SetUint64(in.readUint64(offset))
return nil
}
type mEnumOfInt8 struct {
isStrict bool
values map[int8]struct{}
}
func (m *mEnumOfInt8) getMarshalSize(ctx MarshalerContext) int {
return 1
}
func (m *mEnumOfInt8) getUnmarshalSize(ctx MarshalerContext) int {
return 1
}
func (m *mEnumOfInt8) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if m.isStrict {
if _, ok := m.values[v.Int8()]; !ok {
return newValueError(ErrInvalidEnumValue, v.Int8())
}
}
out.writeUint8(offset, uint8(v.Int8()))
return nil
}
func (m *mEnumOfInt8) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
i := int8(in.readUint8(offset))
if m.isStrict {
if _, ok := m.values[i]; !ok {
return newValueError(ErrInvalidEnumValue, i)
}
}
v.SetInt8(i)
return nil
}
type mEnumOfInt16 struct {
isStrict bool
values map[int16]struct{}
}
func (m *mEnumOfInt16) getMarshalSize(ctx MarshalerContext) int {
return 2
}
func (m *mEnumOfInt16) getUnmarshalSize(ctx MarshalerContext) int {
return 2
}
func (m *mEnumOfInt16) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if m.isStrict {
if _, ok := m.values[v.Int16()]; !ok {
return newValueError(ErrInvalidEnumValue, v.Int16())
}
}
out.writeUint16(offset, uint16(v.Int16()))
return nil
}
func (m *mEnumOfInt16) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
i := int16(in.readUint16(offset))
if m.isStrict {
if _, ok := m.values[i]; !ok {
return newValueError(ErrInvalidEnumValue, i)
}
}
v.SetInt16(i)
return nil
}
type mEnumOfInt32 struct {
isStrict bool
values map[int32]struct{}
}
func (m *mEnumOfInt32) getMarshalSize(ctx MarshalerContext) int {
return 4
}
func (m *mEnumOfInt32) getUnmarshalSize(ctx MarshalerContext) int {
return 4
}
func (m *mEnumOfInt32) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if m.isStrict {
if _, ok := m.values[v.Int32()]; !ok {
return newValueError(ErrInvalidEnumValue, v.Int32())
}
}
out.writeUint32(offset, uint32(v.Int32()))
return nil
}
func (m *mEnumOfInt32) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
i := int32(in.readUint32(offset))
if m.isStrict {
if _, ok := m.values[i]; !ok {
return newValueError(ErrInvalidEnumValue, i)
}
}
v.SetInt32(i)
return nil
}
type mEnumOfInt64 struct {
isStrict bool
values map[int64]struct{}
}
func (m *mEnumOfInt64) getMarshalSize(ctx MarshalerContext) int {
return 8
}
func (m *mEnumOfInt64) getUnmarshalSize(ctx MarshalerContext) int {
return 8
}
func (m *mEnumOfInt64) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if m.isStrict {
if _, ok := m.values[v.Int64()]; !ok {
return newValueError(ErrInvalidEnumValue, v.Int64())
}
}
out.writeUint64(offset, uint64(v.Int64()))
return nil
}
func (m *mEnumOfInt64) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
i := int64(in.readUint64(offset))
if m.isStrict {
if _, ok := m.values[i]; !ok {
return newValueError(ErrInvalidEnumValue, i)
}
}
v.SetInt64(i)
return nil
}
type mEnumOfUint8 struct {
isStrict bool
values map[uint8]struct{}
}
func (m *mEnumOfUint8) getMarshalSize(ctx MarshalerContext) int {
return 1
}
func (m *mEnumOfUint8) getUnmarshalSize(ctx MarshalerContext) int {
return 1
}
func (m *mEnumOfUint8) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if m.isStrict {
if _, ok := m.values[v.Uint8()]; !ok {
return newValueError(ErrInvalidEnumValue, v.Uint8())
}
}
out.writeUint8(offset, v.Uint8())
return nil
}
func (m *mEnumOfUint8) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
i := in.readUint8(offset)
if m.isStrict {
if _, ok := m.values[i]; !ok {
return newValueError(ErrInvalidEnumValue, i)
}
}
v.SetUint8(i)
return nil
}
type mEnumOfUint16 struct {
isStrict bool
values map[uint16]struct{}
}
func (m *mEnumOfUint16) getMarshalSize(ctx MarshalerContext) int {
return 2
}
func (m *mEnumOfUint16) getUnmarshalSize(ctx MarshalerContext) int {
return 2
}
func (m *mEnumOfUint16) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if m.isStrict {
if _, ok := m.values[v.Uint16()]; !ok {
return newValueError(ErrInvalidEnumValue, v.Uint16())
}
}
out.writeUint16(offset, v.Uint16())
return nil
}
func (m *mEnumOfUint16) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
i := in.readUint16(offset)
if m.isStrict {
if _, ok := m.values[i]; !ok {
return newValueError(ErrInvalidEnumValue, i)
}
}
v.SetUint16(i)
return nil
}
type mEnumOfUint32 struct {
isStrict bool
values map[uint32]struct{}
}
func (m *mEnumOfUint32) getMarshalSize(ctx MarshalerContext) int {
return 4
}
func (m *mEnumOfUint32) getUnmarshalSize(ctx MarshalerContext) int {
return 4
}
func (m *mEnumOfUint32) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if m.isStrict {
if _, ok := m.values[v.Uint32()]; !ok {
return newValueError(ErrInvalidEnumValue, v.Uint32())
}
}
out.writeUint32(offset, v.Uint32())
return nil
}
func (m *mEnumOfUint32) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
i := in.readUint32(offset)
if m.isStrict {
if _, ok := m.values[i]; !ok {
return newValueError(ErrInvalidEnumValue, i)
}
}
v.SetUint32(i)
return nil
}
type mEnumOfUint64 struct {
isStrict bool
values map[uint64]struct{}
}
func (m *mEnumOfUint64) getMarshalSize(ctx MarshalerContext) int {
return 8
}
func (m *mEnumOfUint64) getUnmarshalSize(ctx MarshalerContext) int {
return 8
}
func (m *mEnumOfUint64) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if m.isStrict {
if _, ok := m.values[v.Uint64()]; !ok {
return newValueError(ErrInvalidEnumValue, v.Uint64())
}
}
out.writeUint64(offset, v.Uint64())
return nil
}
func (m *mEnumOfUint64) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
i := in.readUint64(offset)
if m.isStrict {
if _, ok := m.values[i]; !ok {
return newValueError(ErrInvalidEnumValue, i)
}
}
v.SetUint64(i)
return nil
}
type mBitsOfUint8 struct {
isStrict bool
mask uint8
}
func (m *mBitsOfUint8) getMarshalSize(ctx MarshalerContext) int {
return 1
}
func (m *mBitsOfUint8) getUnmarshalSize(ctx MarshalerContext) int {
return 1
}
func (m *mBitsOfUint8) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if m.isStrict {
if (v.Uint8() & m.mask) != v.Uint8() {
return newValueError(ErrInvalidBitsValue, v.Uint8())
}
}
out.writeUint8(offset, v.Uint8())
return nil
}
func (m *mBitsOfUint8) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
i := in.readUint8(offset)
if m.isStrict {
if (i & m.mask) != i {
return newValueError(ErrInvalidBitsValue, i)
}
}
v.SetUint8(i)
return nil
}
type mBitsOfUint16 struct {
isStrict bool
mask uint16
}
func (m *mBitsOfUint16) getMarshalSize(ctx MarshalerContext) int {
return 2
}
func (m *mBitsOfUint16) getUnmarshalSize(ctx MarshalerContext) int {
return 2
}
func (m *mBitsOfUint16) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if m.isStrict {
if (v.Uint16() & m.mask) != v.Uint16() {
return newValueError(ErrInvalidBitsValue, v.Uint16())
}
}
out.writeUint16(offset, v.Uint16())
return nil
}
func (m *mBitsOfUint16) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
i := in.readUint16(offset)
if m.isStrict {
if (i & m.mask) != i {
return newValueError(ErrInvalidBitsValue, i)
}
}
v.SetUint16(i)
return nil
}
type mBitsOfUint32 struct {
isStrict bool
mask uint32
}
func (m *mBitsOfUint32) getMarshalSize(ctx MarshalerContext) int {
return 4
}
func (m *mBitsOfUint32) getUnmarshalSize(ctx MarshalerContext) int {
return 4
}
func (m *mBitsOfUint32) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if m.isStrict {
if (v.Uint32() & m.mask) != v.Uint32() {
return newValueError(ErrInvalidBitsValue, v.Uint32())
}
}
out.writeUint32(offset, v.Uint32())
return nil
}
func (m *mBitsOfUint32) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
i := in.readUint32(offset)
if m.isStrict {
if (i & m.mask) != i {
return newValueError(ErrInvalidBitsValue, i)
}
}
v.SetUint32(i)
return nil
}
type mBitsOfUint64 struct {
isStrict bool
mask uint64
}
func (m *mBitsOfUint64) getMarshalSize(ctx MarshalerContext) int {
return 8
}
func (m *mBitsOfUint64) getUnmarshalSize(ctx MarshalerContext) int {
return 8
}
func (m *mBitsOfUint64) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if m.isStrict {
if (v.Uint64() & m.mask) != v.Uint64() {
return newValueError(ErrInvalidBitsValue, v.Uint64())
}
}
out.writeUint64(offset, v.Uint64())
return nil
}
func (m *mBitsOfUint64) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
i := in.readUint64(offset)
if m.isStrict {
if (i & m.mask) != i {
return newValueError(ErrInvalidBitsValue, i)
}
}
v.SetUint64(i)
return nil
}
type mFloat32 struct{}
func (m *mFloat32) getMarshalSize(ctx MarshalerContext) int {
return 4
}
func (m *mFloat32) getUnmarshalSize(ctx MarshalerContext) int {
return 4
}
func (m *mFloat32) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
out.writeUint32(offset, math.Float32bits(v.Float32()))
return nil
}
func (m *mFloat32) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
v.SetFloat32(math.Float32frombits(in.readUint32(offset)))
return nil
}
type mFloat64 struct{}
func (m *mFloat64) getMarshalSize(ctx MarshalerContext) int {
return 8
}
func (m *mFloat64) getUnmarshalSize(ctx MarshalerContext) int {
return 8
}
func (m *mFloat64) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
out.writeUint64(offset, math.Float64bits(v.Float64()))
return nil
}
func (m *mFloat64) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
v.SetFloat64(math.Float64frombits(in.readUint64(offset)))
return nil
}
type mString int
func (m *mString) getMarshalSize(ctx MarshalerContext) int {
return 16
}
func (m *mString) getUnmarshalSize(ctx MarshalerContext) int {
return 16
}
func (m *mString) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
var (
maxSize = int(*m)
s = v.String()
length = len(s)
)
if maxSize < length {
return newExpectError(ErrStringTooLong, maxSize, length)
}
if !utf8.ValidString(s) {
return newValueError(ErrStringNotUTF8, v)
}
// length, allocPresent
out.writeUint64(offset, uint64(length))
out.writeUint64(offset+8, allocPresent)
// Create a new out-of-line object and write bytes of the string.
head, err := out.newObject(length, depth)
if err != nil {
return err
}
copy(out.buffer[head:], s)
return nil
}
func (m *mString) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
size := in.readUint64(offset)
ptr := in.readUint64(offset + 8)
switch ptr {
case noAlloc:
return newValueError(ErrUnexpectedNullRef, "string")
case allocPresent:
return m.unmarshalWithUncheckedSize(in, depth, v, int(size))
default:
return newValueError(ErrBadRefEncoding, "string")
}
}
func (m *mString) unmarshalWithUncheckedSize(in *decoder, depth int, v unsafevalue.Value, size int) error {
if maxSize := int(*m); size < 0 || maxSize < size {
return newExpectError(ErrStringTooLong, maxSize, size)
}
start, err := in.newObject(size, depth)
if err != nil {
return err
}
s := string(in.buffer[start:][:size])
if !utf8.ValidString(s) {
return newValueError(ErrStringNotUTF8, v)
}
v.SetString(s)
return nil
}
type mOptString uint64
func (m *mOptString) getMarshalSize(ctx MarshalerContext) int {
return 16
}
func (m *mOptString) getUnmarshalSize(ctx MarshalerContext) int {
return 16
}
func (m *mOptString) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
if v.PointerIsNil() {
out.writeUint64(offset, 0)
out.writeUint64(offset+8, noAlloc)
return nil
}
s := mString(*m)
return (&s).marshal(ctx, v.PointerElem(), out, offset, depth)
}
var (
typString = reflect.TypeOf("")
)
func (m *mOptString) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
size := in.readUint64(offset)
ptr := in.readUint64(offset + 8)
switch ptr {
case noAlloc:
if size > 0 {
return newValueError(ErrUnexpectedNullRef, ptr)
}
v.PointerSetNil()
return nil
case allocPresent:
v.PointerSetNew(typString)
s := mString(*m)
return (&s).unmarshalWithUncheckedSize(in, depth, v.PointerElem(), int(size))
default:
return newValueError(ErrBadRefEncoding, v)
}
}
type mHandle struct {
nullable bool
rights zx.Rights
subtype zx.ObjType
}
func (m *mHandle) getMarshalSize(ctx MarshalerContext) int {
return 4
}
func (m *mHandle) getUnmarshalSize(ctx MarshalerContext) int {
return 4
}
func (m *mHandle) isOpt() bool {
return m.nullable
}
func (m *mHandle) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
// The underlying type of all the handles is a uint32, so we're
// safe calling Uint(). This will panic if that is no longer true.
raw := zx.Handle(v.Uint32())
if raw == zx.HandleInvalid {
if !m.isOpt() {
return ErrUnexpectedNullRef
}
out.writeUint32(offset, noHandle)
return nil
}
out.handleDispositions = append(out.handleDispositions, zx.HandleDisposition{
Operation: zx.HandleOpMove,
Handle: raw,
Type: m.subtype,
Rights: m.rights,
Result: zx.ErrOk,
})
out.writeUint32(offset, handlePresent)
return nil
}
func (m *mHandle) requiredRightsArePresent(actual zx.Rights) bool {
if m.rights == zx.RightSameRights {
return true
}
return actual.SupersetOf(m.rights)
}
func (m *mHandle) filterOutUnspecifiedRights(actual zx.Rights) zx.Rights {
if m.rights == zx.RightSameRights {
return actual
}
return actual & m.rights
}
func (m *mHandle) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
h := in.readUint32(offset)
switch uint32(h) {
case noHandle:
if !m.isOpt() {
return ErrUnexpectedNullRef
}
v.SetUint32(uint32(zx.HandleInvalid))
return nil
case handlePresent:
if len(in.handleInfos) == 0 {
return ErrNotEnoughHandles
}
handleInfo := in.handleInfos[0]
in.handleInfos = in.handleInfos[1:]
if m.subtype != zx.ObjTypeNone && m.subtype != handleInfo.Type {
handleClose(&handleInfo.Handle)
return newExpectError(ErrIncorrectHandleType, m.subtype, handleInfo.Type)
}
if !m.requiredRightsArePresent(handleInfo.Rights) {
handleClose(&handleInfo.Handle)
return newExpectError(ErrMissingRequiredHandleRights, m.rights, handleInfo.Rights)
}
handle := handleInfo.Handle
reducedRights := m.filterOutUnspecifiedRights(handleInfo.Rights)
if handleInfo.Rights != reducedRights {
var err error
handle, err = handleReplace(handle, reducedRights)
if err != nil {
handleClose(&handleInfo.Handle)
return newValueError(ErrUnableToReduceHandleRights, handle)
}
}
v.SetUint32(uint32(handle))
return nil
default:
return newValueError(ErrBadHandleEncoding, h)
}
}
// mProtocol marshals FIDL protocols' client and server ends. A client end
// (a.k.a "a protocol") is represented by a `Proxy`, whose first field is a
// `zx.Channel`. Similarly, a server end (a.k.a. "a protocol request") is
// represented by an `InterfaceRequest` whose first field is a `zx.Channel`.
type mProtocol mHandle
func (m *mProtocol) asHandle() *mHandle {
h := mHandle(*m)
return &h
}
func (m *mProtocol) getMarshalSize(ctx MarshalerContext) int {
return m.asHandle().getMarshalSize(ctx)
}
func (m *mProtocol) getUnmarshalSize(ctx MarshalerContext) int {
return m.asHandle().getUnmarshalSize(ctx)
}
func (m *mProtocol) marshal(ctx MarshalerContext, v unsafevalue.Value, out *encoder, offset int, depth int) error {
return m.asHandle().marshal(ctx, v.StructFieldOffset(0), out, offset, depth)
}
func (m *mProtocol) unmarshal(ctx MarshalerContext, in *decoder, offset int, depth int, v unsafevalue.Value) error {
return m.asHandle().unmarshal(ctx, in, offset, depth, v.StructFieldOffset(0))
}