| // 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" |
| |
| "google.golang.org/protobuf/internal/encoding/wire" |
| "google.golang.org/protobuf/internal/strs" |
| 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) |
| unmarshal func(b []byte, p pointer, wtyp wire.Type, opts unmarshalOptions) (unmarshalOutput, error) |
| isInit func(p pointer) error |
| } |
| |
| // valueCoderFuncs is a set of protoreflect.Value encoding functions. |
| type valueCoderFuncs struct { |
| size func(v pref.Value, tagsize int, opts marshalOptions) int |
| marshal func(b []byte, v pref.Value, wiretag uint64, opts marshalOptions) ([]byte, error) |
| unmarshal func(b []byte, v pref.Value, num wire.Number, wtyp wire.Type, opts unmarshalOptions) (pref.Value, unmarshalOutput, error) |
| isInit func(v pref.Value) 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 && strs.EnforceUTF8(fd) { |
| return coderStringSliceValidateUTF8 |
| } |
| if ft.Kind() == reflect.String { |
| return coderStringSlice |
| } |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 && strs.EnforceUTF8(fd) { |
| return coderBytesSliceValidateUTF8 |
| } |
| 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 && strs.EnforceUTF8(fd) { |
| return coderStringNoZeroValidateUTF8 |
| } |
| if ft.Kind() == reflect.String { |
| return coderStringNoZero |
| } |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 && strs.EnforceUTF8(fd) { |
| return coderBytesNoZeroValidateUTF8 |
| } |
| 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 ft.Kind() == reflect.String && strs.EnforceUTF8(fd) { |
| return coderStringValidateUTF8 |
| } |
| if ft.Kind() == reflect.String { |
| return coderString |
| } |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 && strs.EnforceUTF8(fd) { |
| return coderBytesValidateUTF8 |
| } |
| 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.Sprintf("invalid type: no encoder for %v %v %v/%v", fd.FullName(), fd.Cardinality(), fd.Kind(), ft)) |
| } |
| |
| // encoderFuncsForValue returns value functions for a field, used for |
| // extension values and map encoding. |
| func encoderFuncsForValue(fd pref.FieldDescriptor) valueCoderFuncs { |
| switch { |
| case fd.Cardinality() == pref.Repeated && !fd.IsPacked(): |
| switch fd.Kind() { |
| case pref.BoolKind: |
| return coderBoolSliceValue |
| case pref.EnumKind: |
| return coderEnumSliceValue |
| case pref.Int32Kind: |
| return coderInt32SliceValue |
| case pref.Sint32Kind: |
| return coderSint32SliceValue |
| case pref.Uint32Kind: |
| return coderUint32SliceValue |
| case pref.Int64Kind: |
| return coderInt64SliceValue |
| case pref.Sint64Kind: |
| return coderSint64SliceValue |
| case pref.Uint64Kind: |
| return coderUint64SliceValue |
| case pref.Sfixed32Kind: |
| return coderSfixed32SliceValue |
| case pref.Fixed32Kind: |
| return coderFixed32SliceValue |
| case pref.FloatKind: |
| return coderFloatSliceValue |
| case pref.Sfixed64Kind: |
| return coderSfixed64SliceValue |
| case pref.Fixed64Kind: |
| return coderFixed64SliceValue |
| case pref.DoubleKind: |
| return coderDoubleSliceValue |
| case pref.StringKind: |
| // We don't have a UTF-8 validating coder for repeated string fields. |
| // Value coders are used for extensions and maps. |
| // Extensions are never proto3, and maps never contain lists. |
| return coderStringSliceValue |
| case pref.BytesKind: |
| return coderBytesSliceValue |
| case pref.MessageKind: |
| return coderMessageSliceValue |
| case pref.GroupKind: |
| return coderGroupSliceValue |
| } |
| case fd.Cardinality() == pref.Repeated && fd.IsPacked(): |
| switch fd.Kind() { |
| case pref.BoolKind: |
| return coderBoolPackedSliceValue |
| case pref.EnumKind: |
| return coderEnumPackedSliceValue |
| case pref.Int32Kind: |
| return coderInt32PackedSliceValue |
| case pref.Sint32Kind: |
| return coderSint32PackedSliceValue |
| case pref.Uint32Kind: |
| return coderUint32PackedSliceValue |
| case pref.Int64Kind: |
| return coderInt64PackedSliceValue |
| case pref.Sint64Kind: |
| return coderSint64PackedSliceValue |
| case pref.Uint64Kind: |
| return coderUint64PackedSliceValue |
| case pref.Sfixed32Kind: |
| return coderSfixed32PackedSliceValue |
| case pref.Fixed32Kind: |
| return coderFixed32PackedSliceValue |
| case pref.FloatKind: |
| return coderFloatPackedSliceValue |
| case pref.Sfixed64Kind: |
| return coderSfixed64PackedSliceValue |
| case pref.Fixed64Kind: |
| return coderFixed64PackedSliceValue |
| case pref.DoubleKind: |
| return coderDoublePackedSliceValue |
| } |
| default: |
| switch fd.Kind() { |
| default: |
| case pref.BoolKind: |
| return coderBoolValue |
| case pref.EnumKind: |
| return coderEnumValue |
| case pref.Int32Kind: |
| return coderInt32Value |
| case pref.Sint32Kind: |
| return coderSint32Value |
| case pref.Uint32Kind: |
| return coderUint32Value |
| case pref.Int64Kind: |
| return coderInt64Value |
| case pref.Sint64Kind: |
| return coderSint64Value |
| case pref.Uint64Kind: |
| return coderUint64Value |
| case pref.Sfixed32Kind: |
| return coderSfixed32Value |
| case pref.Fixed32Kind: |
| return coderFixed32Value |
| case pref.FloatKind: |
| return coderFloatValue |
| case pref.Sfixed64Kind: |
| return coderSfixed64Value |
| case pref.Fixed64Kind: |
| return coderFixed64Value |
| case pref.DoubleKind: |
| return coderDoubleValue |
| case pref.StringKind: |
| if strs.EnforceUTF8(fd) { |
| return coderStringValueValidateUTF8 |
| } |
| return coderStringValue |
| case pref.BytesKind: |
| return coderBytesValue |
| case pref.MessageKind: |
| return coderMessageValue |
| case pref.GroupKind: |
| return coderGroupValue |
| } |
| } |
| panic(fmt.Sprintf("invalid field: no encoder for %v %v %v", fd.FullName(), fd.Cardinality(), fd.Kind())) |
| } |