blob: 306677c1ee4e384a3f7b7a25769eb07634c6a25f [file] [log] [blame]
Damien Neilc37adef2019-04-01 13:49:56 -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 impl
6
7import (
8 "sort"
9 "sync/atomic"
10
Damien Neilce3384c2019-11-06 13:18:28 -080011 "google.golang.org/protobuf/internal/flags"
Damien Neilc37adef2019-04-01 13:49:56 -070012 proto "google.golang.org/protobuf/proto"
13 pref "google.golang.org/protobuf/reflect/protoreflect"
14 piface "google.golang.org/protobuf/runtime/protoiface"
15)
16
Damien Neile91877d2019-06-27 10:54:42 -070017// marshalOptions is a more efficient representation of MarshalOptions.
18//
19// We don't preserve the AllowPartial flag, because fast-path (un)marshal
20// operations always allow partial messages.
Damien Neilc37adef2019-04-01 13:49:56 -070021type marshalOptions uint
22
23const (
Damien Neile91877d2019-06-27 10:54:42 -070024 marshalDeterministic marshalOptions = 1 << iota
Damien Neilc37adef2019-04-01 13:49:56 -070025 marshalUseCachedSize
26)
27
28func newMarshalOptions(opts piface.MarshalOptions) marshalOptions {
29 var o marshalOptions
Damien Neilc37adef2019-04-01 13:49:56 -070030 if opts.Deterministic {
31 o |= marshalDeterministic
32 }
33 if opts.UseCachedSize {
34 o |= marshalUseCachedSize
35 }
36 return o
37}
38
39func (o marshalOptions) Options() proto.MarshalOptions {
40 return proto.MarshalOptions{
Damien Neile91877d2019-06-27 10:54:42 -070041 AllowPartial: true,
Damien Neilc37adef2019-04-01 13:49:56 -070042 Deterministic: o.Deterministic(),
43 UseCachedSize: o.UseCachedSize(),
44 }
45}
46
Damien Neilc37adef2019-04-01 13:49:56 -070047func (o marshalOptions) Deterministic() bool { return o&marshalDeterministic != 0 }
48func (o marshalOptions) UseCachedSize() bool { return o&marshalUseCachedSize != 0 }
49
50// size is protoreflect.Methods.Size.
Joe Tsaif8b855d2019-07-12 13:37:59 -070051func (mi *MessageInfo) size(m pref.Message, opts piface.MarshalOptions) (size int) {
Joe Tsai0f81b382019-07-10 23:14:31 -070052 var p pointer
53 if ms, ok := m.(*messageState); ok {
54 p = ms.pointer()
55 } else {
56 p = m.(*messageReflectWrapper).pointer()
57 }
Joe Tsaif8b855d2019-07-12 13:37:59 -070058 return mi.sizePointer(p, newMarshalOptions(opts))
Damien Neilc37adef2019-04-01 13:49:56 -070059}
60
Joe Tsai4fe96632019-05-22 05:12:36 -040061func (mi *MessageInfo) sizePointer(p pointer, opts marshalOptions) (size int) {
Damien Neilc37adef2019-04-01 13:49:56 -070062 mi.init()
63 if p.IsNil() {
64 return 0
65 }
66 if opts.UseCachedSize() && mi.sizecacheOffset.IsValid() {
67 return int(atomic.LoadInt32(p.Apply(mi.sizecacheOffset).Int32()))
68 }
69 return mi.sizePointerSlow(p, opts)
70}
71
Joe Tsai4fe96632019-05-22 05:12:36 -040072func (mi *MessageInfo) sizePointerSlow(p pointer, opts marshalOptions) (size int) {
Damien Neilce3384c2019-11-06 13:18:28 -080073 if flags.ProtoLegacy && mi.isMessageSet {
74 size = sizeMessageSet(mi, p, opts)
75 if mi.sizecacheOffset.IsValid() {
76 atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size))
77 }
78 return size
79 }
Damien Neilc37adef2019-04-01 13:49:56 -070080 if mi.extensionOffset.IsValid() {
81 e := p.Apply(mi.extensionOffset).Extensions()
82 size += mi.sizeExtensions(e, opts)
83 }
Damien Neil4ae30bb2019-06-20 10:12:23 -070084 for _, f := range mi.orderedCoderFields {
Damien Neilce413af2019-12-05 16:36:28 -080085 if f.funcs.size == nil {
Damien Neilc37adef2019-04-01 13:49:56 -070086 continue
87 }
Damien Neilce413af2019-12-05 16:36:28 -080088 fptr := p.Apply(f.offset)
89 if f.isPointer && fptr.Elem().IsNil() {
Damien Neilc37adef2019-04-01 13:49:56 -070090 continue
91 }
92 size += f.funcs.size(fptr, f.tagsize, opts)
93 }
94 if mi.unknownOffset.IsValid() {
95 u := *p.Apply(mi.unknownOffset).Bytes()
96 size += len(u)
97 }
98 if mi.sizecacheOffset.IsValid() {
99 atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size))
100 }
101 return size
102}
103
Damien Neil61781dd2020-01-21 13:29:51 -0800104// marshal is protoreflect.Methods.Marshal.
105func (mi *MessageInfo) marshal(m pref.Message, in piface.MarshalInput) (piface.MarshalOutput, error) {
Joe Tsai0f81b382019-07-10 23:14:31 -0700106 var p pointer
107 if ms, ok := m.(*messageState); ok {
108 p = ms.pointer()
109 } else {
110 p = m.(*messageReflectWrapper).pointer()
111 }
Damien Neil61781dd2020-01-21 13:29:51 -0800112 b, err := mi.marshalAppendPointer(in.Buf, p, newMarshalOptions(in.Options))
113 return piface.MarshalOutput{Buf: b}, err
Damien Neilc37adef2019-04-01 13:49:56 -0700114}
115
Joe Tsai4fe96632019-05-22 05:12:36 -0400116func (mi *MessageInfo) marshalAppendPointer(b []byte, p pointer, opts marshalOptions) ([]byte, error) {
Damien Neilc37adef2019-04-01 13:49:56 -0700117 mi.init()
118 if p.IsNil() {
119 return b, nil
120 }
Damien Neilce3384c2019-11-06 13:18:28 -0800121 if flags.ProtoLegacy && mi.isMessageSet {
122 return marshalMessageSet(mi, b, p, opts)
123 }
Damien Neilc37adef2019-04-01 13:49:56 -0700124 var err error
Damien Neilc37adef2019-04-01 13:49:56 -0700125 // The old marshaler encodes extensions at beginning.
126 if mi.extensionOffset.IsValid() {
127 e := p.Apply(mi.extensionOffset).Extensions()
128 // TODO: Special handling for MessageSet?
129 b, err = mi.appendExtensions(b, e, opts)
Damien Neil8c86fc52019-06-19 09:28:29 -0700130 if err != nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700131 return b, err
132 }
133 }
Damien Neil4ae30bb2019-06-20 10:12:23 -0700134 for _, f := range mi.orderedCoderFields {
Damien Neilce413af2019-12-05 16:36:28 -0800135 if f.funcs.marshal == nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700136 continue
137 }
Damien Neilce413af2019-12-05 16:36:28 -0800138 fptr := p.Apply(f.offset)
139 if f.isPointer && fptr.Elem().IsNil() {
Damien Neilc37adef2019-04-01 13:49:56 -0700140 continue
141 }
142 b, err = f.funcs.marshal(b, fptr, f.wiretag, opts)
Damien Neil8c86fc52019-06-19 09:28:29 -0700143 if err != nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700144 return b, err
145 }
146 }
Damien Neilce3384c2019-11-06 13:18:28 -0800147 if mi.unknownOffset.IsValid() && !mi.isMessageSet {
Damien Neilc37adef2019-04-01 13:49:56 -0700148 u := *p.Apply(mi.unknownOffset).Bytes()
149 b = append(b, u...)
150 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700151 return b, nil
Damien Neilc37adef2019-04-01 13:49:56 -0700152}
153
Joe Tsai89d49632019-06-04 16:20:00 -0700154func (mi *MessageInfo) sizeExtensions(ext *map[int32]ExtensionField, opts marshalOptions) (n int) {
Damien Neilc37adef2019-04-01 13:49:56 -0700155 if ext == nil {
156 return 0
157 }
Joe Tsai89d49632019-06-04 16:20:00 -0700158 for _, x := range *ext {
Damien Neil79571e92019-12-09 10:24:36 -0800159 xi := getExtensionFieldInfo(x.Type())
Joe Tsai89d49632019-06-04 16:20:00 -0700160 if xi.funcs.size == nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700161 continue
162 }
Damien Neil68b81c32019-08-22 11:41:32 -0700163 n += xi.funcs.size(x.Value(), xi.tagsize, opts)
Damien Neilc37adef2019-04-01 13:49:56 -0700164 }
165 return n
166}
167
Joe Tsai89d49632019-06-04 16:20:00 -0700168func (mi *MessageInfo) appendExtensions(b []byte, ext *map[int32]ExtensionField, opts marshalOptions) ([]byte, error) {
Damien Neilc37adef2019-04-01 13:49:56 -0700169 if ext == nil {
170 return b, nil
171 }
172
173 switch len(*ext) {
174 case 0:
175 return b, nil
176 case 1:
177 // Fast-path for one extension: Don't bother sorting the keys.
178 var err error
Joe Tsai89d49632019-06-04 16:20:00 -0700179 for _, x := range *ext {
Damien Neil79571e92019-12-09 10:24:36 -0800180 xi := getExtensionFieldInfo(x.Type())
Damien Neil68b81c32019-08-22 11:41:32 -0700181 b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts)
Damien Neilc37adef2019-04-01 13:49:56 -0700182 }
183 return b, err
184 default:
185 // Sort the keys to provide a deterministic encoding.
186 // Not sure this is required, but the old code does it.
187 keys := make([]int, 0, len(*ext))
188 for k := range *ext {
189 keys = append(keys, int(k))
190 }
191 sort.Ints(keys)
192 var err error
Damien Neilc37adef2019-04-01 13:49:56 -0700193 for _, k := range keys {
Joe Tsai89d49632019-06-04 16:20:00 -0700194 x := (*ext)[int32(k)]
Damien Neil79571e92019-12-09 10:24:36 -0800195 xi := getExtensionFieldInfo(x.Type())
Damien Neil68b81c32019-08-22 11:41:32 -0700196 b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts)
Damien Neil8c86fc52019-06-19 09:28:29 -0700197 if err != nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700198 return b, err
199 }
200 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700201 return b, nil
Damien Neilc37adef2019-04-01 13:49:56 -0700202 }
203}