blob: fcef5f3e67bb8b4eb53f17bd4683efa5b451cd90 [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.
// +build fuchsia
package fidl
import (
"errors"
"math"
"reflect"
"strconv"
"strings"
"sync"
"syscall/zx"
"unicode/utf8"
"unsafe"
)
type strictness bool
const (
isFlexible strictness = false
isStrict strictness = true
)
// 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 reflect.Value, out *encoder) error {
m.once.Do(m.init)
return m.delegate.marshal(ctx, v, out)
}
func (m *lazyMarshaler) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
m.once.Do(m.init)
return m.delegate.unmarshal(ctx, in, v)
}
// Marshal marshals (or encodes) a message into the data and handles slices.
func Marshal(message Message, data []byte, handleDispositions []zx.HandleDisposition) (int, int, error) {
return MarshalWithContext(newCtx(), message, data, handleDispositions)
}
// Marshal marshals (or encodes) a message into the data and handles slices.
func MarshalWithContext(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 obsure way withing relfection. Just don't do
// that.
var (
v = reflect.ValueOf(message).Elem()
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]}
out.head = out.newObject(m.getMarshalSize(ctx))
if err := m.marshal(ctx, v, out); err != nil {
return 0, 0, err
}
return len(out.buffer), len(out.handleDispositions), nil
}
// Unmarshal unmarshals (or decodes) into message using the data and handles
// slices.
func Unmarshal(data []byte, handleInfos []zx.HandleInfo, message Message) (int, int, error) {
return UnmarshalWithContext2(newCtx(), data, handleInfos, message)
}
// UnmarshalWithContext2 behaves identically to UnmarshalWithContext but takes a HandleInfo.
func UnmarshalWithContext2(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 obsure way withing relfection. Just don't do
// that.
var (
v = reflect.ValueOf(message).Elem()
m = message.Marshaler()
)
// Get the payload's value and unmarshal it.
nextObject := align(m.getUnmarshalSize(ctx), 8)
in := &decoder{
buffer: data,
handleInfos: handleInfos,
nextObject: nextObject,
}
if err := m.unmarshal(ctx, in, v); err != nil {
return 0, 0, err
}
return in.nextObject, len(handleInfos) - len(in.handleInfos), nil
}
func UnmarshalWithContext(ctx MarshalerContext, data []byte, handles []zx.Handle, message Message) (int, int, error) {
resphi := messageHandleInfosPool.Get().([]zx.HandleInfo)
defer messageHandleInfosPool.Put(resphi)
for i, handle := range handles {
resphi[i] = zx.HandleInfo{
Handle: handle,
Type: zx.ObjectTypeNone,
Rights: zx.RightSameRights,
}
}
return UnmarshalWithContext2(ctx, data, resphi[:len(handles)], message)
}
const tagSizeV1 = "fidl_size_v1"
const tagAlignmentV1 = "fidl_alignment_v1"
const tagOffsetV1 = "fidl_offset_v1"
const tagHandleRights = "fidl_handle_rights"
const tagHandleSubtype = "fidl_handle_subtype"
const tagOrdinal = "fidl_ordinal"
const tagBounds = "fidl_bounds"
const tagMarshalerKind = "fidl"
// 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 {
if len(typ.Name()) == 0 {
return typ.Kind().String()
} else {
return typ.Name() + " (" + typ.Kind().String() + ")"
}
}
// Extracts a list of fields for struct, union, table types that can be used
// for iterating.
// This skips the inital 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 := 1; i < typ.NumField(); i++ {
fields[i-1] = typ.Field(i)
}
return fields
}
// 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 mUint:
return true
case mInt:
return true
case mFloat32:
// Need to validate.
return false
case mFloat64:
// Need to validate.
return false
case mArray:
return matchesWireFormatLayout(marshaler.Marshaler, typ.Elem())
case mStructUnsafeCopy:
return true
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.size != int(typ.Size()) {
return false
}
if marshaler.alignment != typ.Align() {
return false
}
for i, rField := range dataFields(typ) {
field := marshaler.fields[i]
if field.offset != int(rField.Offset) {
return false
}
if !matchesWireFormatLayout(field.Marshaler, rField.Type) {
return false
}
}
return true
case mEmptyStruct:
// Note: empty struct is 0 or 1 bytes at different times in go.
return false
case mHandle:
// 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, mString, mPointer:
return false
default:
panic("unhandledType " + reflect.TypeOf(marshaler).Name())
}
}
func createMarshaler(typ reflect.Type) (Marshaler, error) {
// 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
offsets []int
)
// - 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 dataFields(typ) {
if kind == tableTag && index%2 == 1 {
// Presence field
if field.Type.Kind() != reflect.Bool {
return nil, errors.New("incorrect presence field on " + nicefmt(typ))
}
continue
}
fieldBounds := readBoundsTag(field)
handleRights, handleSubtype, err := readHandleRightsAndSubtype(field)
if err != nil {
return nil, err
}
switch kind {
case structTag:
offset, err := readIntTag(field, tagOffsetV1)
if err != nil {
return nil, err
}
offsets = append(offsets, offset)
case xunionTag, strictXunionTag, tableTag:
ordinal := readOrdinalTag(field)
ordinals = append(ordinals, uint64(ordinal))
default:
}
fieldMarshaler, err := createMarshalerForField(field.Type, fieldBounds, handleRights, handleSubtype)
if err != nil {
return nil, err
}
fields = append(fields, mField{fieldMarshaler, field.Index[0]})
}
size, err := readIntTag(tagField, tagSizeV1)
if err != nil {
return nil, errors.New("error creating marshaller for " + typ.String() + ": " + err.Error())
}
alignment, err := readIntTag(tagField, tagAlignmentV1)
if err != nil {
return nil, errors.New("error creating marshaller for " + typ.String() + ": " + err.Error())
}
switch kind {
case structTag:
if len(fields) == 0 {
return mEmptyStruct{}, nil
}
var structFields []mFieldWithOffset
for i := 0; i < len(fields); i++ {
structFields = append(structFields, mFieldWithOffset{
mField: fields[i],
offset: offsets[i],
})
}
s := mStruct{
fields: structFields,
size: size,
alignment: alignment,
}
if matchesWireFormatLayout(s, typ) {
return mStructUnsafeCopy{
fields: structFields,
size: size,
alignment: alignment,
}, nil
}
return s, nil
case xunionTag, strictXunionTag:
strictness := strictness(kind == strictXunionTag)
ordinalToFields := make(map[uint64]mField)
for i := 0; i < len(fields); i++ {
ordinalToFields[ordinals[i]] = fields[i]
}
return mXUnion{
fields: ordinalToFields,
ordinals: ordinals,
size: size,
alignment: alignment,
strictness: strictness,
}, nil
case tableTag:
return mTable{
fields: fields,
size: size,
alignment: alignment,
ordinals: ordinals,
}, 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.ObjectType, error) {
if !containsHandleType(field.Type) {
// Skip non-handle field types and don't return an error.
return zx.RightSameRights, zx.ObjectTypeNone, nil
}
// Read handle rights
val, ok := field.Tag.Lookup(tagHandleRights)
if !ok {
return zx.RightSameRights, zx.ObjectTypeNone, ErrUnspecifiedHandleRights
}
rights, err := strconv.ParseInt(val, 0, 64)
if err != nil {
return zx.RightSameRights, zx.ObjectTypeNone, err
}
convertedRights := zx.Rights(rights)
// Read handle subtype
val, ok = field.Tag.Lookup(tagHandleSubtype)
if !ok {
return zx.RightSameRights, zx.ObjectTypeNone, ErrUnspecifiedHandleType
}
subtype, err := strconv.ParseInt(val, 0, 64)
if err != nil {
return zx.RightSameRights, zx.ObjectTypeNone, err
}
convertedSubtype := zx.ObjectType(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.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 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 createMarshalerForField(typ reflect.Type, bounds bounds, handleRights zx.Rights, handleSubtype zx.ObjectType) (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 mInterface{
nullable: nullable != 0,
rights: ProtocolRights,
subtype: zx.ObjectTypeChannel}, nil
}
switch typ.Kind() {
case reflect.Bool:
return mBool{}, nil
case reflect.Int8:
return mInt(1), nil
case reflect.Int16:
return mInt(2), nil
case reflect.Int32:
return mInt(4), nil
case reflect.Int64:
return mInt(8), nil
case reflect.Uint8:
return mUint(1), nil
case reflect.Uint16:
return mUint(2), nil
case reflect.Uint32:
return mUint(4), nil
case reflect.Uint64:
return mUint(8), nil
case reflect.Float32:
return mFloat32{}, nil
case reflect.Float64:
return mFloat64{}, nil
case reflect.String:
maxSize, _ := bounds.pop()
return mString(maxSize), nil
case reflect.Array:
elemMarshaler, err := createMarshalerForField(typ.Elem(), bounds, handleRights, handleSubtype)
if err != nil {
return nil, err
}
return mArray{
Marshaler: elemMarshaler,
size: typ.Len(),
}, nil
case reflect.Slice:
maxSize, remainder := bounds.pop()
elemTyp := typ.Elem()
elemMarshaler, err := createMarshalerForField(elemTyp, remainder, handleRights, handleSubtype)
if err != nil {
return nil, err
}
return mVector{
Marshaler: elemMarshaler,
maxSize: maxSize,
sliceTyp: reflect.SliceOf(elemTyp),
// The fast path only supports `[]uint8`. A slice of aliased types must be handled via the slow path.
// We therefore prefer a monomorphic check.
isVectorUint8: elemTyp == reflect.TypeOf(uint8(0)),
}, nil
case reflect.Struct:
return createMarshaler(typ)
case reflect.Ptr:
return createOptMarshalerForField(typ.Elem(), bounds, handleRights, handleSubtype)
default:
return nil, errors.New("unable to create field marshaler for " + nicefmt(typ))
}
}
func createOptMarshalerForField(typ reflect.Type, bounds bounds, handleRights zx.Rights, handleSubtype zx.ObjectType) (Marshaler, error) {
m, err := createMarshalerForField(typ, bounds, handleRights, handleSubtype)
if err != nil {
return nil, err
}
switch m := m.(type) {
case mString:
return mOptString(m), nil
case mVector:
return mOptVector(m), nil
case mEmptyStruct:
return mPointer{
Marshaler: m,
elemTyp: typ,
}, nil
case mStruct, mStructUnsafeCopy:
return mPointer{
Marshaler: m,
elemTyp: 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 reflect.Value, out *encoder) error
unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error
}
// Assert various encoders implement the Marshaler interface.
var _ = []Marshaler{
mStruct{},
mStructUnsafeCopy{},
mEmptyStruct{},
mXUnion{},
mOptXUnion{},
mTable{},
mPointer{},
mArray{},
mVector{},
mOptVector{},
mBool{},
mInt(0),
mUint(0),
mFloat32{},
mFloat64{},
mString(0),
mOptString(0),
}
type mField struct {
Marshaler
index int
}
type mFieldWithOffset struct {
mField
offset int
}
func (m mFieldWithOffset) getMarshalOffset(ctx MarshalerContext) int {
return m.offset
}
func (m mFieldWithOffset) getUnmarshalOffset(ctx MarshalerContext) int {
return m.offset
}
type mStruct struct {
fields []mFieldWithOffset
size, alignment int
}
func (m mStruct) getMarshalSize(ctx MarshalerContext) int {
return m.size
}
func (m mStruct) getUnmarshalSize(ctx MarshalerContext) int {
return m.size
}
func (m mStruct) marshal(ctx MarshalerContext, v reflect.Value, out *encoder) error {
structStart := align(out.head, m.alignment)
for _, field := range m.fields {
out.head = structStart + field.getMarshalOffset(ctx)
if err := field.Marshaler.marshal(ctx, v.Field(field.index), out); err != nil {
return err
}
}
out.head = align(out.head, m.alignment)
return nil
}
func (m mStruct) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
structStart := align(in.head, m.alignment)
for _, field := range m.fields {
in.head = structStart + field.getUnmarshalOffset(ctx)
if err := field.Marshaler.unmarshal(ctx, in, v.Field(field.index)); err != nil {
return err
}
}
in.head = align(in.head, m.alignment)
return nil
}
type mStructUnsafeCopy struct {
fields []mFieldWithOffset
size, alignment int
}
func (m mStructUnsafeCopy) getMarshalSize(ctx MarshalerContext) int {
return m.size
}
func (m mStructUnsafeCopy) getUnmarshalSize(ctx MarshalerContext) int {
return m.size
}
func (m mStructUnsafeCopy) marshal(ctx MarshalerContext, v reflect.Value, out *encoder) error {
// Directly copy the object's memory to the buffer.
out.head = align(out.head, m.alignment)
sh := reflect.SliceHeader{
Data: uintptr(unsafe.Pointer(v.UnsafeAddr())),
Len: m.size,
Cap: m.size,
}
s := *(*[]uint8)(unsafe.Pointer(&sh))
copy(out.buffer[out.head:], s)
out.head += m.size
return nil
}
func (m mStructUnsafeCopy) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
// Directly copy from the buffer to the object's memory.
in.head = align(in.head, m.alignment)
if len(in.buffer) < in.head+m.size {
return ErrPayloadTooSmall
}
sh := reflect.SliceHeader{
Data: uintptr(unsafe.Pointer(v.UnsafeAddr())),
Len: m.size,
Cap: m.size,
}
s := *(*[]uint8)(unsafe.Pointer(&sh))
copy(s, in.buffer[in.head:])
in.head += m.size
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 reflect.Value, out *encoder) error {
out.writeUint(0, 1)
return nil
}
func (_ mEmptyStruct) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
zero, err := in.readUint(1)
if err != nil {
return err
} else if zero != 0 {
return newValueError(ErrInvalidEmptyStruct, zero)
}
return nil
}
type mXUnion struct {
fields map[uint64]mField
ordinals []uint64
size, alignment int
strictness
}
func (m mXUnion) getMarshalSize(ctx MarshalerContext) int {
return m.size
}
func (m mXUnion) getUnmarshalSize(ctx MarshalerContext) int {
return m.size
}
func (m mXUnion) marshal(ctx MarshalerContext, v reflect.Value, out *encoder) error {
var ordinal uint64
ordinal = v.Field(0).Uint()
field, ok := m.fields[ordinal]
if !ok {
return newValueError(ErrInvalidXUnionTag, ordinal)
}
out.writeUint(ordinal, 8)
// Field.
if err := marshalEnvelopePresent(ctx, field, v.Field(field.index), out); err != nil {
return err
}
return nil
}
func (m mXUnion) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
return m.unmarshalWithOptSpecified(ctx, in, v, nil)
}
func (m mXUnion) unmarshalWithOptSpecified(ctx MarshalerContext, in *decoder, v reflect.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, err := in.readUint(8)
if err != nil {
return err
}
// ordinal=0 indicates that there MUST be no envelope.
if ordinal == 0 && !optAllowed {
return newValueError(ErrInvalidXUnionTag, ordinal)
} else if ordinal == 0 && optAllowed {
h, err := unmarshalEnvelopeHeader(in)
if err != nil {
return err
}
if h.isPresent() {
return newValueError(ErrInvalidXUnionTag, ordinal)
}
return nil
}
// If we reach here, ordinal != 0.
field, ok := m.fields[ordinal]
if !ok {
if m.strictness == isStrict {
return newValueError(ErrInvalidXUnionTag, ordinal)
}
v.Field(0).SetUint(ordinal)
unknownData, err := unmarshalEnvelopeUnknown(in)
if err != nil {
return err
}
unknownDataField := v.FieldByName("I_unknownData")
// * FieldByName() returns a zero Value, which is _non-settable_ & non-addressable, if the
// field isn't found.
// * So, we use .CanSet() below on the returned field to check whether the field exists.
// * This enables this code to properly work with FIDL-generated Go bindings that hasn't
// been updated with the UnknownValue field yet.
// * This enables this code to land as a soft transition
// <https://fuchsia.googlesource.com/fuchsia/+/master/docs/development/workflows/multilayer_changes.md#hard-and-soft-transitions>.
if unknownDataField.CanSet() {
unknownDataField.SetBytes(unknownData)
}
return nil
}
if optAllowed {
v.Set(reflect.New(typ))
v = v.Elem()
}
ordinalOrFieldIndex := ordinal
v.Field(0).SetUint(ordinalOrFieldIndex)
var mode unmarshalEnvelopeMode
if optAllowed {
mode = knownMayBeAbsent
} else {
mode = knownMustBePresent
}
isPresent, err := unmarshalEnvelope(ctx, field.Marshaler, in, v.Field(field.index), mode)
if err != nil {
return err
}
if !isPresent {
v.Set(reflect.Zero(reflect.PtrTo(typ)))
}
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 reflect.Value, out *encoder) error {
if v.IsNil() {
out.writeUint(0, 8) // ordinal + padding
marshalEnvelopeAbsent(out)
return nil
} else {
return m.mXUnion.marshal(ctx, v.Elem(), out)
}
}
func (m mOptXUnion) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
return m.unmarshalWithOptSpecified(ctx, in, v, m.typ)
}
type mTable struct {
fields []mField
ordinals []uint64
size, alignment int
}
func (m mTable) getMarshalSize(ctx MarshalerContext) int {
return m.size
}
func (m mTable) getUnmarshalSize(ctx MarshalerContext) int {
return m.size
}
const envelopeSize = 16
type envelopeHeader struct {
byteCount uint32
handleCount uint32
presence uint64
}
func (h envelopeHeader) isPresent() bool {
return h.presence == allocPresent
}
func marshalEnvelopePresent(ctx MarshalerContext, m Marshaler, v reflect.Value, out *encoder) error {
numHandleDispositions := len(out.handleDispositions)
numBytes := len(out.buffer)
head := out.head
out.head = out.newObject(m.getMarshalSize(ctx))
if err := m.marshal(ctx, v, out); err != nil {
return err
}
numHandleDispositions = len(out.handleDispositions) - numHandleDispositions
numBytes = len(out.buffer) - numBytes
out.head = head
out.writeUint(uint64(numBytes), 4)
out.writeUint(uint64(numHandleDispositions), 4)
out.writeUint(allocPresent, 8)
return nil
}
func marshalEnvelopeAbsent(out *encoder) {
out.writeUint(0, 8) // both numBytes, and numHandleDispositions
out.writeUint(noAlloc, 8)
}
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(in *decoder) (envelopeHeader, error) {
var h envelopeHeader
byteCount, err := in.readUint(4)
if err != nil {
return h, err
}
h.byteCount = uint32(byteCount)
handleCount, err := in.readUint(4)
if err != nil {
return h, err
}
h.handleCount = uint32(handleCount)
h.presence, err = in.readUint(8)
if err != nil {
return h, err
}
switch h.presence {
case allocPresent, noAlloc:
break
default:
return h, newValueError(ErrBadRefEncoding, h)
}
if end := in.nextObject + int(h.byteCount); end < 0 || end > len(in.buffer) {
return h, newValueError(ErrEnvelopeTooLong, h)
}
if h.handleCount > uint32(len(in.handleInfos)) {
return h, newValueError(ErrTooManyHandles, h)
}
return h, nil
}
func unmarshalEnvelopeUnknown(in *decoder) ([]byte, error) {
header, err := unmarshalEnvelopeHeader(in)
if err != nil {
return nil, err
}
for i := uint32(0); i < header.handleCount; i++ {
in.handleInfos[0].Handle.Close() // best effort
in.handleInfos = in.handleInfos[1:]
}
// Don't need to check for overflow when calculating the end of the envelope, since
// unmarshalEnvelopeHeader() does that.
start := in.nextObject
end := in.nextObject + int(header.byteCount)
unknownData := in.buffer[start:end]
in.nextObject = end
return unknownData, nil
}
func unmarshalEnvelopeContent(ctx MarshalerContext, header envelopeHeader, m Marshaler, in *decoder, v reflect.Value, mode unmarshalEnvelopeMode) (bool, error) {
savedHead := in.head
in.head = in.nextObject
in.nextObject += align(m.getUnmarshalSize(ctx), 8)
if err := m.unmarshal(ctx, in, v); err != nil {
return false, err
}
in.head = savedHead
return true, nil
}
func unmarshalEnvelope(ctx MarshalerContext, m Marshaler, in *decoder, v reflect.Value, mode unmarshalEnvelopeMode) (bool, error) {
header, err := unmarshalEnvelopeHeader(in)
if err != nil {
return false, err
}
if !header.isPresent() {
if mode == knownMustBePresent {
return false, newValueError(ErrUnexpectedNullRef, v)
}
if header.byteCount != 0 {
return false, newValueError(ErrUnexpectedNumBytes, header.byteCount)
}
if header.handleCount != 0 {
return false, newValueError(ErrUnexpectedNumHandles, header.handleCount)
}
return false, nil
}
return unmarshalEnvelopeContent(ctx, header, m, in, v, mode)
}
func (m mTable) marshal(ctx MarshalerContext, v reflect.Value, out *encoder) error {
// Determining max ordinal.
var (
maxOrdinal uint64
numKnown = len(m.ordinals)
fieldPresent = make([]bool, numKnown)
)
for index := 0; index < numKnown; index++ {
presenceIndex := index*2 + 2
fieldPresent[index] = v.Field(presenceIndex).Bool()
if fieldPresent[index] {
if fieldOrdinal := m.ordinals[index]; maxOrdinal < fieldOrdinal {
maxOrdinal = fieldOrdinal
}
}
}
// Vector of envelopes header.
out.writeUint(maxOrdinal, 8)
out.writeUint(allocPresent, 8)
// Early exit on empty table.
if maxOrdinal == 0 {
return nil
}
// Encode in the out-of-line object.
oldHead := out.head
out.head = out.newObject(int(maxOrdinal) * envelopeSize)
// Envelopes.
var (
ordinal uint64 = 1
index, fieldIndex, presenceIndex = 0, 1, 2
)
for ordinal <= maxOrdinal {
fieldKnown := index < numKnown && ordinal == m.ordinals[index]
if fieldKnown && fieldPresent[index] {
if err := marshalEnvelopePresent(ctx, m.fields[index], v.Field(fieldIndex), out); err != nil {
return err
}
} else {
marshalEnvelopeAbsent(out)
}
ordinal++
if fieldKnown {
index++
fieldIndex += 2 // i.e. skip presenece field
presenceIndex += 2 // i.e. skip field
}
}
// Re-position head.
out.head = oldHead
return nil
}
func (m mTable) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
mou, err := in.readUint(8)
if err != nil {
return err
}
// uints/ints are only guaranteed to be 32 bit longs.
// we use maxOrdinal as an int, so we must make sure that it fits.
if mou > uint64(^uint(0)) {
return newValueError(ErrUnexpectedOrdinal, v)
}
maxOrdinal := mou
allocPtr, err := in.readUint(8)
if err != nil {
return err
}
switch 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, fieldIndex, presenceIndex = 0, 1, 2
)
tableBodyHead := in.nextObject
in.nextObject += int(maxOrdinal) * envelopeSize
oldHead := in.head
in.head = tableBodyHead
for ordinal <= maxOrdinal {
fieldKnown := index < numKnown && ordinal == m.ordinals[index]
if fieldKnown {
if isPresent, err := unmarshalEnvelope(ctx, m.fields[index], in, v.Field(fieldIndex), knownMayBeAbsent); err != nil {
return err
} else if isPresent {
v.Field(presenceIndex).SetBool(true)
}
} else {
if _, err := unmarshalEnvelopeUnknown(in); err != nil {
return err
}
}
ordinal++
if fieldKnown {
index++
fieldIndex += 2 // i.e skip presence field
presenceIndex += 2 // i.e skip field
}
}
in.head = oldHead
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 reflect.Value, out *encoder) error {
// Nil?
if v.IsNil() {
out.writeUint(noAlloc, 8)
return nil
}
// Write out allocation marker.
out.writeUint(allocPresent, 8)
// Set up the out-of-line space and the head.
oldHead := out.head
out.head = out.newObject(align(m.Marshaler.getMarshalSize(ctx), 8))
// Marshal field.
if err := m.Marshaler.marshal(ctx, v.Elem(), out); err != nil {
return err
}
// Re-position head.
out.head = oldHead
return nil
}
func (m mPointer) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
// Nil?
ptr, err := in.readUint(8)
if err != nil {
return err
}
switch ptr {
case noAlloc:
v.Set(reflect.Zero(v.Type()))
return nil
case allocPresent:
// good
default:
return newValueError(ErrBadRefEncoding, v)
}
// Create the new struct.
v.Set(reflect.New(m.elemTyp))
// Set up the out-of-line space and the head.
oldHead := in.head
in.head = in.nextObject
in.nextObject += align(m.Marshaler.getUnmarshalSize(ctx), 8)
// Unmarshal field.
if err := m.Marshaler.unmarshal(ctx, in, v.Elem()); err != nil {
return err
}
// Re-position head.
in.head = oldHead
return nil
}
type mOptUnion struct {
mPointer
mOptXUnion
}
func (m mOptUnion) getMarshalSize(ctx MarshalerContext) int {
return 24
}
func (m mOptUnion) getUnmarshalSize(ctx MarshalerContext) int {
return 24
}
func (m mOptUnion) marshal(ctx MarshalerContext, v reflect.Value, out *encoder) error {
return m.mOptXUnion.marshal(ctx, v, out)
}
func (m mOptUnion) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
return m.mOptXUnion.unmarshal(ctx, in, v)
}
type mArray struct {
Marshaler
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 reflect.Value, out *encoder) error {
for i, len := 0, v.Len(); i < len; i++ {
if err := m.Marshaler.marshal(ctx, v.Index(i), out); err != nil {
return err
}
}
return nil
}
func (m mArray) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
for i, len := 0, v.Len(); i < len; i++ {
if err := m.Marshaler.unmarshal(ctx, in, v.Index(i)); err != nil {
return err
}
}
return nil
}
type mVector struct {
Marshaler
maxSize int
sliceTyp reflect.Type
isVectorUint8 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 reflect.Value, out *encoder) error {
// Bounds check.
vLen := v.Len()
if m.maxSize < vLen {
return newExpectError(ErrVectorTooLong, m.maxSize, vLen)
}
// Vector header.
out.writeUint(uint64(vLen), 8)
out.writeUint(allocPresent, 8)
// Early exit if the vector is empty.
if vLen == 0 {
return nil
}
// Encode in the out-of-line object.
oldHead := out.head
out.head = out.newObject(vLen * m.Marshaler.getMarshalSize(ctx))
// Marshal elements.
if m.isVectorUint8 {
copy(out.buffer[out.head:], v.Bytes())
} else {
for i := 0; i < vLen; i++ {
if err := m.Marshaler.marshal(ctx, v.Index(i), out); err != nil {
return err
}
}
}
// Re-position head.
out.head = oldHead
return nil
}
func (m mVector) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
size, err := in.readUint(8)
if err != nil {
return err
}
ptr, err := in.readUint(8)
if err != nil {
return err
}
switch ptr {
case noAlloc:
return newValueError(ErrUnexpectedNullRef, v)
case allocPresent:
return m.unmarshalWithUncheckedSize(ctx, in, v, int(size))
default:
return newValueError(ErrBadRefEncoding, v)
}
}
func (m mVector) unmarshalWithUncheckedSize(ctx MarshalerContext, in *decoder, v reflect.Value, size int) error {
if size < 0 || m.maxSize < size {
return newExpectError(ErrVectorTooLong, m.maxSize, size)
}
// Unmarshal in the out-of-line object.
oldHead := in.head
in.head = in.nextObject
elemSize := m.Marshaler.getUnmarshalSize(ctx)
in.nextObject += align(size*elemSize, 8)
// Unmarshal elements.
if m.isVectorUint8 {
data := make([]uint8, size, size)
copy(data, in.buffer[in.head:])
v.Set(reflect.ValueOf(data))
} else {
v.Set(reflect.MakeSlice(m.sliceTyp, size, size))
for i := 0; i < size; i++ {
if err := m.Marshaler.unmarshal(ctx, in, v.Index(i)); err != nil {
return err
}
}
}
// Re-position head.
in.head = oldHead
return nil
}
type mOptVector mVector
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 reflect.Value, out *encoder) error {
if v.IsNil() {
out.writeUint(0, 8)
out.writeUint(noAlloc, 8)
return nil
}
return mVector(m).marshal(ctx, v.Elem(), out)
}
func (m mOptVector) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
size, err := in.readUint(8)
if err != nil {
return err
}
ptr, err := in.readUint(8)
if err != nil {
return err
}
switch ptr {
case noAlloc:
v.Set(reflect.Zero(reflect.PtrTo(m.sliceTyp)))
return nil
case allocPresent:
v.Set(reflect.New(m.sliceTyp))
return mVector(m).unmarshalWithUncheckedSize(ctx, in, v.Elem(), 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 reflect.Value, out *encoder) error {
if v.Bool() {
out.writeUint(1, 1)
} else {
out.writeUint(0, 1)
}
return nil
}
func (m mBool) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
b, err := in.readUint(1)
if err != nil {
return err
}
switch b {
case 0, 1:
v.SetBool(b == 1)
return nil
default:
return newValueError(ErrInvalidBoolValue, b)
}
}
// int is size (1 for int8, 2 for int16, etc.)
type mInt int
func (m mInt) getMarshalSize(ctx MarshalerContext) int {
return int(m)
}
func (m mInt) getUnmarshalSize(ctx MarshalerContext) int {
return int(m)
}
func (m mInt) marshal(ctx MarshalerContext, v reflect.Value, out *encoder) error {
size := int(m)
out.writeUint(uint64(v.Int()), size)
return nil
}
func (m mInt) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
size := int(m)
val, err := in.readUint(size)
if err != nil {
return err
}
v.SetInt(int64(val))
return nil
}
// uint is size (1 for uint8, 2 f or uint16, etc.)
type mUint int
func (m mUint) getMarshalSize(ctx MarshalerContext) int {
return int(m)
}
func (m mUint) getUnmarshalSize(ctx MarshalerContext) int {
return int(m)
}
func (m mUint) marshal(ctx MarshalerContext, v reflect.Value, out *encoder) error {
size := int(m)
out.writeUint(v.Uint(), size)
return nil
}
func (m mUint) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
size := int(m)
val, err := in.readUint(size)
if err != nil {
return err
}
v.SetUint(val)
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 reflect.Value, out *encoder) error {
out.writeUint(uint64(math.Float32bits(float32(v.Float()))), 4)
return nil
}
func (m mFloat32) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
val, err := in.readUint(4)
if err != nil {
return err
}
v.SetFloat(float64(math.Float32frombits(uint32(val))))
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 reflect.Value, out *encoder) error {
out.writeUint(math.Float64bits(v.Float()), 8)
return nil
}
func (m mFloat64) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
val, err := in.readUint(8)
if err != nil {
return err
}
v.SetFloat(math.Float64frombits(val))
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 reflect.Value, out *encoder) 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.writeUint(uint64(length), 8)
out.writeUint(allocPresent, 8)
// Create a new out-of-line object and write bytes of the string.
head := out.newObject(length)
copy(out.buffer[head:], s)
return nil
}
func (m mString) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
size, err := in.readUint(8)
if err != nil {
return err
}
ptr, err := in.readUint(8)
if err != nil {
return err
}
switch ptr {
case noAlloc:
return newValueError(ErrUnexpectedNullRef, "string")
case allocPresent:
return m.unmarshalWithUncheckedSize(in, v, int(size))
default:
return newValueError(ErrBadRefEncoding, "string")
}
}
func (m mString) unmarshalWithUncheckedSize(in *decoder, v reflect.Value, size int) error {
if maxSize := int(m); size < 0 || maxSize < size {
return newExpectError(ErrStringTooLong, maxSize, size)
}
start, end := in.nextObject, in.nextObject+size
if len(in.buffer) < end {
return newValueError(ErrMessageTooSmall, v)
}
s := string(in.buffer[start:end])
if !utf8.ValidString(s) {
return newValueError(ErrStringNotUTF8, v)
}
v.SetString(s)
in.nextObject += align(size, 8)
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 reflect.Value, out *encoder) error {
if v.IsNil() {
out.writeUint(0, 8)
out.writeUint(noAlloc, 8)
return nil
}
return mString(m).marshal(ctx, v.Elem(), out)
}
var (
nilString = reflect.Zero(reflect.PtrTo(reflect.TypeOf("")))
typString = reflect.TypeOf("")
)
func (m mOptString) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
size, err := in.readUint(8)
if err != nil {
return err
}
ptr, err := in.readUint(8)
if err != nil {
return err
}
switch ptr {
case noAlloc:
v.Set(nilString)
return nil
case allocPresent:
v.Set(reflect.New(typString))
return mString(m).unmarshalWithUncheckedSize(in, v.Elem(), int(size))
default:
return newValueError(ErrBadRefEncoding, v)
}
}
type mHandle struct {
nullable bool
rights zx.Rights
subtype zx.ObjectType
}
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 reflect.Value, out *encoder) 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.Uint())
if raw == zx.HandleInvalid {
if !m.isOpt() {
return ErrUnexpectedNullHandle
}
out.writeUint(uint64(noHandle), 4)
return nil
}
out.handleDispositions = append(out.handleDispositions, zx.HandleDisposition{
Operation: zx.HandleOpMove,
Handle: raw,
Type: m.subtype,
Rights: m.rights,
Result: zx.ErrOk,
})
out.writeUint(uint64(handlePresent), 4)
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, v reflect.Value) error {
h, err := in.readUint(4)
if err != nil {
return err
}
switch uint32(h) {
case noHandle:
if !m.isOpt() {
return ErrUnexpectedNullHandle
}
v.SetUint(uint64(zx.HandleInvalid))
return nil
case handlePresent:
if len(in.handleInfos) == 0 {
return ErrNotEnoughHandles
}
handleInfo := in.handleInfos[0]
in.handleInfos = in.handleInfos[1:]
if !m.requiredRightsArePresent(handleInfo.Rights) {
return newExpectError(ErrMissingRequiredHandleRights, m.rights, handleInfo.Rights)
}
handle := handleInfo.Handle
reducedRights := m.filterOutUnspecifiedRights(handleInfo.Rights)
if handleInfo.Rights != reducedRights {
handle, err = handle.Replace(reducedRights)
if err != nil {
return newValueError(ErrUnableToReduceHandleRights, handle)
}
}
if m.subtype != zx.ObjectTypeNone && m.subtype != handleInfo.Type {
return newExpectError(ErrIncorrectHandleType, m.subtype, handleInfo.Type)
}
v.SetUint(uint64(handle))
return nil
default:
return newValueError(ErrBadHandleEncoding, h)
}
}
// An interface is represented by a Proxy, whose first field is
// a zx.Channel, and we can just marshal that. Same goes for an
// interface request, which is just an InterfaceRequest whose
// first field is a zx.Channel.
type mInterface mHandle
func (m mInterface) getMarshalSize(ctx MarshalerContext) int {
return mHandle(m).getMarshalSize(ctx)
}
func (m mInterface) getUnmarshalSize(ctx MarshalerContext) int {
return mHandle(m).getUnmarshalSize(ctx)
}
func (m mInterface) marshal(ctx MarshalerContext, v reflect.Value, out *encoder) error {
return mHandle(m).marshal(ctx, v.Field(0), out)
}
func (m mInterface) unmarshal(ctx MarshalerContext, in *decoder, v reflect.Value) error {
return mHandle(m).unmarshal(ctx, in, v.Field(0))
}