| // Copyright 2019 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 impl |
| |
| import ( |
| "fmt" |
| "reflect" |
| |
| pref "google.golang.org/protobuf/reflect/protoreflect" |
| ) |
| |
| // pointerCoderFuncs is a set of pointer encoding functions. |
| type pointerCoderFuncs struct { |
| size func(p pointer, tagsize int, opts marshalOptions) int |
| marshal func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) |
| isInit func(p pointer) error |
| } |
| |
| // ifaceCoderFuncs is a set of interface{} encoding functions. |
| type ifaceCoderFuncs struct { |
| size func(ival interface{}, tagsize int, opts marshalOptions) int |
| marshal func(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) |
| isInit func(ival interface{}) error |
| } |
| |
| // fieldCoder returns pointer functions for a field, used for operating on |
| // struct fields. |
| func fieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs { |
| switch { |
| case fd.IsMap(): |
| return encoderFuncsForMap(fd, ft) |
| case fd.Cardinality() == pref.Repeated && !fd.IsPacked(): |
| // Repeated fields (not packed). |
| if ft.Kind() != reflect.Slice { |
| break |
| } |
| ft := ft.Elem() |
| switch fd.Kind() { |
| case pref.BoolKind: |
| if ft.Kind() == reflect.Bool { |
| return coderBoolSlice |
| } |
| case pref.EnumKind: |
| if ft.Kind() == reflect.Int32 { |
| return coderEnumSlice |
| } |
| case pref.Int32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderInt32Slice |
| } |
| case pref.Sint32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderSint32Slice |
| } |
| case pref.Uint32Kind: |
| if ft.Kind() == reflect.Uint32 { |
| return coderUint32Slice |
| } |
| case pref.Int64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderInt64Slice |
| } |
| case pref.Sint64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderSint64Slice |
| } |
| case pref.Uint64Kind: |
| if ft.Kind() == reflect.Uint64 { |
| return coderUint64Slice |
| } |
| case pref.Sfixed32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderSfixed32Slice |
| } |
| case pref.Fixed32Kind: |
| if ft.Kind() == reflect.Uint32 { |
| return coderFixed32Slice |
| } |
| case pref.FloatKind: |
| if ft.Kind() == reflect.Float32 { |
| return coderFloatSlice |
| } |
| case pref.Sfixed64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderSfixed64Slice |
| } |
| case pref.Fixed64Kind: |
| if ft.Kind() == reflect.Uint64 { |
| return coderFixed64Slice |
| } |
| case pref.DoubleKind: |
| if ft.Kind() == reflect.Float64 { |
| return coderDoubleSlice |
| } |
| case pref.StringKind: |
| if ft.Kind() == reflect.String && fd.Syntax() == pref.Proto3 { |
| return coderStringSliceValidateUTF8 |
| } |
| if ft.Kind() == reflect.String { |
| return coderStringSlice |
| } |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { |
| return coderBytesSlice |
| } |
| case pref.BytesKind: |
| if ft.Kind() == reflect.String { |
| return coderStringSlice |
| } |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { |
| return coderBytesSlice |
| } |
| case pref.MessageKind: |
| return makeMessageSliceFieldCoder(fd, ft) |
| case pref.GroupKind: |
| return makeGroupSliceFieldCoder(fd, ft) |
| } |
| case fd.Cardinality() == pref.Repeated && fd.IsPacked(): |
| // Packed repeated fields. |
| // |
| // Only repeated fields of primitive numeric types |
| // (Varint, Fixed32, or Fixed64 wire type) can be packed. |
| if ft.Kind() != reflect.Slice { |
| break |
| } |
| ft := ft.Elem() |
| switch fd.Kind() { |
| case pref.BoolKind: |
| if ft.Kind() == reflect.Bool { |
| return coderBoolPackedSlice |
| } |
| case pref.EnumKind: |
| if ft.Kind() == reflect.Int32 { |
| return coderEnumPackedSlice |
| } |
| case pref.Int32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderInt32PackedSlice |
| } |
| case pref.Sint32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderSint32PackedSlice |
| } |
| case pref.Uint32Kind: |
| if ft.Kind() == reflect.Uint32 { |
| return coderUint32PackedSlice |
| } |
| case pref.Int64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderInt64PackedSlice |
| } |
| case pref.Sint64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderSint64PackedSlice |
| } |
| case pref.Uint64Kind: |
| if ft.Kind() == reflect.Uint64 { |
| return coderUint64PackedSlice |
| } |
| case pref.Sfixed32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderSfixed32PackedSlice |
| } |
| case pref.Fixed32Kind: |
| if ft.Kind() == reflect.Uint32 { |
| return coderFixed32PackedSlice |
| } |
| case pref.FloatKind: |
| if ft.Kind() == reflect.Float32 { |
| return coderFloatPackedSlice |
| } |
| case pref.Sfixed64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderSfixed64PackedSlice |
| } |
| case pref.Fixed64Kind: |
| if ft.Kind() == reflect.Uint64 { |
| return coderFixed64PackedSlice |
| } |
| case pref.DoubleKind: |
| if ft.Kind() == reflect.Float64 { |
| return coderDoublePackedSlice |
| } |
| } |
| case fd.Kind() == pref.MessageKind: |
| return makeMessageFieldCoder(fd, ft) |
| case fd.Kind() == pref.GroupKind: |
| return makeGroupFieldCoder(fd, ft) |
| case fd.Syntax() == pref.Proto3 && fd.ContainingOneof() == nil: |
| // Populated oneof fields always encode even if set to the zero value, |
| // which normally are not encoded in proto3. |
| switch fd.Kind() { |
| case pref.BoolKind: |
| if ft.Kind() == reflect.Bool { |
| return coderBoolNoZero |
| } |
| case pref.EnumKind: |
| if ft.Kind() == reflect.Int32 { |
| return coderEnumNoZero |
| } |
| case pref.Int32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderInt32NoZero |
| } |
| case pref.Sint32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderSint32NoZero |
| } |
| case pref.Uint32Kind: |
| if ft.Kind() == reflect.Uint32 { |
| return coderUint32NoZero |
| } |
| case pref.Int64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderInt64NoZero |
| } |
| case pref.Sint64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderSint64NoZero |
| } |
| case pref.Uint64Kind: |
| if ft.Kind() == reflect.Uint64 { |
| return coderUint64NoZero |
| } |
| case pref.Sfixed32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderSfixed32NoZero |
| } |
| case pref.Fixed32Kind: |
| if ft.Kind() == reflect.Uint32 { |
| return coderFixed32NoZero |
| } |
| case pref.FloatKind: |
| if ft.Kind() == reflect.Float32 { |
| return coderFloatNoZero |
| } |
| case pref.Sfixed64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderSfixed64NoZero |
| } |
| case pref.Fixed64Kind: |
| if ft.Kind() == reflect.Uint64 { |
| return coderFixed64NoZero |
| } |
| case pref.DoubleKind: |
| if ft.Kind() == reflect.Float64 { |
| return coderDoubleNoZero |
| } |
| case pref.StringKind: |
| if ft.Kind() == reflect.String { |
| return coderStringNoZeroValidateUTF8 |
| } |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { |
| return coderBytesNoZero |
| } |
| case pref.BytesKind: |
| if ft.Kind() == reflect.String { |
| return coderStringNoZero |
| } |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { |
| return coderBytesNoZero |
| } |
| } |
| case ft.Kind() == reflect.Ptr: |
| ft := ft.Elem() |
| switch fd.Kind() { |
| case pref.BoolKind: |
| if ft.Kind() == reflect.Bool { |
| return coderBoolPtr |
| } |
| case pref.EnumKind: |
| if ft.Kind() == reflect.Int32 { |
| return coderEnumPtr |
| } |
| case pref.Int32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderInt32Ptr |
| } |
| case pref.Sint32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderSint32Ptr |
| } |
| case pref.Uint32Kind: |
| if ft.Kind() == reflect.Uint32 { |
| return coderUint32Ptr |
| } |
| case pref.Int64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderInt64Ptr |
| } |
| case pref.Sint64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderSint64Ptr |
| } |
| case pref.Uint64Kind: |
| if ft.Kind() == reflect.Uint64 { |
| return coderUint64Ptr |
| } |
| case pref.Sfixed32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderSfixed32Ptr |
| } |
| case pref.Fixed32Kind: |
| if ft.Kind() == reflect.Uint32 { |
| return coderFixed32Ptr |
| } |
| case pref.FloatKind: |
| if ft.Kind() == reflect.Float32 { |
| return coderFloatPtr |
| } |
| case pref.Sfixed64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderSfixed64Ptr |
| } |
| case pref.Fixed64Kind: |
| if ft.Kind() == reflect.Uint64 { |
| return coderFixed64Ptr |
| } |
| case pref.DoubleKind: |
| if ft.Kind() == reflect.Float64 { |
| return coderDoublePtr |
| } |
| case pref.StringKind: |
| if ft.Kind() == reflect.String { |
| return coderStringPtr |
| } |
| case pref.BytesKind: |
| if ft.Kind() == reflect.String { |
| return coderStringPtr |
| } |
| } |
| default: |
| switch fd.Kind() { |
| case pref.BoolKind: |
| if ft.Kind() == reflect.Bool { |
| return coderBool |
| } |
| case pref.EnumKind: |
| if ft.Kind() == reflect.Int32 { |
| return coderEnum |
| } |
| case pref.Int32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderInt32 |
| } |
| case pref.Sint32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderSint32 |
| } |
| case pref.Uint32Kind: |
| if ft.Kind() == reflect.Uint32 { |
| return coderUint32 |
| } |
| case pref.Int64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderInt64 |
| } |
| case pref.Sint64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderSint64 |
| } |
| case pref.Uint64Kind: |
| if ft.Kind() == reflect.Uint64 { |
| return coderUint64 |
| } |
| case pref.Sfixed32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderSfixed32 |
| } |
| case pref.Fixed32Kind: |
| if ft.Kind() == reflect.Uint32 { |
| return coderFixed32 |
| } |
| case pref.FloatKind: |
| if ft.Kind() == reflect.Float32 { |
| return coderFloat |
| } |
| case pref.Sfixed64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderSfixed64 |
| } |
| case pref.Fixed64Kind: |
| if ft.Kind() == reflect.Uint64 { |
| return coderFixed64 |
| } |
| case pref.DoubleKind: |
| if ft.Kind() == reflect.Float64 { |
| return coderDouble |
| } |
| case pref.StringKind: |
| if fd.Syntax() == pref.Proto3 && ft.Kind() == reflect.String { |
| return coderStringValidateUTF8 |
| } |
| if ft.Kind() == reflect.String { |
| return coderString |
| } |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { |
| return coderBytes |
| } |
| case pref.BytesKind: |
| if ft.Kind() == reflect.String { |
| return coderString |
| } |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { |
| return coderBytes |
| } |
| } |
| } |
| panic(fmt.Errorf("invalid type: no encoder for %v %v %v/%v", fd.FullName(), fd.Cardinality(), fd.Kind(), ft)) |
| } |
| |
| // encoderFuncsForValue returns interface{} value functions for a field, used for |
| // extension values and map encoding. |
| func encoderFuncsForValue(fd pref.FieldDescriptor, ft reflect.Type) ifaceCoderFuncs { |
| switch { |
| case fd.Cardinality() == pref.Repeated && !fd.IsPacked(): |
| if ft.Kind() != reflect.Ptr || ft.Elem().Kind() != reflect.Slice { |
| break |
| } |
| ft := ft.Elem().Elem() |
| switch fd.Kind() { |
| case pref.BoolKind: |
| if ft.Kind() == reflect.Bool { |
| return coderBoolSliceIface |
| } |
| case pref.EnumKind: |
| if ft.Kind() == reflect.Int32 { |
| return coderEnumSliceIface |
| } |
| case pref.Int32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderInt32SliceIface |
| } |
| case pref.Sint32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderSint32SliceIface |
| } |
| case pref.Uint32Kind: |
| if ft.Kind() == reflect.Uint32 { |
| return coderUint32SliceIface |
| } |
| case pref.Int64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderInt64SliceIface |
| } |
| case pref.Sint64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderSint64SliceIface |
| } |
| case pref.Uint64Kind: |
| if ft.Kind() == reflect.Uint64 { |
| return coderUint64SliceIface |
| } |
| case pref.Sfixed32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderSfixed32SliceIface |
| } |
| case pref.Fixed32Kind: |
| if ft.Kind() == reflect.Uint32 { |
| return coderFixed32SliceIface |
| } |
| case pref.FloatKind: |
| if ft.Kind() == reflect.Float32 { |
| return coderFloatSliceIface |
| } |
| case pref.Sfixed64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderSfixed64SliceIface |
| } |
| case pref.Fixed64Kind: |
| if ft.Kind() == reflect.Uint64 { |
| return coderFixed64SliceIface |
| } |
| case pref.DoubleKind: |
| if ft.Kind() == reflect.Float64 { |
| return coderDoubleSliceIface |
| } |
| case pref.StringKind: |
| if ft.Kind() == reflect.String { |
| return coderStringSliceIface |
| } |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { |
| return coderBytesSliceIface |
| } |
| case pref.BytesKind: |
| if ft.Kind() == reflect.String { |
| return coderStringSliceIface |
| } |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { |
| return coderBytesSliceIface |
| } |
| case pref.MessageKind: |
| return coderMessageSliceIface |
| case pref.GroupKind: |
| return coderGroupSliceIface |
| } |
| case fd.Cardinality() == pref.Repeated && fd.IsPacked(): |
| default: |
| switch fd.Kind() { |
| case pref.BoolKind: |
| if ft.Kind() == reflect.Bool { |
| return coderBoolIface |
| } |
| case pref.EnumKind: |
| if ft.Kind() == reflect.Int32 { |
| return coderEnumIface |
| } |
| case pref.Int32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderInt32Iface |
| } |
| case pref.Sint32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderSint32Iface |
| } |
| case pref.Uint32Kind: |
| if ft.Kind() == reflect.Uint32 { |
| return coderUint32Iface |
| } |
| case pref.Int64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderInt64Iface |
| } |
| case pref.Sint64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderSint64Iface |
| } |
| case pref.Uint64Kind: |
| if ft.Kind() == reflect.Uint64 { |
| return coderUint64Iface |
| } |
| case pref.Sfixed32Kind: |
| if ft.Kind() == reflect.Int32 { |
| return coderSfixed32Iface |
| } |
| case pref.Fixed32Kind: |
| if ft.Kind() == reflect.Uint32 { |
| return coderFixed32Iface |
| } |
| case pref.FloatKind: |
| if ft.Kind() == reflect.Float32 { |
| return coderFloatIface |
| } |
| case pref.Sfixed64Kind: |
| if ft.Kind() == reflect.Int64 { |
| return coderSfixed64Iface |
| } |
| case pref.Fixed64Kind: |
| if ft.Kind() == reflect.Uint64 { |
| return coderFixed64Iface |
| } |
| case pref.DoubleKind: |
| if ft.Kind() == reflect.Float64 { |
| return coderDoubleIface |
| } |
| case pref.StringKind: |
| if fd.Syntax() == pref.Proto3 && ft.Kind() == reflect.String { |
| return coderStringIfaceValidateUTF8 |
| } |
| if ft.Kind() == reflect.String { |
| return coderStringIface |
| } |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { |
| return coderBytesIface |
| } |
| case pref.BytesKind: |
| if ft.Kind() == reflect.String { |
| return coderStringIface |
| } |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { |
| return coderBytesIface |
| } |
| case pref.MessageKind: |
| return coderMessageIface |
| case pref.GroupKind: |
| return coderGroupIface |
| } |
| } |
| panic(fmt.Errorf("invalid type: no encoder for %v %v %v/%v", fd.FullName(), fd.Cardinality(), fd.Kind(), ft)) |
| } |