size.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. // 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. package proto
  5. import (
  6. "google.golang.org/protobuf/internal/encoding/messageset"
  7. "google.golang.org/protobuf/internal/encoding/wire"
  8. "google.golang.org/protobuf/reflect/protoreflect"
  9. "google.golang.org/protobuf/runtime/protoiface"
  10. )
  11. // Size returns the size in bytes of the wire-format encoding of m.
  12. func Size(m Message) int {
  13. return MarshalOptions{}.Size(m)
  14. }
  15. // Size returns the size in bytes of the wire-format encoding of m.
  16. func (o MarshalOptions) Size(m Message) int {
  17. return sizeMessage(m.ProtoReflect())
  18. }
  19. func sizeMessage(m protoreflect.Message) (size int) {
  20. if methods := protoMethods(m); methods != nil && methods.Size != nil {
  21. return methods.Size(m, protoiface.MarshalOptions{})
  22. }
  23. return sizeMessageSlow(m)
  24. }
  25. func sizeMessageSlow(m protoreflect.Message) (size int) {
  26. if messageset.IsMessageSet(m.Descriptor()) {
  27. return sizeMessageSet(m)
  28. }
  29. m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
  30. size += sizeField(fd, v)
  31. return true
  32. })
  33. size += len(m.GetUnknown())
  34. return size
  35. }
  36. func sizeField(fd protoreflect.FieldDescriptor, value protoreflect.Value) (size int) {
  37. num := fd.Number()
  38. switch {
  39. case fd.IsList():
  40. return sizeList(num, fd, value.List())
  41. case fd.IsMap():
  42. return sizeMap(num, fd, value.Map())
  43. default:
  44. return wire.SizeTag(num) + sizeSingular(num, fd.Kind(), value)
  45. }
  46. }
  47. func sizeList(num wire.Number, fd protoreflect.FieldDescriptor, list protoreflect.List) (size int) {
  48. if fd.IsPacked() && list.Len() > 0 {
  49. content := 0
  50. for i, llen := 0, list.Len(); i < llen; i++ {
  51. content += sizeSingular(num, fd.Kind(), list.Get(i))
  52. }
  53. return wire.SizeTag(num) + wire.SizeBytes(content)
  54. }
  55. for i, llen := 0, list.Len(); i < llen; i++ {
  56. size += wire.SizeTag(num) + sizeSingular(num, fd.Kind(), list.Get(i))
  57. }
  58. return size
  59. }
  60. func sizeMap(num wire.Number, fd protoreflect.FieldDescriptor, mapv protoreflect.Map) (size int) {
  61. mapv.Range(func(key protoreflect.MapKey, value protoreflect.Value) bool {
  62. size += wire.SizeTag(num)
  63. size += wire.SizeBytes(sizeField(fd.MapKey(), key.Value()) + sizeField(fd.MapValue(), value))
  64. return true
  65. })
  66. return size
  67. }