blob: 973e53a4482e79a8a37138c5c40dfb8b9f9e478e [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"
12 "github.com/golang/protobuf/v2/internal/mapsort"
13 "github.com/golang/protobuf/v2/internal/pragma"
14 "github.com/golang/protobuf/v2/reflect/protoreflect"
Damien Neil0d3e8cc2019-04-01 13:31:55 -070015 "github.com/golang/protobuf/v2/runtime/protoiface"
Damien Neil99f24c32019-03-13 17:06:42 -070016)
17
18// MarshalOptions configures the marshaler.
19//
20// Example usage:
21// b, err := MarshalOptions{Deterministic: true}.Marshal(m)
22type MarshalOptions struct {
23 // Deterministic controls whether the same message will always be
24 // serialized to the same bytes within the same binary.
25 //
26 // Setting this option guarantees that repeated serialization of
27 // the same message will return the same bytes, and that different
28 // processes of the same binary (which may be executing on different
29 // machines) will serialize equal messages to the same bytes.
30 //
31 // Note that the deterministic serialization is NOT canonical across
32 // languages. It is not guaranteed to remain stable over time. It is
33 // unstable across different builds with schema changes due to unknown
34 // fields. Users who need canonical serialization (e.g., persistent
35 // storage in a canonical form, fingerprinting, etc.) must define
36 // their own canonicalization specification and implement their own
37 // serializer rather than relying on this API.
38 //
39 // If deterministic serialization is requested, map entries will be
40 // sorted by keys in lexographical order. This is an implementation
41 // detail and subject to change.
42 Deterministic bool
43
Damien Neil0d3e8cc2019-04-01 13:31:55 -070044 // Reflection forces use of the reflection-based encoder, even for
45 // messages which implement fast-path serialization.
46 Reflection bool
47
Damien Neil99f24c32019-03-13 17:06:42 -070048 pragma.NoUnkeyedLiterals
49}
50
Damien Neil0d3e8cc2019-04-01 13:31:55 -070051var _ = protoiface.MarshalOptions(MarshalOptions{})
52
Damien Neil99f24c32019-03-13 17:06:42 -070053// Marshal returns the wire-format encoding of m.
54func Marshal(m Message) ([]byte, error) {
55 return MarshalOptions{}.MarshalAppend(nil, m)
56}
57
58// Marshal returns the wire-format encoding of m.
59func (o MarshalOptions) Marshal(m Message) ([]byte, error) {
Damien Neil0d3e8cc2019-04-01 13:31:55 -070060 return o.MarshalAppend(nil, m)
Damien Neil99f24c32019-03-13 17:06:42 -070061}
62
63// MarshalAppend appends the wire-format encoding of m to b,
64// returning the result.
65func (o MarshalOptions) MarshalAppend(b []byte, m Message) ([]byte, error) {
Damien Neil0d3e8cc2019-04-01 13:31:55 -070066 if b, err := o.marshalMessageFast(b, m); err != errInternalNoFast {
67 return b, err
68 }
Damien Neil99f24c32019-03-13 17:06:42 -070069 return o.marshalMessage(b, m.ProtoReflect())
70}
71
Damien Neil0d3e8cc2019-04-01 13:31:55 -070072func (o MarshalOptions) marshalMessageFast(b []byte, m Message) ([]byte, error) {
73 if o.Reflection {
74 return nil, errInternalNoFast
75 }
76 methods := protoMethods(m)
77 if methods == nil ||
78 methods.MarshalAppend == nil ||
79 (o.Deterministic && methods.Flags&protoiface.MethodFlagDeterministicMarshal == 0) {
80 return nil, errInternalNoFast
81 }
82 if methods.Size != nil {
83 sz := methods.Size(m)
84 if cap(b) < len(b)+sz {
85 x := make([]byte, len(b), len(b)+sz)
86 copy(x, b)
87 b = x
88 }
89 }
90 return methods.MarshalAppend(b, m, protoiface.MarshalOptions(o))
91}
92
Damien Neil99f24c32019-03-13 17:06:42 -070093func (o MarshalOptions) marshalMessage(b []byte, m protoreflect.Message) ([]byte, error) {
94 // There are many choices for what order we visit fields in. The default one here
95 // is chosen for reasonable efficiency and simplicity given the protoreflect API.
96 // It is not deterministic, since KnownFields.Range does not return fields in any
97 // defined order.
98 //
99 // When using deterministic serialization, we sort the known fields by field number.
100 fields := m.Type().Fields()
101 knownFields := m.KnownFields()
102 var err error
103 o.rangeKnown(knownFields, func(num protoreflect.FieldNumber, value protoreflect.Value) bool {
104 field := fields.ByNumber(num)
105 if field == nil {
106 field = knownFields.ExtensionTypes().ByNumber(num)
107 if field == nil {
108 panic(fmt.Errorf("no descriptor for field %d in %q", num, m.Type().FullName()))
109 }
110 }
111 b, err = o.marshalField(b, field, value)
112 return err == nil
113 })
114 if err != nil {
115 return nil, err
116 }
117 m.UnknownFields().Range(func(_ protoreflect.FieldNumber, raw protoreflect.RawFields) bool {
118 b = append(b, raw...)
119 return true
120 })
121 // TODO: required field checks
122 return b, nil
123}
124
125// rangeKnown visits known fields in field number order when deterministic
126// serialization is enabled.
127func (o MarshalOptions) rangeKnown(knownFields protoreflect.KnownFields, f func(protoreflect.FieldNumber, protoreflect.Value) bool) {
128 if !o.Deterministic {
129 knownFields.Range(f)
130 return
131 }
132 nums := make([]protoreflect.FieldNumber, 0, knownFields.Len())
133 knownFields.Range(func(num protoreflect.FieldNumber, _ protoreflect.Value) bool {
134 nums = append(nums, num)
135 return true
136 })
137 sort.Slice(nums, func(a, b int) bool {
138 return nums[a] < nums[b]
139 })
140 for _, num := range nums {
141 if !f(num, knownFields.Get(num)) {
142 break
143 }
144 }
145}
146
147func (o MarshalOptions) marshalField(b []byte, field protoreflect.FieldDescriptor, value protoreflect.Value) ([]byte, error) {
148 num := field.Number()
149 kind := field.Kind()
150 switch {
151 case field.Cardinality() != protoreflect.Repeated:
152 b = wire.AppendTag(b, num, wireTypes[kind])
153 return o.marshalSingular(b, num, kind, value)
154 case field.IsMap():
155 return o.marshalMap(b, num, kind, field.MessageType(), value.Map())
156 case field.IsPacked():
157 return o.marshalPacked(b, num, kind, value.List())
158 default:
159 return o.marshalList(b, num, kind, value.List())
160 }
161}
162
163func (o MarshalOptions) marshalMap(b []byte, num wire.Number, kind protoreflect.Kind, mdesc protoreflect.MessageDescriptor, mapv protoreflect.Map) ([]byte, error) {
164 keyf := mdesc.Fields().ByNumber(1)
165 valf := mdesc.Fields().ByNumber(2)
166 var err error
167 o.rangeMap(mapv, keyf.Kind(), func(key protoreflect.MapKey, value protoreflect.Value) bool {
168 b = wire.AppendTag(b, num, wire.BytesType)
169 var pos int
170 b, pos = appendSpeculativeLength(b)
171
172 b, err = o.marshalField(b, keyf, key.Value())
173 if err != nil {
174 return false
175 }
176 b, err = o.marshalField(b, valf, value)
177 if err != nil {
178 return false
179 }
180
181 b = finishSpeculativeLength(b, pos)
182 return true
183 })
184 if err != nil {
185 return nil, err
186 }
187 return b, nil
188}
189
190func (o MarshalOptions) rangeMap(mapv protoreflect.Map, kind protoreflect.Kind, f func(protoreflect.MapKey, protoreflect.Value) bool) {
191 if !o.Deterministic {
192 mapv.Range(f)
193 return
194 }
195 mapsort.Range(mapv, kind, f)
196}
197
198func (o MarshalOptions) marshalPacked(b []byte, num wire.Number, kind protoreflect.Kind, list protoreflect.List) ([]byte, error) {
199 b = wire.AppendTag(b, num, wire.BytesType)
200 b, pos := appendSpeculativeLength(b)
201 for i, llen := 0, list.Len(); i < llen; i++ {
202 var err error
203 b, err = o.marshalSingular(b, num, kind, list.Get(i))
204 if err != nil {
205 return nil, err
206 }
207 }
208 b = finishSpeculativeLength(b, pos)
209 return b, nil
210}
211
212func (o MarshalOptions) marshalList(b []byte, num wire.Number, kind protoreflect.Kind, list protoreflect.List) ([]byte, error) {
213 for i, llen := 0, list.Len(); i < llen; i++ {
214 var err error
215 b = wire.AppendTag(b, num, wireTypes[kind])
216 b, err = o.marshalSingular(b, num, kind, list.Get(i))
217 if err != nil {
218 return nil, err
219 }
220 }
221 return b, nil
222}
223
224// When encoding length-prefixed fields, we speculatively set aside some number of bytes
225// for the length, encode the data, and then encode the length (shifting the data if necessary
226// to make room).
227const speculativeLength = 1
228
229func appendSpeculativeLength(b []byte) ([]byte, int) {
230 pos := len(b)
231 b = append(b, "\x00\x00\x00\x00"[:speculativeLength]...)
232 return b, pos
233}
234
235func finishSpeculativeLength(b []byte, pos int) []byte {
236 mlen := len(b) - pos - speculativeLength
237 msiz := wire.SizeVarint(uint64(mlen))
238 if msiz != speculativeLength {
239 for i := 0; i < msiz-speculativeLength; i++ {
240 b = append(b, 0)
241 }
242 copy(b[pos+msiz:], b[pos+speculativeLength:])
243 b = b[:pos+msiz+mlen]
244 }
245 wire.AppendVarint(b[:pos], uint64(mlen))
246 return b
247}