| // 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/encoding/protowire" | |
| "google.golang.org/protobuf/internal/strs" | |
| "google.golang.org/protobuf/reflect/protoreflect" | |
| ) | |
| // pointerCoderFuncs is a set of pointer encoding functions. | |
| type pointerCoderFuncs struct { | |
| mi *MessageInfo | |
| size func(p pointer, f *coderFieldInfo, opts marshalOptions) int | |
| marshal func(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) | |
| unmarshal func(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (unmarshalOutput, error) | |
| isInit func(p pointer, f *coderFieldInfo) error | |
| merge func(dst, src pointer, f *coderFieldInfo, opts mergeOptions) | |
| } | |
| // valueCoderFuncs is a set of protoreflect.Value encoding functions. | |
| type valueCoderFuncs struct { | |
| size func(v protoreflect.Value, tagsize int, opts marshalOptions) int | |
| marshal func(b []byte, v protoreflect.Value, wiretag uint64, opts marshalOptions) ([]byte, error) | |
| unmarshal func(b []byte, v protoreflect.Value, num protowire.Number, wtyp protowire.Type, opts unmarshalOptions) (protoreflect.Value, unmarshalOutput, error) | |
| isInit func(v protoreflect.Value) error | |
| merge func(dst, src protoreflect.Value, opts mergeOptions) protoreflect.Value | |
| } | |
| // fieldCoder returns pointer functions for a field, used for operating on | |
| // struct fields. | |
| func fieldCoder(fd protoreflect.FieldDescriptor, ft reflect.Type) (*MessageInfo, pointerCoderFuncs) { | |
| switch { | |
| case fd.IsMap(): | |
| return encoderFuncsForMap(fd, ft) | |
| case fd.Cardinality() == protoreflect.Repeated && !fd.IsPacked(): | |
| // Repeated fields (not packed). | |
| if ft.Kind() != reflect.Slice { | |
| break | |
| } | |
| ft := ft.Elem() | |
| switch fd.Kind() { | |
| case protoreflect.BoolKind: | |
| if ft.Kind() == reflect.Bool { | |
| return nil, coderBoolSlice | |
| } | |
| case protoreflect.EnumKind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderEnumSlice | |
| } | |
| case protoreflect.Int32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderInt32Slice | |
| } | |
| case protoreflect.Sint32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderSint32Slice | |
| } | |
| case protoreflect.Uint32Kind: | |
| if ft.Kind() == reflect.Uint32 { | |
| return nil, coderUint32Slice | |
| } | |
| case protoreflect.Int64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderInt64Slice | |
| } | |
| case protoreflect.Sint64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderSint64Slice | |
| } | |
| case protoreflect.Uint64Kind: | |
| if ft.Kind() == reflect.Uint64 { | |
| return nil, coderUint64Slice | |
| } | |
| case protoreflect.Sfixed32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderSfixed32Slice | |
| } | |
| case protoreflect.Fixed32Kind: | |
| if ft.Kind() == reflect.Uint32 { | |
| return nil, coderFixed32Slice | |
| } | |
| case protoreflect.FloatKind: | |
| if ft.Kind() == reflect.Float32 { | |
| return nil, coderFloatSlice | |
| } | |
| case protoreflect.Sfixed64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderSfixed64Slice | |
| } | |
| case protoreflect.Fixed64Kind: | |
| if ft.Kind() == reflect.Uint64 { | |
| return nil, coderFixed64Slice | |
| } | |
| case protoreflect.DoubleKind: | |
| if ft.Kind() == reflect.Float64 { | |
| return nil, coderDoubleSlice | |
| } | |
| case protoreflect.StringKind: | |
| if ft.Kind() == reflect.String && strs.EnforceUTF8(fd) { | |
| return nil, coderStringSliceValidateUTF8 | |
| } | |
| if ft.Kind() == reflect.String { | |
| return nil, coderStringSlice | |
| } | |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 && strs.EnforceUTF8(fd) { | |
| return nil, coderBytesSliceValidateUTF8 | |
| } | |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { | |
| return nil, coderBytesSlice | |
| } | |
| case protoreflect.BytesKind: | |
| if ft.Kind() == reflect.String { | |
| return nil, coderStringSlice | |
| } | |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { | |
| return nil, coderBytesSlice | |
| } | |
| case protoreflect.MessageKind: | |
| return getMessageInfo(ft), makeMessageSliceFieldCoder(fd, ft) | |
| case protoreflect.GroupKind: | |
| return getMessageInfo(ft), makeGroupSliceFieldCoder(fd, ft) | |
| } | |
| case fd.Cardinality() == protoreflect.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 protoreflect.BoolKind: | |
| if ft.Kind() == reflect.Bool { | |
| return nil, coderBoolPackedSlice | |
| } | |
| case protoreflect.EnumKind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderEnumPackedSlice | |
| } | |
| case protoreflect.Int32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderInt32PackedSlice | |
| } | |
| case protoreflect.Sint32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderSint32PackedSlice | |
| } | |
| case protoreflect.Uint32Kind: | |
| if ft.Kind() == reflect.Uint32 { | |
| return nil, coderUint32PackedSlice | |
| } | |
| case protoreflect.Int64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderInt64PackedSlice | |
| } | |
| case protoreflect.Sint64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderSint64PackedSlice | |
| } | |
| case protoreflect.Uint64Kind: | |
| if ft.Kind() == reflect.Uint64 { | |
| return nil, coderUint64PackedSlice | |
| } | |
| case protoreflect.Sfixed32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderSfixed32PackedSlice | |
| } | |
| case protoreflect.Fixed32Kind: | |
| if ft.Kind() == reflect.Uint32 { | |
| return nil, coderFixed32PackedSlice | |
| } | |
| case protoreflect.FloatKind: | |
| if ft.Kind() == reflect.Float32 { | |
| return nil, coderFloatPackedSlice | |
| } | |
| case protoreflect.Sfixed64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderSfixed64PackedSlice | |
| } | |
| case protoreflect.Fixed64Kind: | |
| if ft.Kind() == reflect.Uint64 { | |
| return nil, coderFixed64PackedSlice | |
| } | |
| case protoreflect.DoubleKind: | |
| if ft.Kind() == reflect.Float64 { | |
| return nil, coderDoublePackedSlice | |
| } | |
| } | |
| case fd.Kind() == protoreflect.MessageKind: | |
| return getMessageInfo(ft), makeMessageFieldCoder(fd, ft) | |
| case fd.Kind() == protoreflect.GroupKind: | |
| return getMessageInfo(ft), makeGroupFieldCoder(fd, ft) | |
| case !fd.HasPresence() && 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 protoreflect.BoolKind: | |
| if ft.Kind() == reflect.Bool { | |
| return nil, coderBoolNoZero | |
| } | |
| case protoreflect.EnumKind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderEnumNoZero | |
| } | |
| case protoreflect.Int32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderInt32NoZero | |
| } | |
| case protoreflect.Sint32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderSint32NoZero | |
| } | |
| case protoreflect.Uint32Kind: | |
| if ft.Kind() == reflect.Uint32 { | |
| return nil, coderUint32NoZero | |
| } | |
| case protoreflect.Int64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderInt64NoZero | |
| } | |
| case protoreflect.Sint64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderSint64NoZero | |
| } | |
| case protoreflect.Uint64Kind: | |
| if ft.Kind() == reflect.Uint64 { | |
| return nil, coderUint64NoZero | |
| } | |
| case protoreflect.Sfixed32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderSfixed32NoZero | |
| } | |
| case protoreflect.Fixed32Kind: | |
| if ft.Kind() == reflect.Uint32 { | |
| return nil, coderFixed32NoZero | |
| } | |
| case protoreflect.FloatKind: | |
| if ft.Kind() == reflect.Float32 { | |
| return nil, coderFloatNoZero | |
| } | |
| case protoreflect.Sfixed64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderSfixed64NoZero | |
| } | |
| case protoreflect.Fixed64Kind: | |
| if ft.Kind() == reflect.Uint64 { | |
| return nil, coderFixed64NoZero | |
| } | |
| case protoreflect.DoubleKind: | |
| if ft.Kind() == reflect.Float64 { | |
| return nil, coderDoubleNoZero | |
| } | |
| case protoreflect.StringKind: | |
| if ft.Kind() == reflect.String && strs.EnforceUTF8(fd) { | |
| return nil, coderStringNoZeroValidateUTF8 | |
| } | |
| if ft.Kind() == reflect.String { | |
| return nil, coderStringNoZero | |
| } | |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 && strs.EnforceUTF8(fd) { | |
| return nil, coderBytesNoZeroValidateUTF8 | |
| } | |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { | |
| return nil, coderBytesNoZero | |
| } | |
| case protoreflect.BytesKind: | |
| if ft.Kind() == reflect.String { | |
| return nil, coderStringNoZero | |
| } | |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { | |
| return nil, coderBytesNoZero | |
| } | |
| } | |
| case ft.Kind() == reflect.Ptr: | |
| ft := ft.Elem() | |
| switch fd.Kind() { | |
| case protoreflect.BoolKind: | |
| if ft.Kind() == reflect.Bool { | |
| return nil, coderBoolPtr | |
| } | |
| case protoreflect.EnumKind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderEnumPtr | |
| } | |
| case protoreflect.Int32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderInt32Ptr | |
| } | |
| case protoreflect.Sint32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderSint32Ptr | |
| } | |
| case protoreflect.Uint32Kind: | |
| if ft.Kind() == reflect.Uint32 { | |
| return nil, coderUint32Ptr | |
| } | |
| case protoreflect.Int64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderInt64Ptr | |
| } | |
| case protoreflect.Sint64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderSint64Ptr | |
| } | |
| case protoreflect.Uint64Kind: | |
| if ft.Kind() == reflect.Uint64 { | |
| return nil, coderUint64Ptr | |
| } | |
| case protoreflect.Sfixed32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderSfixed32Ptr | |
| } | |
| case protoreflect.Fixed32Kind: | |
| if ft.Kind() == reflect.Uint32 { | |
| return nil, coderFixed32Ptr | |
| } | |
| case protoreflect.FloatKind: | |
| if ft.Kind() == reflect.Float32 { | |
| return nil, coderFloatPtr | |
| } | |
| case protoreflect.Sfixed64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderSfixed64Ptr | |
| } | |
| case protoreflect.Fixed64Kind: | |
| if ft.Kind() == reflect.Uint64 { | |
| return nil, coderFixed64Ptr | |
| } | |
| case protoreflect.DoubleKind: | |
| if ft.Kind() == reflect.Float64 { | |
| return nil, coderDoublePtr | |
| } | |
| case protoreflect.StringKind: | |
| if ft.Kind() == reflect.String && strs.EnforceUTF8(fd) { | |
| return nil, coderStringPtrValidateUTF8 | |
| } | |
| if ft.Kind() == reflect.String { | |
| return nil, coderStringPtr | |
| } | |
| case protoreflect.BytesKind: | |
| if ft.Kind() == reflect.String { | |
| return nil, coderStringPtr | |
| } | |
| } | |
| default: | |
| switch fd.Kind() { | |
| case protoreflect.BoolKind: | |
| if ft.Kind() == reflect.Bool { | |
| return nil, coderBool | |
| } | |
| case protoreflect.EnumKind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderEnum | |
| } | |
| case protoreflect.Int32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderInt32 | |
| } | |
| case protoreflect.Sint32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderSint32 | |
| } | |
| case protoreflect.Uint32Kind: | |
| if ft.Kind() == reflect.Uint32 { | |
| return nil, coderUint32 | |
| } | |
| case protoreflect.Int64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderInt64 | |
| } | |
| case protoreflect.Sint64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderSint64 | |
| } | |
| case protoreflect.Uint64Kind: | |
| if ft.Kind() == reflect.Uint64 { | |
| return nil, coderUint64 | |
| } | |
| case protoreflect.Sfixed32Kind: | |
| if ft.Kind() == reflect.Int32 { | |
| return nil, coderSfixed32 | |
| } | |
| case protoreflect.Fixed32Kind: | |
| if ft.Kind() == reflect.Uint32 { | |
| return nil, coderFixed32 | |
| } | |
| case protoreflect.FloatKind: | |
| if ft.Kind() == reflect.Float32 { | |
| return nil, coderFloat | |
| } | |
| case protoreflect.Sfixed64Kind: | |
| if ft.Kind() == reflect.Int64 { | |
| return nil, coderSfixed64 | |
| } | |
| case protoreflect.Fixed64Kind: | |
| if ft.Kind() == reflect.Uint64 { | |
| return nil, coderFixed64 | |
| } | |
| case protoreflect.DoubleKind: | |
| if ft.Kind() == reflect.Float64 { | |
| return nil, coderDouble | |
| } | |
| case protoreflect.StringKind: | |
| if ft.Kind() == reflect.String && strs.EnforceUTF8(fd) { | |
| return nil, coderStringValidateUTF8 | |
| } | |
| if ft.Kind() == reflect.String { | |
| return nil, coderString | |
| } | |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 && strs.EnforceUTF8(fd) { | |
| return nil, coderBytesValidateUTF8 | |
| } | |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { | |
| return nil, coderBytes | |
| } | |
| case protoreflect.BytesKind: | |
| if ft.Kind() == reflect.String { | |
| return nil, coderString | |
| } | |
| if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 { | |
| return nil, 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 protoreflect.FieldDescriptor) valueCoderFuncs { | |
| switch { | |
| case fd.Cardinality() == protoreflect.Repeated && !fd.IsPacked(): | |
| switch fd.Kind() { | |
| case protoreflect.BoolKind: | |
| return coderBoolSliceValue | |
| case protoreflect.EnumKind: | |
| return coderEnumSliceValue | |
| case protoreflect.Int32Kind: | |
| return coderInt32SliceValue | |
| case protoreflect.Sint32Kind: | |
| return coderSint32SliceValue | |
| case protoreflect.Uint32Kind: | |
| return coderUint32SliceValue | |
| case protoreflect.Int64Kind: | |
| return coderInt64SliceValue | |
| case protoreflect.Sint64Kind: | |
| return coderSint64SliceValue | |
| case protoreflect.Uint64Kind: | |
| return coderUint64SliceValue | |
| case protoreflect.Sfixed32Kind: | |
| return coderSfixed32SliceValue | |
| case protoreflect.Fixed32Kind: | |
| return coderFixed32SliceValue | |
| case protoreflect.FloatKind: | |
| return coderFloatSliceValue | |
| case protoreflect.Sfixed64Kind: | |
| return coderSfixed64SliceValue | |
| case protoreflect.Fixed64Kind: | |
| return coderFixed64SliceValue | |
| case protoreflect.DoubleKind: | |
| return coderDoubleSliceValue | |
| case protoreflect.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 protoreflect.BytesKind: | |
| return coderBytesSliceValue | |
| case protoreflect.MessageKind: | |
| return coderMessageSliceValue | |
| case protoreflect.GroupKind: | |
| return coderGroupSliceValue | |
| } | |
| case fd.Cardinality() == protoreflect.Repeated && fd.IsPacked(): | |
| switch fd.Kind() { | |
| case protoreflect.BoolKind: | |
| return coderBoolPackedSliceValue | |
| case protoreflect.EnumKind: | |
| return coderEnumPackedSliceValue | |
| case protoreflect.Int32Kind: | |
| return coderInt32PackedSliceValue | |
| case protoreflect.Sint32Kind: | |
| return coderSint32PackedSliceValue | |
| case protoreflect.Uint32Kind: | |
| return coderUint32PackedSliceValue | |
| case protoreflect.Int64Kind: | |
| return coderInt64PackedSliceValue | |
| case protoreflect.Sint64Kind: | |
| return coderSint64PackedSliceValue | |
| case protoreflect.Uint64Kind: | |
| return coderUint64PackedSliceValue | |
| case protoreflect.Sfixed32Kind: | |
| return coderSfixed32PackedSliceValue | |
| case protoreflect.Fixed32Kind: | |
| return coderFixed32PackedSliceValue | |
| case protoreflect.FloatKind: | |
| return coderFloatPackedSliceValue | |
| case protoreflect.Sfixed64Kind: | |
| return coderSfixed64PackedSliceValue | |
| case protoreflect.Fixed64Kind: | |
| return coderFixed64PackedSliceValue | |
| case protoreflect.DoubleKind: | |
| return coderDoublePackedSliceValue | |
| } | |
| default: | |
| switch fd.Kind() { | |
| default: | |
| case protoreflect.BoolKind: | |
| return coderBoolValue | |
| case protoreflect.EnumKind: | |
| return coderEnumValue | |
| case protoreflect.Int32Kind: | |
| return coderInt32Value | |
| case protoreflect.Sint32Kind: | |
| return coderSint32Value | |
| case protoreflect.Uint32Kind: | |
| return coderUint32Value | |
| case protoreflect.Int64Kind: | |
| return coderInt64Value | |
| case protoreflect.Sint64Kind: | |
| return coderSint64Value | |
| case protoreflect.Uint64Kind: | |
| return coderUint64Value | |
| case protoreflect.Sfixed32Kind: | |
| return coderSfixed32Value | |
| case protoreflect.Fixed32Kind: | |
| return coderFixed32Value | |
| case protoreflect.FloatKind: | |
| return coderFloatValue | |
| case protoreflect.Sfixed64Kind: | |
| return coderSfixed64Value | |
| case protoreflect.Fixed64Kind: | |
| return coderFixed64Value | |
| case protoreflect.DoubleKind: | |
| return coderDoubleValue | |
| case protoreflect.StringKind: | |
| if strs.EnforceUTF8(fd) { | |
| return coderStringValueValidateUTF8 | |
| } | |
| return coderStringValue | |
| case protoreflect.BytesKind: | |
| return coderBytesValue | |
| case protoreflect.MessageKind: | |
| return coderMessageValue | |
| case protoreflect.GroupKind: | |
| return coderGroupValue | |
| } | |
| } | |
| panic(fmt.Sprintf("invalid field: no encoder for %v %v %v", fd.FullName(), fd.Cardinality(), fd.Kind())) | |
| } |