package protojson
import (
)
const defaultIndent = " "
func ( proto.Message) string {
return MarshalOptions{Multiline: true}.Format()
}
func ( proto.Message) ([]byte, error) {
return MarshalOptions{}.Marshal()
}
type MarshalOptions struct {
pragma.NoUnkeyedLiterals
Multiline bool
Indent string
AllowPartial bool
UseProtoNames bool
UseEnumNumbers bool
EmitUnpopulated bool
Resolver interface {
protoregistry.ExtensionTypeResolver
protoregistry.MessageTypeResolver
}
}
func ( MarshalOptions) ( proto.Message) string {
if == nil || !.ProtoReflect().IsValid() {
return "<nil>"
}
.AllowPartial = true
, := .Marshal()
return string()
}
func ( MarshalOptions) ( proto.Message) ([]byte, error) {
return .marshal()
}
func ( MarshalOptions) ( proto.Message) ([]byte, error) {
if .Multiline && .Indent == "" {
.Indent = defaultIndent
}
if .Resolver == nil {
.Resolver = protoregistry.GlobalTypes
}
, := json.NewEncoder(.Indent)
if != nil {
return nil,
}
if == nil {
return []byte("{}"), nil
}
:= encoder{, }
if := .marshalMessage(.ProtoReflect(), ""); != nil {
return nil,
}
if .AllowPartial {
return .Bytes(), nil
}
return .Bytes(), proto.CheckInitialized()
}
type encoder struct {
*json.Encoder
opts MarshalOptions
}
var typeFieldDesc = func() protoreflect.FieldDescriptor {
var filedesc.Field
.L0.FullName = "@type"
.L0.Index = -1
.L1.Cardinality = protoreflect.Optional
.L1.Kind = protoreflect.StringKind
return &
}()
type typeURLFieldRanger struct {
order.FieldRanger
typeURL string
}
func ( typeURLFieldRanger) ( func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
if !(typeFieldDesc, protoreflect.ValueOfString(.typeURL)) {
return
}
.FieldRanger.Range()
}
type unpopulatedFieldRanger struct{ protoreflect.Message }
func ( unpopulatedFieldRanger) ( func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
:= .Descriptor().Fields()
for := 0; < .Len(); ++ {
:= .Get()
if .Has() || .ContainingOneof() != nil {
continue
}
:= .Get()
:= .Syntax() == protoreflect.Proto2 && .Default().IsValid()
:= .Cardinality() != protoreflect.Repeated && .Message() != nil
if || {
= protoreflect.Value{}
}
if !(, ) {
return
}
}
.Message.Range()
}
func ( encoder) ( protoreflect.Message, string) error {
if !flags.ProtoLegacy && messageset.IsMessageSet(.Descriptor()) {
return errors.New("no support for proto1 MessageSets")
}
if := wellKnownTypeMarshaler(.Descriptor().FullName()); != nil {
return (, )
}
.StartObject()
defer .EndObject()
var order.FieldRanger =
if .opts.EmitUnpopulated {
= unpopulatedFieldRanger{}
}
if != "" {
= typeURLFieldRanger{, }
}
var error
order.RangeFields(, order.IndexNameFieldOrder, func( protoreflect.FieldDescriptor, protoreflect.Value) bool {
:= .JSONName()
if .opts.UseProtoNames {
= .TextName()
}
if = .WriteName(); != nil {
return false
}
if = .marshalValue(, ); != nil {
return false
}
return true
})
return
}
func ( encoder) ( protoreflect.Value, protoreflect.FieldDescriptor) error {
switch {
case .IsList():
return .marshalList(.List(), )
case .IsMap():
return .marshalMap(.Map(), )
default:
return .marshalSingular(, )
}
}
func ( encoder) ( protoreflect.Value, protoreflect.FieldDescriptor) error {
if !.IsValid() {
.WriteNull()
return nil
}
switch := .Kind(); {
case protoreflect.BoolKind:
.WriteBool(.Bool())
case protoreflect.StringKind:
if .WriteString(.String()) != nil {
return errors.InvalidUTF8(string(.FullName()))
}
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
.WriteInt(.Int())
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
.WriteUint(.Uint())
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind,
protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind:
.WriteString(.String())
case protoreflect.FloatKind:
.WriteFloat(.Float(), 32)
case protoreflect.DoubleKind:
.WriteFloat(.Float(), 64)
case protoreflect.BytesKind:
.WriteString(base64.StdEncoding.EncodeToString(.Bytes()))
case protoreflect.EnumKind:
if .Enum().FullName() == genid.NullValue_enum_fullname {
.WriteNull()
} else {
:= .Enum().Values().ByNumber(.Enum())
if .opts.UseEnumNumbers || == nil {
.WriteInt(int64(.Enum()))
} else {
.WriteString(string(.Name()))
}
}
case protoreflect.MessageKind, protoreflect.GroupKind:
if := .marshalMessage(.Message(), ""); != nil {
return
}
default:
panic(fmt.Sprintf("%v has unknown kind: %v", .FullName(), ))
}
return nil
}
func ( encoder) ( protoreflect.List, protoreflect.FieldDescriptor) error {
.StartArray()
defer .EndArray()
for := 0; < .Len(); ++ {
:= .Get()
if := .marshalSingular(, ); != nil {
return
}
}
return nil
}
func ( encoder) ( protoreflect.Map, protoreflect.FieldDescriptor) error {
.StartObject()
defer .EndObject()
var error
order.RangeEntries(, order.GenericKeyOrder, func( protoreflect.MapKey, protoreflect.Value) bool {
if = .WriteName(.String()); != nil {
return false
}
if = .marshalSingular(, .MapValue()); != nil {
return false
}
return true
})
return
}