| // 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 |
| ) |
| |
| // 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) error { |
| m.once.Do(m.init) |
| return m.delegate.marshal(ctx, v, out, offset) |
| } |
| |
| func (m *lazyMarshaler) unmarshal(ctx MarshalerContext, in *decoder, offset int, v unsafevalue.Value) error { |
| m.once.Do(m.init) |
| return m.delegate.unmarshal(ctx, in, offset, 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 = 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 := out.newObject(m.getMarshalSize(ctx)) |
| if err := m.marshal(ctx, v, out, offset); 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 = 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)) |
| if err != nil { |
| return 0, 0, err |
| } |
| if err := m.unmarshal(ctx, in, offset, 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) |
| |
| handleInfos := resphi[:len(handles)] |
| for i, handle := range handles { |
| handleInfos[i] = zx.HandleInfo{ |
| Handle: handle, |
| Type: zx.ObjectTypeNone, |
| Rights: zx.RightSameRights, |
| } |
| } |
| |
| return UnmarshalWithContext2(ctx, data, handleInfos, 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 { |
| 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" || fieldName == "I_unknownHandles" |
| } |
| |
| // 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 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 != 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, mInterface: |
| // 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()) |
| } |
| } |
| |
| 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 |
| wireOffsets []int |
| presenceOffsets []uintptr |
| ) |
| |
| // - 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 == 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: |
| offset, err := readIntTag(field, tagOffsetV1) |
| if err != nil { |
| return nil, err |
| } |
| wireOffsets = append(wireOffsets, 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], field.Offset}) |
| } |
| |
| 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 []mFieldWithWireOffset |
| for i := 0; i < len(fields); i++ { |
| structFields = append(structFields, mFieldWithWireOffset{ |
| mField: fields[i], |
| wireOffset: wireOffsets[i], |
| }) |
| } |
| s := mStruct{ |
| fields: structFields, |
| size: size, |
| alignment: alignment, |
| } |
| if matchesWireFormatLayout(s, typ) { |
| return mStructUnsafeCopy{ |
| size: size, |
| }, 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{ |
| typ: typ, |
| fields: ordinalToFields, |
| ordinals: ordinals, |
| size: size, |
| alignment: alignment, |
| strictness: strictness, |
| }, nil |
| case tableTag: |
| return mTable{ |
| fields: fields, |
| presenceOffsets: presenceOffsets, |
| 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 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 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 |
| } |
| |
| 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() |
| 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(), |
| rtElemSize: typ.Elem().Size(), |
| }, 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, |
| elemTyp: elemTyp, |
| useUnsafeCopy: matchesWireFormatLayout(elemMarshaler, elemTyp), |
| }, 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{ |
| mVector: m, |
| sliceTyp: typ, |
| }, 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 unsafevalue.Value, out *encoder, offset int) error |
| unmarshal(ctx MarshalerContext, in *decoder, offset int, v unsafevalue.Value) error |
| } |
| |
| // Assert various encoders implement the Marshaler interface. |
| var _ = []Marshaler{ |
| mStruct{}, |
| mStructUnsafeCopy{}, |
| mEmptyStruct{}, |
| mXUnion{}, |
| mOptXUnion{}, |
| mTable{}, |
| mPointer{}, |
| mArray{}, |
| mVector{}, |
| mOptVector{}, |
| mBool{}, |
| mInt8{}, |
| mInt16{}, |
| mInt32{}, |
| mInt64{}, |
| mUint8{}, |
| mUint16{}, |
| mUint32{}, |
| mUint64{}, |
| mEnumOfInt8{}, |
| mEnumOfInt16{}, |
| mEnumOfInt32{}, |
| mEnumOfInt64{}, |
| mEnumOfUint8{}, |
| mEnumOfUint16{}, |
| mEnumOfUint32{}, |
| mEnumOfUint64{}, |
| mBitsOfUint8{}, |
| mBitsOfUint16{}, |
| mBitsOfUint32{}, |
| mBitsOfUint64{}, |
| mFloat32{}, |
| mFloat64{}, |
| mString(0), |
| mOptString(0), |
| } |
| |
| type mField struct { |
| Marshaler |
| index int |
| offset uintptr |
| } |
| |
| type mFieldWithWireOffset struct { |
| mField |
| wireOffset int |
| } |
| |
| type mStruct struct { |
| fields []mFieldWithWireOffset |
| 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 unsafevalue.Value, out *encoder, offset int) error { |
| for _, field := range m.fields { |
| fieldOffset := offset + field.wireOffset |
| if err := field.Marshaler.marshal(ctx, v.StructFieldOffset(field.offset), out, fieldOffset); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
| |
| func (m mStruct) unmarshal(ctx MarshalerContext, in *decoder, offset int, v unsafevalue.Value) error { |
| for _, field := range m.fields { |
| fieldOffset := offset + field.wireOffset |
| if err := field.Marshaler.unmarshal(ctx, in, fieldOffset, v.StructFieldOffset(field.offset)); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
| |
| type mStructUnsafeCopy struct { |
| size 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 unsafevalue.Value, out *encoder, offset int) error { |
| // Directly copy the object's memory to the buffer. |
| sh := reflect.SliceHeader{ |
| Data: uintptr(unsafe.Pointer(v.UnsafeAddr())), |
| Len: m.size, |
| Cap: m.size, |
| } |
| s := *(*[]uint8)(unsafe.Pointer(&sh)) |
| copy(out.buffer[offset:], s) |
| return nil |
| } |
| |
| func (m mStructUnsafeCopy) unmarshal(ctx MarshalerContext, in *decoder, offset int, v unsafevalue.Value) error { |
| // Directly copy from the buffer to the object's memory. |
| if len(in.buffer) < offset+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[offset:]) |
| 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) error { |
| out.writeUint8(offset, 0) |
| return nil |
| } |
| |
| func (_ mEmptyStruct) unmarshal(ctx MarshalerContext, in *decoder, offset int, v unsafevalue.Value) error { |
| if structByte := in.readUint8(offset); structByte != 0 { |
| return newValueError(ErrInvalidEmptyStruct, structByte) |
| } |
| |
| return nil |
| } |
| |
| type mXUnion struct { |
| typ reflect.Type |
| 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 unsafevalue.Value, out *encoder, offset int) error { |
| var ordinal uint64 |
| ordinal = v.StructFieldOffset(0).Uint64() |
| field, ok := m.fields[ordinal] |
| out.writeUint64(offset, ordinal) |
| if !ok { |
| if m.strictness == isStrict { |
| return newValueError(ErrInvalidXUnionTag, ordinal) |
| } |
| |
| bytesFld, bytesOk := m.typ.FieldByName("I_unknownData") |
| handlesFld, handlesOk := m.typ.FieldByName("I_unknownHandles") |
| if bytesOk && handlesOk { |
| marshalEnvelopeUnknown( |
| out, |
| offset+8, |
| v.StructFieldOffset(bytesFld.Offset).Bytes(), |
| v.StructFieldOffset(handlesFld.Offset).HandleInfos()) |
| } |
| return nil |
| } |
| |
| // Field. |
| if err := marshalEnvelopePresent(ctx, field, v.StructFieldOffset(field.offset), out, offset+8); err != nil { |
| return err |
| } |
| |
| return nil |
| } |
| |
| func (m mXUnion) unmarshal(ctx MarshalerContext, in *decoder, offset int, v unsafevalue.Value) error { |
| return m.unmarshalWithOptSpecified(ctx, in, offset, v, nil) |
| } |
| |
| func (m mXUnion) unmarshalWithOptSpecified(ctx MarshalerContext, in *decoder, offset 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 { |
| if !optAllowed { |
| return newValueError(ErrInvalidXUnionTag, ordinal) |
| } |
| |
| h, err := unmarshalEnvelopeHeader(in, offset+8) |
| 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 { |
| // Best effort. |
| _, unknownHandles, err := unmarshalEnvelopeUnknown(in, offset+8) |
| if err == nil { |
| for i := range unknownHandles { |
| _ = handleClose(&unknownHandles[i].Handle) |
| } |
| } |
| return newValueError(ErrInvalidXUnionTag, ordinal) |
| } |
| |
| v.StructFieldOffset(0).SetUint64(ordinal) |
| |
| unknownData, unknownHandles, err := unmarshalEnvelopeUnknown(in, offset+8) |
| if err != nil { |
| return err |
| } |
| |
| fld, ok := m.typ.FieldByName("I_unknownData") |
| if ok { |
| v.StructFieldOffset(fld.Offset).SetBytes(unknownData) |
| } |
| fld, ok = m.typ.FieldByName("I_unknownHandles") |
| if ok { |
| v.StructFieldOffset(fld.Offset).SetHandleInfos(unknownHandles) |
| } |
| |
| 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, 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) error { |
| if v.PointerIsNil() { |
| out.writeUint64(offset, 0) // ordinal + padding |
| marshalEnvelopeAbsent(out, offset+8) |
| return nil |
| } else { |
| return m.mXUnion.marshal(ctx, v.PointerElem(), out, offset) |
| } |
| } |
| |
| func (m mOptXUnion) unmarshal(ctx MarshalerContext, in *decoder, offset int, v unsafevalue.Value) error { |
| return m.unmarshalWithOptSpecified(ctx, in, offset, 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 |
| } |
| |
| 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 unsafevalue.Value, out *encoder, offset int) error { |
| numHandleDispositions := len(out.handleDispositions) |
| numBytes := len(out.buffer) |
| outOfLineOffset := out.newObject(m.getMarshalSize(ctx)) |
| if err := m.marshal(ctx, v, out, outOfLineOffset); err != nil { |
| return err |
| } |
| numHandleDispositions = len(out.handleDispositions) - numHandleDispositions |
| numBytes = len(out.buffer) - numBytes |
| out.writeUint32(offset, uint32(numBytes)) |
| out.writeUint32(offset+4, uint32(numHandleDispositions)) |
| out.writeUint64(offset+8, allocPresent) |
| return nil |
| } |
| |
| func marshalEnvelopeAbsent(out *encoder, offset int) { |
| out.writeUint64(offset, 0) // both numBytes, and numHandleDispositions |
| out.writeUint64(offset+8, noAlloc) |
| } |
| |
| func marshalEnvelopeUnknown(out *encoder, offset int, unknownData []byte, unknownHandles []zx.HandleInfo) { |
| outOfLineOffset := out.newObject(len(unknownData)) |
| copy(out.buffer[outOfLineOffset:], unknownData) |
| for _, info := range unknownHandles { |
| out.handleDispositions = append(out.handleDispositions, zx.HandleDisposition{ |
| Operation: zx.HandleOpMove, |
| Handle: info.Handle, |
| Type: info.Type, |
| Rights: info.Rights, |
| Result: zx.ErrOk, |
| }) |
| } |
| out.writeUint32(offset, uint32(len(unknownData))) |
| out.writeUint32(offset+4, uint32(len(unknownHandles))) |
| out.writeUint64(offset+8, allocPresent) |
| } |
| |
| 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, offset int) (envelopeHeader, error) { |
| h := envelopeHeader{ |
| byteCount: in.readUint32(offset), |
| handleCount: in.readUint32(offset + 4), |
| presence: in.readUint64(offset + 8), |
| } |
| |
| switch h.presence { |
| case allocPresent, noAlloc: |
| default: |
| return h, newValueError(ErrBadRefEncoding, h) |
| } |
| |
| if h.handleCount > uint32(len(in.handleInfos)) { |
| return h, newValueError(ErrTooManyHandles, h) |
| } |
| |
| return h, nil |
| } |
| |
| func unmarshalEnvelopeUnknown(in *decoder, offset int) ([]byte, []zx.HandleInfo, error) { |
| header, err := unmarshalEnvelopeHeader(in, offset) |
| if err != nil { |
| return nil, nil, err |
| } |
| |
| var unknownHandles []zx.HandleInfo |
| 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 |
| } |
| |
| start, err := in.newObject(int(header.byteCount)) |
| if err != nil { |
| return nil, nil, err |
| } |
| unknownData := in.buffer[start:][:header.byteCount] |
| |
| return unknownData, unknownHandles, nil |
| } |
| |
| func unmarshalEnvelopeContent(ctx MarshalerContext, header envelopeHeader, m Marshaler, in *decoder, v unsafevalue.Value, mode unmarshalEnvelopeMode) (bool, error) { |
| outOfLineOffset, err := in.newObject(m.getUnmarshalSize(ctx)) |
| if err != nil { |
| return false, err |
| } |
| if err := m.unmarshal(ctx, in, outOfLineOffset, v); err != nil { |
| return false, err |
| } |
| |
| return true, nil |
| } |
| |
| func unmarshalEnvelope(ctx MarshalerContext, m Marshaler, in *decoder, offset int, v unsafevalue.Value, mode unmarshalEnvelopeMode) (bool, error) { |
| header, err := unmarshalEnvelopeHeader(in, offset) |
| 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 unsafevalue.Value, out *encoder, offset 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 I_unknownData type {})", rawUnknownData) |
| } |
| // Determining max ordinal from unknown ordinals. |
| for unknownOrdinal := range unknownData { |
| if maxOrdinal < unknownOrdinal { |
| maxOrdinal = unknownOrdinal |
| } |
| } |
| } |
| |
| // 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 := out.newObject(int(maxOrdinal) * envelopeSize) |
| |
| // 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); 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(out, envelopeOffset) |
| } |
| } else if unknownField, ok := unknownData[ordinal]; ok { |
| marshalEnvelopeUnknown( |
| out, |
| envelopeOffset, |
| unknownField.Bytes, |
| unknownField.Handles, |
| ) |
| } else { |
| marshalEnvelopeAbsent(out, envelopeOffset) |
| } |
| |
| ordinal++ |
| envelopeOffset += 16 |
| if fieldKnown { |
| index++ |
| } |
| } |
| |
| return nil |
| } |
| |
| func (m mTable) unmarshal(ctx MarshalerContext, in *decoder, offset int, v unsafevalue.Value) error { |
| mou := in.readUint64(offset) |
| // 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 |
| |
| 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) |
| 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, v.StructFieldOffset(m.fields[index].offset), knownMayBeAbsent); err != nil { |
| return err |
| } else if isPresent { |
| v.StructFieldOffset(m.presenceOffsets[index]).SetBool(true) |
| } |
| } else { |
| bytes, handles, err := unmarshalEnvelopeUnknown(in, envelopeOffset) |
| if err != nil { |
| return err |
| } |
| if len(bytes) > 0 || len(handles) > 0 { |
| if unknownData == nil { |
| unknownData = make(map[uint64]UnknownData) |
| v.StructFieldOffset(unknownTableDataOffset).SetInterface(unknownData) |
| } |
| unknownData[ordinal] = UnknownData{ |
| Bytes: bytes, |
| Handles: handles, |
| } |
| } |
| } |
| ordinal++ |
| envelopeOffset += 16 |
| if fieldKnown { |
| index++ |
| } |
| } |
| 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) 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 := out.newObject(align(m.Marshaler.getMarshalSize(ctx), 8)) |
| |
| // Marshal field. |
| if err := m.Marshaler.marshal(ctx, v.PointerElem(), out, outOfLineOffset); err != nil { |
| return err |
| } |
| |
| return nil |
| } |
| |
| func (m mPointer) unmarshal(ctx MarshalerContext, in *decoder, offset 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)) |
| if err != nil { |
| return err |
| } |
| |
| // Unmarshal field. |
| if err := m.Marshaler.unmarshal(ctx, in, outOfLineOffset, v.PointerElem()); err != nil { |
| return err |
| } |
| |
| 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 unsafevalue.Value, out *encoder, offset int) error { |
| return m.mOptXUnion.marshal(ctx, v, out, offset) |
| } |
| |
| func (m mOptUnion) unmarshal(ctx MarshalerContext, in *decoder, offset int, v unsafevalue.Value) error { |
| return m.mOptXUnion.unmarshal(ctx, in, offset, v) |
| } |
| |
| 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) 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); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
| |
| func (m mArray) unmarshal(ctx MarshalerContext, in *decoder, offset 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, 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) 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 := out.newObject(vLen * m.Marshaler.getMarshalSize(ctx)) |
| |
| // 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); err != nil { |
| return err |
| } |
| } |
| } |
| |
| return nil |
| } |
| |
| func (m mVector) unmarshal(ctx MarshalerContext, in *decoder, offset 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, v, int(size)) |
| default: |
| return newValueError(ErrBadRefEncoding, v) |
| } |
| } |
| |
| func (m mVector) unmarshalWithUncheckedSize(ctx MarshalerContext, in *decoder, 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) |
| 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, 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) error { |
| if v.PointerIsNil() { |
| out.writeUint64(offset, 0) |
| out.writeUint64(offset+8, noAlloc) |
| return nil |
| } |
| |
| return m.mVector.marshal(ctx, v.PointerElem(), out, offset) |
| } |
| |
| func (m mOptVector) unmarshal(ctx MarshalerContext, in *decoder, offset int, v unsafevalue.Value) error { |
| size := in.readUint64(offset) |
| ptr := in.readUint64(offset + 8) |
| switch ptr { |
| case noAlloc: |
| v.PointerSetNil() |
| return nil |
| case allocPresent: |
| v.PointerSetNew(m.sliceTyp) |
| return m.mVector.unmarshalWithUncheckedSize(ctx, in, 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) 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, 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) error { |
| out.writeUint8(offset, uint8(v.Int8())) |
| return nil |
| } |
| |
| func (m mInt8) unmarshal(ctx MarshalerContext, in *decoder, offset 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) error { |
| out.writeUint16(offset, uint16(v.Int16())) |
| return nil |
| } |
| |
| func (m mInt16) unmarshal(ctx MarshalerContext, in *decoder, offset 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) error { |
| out.writeUint32(offset, uint32(v.Int32())) |
| return nil |
| } |
| |
| func (m mInt32) unmarshal(ctx MarshalerContext, in *decoder, offset 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) error { |
| out.writeUint64(offset, uint64(v.Int64())) |
| return nil |
| } |
| |
| func (m mInt64) unmarshal(ctx MarshalerContext, in *decoder, offset 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) error { |
| out.writeUint8(offset, v.Uint8()) |
| return nil |
| } |
| |
| func (m mUint8) unmarshal(ctx MarshalerContext, in *decoder, offset 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) error { |
| out.writeUint16(offset, v.Uint16()) |
| return nil |
| } |
| |
| func (m mUint16) unmarshal(ctx MarshalerContext, in *decoder, offset 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) error { |
| out.writeUint32(offset, v.Uint32()) |
| return nil |
| } |
| |
| func (m mUint32) unmarshal(ctx MarshalerContext, in *decoder, offset 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) error { |
| out.writeUint64(offset, v.Uint64()) |
| return nil |
| } |
| |
| func (m mUint64) unmarshal(ctx MarshalerContext, in *decoder, offset 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) 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, 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) 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, 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) 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, 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) 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, 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) 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, 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) 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, 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) 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, 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) 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, 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) 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, 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) 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, 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) 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, 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) 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, 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) error { |
| out.writeUint32(offset, math.Float32bits(v.Float32())) |
| return nil |
| } |
| |
| func (m mFloat32) unmarshal(ctx MarshalerContext, in *decoder, offset 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) error { |
| out.writeUint64(offset, math.Float64bits(v.Float64())) |
| return nil |
| } |
| |
| func (m mFloat64) unmarshal(ctx MarshalerContext, in *decoder, offset 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) 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 := out.newObject(length) |
| copy(out.buffer[head:], s) |
| |
| return nil |
| } |
| |
| func (m mString) unmarshal(ctx MarshalerContext, in *decoder, offset 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, v, int(size)) |
| default: |
| return newValueError(ErrBadRefEncoding, "string") |
| } |
| } |
| |
| func (m mString) unmarshalWithUncheckedSize(in *decoder, v unsafevalue.Value, size int) error { |
| if maxSize := int(m); size < 0 || maxSize < size { |
| return newExpectError(ErrStringTooLong, maxSize, size) |
| } |
| start, err := in.newObject(size) |
| 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) error { |
| if v.PointerIsNil() { |
| out.writeUint64(offset, 0) |
| out.writeUint64(offset+8, noAlloc) |
| return nil |
| } |
| |
| return mString(m).marshal(ctx, v.PointerElem(), out, offset) |
| } |
| |
| var ( |
| typString = reflect.TypeOf("") |
| ) |
| |
| func (m mOptString) unmarshal(ctx MarshalerContext, in *decoder, offset int, v unsafevalue.Value) error { |
| size := in.readUint64(offset) |
| ptr := in.readUint64(offset + 8) |
| switch ptr { |
| case noAlloc: |
| v.PointerSetNil() |
| return nil |
| case allocPresent: |
| v.PointerSetNew(typString) |
| return mString(m).unmarshalWithUncheckedSize(in, v.PointerElem(), 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 unsafevalue.Value, out *encoder, offset 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 ErrUnexpectedNullHandle |
| } |
| 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, v unsafevalue.Value) error { |
| h := in.readUint32(offset) |
| switch uint32(h) { |
| case noHandle: |
| if !m.isOpt() { |
| return ErrUnexpectedNullHandle |
| } |
| 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.requiredRightsArePresent(handleInfo.Rights) { |
| return newExpectError(ErrMissingRequiredHandleRights, m.rights, handleInfo.Rights) |
| } |
| |
| handle := handleInfo.Handle |
| reducedRights := m.filterOutUnspecifiedRights(handleInfo.Rights) |
| if handleInfo.Rights != reducedRights { |
| handle, err := handleReplace(handle, 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.SetUint32(uint32(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 unsafevalue.Value, out *encoder, offset int) error { |
| return mHandle(m).marshal(ctx, v.StructFieldOffset(0), out, offset) |
| } |
| |
| func (m mInterface) unmarshal(ctx MarshalerContext, in *decoder, offset int, v unsafevalue.Value) error { |
| return mHandle(m).unmarshal(ctx, in, offset, v.StructFieldOffset(0)) |
| } |