1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsenpackage impl 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "math" 9*1c12ee1eSDan Willemsen "sort" 10*1c12ee1eSDan Willemsen "sync/atomic" 11*1c12ee1eSDan Willemsen 12*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/flags" 13*1c12ee1eSDan Willemsen proto "google.golang.org/protobuf/proto" 14*1c12ee1eSDan Willemsen piface "google.golang.org/protobuf/runtime/protoiface" 15*1c12ee1eSDan Willemsen) 16*1c12ee1eSDan Willemsen 17*1c12ee1eSDan Willemsentype marshalOptions struct { 18*1c12ee1eSDan Willemsen flags piface.MarshalInputFlags 19*1c12ee1eSDan Willemsen} 20*1c12ee1eSDan Willemsen 21*1c12ee1eSDan Willemsenfunc (o marshalOptions) Options() proto.MarshalOptions { 22*1c12ee1eSDan Willemsen return proto.MarshalOptions{ 23*1c12ee1eSDan Willemsen AllowPartial: true, 24*1c12ee1eSDan Willemsen Deterministic: o.Deterministic(), 25*1c12ee1eSDan Willemsen UseCachedSize: o.UseCachedSize(), 26*1c12ee1eSDan Willemsen } 27*1c12ee1eSDan Willemsen} 28*1c12ee1eSDan Willemsen 29*1c12ee1eSDan Willemsenfunc (o marshalOptions) Deterministic() bool { return o.flags&piface.MarshalDeterministic != 0 } 30*1c12ee1eSDan Willemsenfunc (o marshalOptions) UseCachedSize() bool { return o.flags&piface.MarshalUseCachedSize != 0 } 31*1c12ee1eSDan Willemsen 32*1c12ee1eSDan Willemsen// size is protoreflect.Methods.Size. 33*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) size(in piface.SizeInput) piface.SizeOutput { 34*1c12ee1eSDan Willemsen var p pointer 35*1c12ee1eSDan Willemsen if ms, ok := in.Message.(*messageState); ok { 36*1c12ee1eSDan Willemsen p = ms.pointer() 37*1c12ee1eSDan Willemsen } else { 38*1c12ee1eSDan Willemsen p = in.Message.(*messageReflectWrapper).pointer() 39*1c12ee1eSDan Willemsen } 40*1c12ee1eSDan Willemsen size := mi.sizePointer(p, marshalOptions{ 41*1c12ee1eSDan Willemsen flags: in.Flags, 42*1c12ee1eSDan Willemsen }) 43*1c12ee1eSDan Willemsen return piface.SizeOutput{Size: size} 44*1c12ee1eSDan Willemsen} 45*1c12ee1eSDan Willemsen 46*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) sizePointer(p pointer, opts marshalOptions) (size int) { 47*1c12ee1eSDan Willemsen mi.init() 48*1c12ee1eSDan Willemsen if p.IsNil() { 49*1c12ee1eSDan Willemsen return 0 50*1c12ee1eSDan Willemsen } 51*1c12ee1eSDan Willemsen if opts.UseCachedSize() && mi.sizecacheOffset.IsValid() { 52*1c12ee1eSDan Willemsen if size := atomic.LoadInt32(p.Apply(mi.sizecacheOffset).Int32()); size >= 0 { 53*1c12ee1eSDan Willemsen return int(size) 54*1c12ee1eSDan Willemsen } 55*1c12ee1eSDan Willemsen } 56*1c12ee1eSDan Willemsen return mi.sizePointerSlow(p, opts) 57*1c12ee1eSDan Willemsen} 58*1c12ee1eSDan Willemsen 59*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) sizePointerSlow(p pointer, opts marshalOptions) (size int) { 60*1c12ee1eSDan Willemsen if flags.ProtoLegacy && mi.isMessageSet { 61*1c12ee1eSDan Willemsen size = sizeMessageSet(mi, p, opts) 62*1c12ee1eSDan Willemsen if mi.sizecacheOffset.IsValid() { 63*1c12ee1eSDan Willemsen atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size)) 64*1c12ee1eSDan Willemsen } 65*1c12ee1eSDan Willemsen return size 66*1c12ee1eSDan Willemsen } 67*1c12ee1eSDan Willemsen if mi.extensionOffset.IsValid() { 68*1c12ee1eSDan Willemsen e := p.Apply(mi.extensionOffset).Extensions() 69*1c12ee1eSDan Willemsen size += mi.sizeExtensions(e, opts) 70*1c12ee1eSDan Willemsen } 71*1c12ee1eSDan Willemsen for _, f := range mi.orderedCoderFields { 72*1c12ee1eSDan Willemsen if f.funcs.size == nil { 73*1c12ee1eSDan Willemsen continue 74*1c12ee1eSDan Willemsen } 75*1c12ee1eSDan Willemsen fptr := p.Apply(f.offset) 76*1c12ee1eSDan Willemsen if f.isPointer && fptr.Elem().IsNil() { 77*1c12ee1eSDan Willemsen continue 78*1c12ee1eSDan Willemsen } 79*1c12ee1eSDan Willemsen size += f.funcs.size(fptr, f, opts) 80*1c12ee1eSDan Willemsen } 81*1c12ee1eSDan Willemsen if mi.unknownOffset.IsValid() { 82*1c12ee1eSDan Willemsen if u := mi.getUnknownBytes(p); u != nil { 83*1c12ee1eSDan Willemsen size += len(*u) 84*1c12ee1eSDan Willemsen } 85*1c12ee1eSDan Willemsen } 86*1c12ee1eSDan Willemsen if mi.sizecacheOffset.IsValid() { 87*1c12ee1eSDan Willemsen if size > math.MaxInt32 { 88*1c12ee1eSDan Willemsen // The size is too large for the int32 sizecache field. 89*1c12ee1eSDan Willemsen // We will need to recompute the size when encoding; 90*1c12ee1eSDan Willemsen // unfortunately expensive, but better than invalid output. 91*1c12ee1eSDan Willemsen atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), -1) 92*1c12ee1eSDan Willemsen } else { 93*1c12ee1eSDan Willemsen atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size)) 94*1c12ee1eSDan Willemsen } 95*1c12ee1eSDan Willemsen } 96*1c12ee1eSDan Willemsen return size 97*1c12ee1eSDan Willemsen} 98*1c12ee1eSDan Willemsen 99*1c12ee1eSDan Willemsen// marshal is protoreflect.Methods.Marshal. 100*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) marshal(in piface.MarshalInput) (out piface.MarshalOutput, err error) { 101*1c12ee1eSDan Willemsen var p pointer 102*1c12ee1eSDan Willemsen if ms, ok := in.Message.(*messageState); ok { 103*1c12ee1eSDan Willemsen p = ms.pointer() 104*1c12ee1eSDan Willemsen } else { 105*1c12ee1eSDan Willemsen p = in.Message.(*messageReflectWrapper).pointer() 106*1c12ee1eSDan Willemsen } 107*1c12ee1eSDan Willemsen b, err := mi.marshalAppendPointer(in.Buf, p, marshalOptions{ 108*1c12ee1eSDan Willemsen flags: in.Flags, 109*1c12ee1eSDan Willemsen }) 110*1c12ee1eSDan Willemsen return piface.MarshalOutput{Buf: b}, err 111*1c12ee1eSDan Willemsen} 112*1c12ee1eSDan Willemsen 113*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) marshalAppendPointer(b []byte, p pointer, opts marshalOptions) ([]byte, error) { 114*1c12ee1eSDan Willemsen mi.init() 115*1c12ee1eSDan Willemsen if p.IsNil() { 116*1c12ee1eSDan Willemsen return b, nil 117*1c12ee1eSDan Willemsen } 118*1c12ee1eSDan Willemsen if flags.ProtoLegacy && mi.isMessageSet { 119*1c12ee1eSDan Willemsen return marshalMessageSet(mi, b, p, opts) 120*1c12ee1eSDan Willemsen } 121*1c12ee1eSDan Willemsen var err error 122*1c12ee1eSDan Willemsen // The old marshaler encodes extensions at beginning. 123*1c12ee1eSDan Willemsen if mi.extensionOffset.IsValid() { 124*1c12ee1eSDan Willemsen e := p.Apply(mi.extensionOffset).Extensions() 125*1c12ee1eSDan Willemsen // TODO: Special handling for MessageSet? 126*1c12ee1eSDan Willemsen b, err = mi.appendExtensions(b, e, opts) 127*1c12ee1eSDan Willemsen if err != nil { 128*1c12ee1eSDan Willemsen return b, err 129*1c12ee1eSDan Willemsen } 130*1c12ee1eSDan Willemsen } 131*1c12ee1eSDan Willemsen for _, f := range mi.orderedCoderFields { 132*1c12ee1eSDan Willemsen if f.funcs.marshal == nil { 133*1c12ee1eSDan Willemsen continue 134*1c12ee1eSDan Willemsen } 135*1c12ee1eSDan Willemsen fptr := p.Apply(f.offset) 136*1c12ee1eSDan Willemsen if f.isPointer && fptr.Elem().IsNil() { 137*1c12ee1eSDan Willemsen continue 138*1c12ee1eSDan Willemsen } 139*1c12ee1eSDan Willemsen b, err = f.funcs.marshal(b, fptr, f, opts) 140*1c12ee1eSDan Willemsen if err != nil { 141*1c12ee1eSDan Willemsen return b, err 142*1c12ee1eSDan Willemsen } 143*1c12ee1eSDan Willemsen } 144*1c12ee1eSDan Willemsen if mi.unknownOffset.IsValid() && !mi.isMessageSet { 145*1c12ee1eSDan Willemsen if u := mi.getUnknownBytes(p); u != nil { 146*1c12ee1eSDan Willemsen b = append(b, (*u)...) 147*1c12ee1eSDan Willemsen } 148*1c12ee1eSDan Willemsen } 149*1c12ee1eSDan Willemsen return b, nil 150*1c12ee1eSDan Willemsen} 151*1c12ee1eSDan Willemsen 152*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) sizeExtensions(ext *map[int32]ExtensionField, opts marshalOptions) (n int) { 153*1c12ee1eSDan Willemsen if ext == nil { 154*1c12ee1eSDan Willemsen return 0 155*1c12ee1eSDan Willemsen } 156*1c12ee1eSDan Willemsen for _, x := range *ext { 157*1c12ee1eSDan Willemsen xi := getExtensionFieldInfo(x.Type()) 158*1c12ee1eSDan Willemsen if xi.funcs.size == nil { 159*1c12ee1eSDan Willemsen continue 160*1c12ee1eSDan Willemsen } 161*1c12ee1eSDan Willemsen n += xi.funcs.size(x.Value(), xi.tagsize, opts) 162*1c12ee1eSDan Willemsen } 163*1c12ee1eSDan Willemsen return n 164*1c12ee1eSDan Willemsen} 165*1c12ee1eSDan Willemsen 166*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) appendExtensions(b []byte, ext *map[int32]ExtensionField, opts marshalOptions) ([]byte, error) { 167*1c12ee1eSDan Willemsen if ext == nil { 168*1c12ee1eSDan Willemsen return b, nil 169*1c12ee1eSDan Willemsen } 170*1c12ee1eSDan Willemsen 171*1c12ee1eSDan Willemsen switch len(*ext) { 172*1c12ee1eSDan Willemsen case 0: 173*1c12ee1eSDan Willemsen return b, nil 174*1c12ee1eSDan Willemsen case 1: 175*1c12ee1eSDan Willemsen // Fast-path for one extension: Don't bother sorting the keys. 176*1c12ee1eSDan Willemsen var err error 177*1c12ee1eSDan Willemsen for _, x := range *ext { 178*1c12ee1eSDan Willemsen xi := getExtensionFieldInfo(x.Type()) 179*1c12ee1eSDan Willemsen b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts) 180*1c12ee1eSDan Willemsen } 181*1c12ee1eSDan Willemsen return b, err 182*1c12ee1eSDan Willemsen default: 183*1c12ee1eSDan Willemsen // Sort the keys to provide a deterministic encoding. 184*1c12ee1eSDan Willemsen // Not sure this is required, but the old code does it. 185*1c12ee1eSDan Willemsen keys := make([]int, 0, len(*ext)) 186*1c12ee1eSDan Willemsen for k := range *ext { 187*1c12ee1eSDan Willemsen keys = append(keys, int(k)) 188*1c12ee1eSDan Willemsen } 189*1c12ee1eSDan Willemsen sort.Ints(keys) 190*1c12ee1eSDan Willemsen var err error 191*1c12ee1eSDan Willemsen for _, k := range keys { 192*1c12ee1eSDan Willemsen x := (*ext)[int32(k)] 193*1c12ee1eSDan Willemsen xi := getExtensionFieldInfo(x.Type()) 194*1c12ee1eSDan Willemsen b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts) 195*1c12ee1eSDan Willemsen if err != nil { 196*1c12ee1eSDan Willemsen return b, err 197*1c12ee1eSDan Willemsen } 198*1c12ee1eSDan Willemsen } 199*1c12ee1eSDan Willemsen return b, nil 200*1c12ee1eSDan Willemsen } 201*1c12ee1eSDan Willemsen} 202