blob: 892377463dd2c19891c7ac07ae37e0d73cbc2e4c [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 Neil524c6062020-01-28 13:32:01 -080017type marshalOptions piface.MarshalOptions
Damien Neilc37adef2019-04-01 13:49:56 -070018
19func (o marshalOptions) Options() proto.MarshalOptions {
20 return proto.MarshalOptions{
Damien Neile91877d2019-06-27 10:54:42 -070021 AllowPartial: true,
Damien Neilc37adef2019-04-01 13:49:56 -070022 Deterministic: o.Deterministic(),
23 UseCachedSize: o.UseCachedSize(),
24 }
25}
26
Damien Neil524c6062020-01-28 13:32:01 -080027func (o marshalOptions) Deterministic() bool { return o.Flags&piface.MarshalDeterministic != 0 }
28func (o marshalOptions) UseCachedSize() bool { return o.Flags&piface.MarshalUseCachedSize != 0 }
Damien Neilc37adef2019-04-01 13:49:56 -070029
30// size is protoreflect.Methods.Size.
Joe Tsaif8b855d2019-07-12 13:37:59 -070031func (mi *MessageInfo) size(m pref.Message, opts piface.MarshalOptions) (size int) {
Joe Tsai0f81b382019-07-10 23:14:31 -070032 var p pointer
33 if ms, ok := m.(*messageState); ok {
34 p = ms.pointer()
35 } else {
36 p = m.(*messageReflectWrapper).pointer()
37 }
Damien Neil524c6062020-01-28 13:32:01 -080038 return mi.sizePointer(p, marshalOptions(opts))
Damien Neilc37adef2019-04-01 13:49:56 -070039}
40
Joe Tsai4fe96632019-05-22 05:12:36 -040041func (mi *MessageInfo) sizePointer(p pointer, opts marshalOptions) (size int) {
Damien Neilc37adef2019-04-01 13:49:56 -070042 mi.init()
43 if p.IsNil() {
44 return 0
45 }
46 if opts.UseCachedSize() && mi.sizecacheOffset.IsValid() {
47 return int(atomic.LoadInt32(p.Apply(mi.sizecacheOffset).Int32()))
48 }
49 return mi.sizePointerSlow(p, opts)
50}
51
Joe Tsai4fe96632019-05-22 05:12:36 -040052func (mi *MessageInfo) sizePointerSlow(p pointer, opts marshalOptions) (size int) {
Damien Neilce3384c2019-11-06 13:18:28 -080053 if flags.ProtoLegacy && mi.isMessageSet {
54 size = sizeMessageSet(mi, p, opts)
55 if mi.sizecacheOffset.IsValid() {
56 atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size))
57 }
58 return size
59 }
Damien Neilc37adef2019-04-01 13:49:56 -070060 if mi.extensionOffset.IsValid() {
61 e := p.Apply(mi.extensionOffset).Extensions()
62 size += mi.sizeExtensions(e, opts)
63 }
Damien Neil4ae30bb2019-06-20 10:12:23 -070064 for _, f := range mi.orderedCoderFields {
Damien Neilce413af2019-12-05 16:36:28 -080065 if f.funcs.size == nil {
Damien Neilc37adef2019-04-01 13:49:56 -070066 continue
67 }
Damien Neilce413af2019-12-05 16:36:28 -080068 fptr := p.Apply(f.offset)
69 if f.isPointer && fptr.Elem().IsNil() {
Damien Neilc37adef2019-04-01 13:49:56 -070070 continue
71 }
Damien Neil316febd2020-02-09 12:26:50 -080072 size += f.funcs.size(fptr, f, opts)
Damien Neilc37adef2019-04-01 13:49:56 -070073 }
74 if mi.unknownOffset.IsValid() {
75 u := *p.Apply(mi.unknownOffset).Bytes()
76 size += len(u)
77 }
78 if mi.sizecacheOffset.IsValid() {
79 atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size))
80 }
81 return size
82}
83
Damien Neil61781dd2020-01-21 13:29:51 -080084// marshal is protoreflect.Methods.Marshal.
Damien Neild30e5612020-01-22 10:28:16 -080085func (mi *MessageInfo) marshal(m pref.Message, in piface.MarshalInput, opts piface.MarshalOptions) (piface.MarshalOutput, error) {
Joe Tsai0f81b382019-07-10 23:14:31 -070086 var p pointer
87 if ms, ok := m.(*messageState); ok {
88 p = ms.pointer()
89 } else {
90 p = m.(*messageReflectWrapper).pointer()
91 }
Damien Neil524c6062020-01-28 13:32:01 -080092 b, err := mi.marshalAppendPointer(in.Buf, p, marshalOptions(opts))
Damien Neil61781dd2020-01-21 13:29:51 -080093 return piface.MarshalOutput{Buf: b}, err
Damien Neilc37adef2019-04-01 13:49:56 -070094}
95
Joe Tsai4fe96632019-05-22 05:12:36 -040096func (mi *MessageInfo) marshalAppendPointer(b []byte, p pointer, opts marshalOptions) ([]byte, error) {
Damien Neilc37adef2019-04-01 13:49:56 -070097 mi.init()
98 if p.IsNil() {
99 return b, nil
100 }
Damien Neilce3384c2019-11-06 13:18:28 -0800101 if flags.ProtoLegacy && mi.isMessageSet {
102 return marshalMessageSet(mi, b, p, opts)
103 }
Damien Neilc37adef2019-04-01 13:49:56 -0700104 var err error
Damien Neilc37adef2019-04-01 13:49:56 -0700105 // The old marshaler encodes extensions at beginning.
106 if mi.extensionOffset.IsValid() {
107 e := p.Apply(mi.extensionOffset).Extensions()
108 // TODO: Special handling for MessageSet?
109 b, err = mi.appendExtensions(b, e, opts)
Damien Neil8c86fc52019-06-19 09:28:29 -0700110 if err != nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700111 return b, err
112 }
113 }
Damien Neil4ae30bb2019-06-20 10:12:23 -0700114 for _, f := range mi.orderedCoderFields {
Damien Neilce413af2019-12-05 16:36:28 -0800115 if f.funcs.marshal == nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700116 continue
117 }
Damien Neilce413af2019-12-05 16:36:28 -0800118 fptr := p.Apply(f.offset)
119 if f.isPointer && fptr.Elem().IsNil() {
Damien Neilc37adef2019-04-01 13:49:56 -0700120 continue
121 }
Damien Neil316febd2020-02-09 12:26:50 -0800122 b, err = f.funcs.marshal(b, fptr, f, opts)
Damien Neil8c86fc52019-06-19 09:28:29 -0700123 if err != nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700124 return b, err
125 }
126 }
Damien Neilce3384c2019-11-06 13:18:28 -0800127 if mi.unknownOffset.IsValid() && !mi.isMessageSet {
Damien Neilc37adef2019-04-01 13:49:56 -0700128 u := *p.Apply(mi.unknownOffset).Bytes()
129 b = append(b, u...)
130 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700131 return b, nil
Damien Neilc37adef2019-04-01 13:49:56 -0700132}
133
Joe Tsai89d49632019-06-04 16:20:00 -0700134func (mi *MessageInfo) sizeExtensions(ext *map[int32]ExtensionField, opts marshalOptions) (n int) {
Damien Neilc37adef2019-04-01 13:49:56 -0700135 if ext == nil {
136 return 0
137 }
Joe Tsai89d49632019-06-04 16:20:00 -0700138 for _, x := range *ext {
Damien Neil79571e92019-12-09 10:24:36 -0800139 xi := getExtensionFieldInfo(x.Type())
Joe Tsai89d49632019-06-04 16:20:00 -0700140 if xi.funcs.size == nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700141 continue
142 }
Damien Neil68b81c32019-08-22 11:41:32 -0700143 n += xi.funcs.size(x.Value(), xi.tagsize, opts)
Damien Neilc37adef2019-04-01 13:49:56 -0700144 }
145 return n
146}
147
Joe Tsai89d49632019-06-04 16:20:00 -0700148func (mi *MessageInfo) appendExtensions(b []byte, ext *map[int32]ExtensionField, opts marshalOptions) ([]byte, error) {
Damien Neilc37adef2019-04-01 13:49:56 -0700149 if ext == nil {
150 return b, nil
151 }
152
153 switch len(*ext) {
154 case 0:
155 return b, nil
156 case 1:
157 // Fast-path for one extension: Don't bother sorting the keys.
158 var err error
Joe Tsai89d49632019-06-04 16:20:00 -0700159 for _, x := range *ext {
Damien Neil79571e92019-12-09 10:24:36 -0800160 xi := getExtensionFieldInfo(x.Type())
Damien Neil68b81c32019-08-22 11:41:32 -0700161 b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts)
Damien Neilc37adef2019-04-01 13:49:56 -0700162 }
163 return b, err
164 default:
165 // Sort the keys to provide a deterministic encoding.
166 // Not sure this is required, but the old code does it.
167 keys := make([]int, 0, len(*ext))
168 for k := range *ext {
169 keys = append(keys, int(k))
170 }
171 sort.Ints(keys)
172 var err error
Damien Neilc37adef2019-04-01 13:49:56 -0700173 for _, k := range keys {
Joe Tsai89d49632019-06-04 16:20:00 -0700174 x := (*ext)[int32(k)]
Damien Neil79571e92019-12-09 10:24:36 -0800175 xi := getExtensionFieldInfo(x.Type())
Damien Neil68b81c32019-08-22 11:41:32 -0700176 b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts)
Damien Neil8c86fc52019-06-19 09:28:29 -0700177 if err != nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700178 return b, err
179 }
180 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700181 return b, nil
Damien Neilc37adef2019-04-01 13:49:56 -0700182 }
183}