blob: adf3de4cfc09a3b8665d8e61300c7ca32209b1ec [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 Neil0d3e8cc2019-04-01 13:31:55 -070072 if b, err := o.marshalMessageFast(b, m); err != errInternalNoFast {
73 return b, err
74 }
Damien Neil99f24c32019-03-13 17:06:42 -070075 return o.marshalMessage(b, m.ProtoReflect())
76}
77
Damien Neil0d3e8cc2019-04-01 13:31:55 -070078func (o MarshalOptions) marshalMessageFast(b []byte, m Message) ([]byte, error) {
79 if o.Reflection {
80 return nil, errInternalNoFast
81 }
82 methods := protoMethods(m)
83 if methods == nil ||
84 methods.MarshalAppend == nil ||
85 (o.Deterministic && methods.Flags&protoiface.MethodFlagDeterministicMarshal == 0) {
86 return nil, errInternalNoFast
87 }
88 if methods.Size != nil {
89 sz := methods.Size(m)
90 if cap(b) < len(b)+sz {
91 x := make([]byte, len(b), len(b)+sz)
92 copy(x, b)
93 b = x
94 }
95 }
96 return methods.MarshalAppend(b, m, protoiface.MarshalOptions(o))
97}
98
Damien Neil99f24c32019-03-13 17:06:42 -070099func (o MarshalOptions) marshalMessage(b []byte, m protoreflect.Message) ([]byte, error) {
100 // There are many choices for what order we visit fields in. The default one here
101 // is chosen for reasonable efficiency and simplicity given the protoreflect API.
102 // It is not deterministic, since KnownFields.Range does not return fields in any
103 // defined order.
104 //
105 // When using deterministic serialization, we sort the known fields by field number.
106 fields := m.Type().Fields()
107 knownFields := m.KnownFields()
108 var err error
Damien Neil96c229a2019-04-03 12:17:24 -0700109 var nerr errors.NonFatal
Damien Neil99f24c32019-03-13 17:06:42 -0700110 o.rangeKnown(knownFields, func(num protoreflect.FieldNumber, value protoreflect.Value) bool {
111 field := fields.ByNumber(num)
112 if field == nil {
113 field = knownFields.ExtensionTypes().ByNumber(num)
114 if field == nil {
115 panic(fmt.Errorf("no descriptor for field %d in %q", num, m.Type().FullName()))
116 }
117 }
118 b, err = o.marshalField(b, field, value)
Damien Neil96c229a2019-04-03 12:17:24 -0700119 if nerr.Merge(err) {
120 err = nil
121 return true
122 }
123 return false
Damien Neil99f24c32019-03-13 17:06:42 -0700124 })
125 if err != nil {
Damien Neil96c229a2019-04-03 12:17:24 -0700126 return b, err
Damien Neil99f24c32019-03-13 17:06:42 -0700127 }
128 m.UnknownFields().Range(func(_ protoreflect.FieldNumber, raw protoreflect.RawFields) bool {
129 b = append(b, raw...)
130 return true
131 })
Damien Neil96c229a2019-04-03 12:17:24 -0700132 if !o.AllowPartial {
133 checkRequiredFields(m, &nerr)
134 }
135 return b, nerr.E
Damien Neil99f24c32019-03-13 17:06:42 -0700136}
137
138// rangeKnown visits known fields in field number order when deterministic
139// serialization is enabled.
140func (o MarshalOptions) rangeKnown(knownFields protoreflect.KnownFields, f func(protoreflect.FieldNumber, protoreflect.Value) bool) {
141 if !o.Deterministic {
142 knownFields.Range(f)
143 return
144 }
145 nums := make([]protoreflect.FieldNumber, 0, knownFields.Len())
146 knownFields.Range(func(num protoreflect.FieldNumber, _ protoreflect.Value) bool {
147 nums = append(nums, num)
148 return true
149 })
150 sort.Slice(nums, func(a, b int) bool {
151 return nums[a] < nums[b]
152 })
153 for _, num := range nums {
154 if !f(num, knownFields.Get(num)) {
155 break
156 }
157 }
158}
159
160func (o MarshalOptions) marshalField(b []byte, field protoreflect.FieldDescriptor, value protoreflect.Value) ([]byte, error) {
161 num := field.Number()
162 kind := field.Kind()
163 switch {
164 case field.Cardinality() != protoreflect.Repeated:
165 b = wire.AppendTag(b, num, wireTypes[kind])
166 return o.marshalSingular(b, num, kind, value)
167 case field.IsMap():
168 return o.marshalMap(b, num, kind, field.MessageType(), value.Map())
169 case field.IsPacked():
170 return o.marshalPacked(b, num, kind, value.List())
171 default:
172 return o.marshalList(b, num, kind, value.List())
173 }
174}
175
176func (o MarshalOptions) marshalMap(b []byte, num wire.Number, kind protoreflect.Kind, mdesc protoreflect.MessageDescriptor, mapv protoreflect.Map) ([]byte, error) {
177 keyf := mdesc.Fields().ByNumber(1)
178 valf := mdesc.Fields().ByNumber(2)
Damien Neil96c229a2019-04-03 12:17:24 -0700179 var nerr errors.NonFatal
Damien Neil99f24c32019-03-13 17:06:42 -0700180 var err error
181 o.rangeMap(mapv, keyf.Kind(), func(key protoreflect.MapKey, value protoreflect.Value) bool {
182 b = wire.AppendTag(b, num, wire.BytesType)
183 var pos int
184 b, pos = appendSpeculativeLength(b)
185
186 b, err = o.marshalField(b, keyf, key.Value())
Damien Neil96c229a2019-04-03 12:17:24 -0700187 if !nerr.Merge(err) {
Damien Neil99f24c32019-03-13 17:06:42 -0700188 return false
189 }
190 b, err = o.marshalField(b, valf, value)
Damien Neil96c229a2019-04-03 12:17:24 -0700191 if !nerr.Merge(err) {
Damien Neil99f24c32019-03-13 17:06:42 -0700192 return false
193 }
Damien Neil96c229a2019-04-03 12:17:24 -0700194 err = nil
Damien Neil99f24c32019-03-13 17:06:42 -0700195
196 b = finishSpeculativeLength(b, pos)
197 return true
198 })
199 if err != nil {
Damien Neil96c229a2019-04-03 12:17:24 -0700200 return b, err
Damien Neil99f24c32019-03-13 17:06:42 -0700201 }
Damien Neil96c229a2019-04-03 12:17:24 -0700202 return b, nerr.E
Damien Neil99f24c32019-03-13 17:06:42 -0700203}
204
205func (o MarshalOptions) rangeMap(mapv protoreflect.Map, kind protoreflect.Kind, f func(protoreflect.MapKey, protoreflect.Value) bool) {
206 if !o.Deterministic {
207 mapv.Range(f)
208 return
209 }
210 mapsort.Range(mapv, kind, f)
211}
212
213func (o MarshalOptions) marshalPacked(b []byte, num wire.Number, kind protoreflect.Kind, list protoreflect.List) ([]byte, error) {
214 b = wire.AppendTag(b, num, wire.BytesType)
215 b, pos := appendSpeculativeLength(b)
Damien Neil96c229a2019-04-03 12:17:24 -0700216 var nerr errors.NonFatal
Damien Neil99f24c32019-03-13 17:06:42 -0700217 for i, llen := 0, list.Len(); i < llen; i++ {
218 var err error
219 b, err = o.marshalSingular(b, num, kind, list.Get(i))
Damien Neil96c229a2019-04-03 12:17:24 -0700220 if !nerr.Merge(err) {
221 return b, err
Damien Neil99f24c32019-03-13 17:06:42 -0700222 }
223 }
224 b = finishSpeculativeLength(b, pos)
Damien Neil96c229a2019-04-03 12:17:24 -0700225 return b, nerr.E
Damien Neil99f24c32019-03-13 17:06:42 -0700226}
227
228func (o MarshalOptions) marshalList(b []byte, num wire.Number, kind protoreflect.Kind, list protoreflect.List) ([]byte, error) {
Damien Neil96c229a2019-04-03 12:17:24 -0700229 var nerr errors.NonFatal
Damien Neil99f24c32019-03-13 17:06:42 -0700230 for i, llen := 0, list.Len(); i < llen; i++ {
231 var err error
232 b = wire.AppendTag(b, num, wireTypes[kind])
233 b, err = o.marshalSingular(b, num, kind, list.Get(i))
Damien Neil96c229a2019-04-03 12:17:24 -0700234 if !nerr.Merge(err) {
235 return b, err
Damien Neil99f24c32019-03-13 17:06:42 -0700236 }
237 }
Damien Neil96c229a2019-04-03 12:17:24 -0700238 return b, nerr.E
Damien Neil99f24c32019-03-13 17:06:42 -0700239}
240
241// When encoding length-prefixed fields, we speculatively set aside some number of bytes
242// for the length, encode the data, and then encode the length (shifting the data if necessary
243// to make room).
244const speculativeLength = 1
245
246func appendSpeculativeLength(b []byte) ([]byte, int) {
247 pos := len(b)
248 b = append(b, "\x00\x00\x00\x00"[:speculativeLength]...)
249 return b, pos
250}
251
252func finishSpeculativeLength(b []byte, pos int) []byte {
253 mlen := len(b) - pos - speculativeLength
254 msiz := wire.SizeVarint(uint64(mlen))
255 if msiz != speculativeLength {
256 for i := 0; i < msiz-speculativeLength; i++ {
257 b = append(b, 0)
258 }
259 copy(b[pos+msiz:], b[pos+speculativeLength:])
260 b = b[:pos+msiz+mlen]
261 }
262 wire.AppendVarint(b[:pos], uint64(mlen))
263 return b
264}