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