blob: ec08ed61bc8a224e2ff6bd78d714469c6e262575 [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"
Damien Neilc37adef2019-04-01 13:49:56 -070013 piface "google.golang.org/protobuf/runtime/protoiface"
14)
15
Damien Neil466dd772020-02-14 14:49:35 -080016type marshalOptions struct {
17 flags piface.MarshalInputFlags
18}
Damien Neilc37adef2019-04-01 13:49:56 -070019
20func (o marshalOptions) Options() proto.MarshalOptions {
21 return proto.MarshalOptions{
Damien Neile91877d2019-06-27 10:54:42 -070022 AllowPartial: true,
Damien Neilc37adef2019-04-01 13:49:56 -070023 Deterministic: o.Deterministic(),
24 UseCachedSize: o.UseCachedSize(),
25 }
26}
27
Damien Neil466dd772020-02-14 14:49:35 -080028func (o marshalOptions) Deterministic() bool { return o.flags&piface.MarshalDeterministic != 0 }
29func (o marshalOptions) UseCachedSize() bool { return o.flags&piface.MarshalUseCachedSize != 0 }
Damien Neilc37adef2019-04-01 13:49:56 -070030
31// size is protoreflect.Methods.Size.
Damien Neil466dd772020-02-14 14:49:35 -080032func (mi *MessageInfo) size(in piface.SizeInput) piface.SizeOutput {
Joe Tsai0f81b382019-07-10 23:14:31 -070033 var p pointer
Damien Neil466dd772020-02-14 14:49:35 -080034 if ms, ok := in.Message.(*messageState); ok {
Joe Tsai0f81b382019-07-10 23:14:31 -070035 p = ms.pointer()
36 } else {
Damien Neil466dd772020-02-14 14:49:35 -080037 p = in.Message.(*messageReflectWrapper).pointer()
Joe Tsai0f81b382019-07-10 23:14:31 -070038 }
Damien Neil466dd772020-02-14 14:49:35 -080039 size := mi.sizePointer(p, marshalOptions{
40 flags: in.Flags,
41 })
42 return piface.SizeOutput{Size: size}
Damien Neilc37adef2019-04-01 13:49:56 -070043}
44
Joe Tsai4fe96632019-05-22 05:12:36 -040045func (mi *MessageInfo) sizePointer(p pointer, opts marshalOptions) (size int) {
Damien Neilc37adef2019-04-01 13:49:56 -070046 mi.init()
47 if p.IsNil() {
48 return 0
49 }
50 if opts.UseCachedSize() && mi.sizecacheOffset.IsValid() {
51 return int(atomic.LoadInt32(p.Apply(mi.sizecacheOffset).Int32()))
52 }
53 return mi.sizePointerSlow(p, opts)
54}
55
Joe Tsai4fe96632019-05-22 05:12:36 -040056func (mi *MessageInfo) sizePointerSlow(p pointer, opts marshalOptions) (size int) {
Damien Neilce3384c2019-11-06 13:18:28 -080057 if flags.ProtoLegacy && mi.isMessageSet {
58 size = sizeMessageSet(mi, p, opts)
59 if mi.sizecacheOffset.IsValid() {
60 atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size))
61 }
62 return size
63 }
Damien Neilc37adef2019-04-01 13:49:56 -070064 if mi.extensionOffset.IsValid() {
65 e := p.Apply(mi.extensionOffset).Extensions()
66 size += mi.sizeExtensions(e, opts)
67 }
Damien Neil4ae30bb2019-06-20 10:12:23 -070068 for _, f := range mi.orderedCoderFields {
Damien Neilce413af2019-12-05 16:36:28 -080069 if f.funcs.size == nil {
Damien Neilc37adef2019-04-01 13:49:56 -070070 continue
71 }
Damien Neilce413af2019-12-05 16:36:28 -080072 fptr := p.Apply(f.offset)
73 if f.isPointer && fptr.Elem().IsNil() {
Damien Neilc37adef2019-04-01 13:49:56 -070074 continue
75 }
Damien Neil316febd2020-02-09 12:26:50 -080076 size += f.funcs.size(fptr, f, opts)
Damien Neilc37adef2019-04-01 13:49:56 -070077 }
78 if mi.unknownOffset.IsValid() {
79 u := *p.Apply(mi.unknownOffset).Bytes()
80 size += len(u)
81 }
82 if mi.sizecacheOffset.IsValid() {
83 atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size))
84 }
85 return size
86}
87
Damien Neil61781dd2020-01-21 13:29:51 -080088// marshal is protoreflect.Methods.Marshal.
Damien Neil466dd772020-02-14 14:49:35 -080089func (mi *MessageInfo) marshal(in piface.MarshalInput) (out piface.MarshalOutput, err error) {
Joe Tsai0f81b382019-07-10 23:14:31 -070090 var p pointer
Damien Neil466dd772020-02-14 14:49:35 -080091 if ms, ok := in.Message.(*messageState); ok {
Joe Tsai0f81b382019-07-10 23:14:31 -070092 p = ms.pointer()
93 } else {
Damien Neil466dd772020-02-14 14:49:35 -080094 p = in.Message.(*messageReflectWrapper).pointer()
Joe Tsai0f81b382019-07-10 23:14:31 -070095 }
Damien Neil466dd772020-02-14 14:49:35 -080096 b, err := mi.marshalAppendPointer(in.Buf, p, marshalOptions{
97 flags: in.Flags,
98 })
Damien Neil61781dd2020-01-21 13:29:51 -080099 return piface.MarshalOutput{Buf: b}, err
Damien Neilc37adef2019-04-01 13:49:56 -0700100}
101
Joe Tsai4fe96632019-05-22 05:12:36 -0400102func (mi *MessageInfo) marshalAppendPointer(b []byte, p pointer, opts marshalOptions) ([]byte, error) {
Damien Neilc37adef2019-04-01 13:49:56 -0700103 mi.init()
104 if p.IsNil() {
105 return b, nil
106 }
Damien Neilce3384c2019-11-06 13:18:28 -0800107 if flags.ProtoLegacy && mi.isMessageSet {
108 return marshalMessageSet(mi, b, p, opts)
109 }
Damien Neilc37adef2019-04-01 13:49:56 -0700110 var err error
Damien Neilc37adef2019-04-01 13:49:56 -0700111 // The old marshaler encodes extensions at beginning.
112 if mi.extensionOffset.IsValid() {
113 e := p.Apply(mi.extensionOffset).Extensions()
114 // TODO: Special handling for MessageSet?
115 b, err = mi.appendExtensions(b, e, opts)
Damien Neil8c86fc52019-06-19 09:28:29 -0700116 if err != nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700117 return b, err
118 }
119 }
Damien Neil4ae30bb2019-06-20 10:12:23 -0700120 for _, f := range mi.orderedCoderFields {
Damien Neilce413af2019-12-05 16:36:28 -0800121 if f.funcs.marshal == nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700122 continue
123 }
Damien Neilce413af2019-12-05 16:36:28 -0800124 fptr := p.Apply(f.offset)
125 if f.isPointer && fptr.Elem().IsNil() {
Damien Neilc37adef2019-04-01 13:49:56 -0700126 continue
127 }
Damien Neil316febd2020-02-09 12:26:50 -0800128 b, err = f.funcs.marshal(b, fptr, f, opts)
Damien Neil8c86fc52019-06-19 09:28:29 -0700129 if err != nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700130 return b, err
131 }
132 }
Damien Neilce3384c2019-11-06 13:18:28 -0800133 if mi.unknownOffset.IsValid() && !mi.isMessageSet {
Damien Neilc37adef2019-04-01 13:49:56 -0700134 u := *p.Apply(mi.unknownOffset).Bytes()
135 b = append(b, u...)
136 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700137 return b, nil
Damien Neilc37adef2019-04-01 13:49:56 -0700138}
139
Joe Tsai89d49632019-06-04 16:20:00 -0700140func (mi *MessageInfo) sizeExtensions(ext *map[int32]ExtensionField, opts marshalOptions) (n int) {
Damien Neilc37adef2019-04-01 13:49:56 -0700141 if ext == nil {
142 return 0
143 }
Joe Tsai89d49632019-06-04 16:20:00 -0700144 for _, x := range *ext {
Damien Neil79571e92019-12-09 10:24:36 -0800145 xi := getExtensionFieldInfo(x.Type())
Joe Tsai89d49632019-06-04 16:20:00 -0700146 if xi.funcs.size == nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700147 continue
148 }
Damien Neil68b81c32019-08-22 11:41:32 -0700149 n += xi.funcs.size(x.Value(), xi.tagsize, opts)
Damien Neilc37adef2019-04-01 13:49:56 -0700150 }
151 return n
152}
153
Joe Tsai89d49632019-06-04 16:20:00 -0700154func (mi *MessageInfo) appendExtensions(b []byte, ext *map[int32]ExtensionField, opts marshalOptions) ([]byte, error) {
Damien Neilc37adef2019-04-01 13:49:56 -0700155 if ext == nil {
156 return b, nil
157 }
158
159 switch len(*ext) {
160 case 0:
161 return b, nil
162 case 1:
163 // Fast-path for one extension: Don't bother sorting the keys.
164 var err error
Joe Tsai89d49632019-06-04 16:20:00 -0700165 for _, x := range *ext {
Damien Neil79571e92019-12-09 10:24:36 -0800166 xi := getExtensionFieldInfo(x.Type())
Damien Neil68b81c32019-08-22 11:41:32 -0700167 b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts)
Damien Neilc37adef2019-04-01 13:49:56 -0700168 }
169 return b, err
170 default:
171 // Sort the keys to provide a deterministic encoding.
172 // Not sure this is required, but the old code does it.
173 keys := make([]int, 0, len(*ext))
174 for k := range *ext {
175 keys = append(keys, int(k))
176 }
177 sort.Ints(keys)
178 var err error
Damien Neilc37adef2019-04-01 13:49:56 -0700179 for _, k := range keys {
Joe Tsai89d49632019-06-04 16:20:00 -0700180 x := (*ext)[int32(k)]
Damien Neil79571e92019-12-09 10:24:36 -0800181 xi := getExtensionFieldInfo(x.Type())
Damien Neil68b81c32019-08-22 11:41:32 -0700182 b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts)
Damien Neil8c86fc52019-06-19 09:28:29 -0700183 if err != nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700184 return b, err
185 }
186 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700187 return b, nil
Damien Neilc37adef2019-04-01 13:49:56 -0700188 }
189}