blob: 91fd6723ab8a3542c3cf896cacb074e0069b8ae6 [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001package dynamic
2
3// Binary serialization and de-serialization for dynamic messages
4
5import (
6 "fmt"
Zack Williamse940c7a2019-08-21 14:25:39 -07007 "github.com/golang/protobuf/proto"
Scott Baker4a35a702019-11-26 08:17:33 -08008 "github.com/jhump/protoreflect/codec"
9 "io"
Zack Williamse940c7a2019-08-21 14:25:39 -070010)
11
12// defaultDeterminism, if true, will mean that calls to Marshal will produce
13// deterministic output. This is used to make the output of proto.Marshal(...)
14// deterministic (since there is no way to have that convey determinism intent).
15// **This is only used from tests.**
16var defaultDeterminism = false
17
18// Marshal serializes this message to bytes, returning an error if the operation
19// fails. The resulting bytes are in the standard protocol buffer binary format.
20func (m *Message) Marshal() ([]byte, error) {
Scott Baker4a35a702019-11-26 08:17:33 -080021 var b codec.Buffer
22 b.SetDeterministic(defaultDeterminism)
23 if err := m.marshal(&b); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -070024 return nil, err
25 }
Scott Baker4a35a702019-11-26 08:17:33 -080026 return b.Bytes(), nil
Zack Williamse940c7a2019-08-21 14:25:39 -070027}
28
29// MarshalAppend behaves exactly the same as Marshal, except instead of allocating a
30// new byte slice to marshal into, it uses the provided byte slice. The backing array
31// for the returned byte slice *may* be the same as the one that was passed in, but
32// it's not guaranteed as a new backing array will automatically be allocated if
33// more bytes need to be written than the provided buffer has capacity for.
34func (m *Message) MarshalAppend(b []byte) ([]byte, error) {
Scott Baker4a35a702019-11-26 08:17:33 -080035 codedBuf := codec.NewBuffer(b)
36 codedBuf.SetDeterministic(defaultDeterminism)
37 if err := m.marshal(codedBuf); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -070038 return nil, err
39 }
Scott Baker4a35a702019-11-26 08:17:33 -080040 return codedBuf.Bytes(), nil
Zack Williamse940c7a2019-08-21 14:25:39 -070041}
42
43// MarshalDeterministic serializes this message to bytes in a deterministic way,
44// returning an error if the operation fails. This differs from Marshal in that
45// map keys will be sorted before serializing to bytes. The protobuf spec does
46// not define ordering for map entries, so Marshal will use standard Go map
47// iteration order (which will be random). But for cases where determinism is
48// more important than performance, use this method instead.
49func (m *Message) MarshalDeterministic() ([]byte, error) {
Scott Baker4a35a702019-11-26 08:17:33 -080050 var b codec.Buffer
51 b.SetDeterministic(true)
52 if err := m.marshal(&b); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -070053 return nil, err
54 }
Scott Baker4a35a702019-11-26 08:17:33 -080055 return b.Bytes(), nil
Zack Williamse940c7a2019-08-21 14:25:39 -070056}
57
Scott Baker4a35a702019-11-26 08:17:33 -080058// MarshalAppendDeterministic behaves exactly the same as MarshalDeterministic,
59// except instead of allocating a new byte slice to marshal into, it uses the
60// provided byte slice. The backing array for the returned byte slice *may* be
61// the same as the one that was passed in, but it's not guaranteed as a new
62// backing array will automatically be allocated if more bytes need to be written
63// than the provided buffer has capacity for.
64func (m *Message) MarshalAppendDeterministic(b []byte) ([]byte, error) {
65 codedBuf := codec.NewBuffer(b)
66 codedBuf.SetDeterministic(true)
67 if err := m.marshal(codedBuf); err != nil {
68 return nil, err
69 }
70 return codedBuf.Bytes(), nil
71}
72
73func (m *Message) marshal(b *codec.Buffer) error {
74 if err := m.marshalKnownFields(b); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -070075 return err
76 }
77 return m.marshalUnknownFields(b)
78}
79
Scott Baker4a35a702019-11-26 08:17:33 -080080func (m *Message) marshalKnownFields(b *codec.Buffer) error {
Zack Williamse940c7a2019-08-21 14:25:39 -070081 for _, tag := range m.knownFieldTags() {
82 itag := int32(tag)
83 val := m.values[itag]
84 fd := m.FindFieldDescriptor(itag)
85 if fd == nil {
86 panic(fmt.Sprintf("Couldn't find field for tag %d", itag))
87 }
Scott Baker4a35a702019-11-26 08:17:33 -080088 if err := b.EncodeFieldValue(fd, val); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -070089 return err
90 }
91 }
92 return nil
93}
94
Scott Baker4a35a702019-11-26 08:17:33 -080095func (m *Message) marshalUnknownFields(b *codec.Buffer) error {
Zack Williamse940c7a2019-08-21 14:25:39 -070096 for _, tag := range m.unknownFieldTags() {
97 itag := int32(tag)
98 sl := m.unknownFields[itag]
99 for _, u := range sl {
Scott Baker4a35a702019-11-26 08:17:33 -0800100 if err := b.EncodeTagAndWireType(itag, u.Encoding); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700101 return err
102 }
103 switch u.Encoding {
104 case proto.WireBytes:
Scott Baker4a35a702019-11-26 08:17:33 -0800105 if err := b.EncodeRawBytes(u.Contents); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700106 return err
107 }
108 case proto.WireStartGroup:
Scott Baker4a35a702019-11-26 08:17:33 -0800109 _, _ = b.Write(u.Contents)
110 if err := b.EncodeTagAndWireType(itag, proto.WireEndGroup); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700111 return err
112 }
113 case proto.WireFixed32:
Scott Baker4a35a702019-11-26 08:17:33 -0800114 if err := b.EncodeFixed32(u.Value); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700115 return err
116 }
117 case proto.WireFixed64:
Scott Baker4a35a702019-11-26 08:17:33 -0800118 if err := b.EncodeFixed64(u.Value); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700119 return err
120 }
121 case proto.WireVarint:
Scott Baker4a35a702019-11-26 08:17:33 -0800122 if err := b.EncodeVarint(u.Value); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700123 return err
124 }
125 default:
Scott Baker4a35a702019-11-26 08:17:33 -0800126 return codec.ErrBadWireType
Zack Williamse940c7a2019-08-21 14:25:39 -0700127 }
128 }
129 }
130 return nil
131}
132
Zack Williamse940c7a2019-08-21 14:25:39 -0700133// Unmarshal de-serializes the message that is present in the given bytes into
134// this message. It first resets the current message. It returns an error if the
135// given bytes do not contain a valid encoding of this message type.
136func (m *Message) Unmarshal(b []byte) error {
137 m.Reset()
138 if err := m.UnmarshalMerge(b); err != nil {
139 return err
140 }
141 return m.Validate()
142}
143
144// UnmarshalMerge de-serializes the message that is present in the given bytes
145// into this message. Unlike Unmarshal, it does not first reset the message,
146// instead merging the data in the given bytes into the existing data in this
147// message.
148func (m *Message) UnmarshalMerge(b []byte) error {
Scott Baker4a35a702019-11-26 08:17:33 -0800149 return m.unmarshal(codec.NewBuffer(b), false)
Zack Williamse940c7a2019-08-21 14:25:39 -0700150}
151
Scott Baker4a35a702019-11-26 08:17:33 -0800152func (m *Message) unmarshal(buf *codec.Buffer, isGroup bool) error {
153 for !buf.EOF() {
154 fd, val, err := buf.DecodeFieldValue(m.FindFieldDescriptor, m.mf)
Zack Williamse940c7a2019-08-21 14:25:39 -0700155 if err != nil {
Scott Baker4a35a702019-11-26 08:17:33 -0800156 if err == codec.ErrWireTypeEndGroup {
157 if isGroup {
158 // finished parsing group
159 return nil
160 }
161 return codec.ErrBadWireType
162 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700163 return err
164 }
Scott Baker4a35a702019-11-26 08:17:33 -0800165
Zack Williamse940c7a2019-08-21 14:25:39 -0700166 if fd == nil {
Scott Baker4a35a702019-11-26 08:17:33 -0800167 if m.unknownFields == nil {
168 m.unknownFields = map[int32][]UnknownField{}
Zack Williamse940c7a2019-08-21 14:25:39 -0700169 }
Scott Baker4a35a702019-11-26 08:17:33 -0800170 uv := val.(codec.UnknownField)
171 u := UnknownField{
172 Encoding: uv.Encoding,
173 Value: uv.Value,
174 Contents: uv.Contents,
Zack Williamse940c7a2019-08-21 14:25:39 -0700175 }
Scott Baker4a35a702019-11-26 08:17:33 -0800176 m.unknownFields[uv.Tag] = append(m.unknownFields[uv.Tag], u)
177 } else if err := mergeField(m, fd, val); err != nil {
178 return err
Zack Williamse940c7a2019-08-21 14:25:39 -0700179 }
180 }
181 if isGroup {
182 return io.ErrUnexpectedEOF
183 }
184 return nil
185}