blob: 98410a68fa321f6ee418d92e2aacf32d1e3b6de5 [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
50 pragma.NoUnkeyedLiterals
51}
52
Damien Neil0d3e8cc2019-04-01 13:31:55 -070053var _ = protoiface.MarshalOptions(MarshalOptions{})
54
Damien Neil99f24c32019-03-13 17:06:42 -070055// Marshal returns the wire-format encoding of m.
56func Marshal(m Message) ([]byte, error) {
57 return MarshalOptions{}.MarshalAppend(nil, m)
58}
59
60// Marshal returns the wire-format encoding of m.
61func (o MarshalOptions) Marshal(m Message) ([]byte, error) {
Damien Neil0d3e8cc2019-04-01 13:31:55 -070062 return o.MarshalAppend(nil, m)
Damien Neil99f24c32019-03-13 17:06:42 -070063}
64
65// MarshalAppend appends the wire-format encoding of m to b,
66// returning the result.
67func (o MarshalOptions) MarshalAppend(b []byte, m Message) ([]byte, error) {
Damien Neil3016b732019-04-07 12:43:10 -070068 out, err := o.marshalMessageFast(b, m)
Damien Neil4686e232019-04-05 13:31:40 -070069 if err == errInternalNoFast {
Damien Neil3016b732019-04-07 12:43:10 -070070 out, err = o.marshalMessage(b, m.ProtoReflect())
Damien Neil4686e232019-04-05 13:31:40 -070071 }
72 var nerr errors.NonFatal
73 if !nerr.Merge(err) {
Damien Neil3016b732019-04-07 12:43:10 -070074 return out, err
Damien Neil0d3e8cc2019-04-01 13:31:55 -070075 }
Damien Neil4686e232019-04-05 13:31:40 -070076 if !o.AllowPartial {
77 nerr.Merge(IsInitialized(m))
78 }
Damien Neil3016b732019-04-07 12:43:10 -070079 return out, nerr.E
Damien Neil99f24c32019-03-13 17:06:42 -070080}
81
Damien Neil0d3e8cc2019-04-01 13:31:55 -070082func (o MarshalOptions) marshalMessageFast(b []byte, m Message) ([]byte, error) {
Damien Neil0d3e8cc2019-04-01 13:31:55 -070083 methods := protoMethods(m)
84 if methods == nil ||
85 methods.MarshalAppend == nil ||
86 (o.Deterministic && methods.Flags&protoiface.MethodFlagDeterministicMarshal == 0) {
87 return nil, errInternalNoFast
88 }
89 if methods.Size != nil {
90 sz := methods.Size(m)
91 if cap(b) < len(b)+sz {
92 x := make([]byte, len(b), len(b)+sz)
93 copy(x, b)
94 b = x
95 }
96 }
97 return methods.MarshalAppend(b, m, protoiface.MarshalOptions(o))
98}
99
Damien Neil99f24c32019-03-13 17:06:42 -0700100func (o MarshalOptions) marshalMessage(b []byte, m protoreflect.Message) ([]byte, error) {
101 // There are many choices for what order we visit fields in. The default one here
102 // is chosen for reasonable efficiency and simplicity given the protoreflect API.
103 // It is not deterministic, since KnownFields.Range does not return fields in any
104 // defined order.
105 //
106 // When using deterministic serialization, we sort the known fields by field number.
107 fields := m.Type().Fields()
108 knownFields := m.KnownFields()
109 var err error
Damien Neil96c229a2019-04-03 12:17:24 -0700110 var nerr errors.NonFatal
Damien Neil99f24c32019-03-13 17:06:42 -0700111 o.rangeKnown(knownFields, func(num protoreflect.FieldNumber, value protoreflect.Value) bool {
112 field := fields.ByNumber(num)
113 if field == nil {
114 field = knownFields.ExtensionTypes().ByNumber(num)
115 if field == nil {
116 panic(fmt.Errorf("no descriptor for field %d in %q", num, m.Type().FullName()))
117 }
118 }
119 b, err = o.marshalField(b, field, value)
Damien Neil96c229a2019-04-03 12:17:24 -0700120 if nerr.Merge(err) {
121 err = nil
122 return true
123 }
124 return false
Damien Neil99f24c32019-03-13 17:06:42 -0700125 })
126 if err != nil {
Damien Neil96c229a2019-04-03 12:17:24 -0700127 return b, err
Damien Neil99f24c32019-03-13 17:06:42 -0700128 }
129 m.UnknownFields().Range(func(_ protoreflect.FieldNumber, raw protoreflect.RawFields) bool {
130 b = append(b, raw...)
131 return true
132 })
Damien Neil96c229a2019-04-03 12:17:24 -0700133 return b, nerr.E
Damien Neil99f24c32019-03-13 17:06:42 -0700134}
135
136// rangeKnown visits known fields in field number order when deterministic
137// serialization is enabled.
138func (o MarshalOptions) rangeKnown(knownFields protoreflect.KnownFields, f func(protoreflect.FieldNumber, protoreflect.Value) bool) {
139 if !o.Deterministic {
140 knownFields.Range(f)
141 return
142 }
143 nums := make([]protoreflect.FieldNumber, 0, knownFields.Len())
144 knownFields.Range(func(num protoreflect.FieldNumber, _ protoreflect.Value) bool {
145 nums = append(nums, num)
146 return true
147 })
148 sort.Slice(nums, func(a, b int) bool {
149 return nums[a] < nums[b]
150 })
151 for _, num := range nums {
152 if !f(num, knownFields.Get(num)) {
153 break
154 }
155 }
156}
157
158func (o MarshalOptions) marshalField(b []byte, field protoreflect.FieldDescriptor, value protoreflect.Value) ([]byte, error) {
159 num := field.Number()
160 kind := field.Kind()
161 switch {
162 case field.Cardinality() != protoreflect.Repeated:
163 b = wire.AppendTag(b, num, wireTypes[kind])
164 return o.marshalSingular(b, num, kind, value)
165 case field.IsMap():
166 return o.marshalMap(b, num, kind, field.MessageType(), value.Map())
167 case field.IsPacked():
168 return o.marshalPacked(b, num, kind, value.List())
169 default:
170 return o.marshalList(b, num, kind, value.List())
171 }
172}
173
174func (o MarshalOptions) marshalMap(b []byte, num wire.Number, kind protoreflect.Kind, mdesc protoreflect.MessageDescriptor, mapv protoreflect.Map) ([]byte, error) {
175 keyf := mdesc.Fields().ByNumber(1)
176 valf := mdesc.Fields().ByNumber(2)
Damien Neil96c229a2019-04-03 12:17:24 -0700177 var nerr errors.NonFatal
Damien Neil99f24c32019-03-13 17:06:42 -0700178 var err error
179 o.rangeMap(mapv, keyf.Kind(), func(key protoreflect.MapKey, value protoreflect.Value) bool {
180 b = wire.AppendTag(b, num, wire.BytesType)
181 var pos int
182 b, pos = appendSpeculativeLength(b)
183
184 b, err = o.marshalField(b, keyf, key.Value())
Damien Neil96c229a2019-04-03 12:17:24 -0700185 if !nerr.Merge(err) {
Damien Neil99f24c32019-03-13 17:06:42 -0700186 return false
187 }
188 b, err = o.marshalField(b, valf, value)
Damien Neil96c229a2019-04-03 12:17:24 -0700189 if !nerr.Merge(err) {
Damien Neil99f24c32019-03-13 17:06:42 -0700190 return false
191 }
Damien Neil96c229a2019-04-03 12:17:24 -0700192 err = nil
Damien Neil99f24c32019-03-13 17:06:42 -0700193
194 b = finishSpeculativeLength(b, pos)
195 return true
196 })
197 if err != nil {
Damien Neil96c229a2019-04-03 12:17:24 -0700198 return b, err
Damien Neil99f24c32019-03-13 17:06:42 -0700199 }
Damien Neil96c229a2019-04-03 12:17:24 -0700200 return b, nerr.E
Damien Neil99f24c32019-03-13 17:06:42 -0700201}
202
203func (o MarshalOptions) rangeMap(mapv protoreflect.Map, kind protoreflect.Kind, f func(protoreflect.MapKey, protoreflect.Value) bool) {
204 if !o.Deterministic {
205 mapv.Range(f)
206 return
207 }
208 mapsort.Range(mapv, kind, f)
209}
210
211func (o MarshalOptions) marshalPacked(b []byte, num wire.Number, kind protoreflect.Kind, list protoreflect.List) ([]byte, error) {
212 b = wire.AppendTag(b, num, wire.BytesType)
213 b, pos := appendSpeculativeLength(b)
Damien Neil96c229a2019-04-03 12:17:24 -0700214 var nerr errors.NonFatal
Damien Neil99f24c32019-03-13 17:06:42 -0700215 for i, llen := 0, list.Len(); i < llen; i++ {
216 var err error
217 b, err = o.marshalSingular(b, num, kind, list.Get(i))
Damien Neil96c229a2019-04-03 12:17:24 -0700218 if !nerr.Merge(err) {
219 return b, err
Damien Neil99f24c32019-03-13 17:06:42 -0700220 }
221 }
222 b = finishSpeculativeLength(b, pos)
Damien Neil96c229a2019-04-03 12:17:24 -0700223 return b, nerr.E
Damien Neil99f24c32019-03-13 17:06:42 -0700224}
225
226func (o MarshalOptions) marshalList(b []byte, num wire.Number, kind protoreflect.Kind, list protoreflect.List) ([]byte, error) {
Damien Neil96c229a2019-04-03 12:17:24 -0700227 var nerr errors.NonFatal
Damien Neil99f24c32019-03-13 17:06:42 -0700228 for i, llen := 0, list.Len(); i < llen; i++ {
229 var err error
230 b = wire.AppendTag(b, num, wireTypes[kind])
231 b, err = o.marshalSingular(b, num, kind, list.Get(i))
Damien Neil96c229a2019-04-03 12:17:24 -0700232 if !nerr.Merge(err) {
233 return b, err
Damien Neil99f24c32019-03-13 17:06:42 -0700234 }
235 }
Damien Neil96c229a2019-04-03 12:17:24 -0700236 return b, nerr.E
Damien Neil99f24c32019-03-13 17:06:42 -0700237}
238
239// When encoding length-prefixed fields, we speculatively set aside some number of bytes
240// for the length, encode the data, and then encode the length (shifting the data if necessary
241// to make room).
242const speculativeLength = 1
243
244func appendSpeculativeLength(b []byte) ([]byte, int) {
245 pos := len(b)
246 b = append(b, "\x00\x00\x00\x00"[:speculativeLength]...)
247 return b, pos
248}
249
250func finishSpeculativeLength(b []byte, pos int) []byte {
251 mlen := len(b) - pos - speculativeLength
252 msiz := wire.SizeVarint(uint64(mlen))
253 if msiz != speculativeLength {
254 for i := 0; i < msiz-speculativeLength; i++ {
255 b = append(b, 0)
256 }
257 copy(b[pos+msiz:], b[pos+speculativeLength:])
258 b = b[:pos+msiz+mlen]
259 }
260 wire.AppendVarint(b[:pos], uint64(mlen))
261 return b
262}