xref: /aosp_15_r20/external/golang-protobuf/proto/size.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
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