blob: fc3ce9234ec179a90e2bb1edc673e173b997aa00 [file] [log] [blame]
Damien Neil99f24c32019-03-13 17:06:42 -07001// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package proto
6
7import (
8 "fmt"
9 "sort"
10
11 "github.com/golang/protobuf/v2/internal/encoding/wire"
Damien Neil96c229a2019-04-03 12:17:24 -070012 "github.com/golang/protobuf/v2/internal/errors"
Damien Neil99f24c32019-03-13 17:06:42 -070013 "github.com/golang/protobuf/v2/internal/mapsort"
14 "github.com/golang/protobuf/v2/internal/pragma"
15 "github.com/golang/protobuf/v2/reflect/protoreflect"
Damien Neil0d3e8cc2019-04-01 13:31:55 -070016 "github.com/golang/protobuf/v2/runtime/protoiface"
Damien Neil99f24c32019-03-13 17:06:42 -070017)
18
19// MarshalOptions configures the marshaler.
20//
21// Example usage:
22// b, err := MarshalOptions{Deterministic: true}.Marshal(m)
23type MarshalOptions struct {
Damien Neil96c229a2019-04-03 12:17:24 -070024 // AllowPartial allows messages that have missing required fields to marshal
25 // without returning an error. If AllowPartial is false (the default),
26 // Marshal will return an error if there are any missing required fields.
27 AllowPartial bool
28
Damien Neil99f24c32019-03-13 17:06:42 -070029 // Deterministic controls whether the same message will always be
30 // serialized to the same bytes within the same binary.
31 //
32 // Setting this option guarantees that repeated serialization of
33 // the same message will return the same bytes, and that different
34 // processes of the same binary (which may be executing on different
35 // machines) will serialize equal messages to the same bytes.
36 //
37 // Note that the deterministic serialization is NOT canonical across
38 // languages. It is not guaranteed to remain stable over time. It is
39 // unstable across different builds with schema changes due to unknown
40 // fields. Users who need canonical serialization (e.g., persistent
41 // storage in a canonical form, fingerprinting, etc.) must define
42 // their own canonicalization specification and implement their own
43 // serializer rather than relying on this API.
44 //
45 // If deterministic serialization is requested, map entries will be
46 // sorted by keys in lexographical order. This is an implementation
47 // detail and subject to change.
48 Deterministic bool
49
Damien Neil0d3e8cc2019-04-01 13:31:55 -070050 // Reflection forces use of the reflection-based encoder, even for
51 // messages which implement fast-path serialization.
52 Reflection bool
53
Damien Neil99f24c32019-03-13 17:06:42 -070054 pragma.NoUnkeyedLiterals
55}
56
Damien Neil0d3e8cc2019-04-01 13:31:55 -070057var _ = protoiface.MarshalOptions(MarshalOptions{})
58
Damien Neil99f24c32019-03-13 17:06:42 -070059// Marshal returns the wire-format encoding of m.
60func Marshal(m Message) ([]byte, error) {
61 return MarshalOptions{}.MarshalAppend(nil, m)
62}
63
64// Marshal returns the wire-format encoding of m.
65func (o MarshalOptions) Marshal(m Message) ([]byte, error) {
Damien Neil0d3e8cc2019-04-01 13:31:55 -070066 return o.MarshalAppend(nil, m)
Damien Neil99f24c32019-03-13 17:06:42 -070067}
68
69// MarshalAppend appends the wire-format encoding of m to b,
70// returning the result.
71func (o MarshalOptions) MarshalAppend(b []byte, m Message) ([]byte, error) {
Damien Neil4686e232019-04-05 13:31:40 -070072 b, err := o.marshalMessageFast(b, m)
73 if err == errInternalNoFast {
74 b, err = o.marshalMessage(b, m.ProtoReflect())
75 }
76 var nerr errors.NonFatal
77 if !nerr.Merge(err) {
Damien Neil0d3e8cc2019-04-01 13:31:55 -070078 return b, err
79 }
Damien Neil4686e232019-04-05 13:31:40 -070080 if !o.AllowPartial {
81 nerr.Merge(IsInitialized(m))
82 }
83 return b, nerr.E
Damien Neil99f24c32019-03-13 17:06:42 -070084}
85
Damien Neil0d3e8cc2019-04-01 13:31:55 -070086func (o MarshalOptions) marshalMessageFast(b []byte, m Message) ([]byte, error) {
87 if o.Reflection {
88 return nil, errInternalNoFast
89 }
90 methods := protoMethods(m)
91 if methods == nil ||
92 methods.MarshalAppend == nil ||
93 (o.Deterministic && methods.Flags&protoiface.MethodFlagDeterministicMarshal == 0) {
94 return nil, errInternalNoFast
95 }
96 if methods.Size != nil {
97 sz := methods.Size(m)
98 if cap(b) < len(b)+sz {
99 x := make([]byte, len(b), len(b)+sz)
100 copy(x, b)
101 b = x
102 }
103 }
104 return methods.MarshalAppend(b, m, protoiface.MarshalOptions(o))
105}
106
Damien Neil99f24c32019-03-13 17:06:42 -0700107func (o MarshalOptions) marshalMessage(b []byte, m protoreflect.Message) ([]byte, error) {
108 // There are many choices for what order we visit fields in. The default one here
109 // is chosen for reasonable efficiency and simplicity given the protoreflect API.
110 // It is not deterministic, since KnownFields.Range does not return fields in any
111 // defined order.
112 //
113 // When using deterministic serialization, we sort the known fields by field number.
114 fields := m.Type().Fields()
115 knownFields := m.KnownFields()
116 var err error
Damien Neil96c229a2019-04-03 12:17:24 -0700117 var nerr errors.NonFatal
Damien Neil99f24c32019-03-13 17:06:42 -0700118 o.rangeKnown(knownFields, func(num protoreflect.FieldNumber, value protoreflect.Value) bool {
119 field := fields.ByNumber(num)
120 if field == nil {
121 field = knownFields.ExtensionTypes().ByNumber(num)
122 if field == nil {
123 panic(fmt.Errorf("no descriptor for field %d in %q", num, m.Type().FullName()))
124 }
125 }
126 b, err = o.marshalField(b, field, value)
Damien Neil96c229a2019-04-03 12:17:24 -0700127 if nerr.Merge(err) {
128 err = nil
129 return true
130 }
131 return false
Damien Neil99f24c32019-03-13 17:06:42 -0700132 })
133 if err != nil {
Damien Neil96c229a2019-04-03 12:17:24 -0700134 return b, err
Damien Neil99f24c32019-03-13 17:06:42 -0700135 }
136 m.UnknownFields().Range(func(_ protoreflect.FieldNumber, raw protoreflect.RawFields) bool {
137 b = append(b, raw...)
138 return true
139 })
Damien Neil96c229a2019-04-03 12:17:24 -0700140 return b, nerr.E
Damien Neil99f24c32019-03-13 17:06:42 -0700141}
142
143// rangeKnown visits known fields in field number order when deterministic
144// serialization is enabled.
145func (o MarshalOptions) rangeKnown(knownFields protoreflect.KnownFields, f func(protoreflect.FieldNumber, protoreflect.Value) bool) {
146 if !o.Deterministic {
147 knownFields.Range(f)
148 return
149 }
150 nums := make([]protoreflect.FieldNumber, 0, knownFields.Len())
151 knownFields.Range(func(num protoreflect.FieldNumber, _ protoreflect.Value) bool {
152 nums = append(nums, num)
153 return true
154 })
155 sort.Slice(nums, func(a, b int) bool {
156 return nums[a] < nums[b]
157 })
158 for _, num := range nums {
159 if !f(num, knownFields.Get(num)) {
160 break
161 }
162 }
163}
164
165func (o MarshalOptions) marshalField(b []byte, field protoreflect.FieldDescriptor, value protoreflect.Value) ([]byte, error) {
166 num := field.Number()
167 kind := field.Kind()
168 switch {
169 case field.Cardinality() != protoreflect.Repeated:
170 b = wire.AppendTag(b, num, wireTypes[kind])
171 return o.marshalSingular(b, num, kind, value)
172 case field.IsMap():
173 return o.marshalMap(b, num, kind, field.MessageType(), value.Map())
174 case field.IsPacked():
175 return o.marshalPacked(b, num, kind, value.List())
176 default:
177 return o.marshalList(b, num, kind, value.List())
178 }
179}
180
181func (o MarshalOptions) marshalMap(b []byte, num wire.Number, kind protoreflect.Kind, mdesc protoreflect.MessageDescriptor, mapv protoreflect.Map) ([]byte, error) {
182 keyf := mdesc.Fields().ByNumber(1)
183 valf := mdesc.Fields().ByNumber(2)
Damien Neil96c229a2019-04-03 12:17:24 -0700184 var nerr errors.NonFatal
Damien Neil99f24c32019-03-13 17:06:42 -0700185 var err error
186 o.rangeMap(mapv, keyf.Kind(), func(key protoreflect.MapKey, value protoreflect.Value) bool {
187 b = wire.AppendTag(b, num, wire.BytesType)
188 var pos int
189 b, pos = appendSpeculativeLength(b)
190
191 b, err = o.marshalField(b, keyf, key.Value())
Damien Neil96c229a2019-04-03 12:17:24 -0700192 if !nerr.Merge(err) {
Damien Neil99f24c32019-03-13 17:06:42 -0700193 return false
194 }
195 b, err = o.marshalField(b, valf, value)
Damien Neil96c229a2019-04-03 12:17:24 -0700196 if !nerr.Merge(err) {
Damien Neil99f24c32019-03-13 17:06:42 -0700197 return false
198 }
Damien Neil96c229a2019-04-03 12:17:24 -0700199 err = nil
Damien Neil99f24c32019-03-13 17:06:42 -0700200
201 b = finishSpeculativeLength(b, pos)
202 return true
203 })
204 if err != nil {
Damien Neil96c229a2019-04-03 12:17:24 -0700205 return b, err
Damien Neil99f24c32019-03-13 17:06:42 -0700206 }
Damien Neil96c229a2019-04-03 12:17:24 -0700207 return b, nerr.E
Damien Neil99f24c32019-03-13 17:06:42 -0700208}
209
210func (o MarshalOptions) rangeMap(mapv protoreflect.Map, kind protoreflect.Kind, f func(protoreflect.MapKey, protoreflect.Value) bool) {
211 if !o.Deterministic {
212 mapv.Range(f)
213 return
214 }
215 mapsort.Range(mapv, kind, f)
216}
217
218func (o MarshalOptions) marshalPacked(b []byte, num wire.Number, kind protoreflect.Kind, list protoreflect.List) ([]byte, error) {
219 b = wire.AppendTag(b, num, wire.BytesType)
220 b, pos := appendSpeculativeLength(b)
Damien Neil96c229a2019-04-03 12:17:24 -0700221 var nerr errors.NonFatal
Damien Neil99f24c32019-03-13 17:06:42 -0700222 for i, llen := 0, list.Len(); i < llen; i++ {
223 var err error
224 b, err = o.marshalSingular(b, num, kind, list.Get(i))
Damien Neil96c229a2019-04-03 12:17:24 -0700225 if !nerr.Merge(err) {
226 return b, err
Damien Neil99f24c32019-03-13 17:06:42 -0700227 }
228 }
229 b = finishSpeculativeLength(b, pos)
Damien Neil96c229a2019-04-03 12:17:24 -0700230 return b, nerr.E
Damien Neil99f24c32019-03-13 17:06:42 -0700231}
232
233func (o MarshalOptions) marshalList(b []byte, num wire.Number, kind protoreflect.Kind, list protoreflect.List) ([]byte, error) {
Damien Neil96c229a2019-04-03 12:17:24 -0700234 var nerr errors.NonFatal
Damien Neil99f24c32019-03-13 17:06:42 -0700235 for i, llen := 0, list.Len(); i < llen; i++ {
236 var err error
237 b = wire.AppendTag(b, num, wireTypes[kind])
238 b, err = o.marshalSingular(b, num, kind, list.Get(i))
Damien Neil96c229a2019-04-03 12:17:24 -0700239 if !nerr.Merge(err) {
240 return b, err
Damien Neil99f24c32019-03-13 17:06:42 -0700241 }
242 }
Damien Neil96c229a2019-04-03 12:17:24 -0700243 return b, nerr.E
Damien Neil99f24c32019-03-13 17:06:42 -0700244}
245
246// When encoding length-prefixed fields, we speculatively set aside some number of bytes
247// for the length, encode the data, and then encode the length (shifting the data if necessary
248// to make room).
249const speculativeLength = 1
250
251func appendSpeculativeLength(b []byte) ([]byte, int) {
252 pos := len(b)
253 b = append(b, "\x00\x00\x00\x00"[:speculativeLength]...)
254 return b, pos
255}
256
257func finishSpeculativeLength(b []byte, pos int) []byte {
258 mlen := len(b) - pos - speculativeLength
259 msiz := wire.SizeVarint(uint64(mlen))
260 if msiz != speculativeLength {
261 for i := 0; i < msiz-speculativeLength; i++ {
262 b = append(b, 0)
263 }
264 copy(b[pos+msiz:], b[pos+speculativeLength:])
265 b = b[:pos+msiz+mlen]
266 }
267 wire.AppendVarint(b[:pos], uint64(mlen))
268 return b
269}