package proto
import (
)
const wrapTextMarshalV2 = false
type TextMarshaler struct {
Compact bool
ExpandAny bool
}
func ( *TextMarshaler) ( io.Writer, Message) error {
, := .marshal()
if len() > 0 {
if , := .Write(); != nil {
return
}
}
return
}
func ( *TextMarshaler) ( Message) string {
, := .marshal()
return string()
}
func ( *TextMarshaler) ( Message) ([]byte, error) {
:= MessageReflect()
if == nil || !.IsValid() {
return []byte("<nil>"), nil
}
if wrapTextMarshalV2 {
if , := .(encoding.TextMarshaler); {
return .MarshalText()
}
:= prototext.MarshalOptions{
AllowPartial: true,
EmitUnknown: true,
}
if !.Compact {
.Indent = " "
}
if !.ExpandAny {
.Resolver = (*protoregistry.Types)(nil)
}
return .Marshal(.Interface())
} else {
:= &textWriter{
compact: .Compact,
expandAny: .ExpandAny,
complete: true,
}
if , := .(encoding.TextMarshaler); {
, := .MarshalText()
if != nil {
return nil,
}
.Write()
return .buf, nil
}
:= .writeMessage()
return .buf,
}
}
var (
defaultTextMarshaler = TextMarshaler{}
compactTextMarshaler = TextMarshaler{Compact: true}
)
func ( io.Writer, Message) error { return defaultTextMarshaler.Marshal(, ) }
func ( Message) string { return defaultTextMarshaler.Text() }
func ( io.Writer, Message) error { return compactTextMarshaler.Marshal(, ) }
func ( Message) string { return compactTextMarshaler.Text() }
var (
newline = []byte("\n")
endBraceNewline = []byte("}\n")
posInf = []byte("inf")
negInf = []byte("-inf")
nan = []byte("nan")
)
type textWriter struct {
compact bool
expandAny bool
complete bool
indent int
buf []byte
}
func ( *textWriter) ( []byte) ( int, error) {
:= bytes.Count(, newline)
if == 0 {
if !.compact && .complete {
.writeIndent()
}
.buf = append(.buf, ...)
.complete = false
return len(), nil
}
:= bytes.SplitN(, newline, +1)
if .compact {
for , := range {
if > 0 {
.buf = append(.buf, ' ')
++
}
.buf = append(.buf, ...)
+= len()
}
return , nil
}
for , := range {
if .complete {
.writeIndent()
}
.buf = append(.buf, ...)
+= len()
if +1 < len() {
.buf = append(.buf, '\n')
++
}
}
.complete = len([len()-1]) == 0
return , nil
}
func ( *textWriter) ( byte) error {
if .compact && == '\n' {
= ' '
}
if !.compact && .complete {
.writeIndent()
}
.buf = append(.buf, )
.complete = == '\n'
return nil
}
func ( *textWriter) ( protoreflect.FieldDescriptor) {
if !.compact && .complete {
.writeIndent()
}
.complete = false
if .Kind() != protoreflect.GroupKind {
.buf = append(.buf, .Name()...)
.WriteByte(':')
} else {
.buf = append(.buf, .Message().Name()...)
}
if !.compact {
.WriteByte(' ')
}
}
func ( string) bool {
for , := range {
switch {
case == '.' || == '/' || == '_':
continue
case '0' <= && <= '9':
continue
case 'A' <= && <= 'Z':
continue
case 'a' <= && <= 'z':
continue
default:
return true
}
}
return false
}
func ( *textWriter) ( protoreflect.Message) (bool, error) {
:= .Descriptor()
:= .Fields().ByName("type_url")
:= .Fields().ByName("value")
:= .Get().String()
, := protoregistry.GlobalTypes.FindMessageByURL()
if != nil {
return false, nil
}
:= .Get().Bytes()
:= .New()
if := proto.Unmarshal(, .Interface()); != nil {
return false, nil
}
.Write([]byte("["))
if requiresQuotes() {
.writeQuotedString()
} else {
.Write([]byte())
}
if .compact {
.Write([]byte("]:<"))
} else {
.Write([]byte("]: <\n"))
.indent++
}
if := .writeMessage(); != nil {
return true,
}
if .compact {
.Write([]byte("> "))
} else {
.indent--
.Write([]byte(">\n"))
}
return true, nil
}
func ( *textWriter) ( protoreflect.Message) error {
:= .Descriptor()
if .expandAny && .FullName() == "google.protobuf.Any" {
if , := .writeProto3Any(); {
return
}
}
:= .Fields()
for := 0; < .Len(); {
:= .Get()
if := .ContainingOneof(); != nil {
= .WhichOneof()
+= .Fields().Len()
} else {
++
}
if == nil || !.Has() {
continue
}
switch {
case .IsList():
:= .Get().List()
for := 0; < .Len(); ++ {
.writeName()
:= .Get()
if := .writeSingularValue(, ); != nil {
return
}
.WriteByte('\n')
}
case .IsMap():
:= .MapKey()
:= .MapValue()
:= .Get().Map()
type struct{ , protoreflect.Value }
var []
.Range(func( protoreflect.MapKey, protoreflect.Value) bool {
= append(, {.Value(), })
return true
})
sort.Slice(, func(, int) bool {
switch .Kind() {
case protoreflect.BoolKind:
return ![]..Bool() && []..Bool()
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
return []..Int() < []..Int()
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
return []..Uint() < []..Uint()
case protoreflect.StringKind:
return []..String() < []..String()
default:
panic("invalid kind")
}
})
for , := range {
.writeName()
.WriteByte('<')
if !.compact {
.WriteByte('\n')
}
.indent++
.writeName()
if := .writeSingularValue(., ); != nil {
return
}
.WriteByte('\n')
.writeName()
if := .writeSingularValue(., ); != nil {
return
}
.WriteByte('\n')
.indent--
.WriteByte('>')
.WriteByte('\n')
}
default:
.writeName()
if := .writeSingularValue(.Get(), ); != nil {
return
}
.WriteByte('\n')
}
}
if := .GetUnknown(); len() > 0 {
.writeUnknownFields()
}
return .writeExtensions()
}
func ( *textWriter) ( protoreflect.Value, protoreflect.FieldDescriptor) error {
switch .Kind() {
case protoreflect.FloatKind, protoreflect.DoubleKind:
switch := .Float(); {
case math.IsInf(, +1):
.Write(posInf)
case math.IsInf(, -1):
.Write(negInf)
case math.IsNaN():
.Write(nan)
default:
fmt.Fprint(, .Interface())
}
case protoreflect.StringKind:
.writeQuotedString(string(.String()))
case protoreflect.BytesKind:
.writeQuotedString(string(.Bytes()))
case protoreflect.MessageKind, protoreflect.GroupKind:
var , byte = '<', '>'
if .Kind() == protoreflect.GroupKind {
, = '{', '}'
}
.WriteByte()
if !.compact {
.WriteByte('\n')
}
.indent++
:= .Message()
if , := .Interface().(encoding.TextMarshaler); {
, := .MarshalText()
if != nil {
return
}
.Write()
} else {
.writeMessage()
}
.indent--
.WriteByte()
case protoreflect.EnumKind:
if := .Enum().Values().ByNumber(.Enum()); != nil {
fmt.Fprint(, .Name())
} else {
fmt.Fprint(, .Enum())
}
default:
fmt.Fprint(, .Interface())
}
return nil
}
func ( *textWriter) ( string) {
.WriteByte('"')
for := 0; < len(); ++ {
switch := []; {
case '\n':
.buf = append(.buf, `\n`...)
case '\r':
.buf = append(.buf, `\r`...)
case '\t':
.buf = append(.buf, `\t`...)
case '"':
.buf = append(.buf, `\"`...)
case '\\':
.buf = append(.buf, `\\`...)
default:
if := >= 0x20 && < 0x7f; {
.buf = append(.buf, )
} else {
.buf = append(.buf, fmt.Sprintf(`\%03o`, )...)
}
}
}
.WriteByte('"')
}
func ( *textWriter) ( []byte) {
if !.compact {
fmt.Fprintf(, "/* %d unknown bytes */\n", len())
}
for len() > 0 {
, , := protowire.ConsumeTag()
if < 0 {
return
}
= [:]
if == protowire.EndGroupType {
.indent--
.Write(endBraceNewline)
continue
}
fmt.Fprint(, )
if != protowire.StartGroupType {
.WriteByte(':')
}
if !.compact || == protowire.StartGroupType {
.WriteByte(' ')
}
switch {
case protowire.VarintType:
, := protowire.ConsumeVarint()
if < 0 {
return
}
= [:]
fmt.Fprint(, )
case protowire.Fixed32Type:
, := protowire.ConsumeFixed32()
if < 0 {
return
}
= [:]
fmt.Fprint(, )
case protowire.Fixed64Type:
, := protowire.ConsumeFixed64()
if < 0 {
return
}
= [:]
fmt.Fprint(, )
case protowire.BytesType:
, := protowire.ConsumeBytes()
if < 0 {
return
}
= [:]
fmt.Fprintf(, "%q", )
case protowire.StartGroupType:
.WriteByte('{')
.indent++
default:
fmt.Fprintf(, "/* unknown wire type %d */", )
}
.WriteByte('\n')
}
}
func ( *textWriter) ( protoreflect.Message) error {
:= .Descriptor()
if .ExtensionRanges().Len() == 0 {
return nil
}
type struct {
protoreflect.FieldDescriptor
protoreflect.Value
}
var []
.Range(func( protoreflect.FieldDescriptor, protoreflect.Value) bool {
if .IsExtension() {
= append(, {, })
}
return true
})
sort.Slice(, func(, int) bool {
return []..Number() < []..Number()
})
for , := range {
:= string(..FullName())
if isMessageSet(..ContainingMessage()) {
= strings.TrimSuffix(, ".message_set_extension")
}
if !..IsList() {
if := .writeSingularExtension(, ., .); != nil {
return
}
} else {
:= ..List()
for := 0; < .Len(); ++ {
if := .writeSingularExtension(, .Get(), .); != nil {
return
}
}
}
}
return nil
}
func ( *textWriter) ( string, protoreflect.Value, protoreflect.FieldDescriptor) error {
fmt.Fprintf(, "[%s]:", )
if !.compact {
.WriteByte(' ')
}
if := .writeSingularValue(, ); != nil {
return
}
.WriteByte('\n')
return nil
}
func ( *textWriter) () {
if !.complete {
return
}
for := 0; < .indent*2; ++ {
.buf = append(.buf, ' ')
}
.complete = false
}