diff --git a/tx/textual/internal/testdata/message.json b/tx/textual/internal/testdata/message.json new file mode 100644 index 00000000000..0904e2510d9 --- /dev/null +++ b/tx/textual/internal/testdata/message.json @@ -0,0 +1,139 @@ +[ + { + "proto": {}, + "screens": [ + {"text": "Foo object"} + ] + }, + { + "proto": { + "full_name": "nonempty" + }, + "screens": [ + {"text": "Foo object"}, + {"text": "Full name: nonempty", "indent": 1} + ] + }, + { + "proto": { + "full_name": "thing one", + "nickname": ":thing two" + }, + "screens": [ + {"text": "Foo object"}, + {"text": "Full name: thing one", "indent": 1}, + {"text": "Nickname: :thing two", "indent": 1} + ] + }, + { + "proto": { + "full_name": "special child message", + "mtime": { + "seconds": 1136214245 + } + }, + "screens": [ + {"text": "Foo object"}, + {"text": "Full name: special child message", "indent": 1}, + {"text": "Mtime: 2006-01-02T15:04:05Z", "indent": 1} + ] + }, + { + "proto": { + "nickname": "empty child", + "left": {} + }, + "screens": [ + {"text": "Foo object"}, + {"text": "Nickname: empty child", "indent": 1}, + {"text": "Left: Foo object", "indent": 1} + ] + }, + { + "proto": { + "nickname": "empty children", + "left": {}, + "right": {}, + "bar": {} + }, + "screens": [ + {"text": "Foo object"}, + {"text": "Nickname: empty children", "indent": 1}, + {"text": "Left: Foo object", "indent": 1}, + {"text": "Right: Foo object", "indent": 1}, + {"text": "Bar: Bar object", "indent": 1} + ] + }, + { + "proto": { + "full_name": "subfield", + "left": {}, + "right": { + "nickname": "junior" + }, + "bar": {} + }, + "screens": [ + {"text": "Foo object"}, + {"text": "Full name: subfield", "indent": 1}, + {"text": "Left: Foo object", "indent": 1}, + {"text": "Right: Foo object", "indent": 1}, + {"text": "Nickname: junior", "indent": 2}, + {"text": "Bar: Bar object", "indent": 1} + ] + }, + { + "proto": { + "full_name": "deep", + "left": { + "left": {"nickname": "LL"}, + "right": {"nickname": "LR"} + }, + "right": { + "left": {"nickname": "RL"}, + "right": {"nickname": "RR"} + } + }, + "screens": [ + {"text": "Foo object"}, + {"text": "Full name: deep", "indent": 1}, + {"text": "Left: Foo object", "indent": 1}, + {"text": "Left: Foo object", "indent": 2}, + {"text": "Nickname: LL", "indent": 3}, + {"text": "Right: Foo object", "indent": 2}, + {"text": "Nickname: LR", "indent": 3}, + {"text": "Right: Foo object", "indent": 1}, + {"text": "Left: Foo object", "indent": 2}, + {"text": "Nickname: RL", "indent": 3}, + {"text": "Right: Foo object", "indent": 2}, + {"text": "Nickname: RR", "indent": 3} + ] + }, + { + "proto": { + "full_name": " the kitchen sink ", + "mtime": {}, + "left": {}, + "right": { + "nickname": "blub", + "right": {}, + "bar": { + "bar_id": "quux", + "data": [255, 254] + } + } + }, + "screens": [ + {"text": "Foo object"}, + {"text": "Full name: the kitchen sink ", "indent": 1}, + {"text": "Mtime: 1970-01-01T00:00:00Z", "indent": 1}, + {"text": "Left: Foo object", "indent": 1}, + {"text": "Right: Foo object", "indent": 1}, + {"text": "Nickname: blub", "indent": 2}, + {"text": "Right: Foo object", "indent": 2}, + {"text": "Bar: Bar object", "indent": 2}, + {"text": "Bar id: quux", "indent": 3}, + {"text": "Data: FFFE", "indent": 3} + ] + } +] diff --git a/tx/textual/internal/testdata/string.json b/tx/textual/internal/testdata/string.json new file mode 100644 index 00000000000..e37010c3d14 --- /dev/null +++ b/tx/textual/internal/testdata/string.json @@ -0,0 +1,11 @@ +[ + {"text": ""}, + {"text": "x"}, + {"text": "foo"}, + {"text": "\"able"}, + {"text": "unresolved\nambiguities\r\ncost\rbillions"}, + {"text": "stealth whitespace is significant "}, + {"text": "stealth whitespace snailed for your protection @@"}, + {"text": "co\u00F6peration"}, + {"text": "JSON limits unicode to 16 bits, surrogates must be transmitted as-is \uD852\uDF62"} +] diff --git a/tx/textual/internal/testpb/1.proto b/tx/textual/internal/testpb/1.proto index 6bf8012e664..b242f910832 100644 --- a/tx/textual/internal/testpb/1.proto +++ b/tx/textual/internal/testpb/1.proto @@ -39,3 +39,19 @@ message A { double DOUBLE = 110; map MAP = 111; } + +// Foo is a sample message type used for testing message rendering. +message Foo { + string full_name = 1; + string nickname = 2; + google.protobuf.Timestamp mtime = 3; + Foo left = 4; + Foo right = 5; + Bar bar = 8; // skip some field numbers +} + +// Bar is a sample message type used for testing message rendering. +message Bar { + string bar_id = 1; + bytes data = 2; +} diff --git a/tx/textual/internal/testpb/1.pulsar.go b/tx/textual/internal/testpb/1.pulsar.go index 547875c5f49..988d98575a5 100644 --- a/tx/textual/internal/testpb/1.pulsar.go +++ b/tx/textual/internal/testpb/1.pulsar.go @@ -1823,6 +1823,1292 @@ func (x *fastReflection_A) ProtoMethods() *protoiface.Methods { } } +var ( + md_Foo protoreflect.MessageDescriptor + fd_Foo_full_name protoreflect.FieldDescriptor + fd_Foo_nickname protoreflect.FieldDescriptor + fd_Foo_mtime protoreflect.FieldDescriptor + fd_Foo_left protoreflect.FieldDescriptor + fd_Foo_right protoreflect.FieldDescriptor + fd_Foo_bar protoreflect.FieldDescriptor +) + +func init() { + file__1_proto_init() + md_Foo = File__1_proto.Messages().ByName("Foo") + fd_Foo_full_name = md_Foo.Fields().ByName("full_name") + fd_Foo_nickname = md_Foo.Fields().ByName("nickname") + fd_Foo_mtime = md_Foo.Fields().ByName("mtime") + fd_Foo_left = md_Foo.Fields().ByName("left") + fd_Foo_right = md_Foo.Fields().ByName("right") + fd_Foo_bar = md_Foo.Fields().ByName("bar") +} + +var _ protoreflect.Message = (*fastReflection_Foo)(nil) + +type fastReflection_Foo Foo + +func (x *Foo) ProtoReflect() protoreflect.Message { + return (*fastReflection_Foo)(x) +} + +func (x *Foo) slowProtoReflect() protoreflect.Message { + mi := &file__1_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_Foo_messageType fastReflection_Foo_messageType +var _ protoreflect.MessageType = fastReflection_Foo_messageType{} + +type fastReflection_Foo_messageType struct{} + +func (x fastReflection_Foo_messageType) Zero() protoreflect.Message { + return (*fastReflection_Foo)(nil) +} +func (x fastReflection_Foo_messageType) New() protoreflect.Message { + return new(fastReflection_Foo) +} +func (x fastReflection_Foo_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_Foo +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_Foo) Descriptor() protoreflect.MessageDescriptor { + return md_Foo +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_Foo) Type() protoreflect.MessageType { + return _fastReflection_Foo_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_Foo) New() protoreflect.Message { + return new(fastReflection_Foo) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_Foo) Interface() protoreflect.ProtoMessage { + return (*Foo)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_Foo) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.FullName != "" { + value := protoreflect.ValueOfString(x.FullName) + if !f(fd_Foo_full_name, value) { + return + } + } + if x.Nickname != "" { + value := protoreflect.ValueOfString(x.Nickname) + if !f(fd_Foo_nickname, value) { + return + } + } + if x.Mtime != nil { + value := protoreflect.ValueOfMessage(x.Mtime.ProtoReflect()) + if !f(fd_Foo_mtime, value) { + return + } + } + if x.Left != nil { + value := protoreflect.ValueOfMessage(x.Left.ProtoReflect()) + if !f(fd_Foo_left, value) { + return + } + } + if x.Right != nil { + value := protoreflect.ValueOfMessage(x.Right.ProtoReflect()) + if !f(fd_Foo_right, value) { + return + } + } + if x.Bar != nil { + value := protoreflect.ValueOfMessage(x.Bar.ProtoReflect()) + if !f(fd_Foo_bar, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_Foo) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "Foo.full_name": + return x.FullName != "" + case "Foo.nickname": + return x.Nickname != "" + case "Foo.mtime": + return x.Mtime != nil + case "Foo.left": + return x.Left != nil + case "Foo.right": + return x.Right != nil + case "Foo.bar": + return x.Bar != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: Foo")) + } + panic(fmt.Errorf("message Foo does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Foo) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "Foo.full_name": + x.FullName = "" + case "Foo.nickname": + x.Nickname = "" + case "Foo.mtime": + x.Mtime = nil + case "Foo.left": + x.Left = nil + case "Foo.right": + x.Right = nil + case "Foo.bar": + x.Bar = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: Foo")) + } + panic(fmt.Errorf("message Foo does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_Foo) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "Foo.full_name": + value := x.FullName + return protoreflect.ValueOfString(value) + case "Foo.nickname": + value := x.Nickname + return protoreflect.ValueOfString(value) + case "Foo.mtime": + value := x.Mtime + return protoreflect.ValueOfMessage(value.ProtoReflect()) + case "Foo.left": + value := x.Left + return protoreflect.ValueOfMessage(value.ProtoReflect()) + case "Foo.right": + value := x.Right + return protoreflect.ValueOfMessage(value.ProtoReflect()) + case "Foo.bar": + value := x.Bar + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: Foo")) + } + panic(fmt.Errorf("message Foo does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Foo) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "Foo.full_name": + x.FullName = value.Interface().(string) + case "Foo.nickname": + x.Nickname = value.Interface().(string) + case "Foo.mtime": + x.Mtime = value.Message().Interface().(*timestamppb.Timestamp) + case "Foo.left": + x.Left = value.Message().Interface().(*Foo) + case "Foo.right": + x.Right = value.Message().Interface().(*Foo) + case "Foo.bar": + x.Bar = value.Message().Interface().(*Bar) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: Foo")) + } + panic(fmt.Errorf("message Foo does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Foo) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "Foo.mtime": + if x.Mtime == nil { + x.Mtime = new(timestamppb.Timestamp) + } + return protoreflect.ValueOfMessage(x.Mtime.ProtoReflect()) + case "Foo.left": + if x.Left == nil { + x.Left = new(Foo) + } + return protoreflect.ValueOfMessage(x.Left.ProtoReflect()) + case "Foo.right": + if x.Right == nil { + x.Right = new(Foo) + } + return protoreflect.ValueOfMessage(x.Right.ProtoReflect()) + case "Foo.bar": + if x.Bar == nil { + x.Bar = new(Bar) + } + return protoreflect.ValueOfMessage(x.Bar.ProtoReflect()) + case "Foo.full_name": + panic(fmt.Errorf("field full_name of message Foo is not mutable")) + case "Foo.nickname": + panic(fmt.Errorf("field nickname of message Foo is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: Foo")) + } + panic(fmt.Errorf("message Foo does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_Foo) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "Foo.full_name": + return protoreflect.ValueOfString("") + case "Foo.nickname": + return protoreflect.ValueOfString("") + case "Foo.mtime": + m := new(timestamppb.Timestamp) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + case "Foo.left": + m := new(Foo) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + case "Foo.right": + m := new(Foo) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + case "Foo.bar": + m := new(Bar) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: Foo")) + } + panic(fmt.Errorf("message Foo does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_Foo) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in Foo", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_Foo) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Foo) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_Foo) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_Foo) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*Foo) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.FullName) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.Nickname) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Mtime != nil { + l = options.Size(x.Mtime) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Left != nil { + l = options.Size(x.Left) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Right != nil { + l = options.Size(x.Right) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Bar != nil { + l = options.Size(x.Bar) + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*Foo) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Bar != nil { + encoded, err := options.Marshal(x.Bar) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x42 + } + if x.Right != nil { + encoded, err := options.Marshal(x.Right) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x2a + } + if x.Left != nil { + encoded, err := options.Marshal(x.Left) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x22 + } + if x.Mtime != nil { + encoded, err := options.Marshal(x.Mtime) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x1a + } + if len(x.Nickname) > 0 { + i -= len(x.Nickname) + copy(dAtA[i:], x.Nickname) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Nickname))) + i-- + dAtA[i] = 0x12 + } + if len(x.FullName) > 0 { + i -= len(x.FullName) + copy(dAtA[i:], x.FullName) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.FullName))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*Foo) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Foo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Foo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field FullName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.FullName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Nickname", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Nickname = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Mtime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Mtime == nil { + x.Mtime = ×tamppb.Timestamp{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Mtime); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Left", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Left == nil { + x.Left = &Foo{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Left); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Right", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Right == nil { + x.Right = &Foo{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Right); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Bar", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Bar == nil { + x.Bar = &Bar{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Bar); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_Bar protoreflect.MessageDescriptor + fd_Bar_bar_id protoreflect.FieldDescriptor + fd_Bar_data protoreflect.FieldDescriptor +) + +func init() { + file__1_proto_init() + md_Bar = File__1_proto.Messages().ByName("Bar") + fd_Bar_bar_id = md_Bar.Fields().ByName("bar_id") + fd_Bar_data = md_Bar.Fields().ByName("data") +} + +var _ protoreflect.Message = (*fastReflection_Bar)(nil) + +type fastReflection_Bar Bar + +func (x *Bar) ProtoReflect() protoreflect.Message { + return (*fastReflection_Bar)(x) +} + +func (x *Bar) slowProtoReflect() protoreflect.Message { + mi := &file__1_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_Bar_messageType fastReflection_Bar_messageType +var _ protoreflect.MessageType = fastReflection_Bar_messageType{} + +type fastReflection_Bar_messageType struct{} + +func (x fastReflection_Bar_messageType) Zero() protoreflect.Message { + return (*fastReflection_Bar)(nil) +} +func (x fastReflection_Bar_messageType) New() protoreflect.Message { + return new(fastReflection_Bar) +} +func (x fastReflection_Bar_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_Bar +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_Bar) Descriptor() protoreflect.MessageDescriptor { + return md_Bar +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_Bar) Type() protoreflect.MessageType { + return _fastReflection_Bar_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_Bar) New() protoreflect.Message { + return new(fastReflection_Bar) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_Bar) Interface() protoreflect.ProtoMessage { + return (*Bar)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_Bar) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.BarId != "" { + value := protoreflect.ValueOfString(x.BarId) + if !f(fd_Bar_bar_id, value) { + return + } + } + if len(x.Data) != 0 { + value := protoreflect.ValueOfBytes(x.Data) + if !f(fd_Bar_data, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_Bar) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "Bar.bar_id": + return x.BarId != "" + case "Bar.data": + return len(x.Data) != 0 + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: Bar")) + } + panic(fmt.Errorf("message Bar does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Bar) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "Bar.bar_id": + x.BarId = "" + case "Bar.data": + x.Data = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: Bar")) + } + panic(fmt.Errorf("message Bar does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_Bar) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "Bar.bar_id": + value := x.BarId + return protoreflect.ValueOfString(value) + case "Bar.data": + value := x.Data + return protoreflect.ValueOfBytes(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: Bar")) + } + panic(fmt.Errorf("message Bar does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Bar) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "Bar.bar_id": + x.BarId = value.Interface().(string) + case "Bar.data": + x.Data = value.Bytes() + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: Bar")) + } + panic(fmt.Errorf("message Bar does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Bar) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "Bar.bar_id": + panic(fmt.Errorf("field bar_id of message Bar is not mutable")) + case "Bar.data": + panic(fmt.Errorf("field data of message Bar is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: Bar")) + } + panic(fmt.Errorf("message Bar does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_Bar) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "Bar.bar_id": + return protoreflect.ValueOfString("") + case "Bar.data": + return protoreflect.ValueOfBytes(nil) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: Bar")) + } + panic(fmt.Errorf("message Bar does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_Bar) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in Bar", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_Bar) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Bar) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_Bar) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_Bar) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*Bar) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.BarId) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.Data) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*Bar) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.Data) > 0 { + i -= len(x.Data) + copy(dAtA[i:], x.Data) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Data))) + i-- + dAtA[i] = 0x12 + } + if len(x.BarId) > 0 { + i -= len(x.BarId) + copy(dAtA[i:], x.BarId) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.BarId))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*Bar) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Bar: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Bar: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field BarId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.BarId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Data = append(x.Data[:0], dAtA[iNdEx:postIndex]...) + if x.Data == nil { + x.Data = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.27.0 @@ -2072,6 +3358,126 @@ func (x *A) GetMAP() map[string]*A { return nil } +// Foo is a sample message type used for testing message rendering. +type Foo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FullName string `protobuf:"bytes,1,opt,name=full_name,json=fullName,proto3" json:"full_name,omitempty"` + Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname,omitempty"` + Mtime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=mtime,proto3" json:"mtime,omitempty"` + Left *Foo `protobuf:"bytes,4,opt,name=left,proto3" json:"left,omitempty"` + Right *Foo `protobuf:"bytes,5,opt,name=right,proto3" json:"right,omitempty"` + Bar *Bar `protobuf:"bytes,8,opt,name=bar,proto3" json:"bar,omitempty"` // skip some field numbers +} + +func (x *Foo) Reset() { + *x = Foo{} + if protoimpl.UnsafeEnabled { + mi := &file__1_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Foo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Foo) ProtoMessage() {} + +// Deprecated: Use Foo.ProtoReflect.Descriptor instead. +func (*Foo) Descriptor() ([]byte, []int) { + return file__1_proto_rawDescGZIP(), []int{1} +} + +func (x *Foo) GetFullName() string { + if x != nil { + return x.FullName + } + return "" +} + +func (x *Foo) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *Foo) GetMtime() *timestamppb.Timestamp { + if x != nil { + return x.Mtime + } + return nil +} + +func (x *Foo) GetLeft() *Foo { + if x != nil { + return x.Left + } + return nil +} + +func (x *Foo) GetRight() *Foo { + if x != nil { + return x.Right + } + return nil +} + +func (x *Foo) GetBar() *Bar { + if x != nil { + return x.Bar + } + return nil +} + +// Bar is a sample message type used for testing message rendering. +type Bar struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BarId string `protobuf:"bytes,1,opt,name=bar_id,json=barId,proto3" json:"bar_id,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *Bar) Reset() { + *x = Bar{} + if protoimpl.UnsafeEnabled { + mi := &file__1_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bar) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bar) ProtoMessage() {} + +// Deprecated: Use Bar.ProtoReflect.Descriptor instead. +func (*Bar) Descriptor() ([]byte, []int) { + return file__1_proto_rawDescGZIP(), []int{2} +} + +func (x *Bar) GetBarId() string { + if x != nil { + return x.BarId + } + return "" +} + +func (x *Bar) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + var File__1_proto protoreflect.FileDescriptor var file__1_proto_rawDesc = []byte{ @@ -2129,13 +3535,28 @@ var file__1_proto_rawDesc = []byte{ 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x02, 0x2e, 0x41, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x2a, 0x1f, 0x0a, 0x0b, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x6e, 0x65, 0x10, 0x00, 0x12, 0x07, 0x0a, - 0x03, 0x54, 0x77, 0x6f, 0x10, 0x01, 0x42, 0x33, 0x42, 0x06, 0x31, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x50, 0x01, 0x5a, 0x27, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, - 0x2f, 0x74, 0x78, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x61, 0x6c, 0x2f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xbe, 0x01, 0x0a, 0x03, 0x46, 0x6f, 0x6f, 0x12, 0x1b, 0x0a, + 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, + 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, + 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x05, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x04, 0x6c, 0x65, 0x66, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x04, 0x2e, 0x46, 0x6f, 0x6f, 0x52, 0x04, 0x6c, 0x65, + 0x66, 0x74, 0x12, 0x1a, 0x0a, 0x05, 0x72, 0x69, 0x67, 0x68, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x04, 0x2e, 0x46, 0x6f, 0x6f, 0x52, 0x05, 0x72, 0x69, 0x67, 0x68, 0x74, 0x12, 0x16, + 0x0a, 0x03, 0x62, 0x61, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x04, 0x2e, 0x42, 0x61, + 0x72, 0x52, 0x03, 0x62, 0x61, 0x72, 0x22, 0x30, 0x0a, 0x03, 0x42, 0x61, 0x72, 0x12, 0x15, 0x0a, + 0x06, 0x62, 0x61, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x62, + 0x61, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x2a, 0x1f, 0x0a, 0x0b, 0x45, 0x6e, 0x75, 0x6d, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x6e, 0x65, 0x10, 0x00, + 0x12, 0x07, 0x0a, 0x03, 0x54, 0x77, 0x6f, 0x10, 0x01, 0x42, 0x33, 0x42, 0x06, 0x31, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x27, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, + 0x2e, 0x69, 0x6f, 0x2f, 0x74, 0x78, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x61, 0x6c, 0x2f, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2151,27 +3572,33 @@ func file__1_proto_rawDescGZIP() []byte { } var file__1_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file__1_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file__1_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file__1_proto_goTypes = []interface{}{ (Enumeration)(0), // 0: Enumeration (*A)(nil), // 1: A - nil, // 2: A.MAPEntry - (*v1beta1.Coin)(nil), // 3: cosmos.base.v1beta1.Coin - (*timestamppb.Timestamp)(nil), // 4: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 5: google.protobuf.Duration + (*Foo)(nil), // 2: Foo + (*Bar)(nil), // 3: Bar + nil, // 4: A.MAPEntry + (*v1beta1.Coin)(nil), // 5: cosmos.base.v1beta1.Coin + (*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 7: google.protobuf.Duration } var file__1_proto_depIdxs = []int32{ - 3, // 0: A.COIN:type_name -> cosmos.base.v1beta1.Coin - 3, // 1: A.COINS:type_name -> cosmos.base.v1beta1.Coin - 4, // 2: A.TIMESTAMP:type_name -> google.protobuf.Timestamp - 5, // 3: A.DURATION:type_name -> google.protobuf.Duration - 2, // 4: A.MAP:type_name -> A.MAPEntry - 1, // 5: A.MAPEntry.value:type_name -> A - 6, // [6:6] is the sub-list for method output_type - 6, // [6:6] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name + 5, // 0: A.COIN:type_name -> cosmos.base.v1beta1.Coin + 5, // 1: A.COINS:type_name -> cosmos.base.v1beta1.Coin + 6, // 2: A.TIMESTAMP:type_name -> google.protobuf.Timestamp + 7, // 3: A.DURATION:type_name -> google.protobuf.Duration + 4, // 4: A.MAP:type_name -> A.MAPEntry + 6, // 5: Foo.mtime:type_name -> google.protobuf.Timestamp + 2, // 6: Foo.left:type_name -> Foo + 2, // 7: Foo.right:type_name -> Foo + 3, // 8: Foo.bar:type_name -> Bar + 1, // 9: A.MAPEntry.value:type_name -> A + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name } func init() { file__1_proto_init() } @@ -2192,6 +3619,30 @@ func file__1_proto_init() { return nil } } + file__1_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Foo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file__1_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bar); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -2199,7 +3650,7 @@ func file__1_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file__1_proto_rawDesc, NumEnums: 1, - NumMessages: 2, + NumMessages: 4, NumExtensions: 0, NumServices: 0, }, diff --git a/tx/textual/valuerenderer/message.go b/tx/textual/valuerenderer/message.go new file mode 100644 index 00000000000..e87d304bf89 --- /dev/null +++ b/tx/textual/valuerenderer/message.go @@ -0,0 +1,161 @@ +package valuerenderer + +import ( + "context" + "fmt" + "sort" + "strings" + + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" +) + +type messageValueRenderer struct { + tr *Textual + msgDesc protoreflect.MessageDescriptor + fds []protoreflect.FieldDescriptor +} + +func NewMessageValueRenderer(t *Textual, msgDesc protoreflect.MessageDescriptor) ValueRenderer { + fields := msgDesc.Fields() + fds := make([]protoreflect.FieldDescriptor, 0, fields.Len()) + for i := 0; i < fields.Len(); i++ { + fds = append(fds, fields.Get(i)) + } + sort.Slice(fds, func(i, j int) bool { return fds[i].Number() < fds[j].Number() }) + + return &messageValueRenderer{tr: t, msgDesc: msgDesc, fds: fds} +} + +func (mr *messageValueRenderer) header() string { + return fmt.Sprintf("%s object", mr.msgDesc.Name()) +} + +func (mr *messageValueRenderer) Format(ctx context.Context, v protoreflect.Value) ([]Screen, error) { + fullName := v.Message().Descriptor().FullName() + wantFullName := mr.msgDesc.FullName() + if fullName != wantFullName { + return nil, fmt.Errorf(`bad message type: want "%s", got "%s"`, wantFullName, fullName) + } + + screens := make([]Screen, 1) + screens[0].Text = mr.header() + + for _, fd := range mr.fds { + vr, err := mr.tr.GetValueRenderer(fd) + if err != nil { + return nil, err + } + // Skip default values. + if !v.Message().Has(fd) { + continue + } + + subscreens, err := vr.Format(ctx, v.Message().Get(fd)) + if err != nil { + return nil, err + } + if len(subscreens) == 0 { + return nil, fmt.Errorf("empty rendering for field %s", fd.Name()) + } + + headerScreen := Screen{ + Text: fmt.Sprintf("%s: %s", formatFieldName(string(fd.Name())), subscreens[0].Text), + Indent: subscreens[0].Indent + 1, + Expert: subscreens[0].Expert, + } + screens = append(screens, headerScreen) + + for i := 1; i < len(subscreens); i++ { + extraScreen := Screen{ + Text: subscreens[i].Text, + Indent: subscreens[i].Indent + 1, + Expert: subscreens[i].Expert, + } + screens = append(screens, extraScreen) + } + } + + return screens, nil +} + +// formatFieldName formats a field name in sentence case, as specified in: +// https://github.com/cosmos/cosmos-sdk/blob/b6f867d0b674d62e56b27aa4d00f5b6042ebac9e/docs/architecture/adr-050-sign-mode-textual-annex1.md?plain=1#L110 +func formatFieldName(name string) string { + if len(name) == 0 { + return name + } + return strings.ToTitle(name[0:1]) + strings.ReplaceAll(name[1:], "_", " ") +} + +var nilValue = protoreflect.Value{} + +func (mr *messageValueRenderer) Parse(ctx context.Context, screens []Screen) (protoreflect.Value, error) { + if len(screens) == 0 { + return nilValue, fmt.Errorf("expect at least one screen") + } + + wantHeader := fmt.Sprintf("%s object", mr.msgDesc.Name()) + if screens[0].Text != wantHeader { + return nilValue, fmt.Errorf(`bad header: want "%s", got "%s"`, wantHeader, screens[0].Text) + } + if screens[0].Indent != 0 { + return nilValue, fmt.Errorf("bad message indentation: want 0, got %d", screens[0].Indent) + } + + msgType, err := protoregistry.GlobalTypes.FindMessageByName(mr.msgDesc.FullName()) + if err != nil { + return nilValue, err + } + msg := msgType.New() + idx := 1 + + for _, fd := range mr.fds { + if idx >= len(screens) { + // remaining fields are default + break + } + + vr, err := mr.tr.GetValueRenderer(fd) + if err != nil { + return nilValue, err + } + + if screens[idx].Indent != 1 { + return nilValue, fmt.Errorf("bad message indentation: want 1, got %d", screens[idx].Indent) + } + + prefix := formatFieldName(string(fd.Name())) + ": " + if !strings.HasPrefix(screens[idx].Text, prefix) { + // we must have skipped this fd because of a default value + continue + } + + // Make a new screen without the prefix + subscreens := make([]Screen, 1) + subscreens[0] = screens[idx] + subscreens[0].Text = strings.TrimPrefix(screens[idx].Text, prefix) + subscreens[0].Indent-- + idx++ + + // Gather nested screens + for idx < len(screens) && screens[idx].Indent > 1 { + scr := screens[idx] + scr.Indent-- + subscreens = append(subscreens, scr) + idx++ + } + + val, err := vr.Parse(ctx, subscreens) + if err != nil { + return nilValue, err + } + msg.Set(fd, val) + } + + if idx > len(screens) { + return nilValue, fmt.Errorf("leftover screens") + } + + return protoreflect.ValueOfMessage(msg), nil +} diff --git a/tx/textual/valuerenderer/message_test.go b/tx/textual/valuerenderer/message_test.go new file mode 100644 index 00000000000..ef577784601 --- /dev/null +++ b/tx/textual/valuerenderer/message_test.go @@ -0,0 +1,53 @@ +package valuerenderer_test + +import ( + "context" + "encoding/json" + "fmt" + "os" + "testing" + + "cosmossdk.io/tx/textual/valuerenderer" + "github.com/stretchr/testify/require" + + bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" + "cosmossdk.io/tx/textual/internal/testpb" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" +) + +func EmptyCoinMetadataQuerier(ctx context.Context, denom string) (*bankv1beta1.Metadata, error) { + return nil, nil +} + +type messageJsonTest struct { + Proto *testpb.Foo + Screens []valuerenderer.Screen +} + +func TestMessageJsonTestcases(t *testing.T) { + raw, err := os.ReadFile("../internal/testdata/message.json") + require.NoError(t, err) + + var testcases []messageJsonTest + err = json.Unmarshal(raw, &testcases) + require.NoError(t, err) + + tr := valuerenderer.NewTextual(EmptyCoinMetadataQuerier) + for i, tc := range testcases { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + rend := valuerenderer.NewMessageValueRenderer(&tr, (&testpb.Foo{}).ProtoReflect().Descriptor()) + + screens, err := rend.Format(context.Background(), protoreflect.ValueOf(tc.Proto.ProtoReflect())) + require.NoError(t, err) + require.Equal(t, tc.Screens, screens) + + val, err := rend.Parse(context.Background(), screens) + require.NoError(t, err) + msg := val.Message().Interface() + require.IsType(t, &testpb.Foo{}, msg) + foo := msg.(*testpb.Foo) + require.True(t, proto.Equal(foo, tc.Proto)) + }) + } +} diff --git a/tx/textual/valuerenderer/string.go b/tx/textual/valuerenderer/string.go new file mode 100644 index 00000000000..b84a68f51af --- /dev/null +++ b/tx/textual/valuerenderer/string.go @@ -0,0 +1,28 @@ +package valuerenderer + +import ( + "context" + "fmt" + + "google.golang.org/protobuf/reflect/protoreflect" +) + +type stringValueRenderer struct { +} + +// NewStringValueRenderer returns a ValueRenderer for protocol buffer string values. +// It renders the string as-is without quotation. +func NewStringValueRenderer() ValueRenderer { + return stringValueRenderer{} +} + +func (sr stringValueRenderer) Format(_ context.Context, v protoreflect.Value) ([]Screen, error) { + return []Screen{{Text: v.String()}}, nil +} + +func (sr stringValueRenderer) Parse(_ context.Context, screens []Screen) (protoreflect.Value, error) { + if len(screens) != 1 { + return protoreflect.Value{}, fmt.Errorf("expected single screen: %v", screens) + } + return protoreflect.ValueOfString(screens[0].Text), nil +} diff --git a/tx/textual/valuerenderer/string_test.go b/tx/textual/valuerenderer/string_test.go new file mode 100644 index 00000000000..aba222b4c81 --- /dev/null +++ b/tx/textual/valuerenderer/string_test.go @@ -0,0 +1,55 @@ +package valuerenderer_test + +import ( + "context" + "encoding/json" + "fmt" + "os" + "testing" + + "cosmossdk.io/tx/textual/valuerenderer" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/reflect/protoreflect" +) + +type stringJsonTest struct { + Text string +} + +func TestStringJsonTestcases(t *testing.T) { + raw, err := os.ReadFile("../internal/testdata/string.json") + require.NoError(t, err) + + var testcases []stringJsonTest + err = json.Unmarshal(raw, &testcases) + require.NoError(t, err) + + for i, tc := range testcases { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + rend := valuerenderer.NewStringValueRenderer() + + screens, err := rend.Format(context.Background(), protoreflect.ValueOfString(tc.Text)) + require.NoError(t, err) + require.Equal(t, 1, len(screens)) + require.Equal(t, tc.Text, screens[0].Text) + + val, err := rend.Parse(context.Background(), screens) + require.NoError(t, err) + require.Equal(t, tc.Text, val.String()) + }) + } +} + +func TestStringHighUnicode(t *testing.T) { + // We cannot encode Unicode characters beyond the BMP directly in JSON, + // so this case must be a native Go test. + s := "\U00101234" + rend := valuerenderer.NewStringValueRenderer() + screens, err := rend.Format(context.Background(), protoreflect.ValueOfString(s)) + require.NoError(t, err) + require.Equal(t, 1, len(screens)) + require.Equal(t, s, screens[0].Text) + val, err := rend.Parse(context.Background(), screens) + require.NoError(t, err) + require.Equal(t, s, val.String()) +} diff --git a/tx/textual/valuerenderer/valuerenderer.go b/tx/textual/valuerenderer/valuerenderer.go index 675cc8c75db..dafbc1fc2f9 100644 --- a/tx/textual/valuerenderer/valuerenderer.go +++ b/tx/textual/valuerenderer/valuerenderer.go @@ -75,6 +75,9 @@ func (r Textual) GetValueRenderer(fd protoreflect.FieldDescriptor) (ValueRendere return NewIntValueRenderer(), nil } + case fd.Kind() == protoreflect.StringKind: + return stringValueRenderer{}, nil + case fd.Kind() == protoreflect.MessageKind: md := fd.Message() fullName := md.FullName() @@ -83,8 +86,14 @@ func (r Textual) GetValueRenderer(fd protoreflect.FieldDescriptor) (ValueRendere if found { return vr, nil } - // TODO default message renderer - return nil, fmt.Errorf("no value renderer for message %s", fullName) + if fd.IsMap() { + return nil, fmt.Errorf("value renderers cannot format value of type map") + } + if fd.IsList() { + // This will be implemented in https://github.com/cosmos/cosmos-sdk/issues/12714 + return nil, fmt.Errorf("repeated field renderer not yet implemented") + } + return NewMessageValueRenderer(&r, md), nil default: return nil, fmt.Errorf("value renderers cannot format value of type %s", fd.Kind())