package prototext
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
EmitASCII bool
allowInvalidUTF8 bool
AllowPartial bool
EmitUnknown bool
Resolver interface {
protoregistry.ExtensionTypeResolver
protoregistry.MessageTypeResolver
}
}
func ( MarshalOptions) ( proto.Message) string {
if == nil || !.ProtoReflect().IsValid() {
return "<nil>"
}
.allowInvalidUTF8 = true
.AllowPartial = true
.EmitUnknown = true
, := .Marshal()
return string()
}
func ( MarshalOptions) ( proto.Message) ([]byte, error) {
return .marshal()
}
func ( MarshalOptions) ( proto.Message) ([]byte, error) {
var = [2]byte{'{', '}'}
if .Multiline && .Indent == "" {
.Indent = defaultIndent
}
if .Resolver == nil {
.Resolver = protoregistry.GlobalTypes
}
, := text.NewEncoder(.Indent, , .EmitASCII)
if != nil {
return nil,
}
if == nil {
return []byte{}, nil
}
:= encoder{, }
= .marshalMessage(.ProtoReflect(), false)
if != nil {
return nil,
}
:= .Bytes()
if len(.Indent) > 0 && len() > 0 {
= append(, '\n')
}
if .AllowPartial {
return , nil
}
return , proto.CheckInitialized()
}
type encoder struct {
*text.Encoder
opts MarshalOptions
}
func ( encoder) ( protoreflect.Message, bool) error {
:= .Descriptor()
if !flags.ProtoLegacy && messageset.IsMessageSet() {
return errors.New("no support for proto1 MessageSets")
}
if {
.StartMessage()
defer .EndMessage()
}
if .FullName() == genid.Any_message_fullname {
if .marshalAny() {
return nil
}
}
var error
order.RangeFields(, order.IndexNameFieldOrder, func( protoreflect.FieldDescriptor, protoreflect.Value) bool {
if = .marshalField(.TextName(), , ); != nil {
return false
}
return true
})
if != nil {
return
}
if .opts.EmitUnknown {
.marshalUnknown(.GetUnknown())
}
return nil
}
func ( encoder) ( string, protoreflect.Value, protoreflect.FieldDescriptor) error {
switch {
case .IsList():
return .marshalList(, .List(), )
case .IsMap():
return .marshalMap(, .Map(), )
default:
.WriteName()
return .marshalSingular(, )
}
}
func ( encoder) ( protoreflect.Value, protoreflect.FieldDescriptor) error {
:= .Kind()
switch {
case protoreflect.BoolKind:
.WriteBool(.Bool())
case protoreflect.StringKind:
:= .String()
if !.opts.allowInvalidUTF8 && strs.EnforceUTF8() && !utf8.ValidString() {
return errors.InvalidUTF8(string(.FullName()))
}
.WriteString()
case protoreflect.Int32Kind, protoreflect.Int64Kind,
protoreflect.Sint32Kind, protoreflect.Sint64Kind,
protoreflect.Sfixed32Kind, protoreflect.Sfixed64Kind:
.WriteInt(.Int())
case protoreflect.Uint32Kind, protoreflect.Uint64Kind,
protoreflect.Fixed32Kind, protoreflect.Fixed64Kind:
.WriteUint(.Uint())
case protoreflect.FloatKind:
.WriteFloat(.Float(), 32)
case protoreflect.DoubleKind:
.WriteFloat(.Float(), 64)
case protoreflect.BytesKind:
.WriteString(string(.Bytes()))
case protoreflect.EnumKind:
:= .Enum()
if := .Enum().Values().ByNumber(); != nil {
.WriteLiteral(string(.Name()))
} else {
.WriteInt(int64())
}
case protoreflect.MessageKind, protoreflect.GroupKind:
return .marshalMessage(.Message(), true)
default:
panic(fmt.Sprintf("%v has unknown kind: %v", .FullName(), ))
}
return nil
}
func ( encoder) ( string, protoreflect.List, protoreflect.FieldDescriptor) error {
:= .Len()
for := 0; < ; ++ {
.WriteName()
if := .marshalSingular(.Get(), ); != nil {
return
}
}
return nil
}
func ( encoder) ( string, protoreflect.Map, protoreflect.FieldDescriptor) error {
var error
order.RangeEntries(, order.GenericKeyOrder, func( protoreflect.MapKey, protoreflect.Value) bool {
.WriteName()
.StartMessage()
defer .EndMessage()
.WriteName(string(genid.MapEntry_Key_field_name))
= .marshalSingular(.Value(), .MapKey())
if != nil {
return false
}
.WriteName(string(genid.MapEntry_Value_field_name))
= .marshalSingular(, .MapValue())
if != nil {
return false
}
return true
})
return
}
func ( encoder) ( []byte) {
const = 10
const = 16
for len() > 0 {
, , := protowire.ConsumeTag()
= [:]
.WriteName(strconv.FormatInt(int64(), ))
switch {
case protowire.VarintType:
var uint64
, = protowire.ConsumeVarint()
.WriteUint()
case protowire.Fixed32Type:
var uint32
, = protowire.ConsumeFixed32()
.WriteLiteral("0x" + strconv.FormatUint(uint64(), ))
case protowire.Fixed64Type:
var uint64
, = protowire.ConsumeFixed64()
.WriteLiteral("0x" + strconv.FormatUint(, ))
case protowire.BytesType:
var []byte
, = protowire.ConsumeBytes()
.WriteString(string())
case protowire.StartGroupType:
.StartMessage()
var []byte
, = protowire.ConsumeGroup(, )
.()
.EndMessage()
default:
panic(fmt.Sprintf("prototext: error parsing unknown field wire type: %v", ))
}
= [:]
}
}
func ( encoder) ( protoreflect.Message) bool {
:= .Descriptor().Fields()
:= .ByNumber(genid.Any_TypeUrl_field_number)
:= .Get().String()
, := .opts.Resolver.FindMessageByURL()
if != nil {
return false
}
:= .New().Interface()
:= .ByNumber(genid.Any_Value_field_number)
:= .Get()
= proto.UnmarshalOptions{
AllowPartial: true,
Resolver: .opts.Resolver,
}.Unmarshal(.Bytes(), )
if != nil {
return false
}
:= .Snapshot()
.WriteName("[" + + "]")
= .marshalMessage(.ProtoReflect(), true)
if != nil {
.Reset()
return false
}
return true
}