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 proto 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "google.golang.org/protobuf/encoding/protowire" 9*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/encoding/messageset" 10*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 11*1c12ee1eSDan Willemsen "google.golang.org/protobuf/runtime/protoiface" 12*1c12ee1eSDan Willemsen) 13*1c12ee1eSDan Willemsen 14*1c12ee1eSDan Willemsen// Size returns the size in bytes of the wire-format encoding of m. 15*1c12ee1eSDan Willemsenfunc Size(m Message) int { 16*1c12ee1eSDan Willemsen return MarshalOptions{}.Size(m) 17*1c12ee1eSDan Willemsen} 18*1c12ee1eSDan Willemsen 19*1c12ee1eSDan Willemsen// Size returns the size in bytes of the wire-format encoding of m. 20*1c12ee1eSDan Willemsenfunc (o MarshalOptions) Size(m Message) int { 21*1c12ee1eSDan Willemsen // Treat a nil message interface as an empty message; nothing to output. 22*1c12ee1eSDan Willemsen if m == nil { 23*1c12ee1eSDan Willemsen return 0 24*1c12ee1eSDan Willemsen } 25*1c12ee1eSDan Willemsen 26*1c12ee1eSDan Willemsen return o.size(m.ProtoReflect()) 27*1c12ee1eSDan Willemsen} 28*1c12ee1eSDan Willemsen 29*1c12ee1eSDan Willemsen// size is a centralized function that all size operations go through. 30*1c12ee1eSDan Willemsen// For profiling purposes, avoid changing the name of this function or 31*1c12ee1eSDan Willemsen// introducing other code paths for size that do not go through this. 32*1c12ee1eSDan Willemsenfunc (o MarshalOptions) size(m protoreflect.Message) (size int) { 33*1c12ee1eSDan Willemsen methods := protoMethods(m) 34*1c12ee1eSDan Willemsen if methods != nil && methods.Size != nil { 35*1c12ee1eSDan Willemsen out := methods.Size(protoiface.SizeInput{ 36*1c12ee1eSDan Willemsen Message: m, 37*1c12ee1eSDan Willemsen }) 38*1c12ee1eSDan Willemsen return out.Size 39*1c12ee1eSDan Willemsen } 40*1c12ee1eSDan Willemsen if methods != nil && methods.Marshal != nil { 41*1c12ee1eSDan Willemsen // This is not efficient, but we don't have any choice. 42*1c12ee1eSDan Willemsen // This case is mainly used for legacy types with a Marshal method. 43*1c12ee1eSDan Willemsen out, _ := methods.Marshal(protoiface.MarshalInput{ 44*1c12ee1eSDan Willemsen Message: m, 45*1c12ee1eSDan Willemsen }) 46*1c12ee1eSDan Willemsen return len(out.Buf) 47*1c12ee1eSDan Willemsen } 48*1c12ee1eSDan Willemsen return o.sizeMessageSlow(m) 49*1c12ee1eSDan Willemsen} 50*1c12ee1eSDan Willemsen 51*1c12ee1eSDan Willemsenfunc (o MarshalOptions) sizeMessageSlow(m protoreflect.Message) (size int) { 52*1c12ee1eSDan Willemsen if messageset.IsMessageSet(m.Descriptor()) { 53*1c12ee1eSDan Willemsen return o.sizeMessageSet(m) 54*1c12ee1eSDan Willemsen } 55*1c12ee1eSDan Willemsen m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { 56*1c12ee1eSDan Willemsen size += o.sizeField(fd, v) 57*1c12ee1eSDan Willemsen return true 58*1c12ee1eSDan Willemsen }) 59*1c12ee1eSDan Willemsen size += len(m.GetUnknown()) 60*1c12ee1eSDan Willemsen return size 61*1c12ee1eSDan Willemsen} 62*1c12ee1eSDan Willemsen 63*1c12ee1eSDan Willemsenfunc (o MarshalOptions) sizeField(fd protoreflect.FieldDescriptor, value protoreflect.Value) (size int) { 64*1c12ee1eSDan Willemsen num := fd.Number() 65*1c12ee1eSDan Willemsen switch { 66*1c12ee1eSDan Willemsen case fd.IsList(): 67*1c12ee1eSDan Willemsen return o.sizeList(num, fd, value.List()) 68*1c12ee1eSDan Willemsen case fd.IsMap(): 69*1c12ee1eSDan Willemsen return o.sizeMap(num, fd, value.Map()) 70*1c12ee1eSDan Willemsen default: 71*1c12ee1eSDan Willemsen return protowire.SizeTag(num) + o.sizeSingular(num, fd.Kind(), value) 72*1c12ee1eSDan Willemsen } 73*1c12ee1eSDan Willemsen} 74*1c12ee1eSDan Willemsen 75*1c12ee1eSDan Willemsenfunc (o MarshalOptions) sizeList(num protowire.Number, fd protoreflect.FieldDescriptor, list protoreflect.List) (size int) { 76*1c12ee1eSDan Willemsen if fd.IsPacked() && list.Len() > 0 { 77*1c12ee1eSDan Willemsen content := 0 78*1c12ee1eSDan Willemsen for i, llen := 0, list.Len(); i < llen; i++ { 79*1c12ee1eSDan Willemsen content += o.sizeSingular(num, fd.Kind(), list.Get(i)) 80*1c12ee1eSDan Willemsen } 81*1c12ee1eSDan Willemsen return protowire.SizeTag(num) + protowire.SizeBytes(content) 82*1c12ee1eSDan Willemsen } 83*1c12ee1eSDan Willemsen 84*1c12ee1eSDan Willemsen for i, llen := 0, list.Len(); i < llen; i++ { 85*1c12ee1eSDan Willemsen size += protowire.SizeTag(num) + o.sizeSingular(num, fd.Kind(), list.Get(i)) 86*1c12ee1eSDan Willemsen } 87*1c12ee1eSDan Willemsen return size 88*1c12ee1eSDan Willemsen} 89*1c12ee1eSDan Willemsen 90*1c12ee1eSDan Willemsenfunc (o MarshalOptions) sizeMap(num protowire.Number, fd protoreflect.FieldDescriptor, mapv protoreflect.Map) (size int) { 91*1c12ee1eSDan Willemsen mapv.Range(func(key protoreflect.MapKey, value protoreflect.Value) bool { 92*1c12ee1eSDan Willemsen size += protowire.SizeTag(num) 93*1c12ee1eSDan Willemsen size += protowire.SizeBytes(o.sizeField(fd.MapKey(), key.Value()) + o.sizeField(fd.MapValue(), value)) 94*1c12ee1eSDan Willemsen return true 95*1c12ee1eSDan Willemsen }) 96*1c12ee1eSDan Willemsen return size 97*1c12ee1eSDan Willemsen} 98