blob: 39e077a4d7d4de0d0ef704c791da0d348646c5ca [file] [log] [blame]
khenaidooa46458b2021-12-15 16:50:44 -05001package dynamic
2
3// Binary serialization and de-serialization for dynamic messages
4
5import (
6 "fmt"
khenaidooa46458b2021-12-15 16:50:44 -05007 "io"
Abhay Kumara2ae5992025-11-10 14:02:24 +00008
9 "github.com/golang/protobuf/proto"
10
11 "github.com/jhump/protoreflect/codec"
khenaidooa46458b2021-12-15 16:50:44 -050012)
13
14// defaultDeterminism, if true, will mean that calls to Marshal will produce
15// deterministic output. This is used to make the output of proto.Marshal(...)
16// deterministic (since there is no way to have that convey determinism intent).
17// **This is only used from tests.**
18var defaultDeterminism = false
19
20// Marshal serializes this message to bytes, returning an error if the operation
21// fails. The resulting bytes are in the standard protocol buffer binary format.
22func (m *Message) Marshal() ([]byte, error) {
23 var b codec.Buffer
24 b.SetDeterministic(defaultDeterminism)
25 if err := m.marshal(&b); err != nil {
26 return nil, err
27 }
28 return b.Bytes(), nil
29}
30
31// MarshalAppend behaves exactly the same as Marshal, except instead of allocating a
32// new byte slice to marshal into, it uses the provided byte slice. The backing array
33// for the returned byte slice *may* be the same as the one that was passed in, but
34// it's not guaranteed as a new backing array will automatically be allocated if
35// more bytes need to be written than the provided buffer has capacity for.
36func (m *Message) MarshalAppend(b []byte) ([]byte, error) {
37 codedBuf := codec.NewBuffer(b)
38 codedBuf.SetDeterministic(defaultDeterminism)
39 if err := m.marshal(codedBuf); err != nil {
40 return nil, err
41 }
42 return codedBuf.Bytes(), nil
43}
44
45// MarshalDeterministic serializes this message to bytes in a deterministic way,
46// returning an error if the operation fails. This differs from Marshal in that
47// map keys will be sorted before serializing to bytes. The protobuf spec does
48// not define ordering for map entries, so Marshal will use standard Go map
49// iteration order (which will be random). But for cases where determinism is
50// more important than performance, use this method instead.
51func (m *Message) MarshalDeterministic() ([]byte, error) {
52 var b codec.Buffer
53 b.SetDeterministic(true)
54 if err := m.marshal(&b); err != nil {
55 return nil, err
56 }
57 return b.Bytes(), nil
58}
59
60// MarshalAppendDeterministic behaves exactly the same as MarshalDeterministic,
61// except instead of allocating a new byte slice to marshal into, it uses the
62// provided byte slice. The backing array for the returned byte slice *may* be
63// the same as the one that was passed in, but it's not guaranteed as a new
64// backing array will automatically be allocated if more bytes need to be written
65// than the provided buffer has capacity for.
66func (m *Message) MarshalAppendDeterministic(b []byte) ([]byte, error) {
67 codedBuf := codec.NewBuffer(b)
68 codedBuf.SetDeterministic(true)
69 if err := m.marshal(codedBuf); err != nil {
70 return nil, err
71 }
72 return codedBuf.Bytes(), nil
73}
74
75func (m *Message) marshal(b *codec.Buffer) error {
Abhay Kumara2ae5992025-11-10 14:02:24 +000076 if m.GetMessageDescriptor().GetMessageOptions().GetMessageSetWireFormat() {
77 return fmt.Errorf("%s is a message set; marshaling message sets is not implemented", m.GetMessageDescriptor().GetFullyQualifiedName())
78 }
khenaidooa46458b2021-12-15 16:50:44 -050079 if err := m.marshalKnownFields(b); err != nil {
80 return err
81 }
82 return m.marshalUnknownFields(b)
83}
84
85func (m *Message) marshalKnownFields(b *codec.Buffer) error {
86 for _, tag := range m.knownFieldTags() {
87 itag := int32(tag)
88 val := m.values[itag]
89 fd := m.FindFieldDescriptor(itag)
90 if fd == nil {
91 panic(fmt.Sprintf("Couldn't find field for tag %d", itag))
92 }
93 if err := b.EncodeFieldValue(fd, val); err != nil {
94 return err
95 }
96 }
97 return nil
98}
99
100func (m *Message) marshalUnknownFields(b *codec.Buffer) error {
101 for _, tag := range m.unknownFieldTags() {
102 itag := int32(tag)
103 sl := m.unknownFields[itag]
104 for _, u := range sl {
105 if err := b.EncodeTagAndWireType(itag, u.Encoding); err != nil {
106 return err
107 }
108 switch u.Encoding {
109 case proto.WireBytes:
110 if err := b.EncodeRawBytes(u.Contents); err != nil {
111 return err
112 }
113 case proto.WireStartGroup:
114 _, _ = b.Write(u.Contents)
115 if err := b.EncodeTagAndWireType(itag, proto.WireEndGroup); err != nil {
116 return err
117 }
118 case proto.WireFixed32:
119 if err := b.EncodeFixed32(u.Value); err != nil {
120 return err
121 }
122 case proto.WireFixed64:
123 if err := b.EncodeFixed64(u.Value); err != nil {
124 return err
125 }
126 case proto.WireVarint:
127 if err := b.EncodeVarint(u.Value); err != nil {
128 return err
129 }
130 default:
131 return codec.ErrBadWireType
132 }
133 }
134 }
135 return nil
136}
137
138// Unmarshal de-serializes the message that is present in the given bytes into
139// this message. It first resets the current message. It returns an error if the
140// given bytes do not contain a valid encoding of this message type.
141func (m *Message) Unmarshal(b []byte) error {
142 m.Reset()
143 if err := m.UnmarshalMerge(b); err != nil {
144 return err
145 }
146 return m.Validate()
147}
148
149// UnmarshalMerge de-serializes the message that is present in the given bytes
150// into this message. Unlike Unmarshal, it does not first reset the message,
151// instead merging the data in the given bytes into the existing data in this
152// message.
153func (m *Message) UnmarshalMerge(b []byte) error {
154 return m.unmarshal(codec.NewBuffer(b), false)
155}
156
157func (m *Message) unmarshal(buf *codec.Buffer, isGroup bool) error {
Abhay Kumara2ae5992025-11-10 14:02:24 +0000158 if m.GetMessageDescriptor().GetMessageOptions().GetMessageSetWireFormat() {
159 return fmt.Errorf("%s is a message set; unmarshaling message sets is not implemented", m.GetMessageDescriptor().GetFullyQualifiedName())
160 }
khenaidooa46458b2021-12-15 16:50:44 -0500161 for !buf.EOF() {
162 fd, val, err := buf.DecodeFieldValue(m.FindFieldDescriptor, m.mf)
163 if err != nil {
164 if err == codec.ErrWireTypeEndGroup {
165 if isGroup {
166 // finished parsing group
167 return nil
168 }
169 return codec.ErrBadWireType
170 }
171 return err
172 }
173
174 if fd == nil {
175 if m.unknownFields == nil {
176 m.unknownFields = map[int32][]UnknownField{}
177 }
178 uv := val.(codec.UnknownField)
179 u := UnknownField{
180 Encoding: uv.Encoding,
181 Value: uv.Value,
182 Contents: uv.Contents,
183 }
184 m.unknownFields[uv.Tag] = append(m.unknownFields[uv.Tag], u)
185 } else if err := mergeField(m, fd, val); err != nil {
186 return err
187 }
188 }
189 if isGroup {
190 return io.ErrUnexpectedEOF
191 }
192 return nil
193}