Serialize length-prefixed protos once (#27252)

Avoid calling ByteSize() separately in serialize_length_prefixed(). The serialized payload already carries the exact length to prefix, so this keeps behavior intact while avoiding a duplicate serialization-sized pass.

Closes #27252

COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/27252 from Zaczero:python-serialize-length-prefixed-once 8a4f60b4c7
PiperOrigin-RevId: 923539199
This commit is contained in:
Kamil Monicz 2026-05-29 12:14:46 -07:00 committed by Copybara-Service
parent 00f4fcc7af
commit e090f8ae77
2 changed files with 27 additions and 2 deletions

View file

@ -11,6 +11,7 @@
import io
import unittest
from google.protobuf import message
from google.protobuf import proto
from google.protobuf.internal import encoder
from google.protobuf.internal import test_proto2_pb2
@ -77,6 +78,29 @@ class ProtoTest(unittest.TestCase):
str(context.exception),
)
def test_serialize_length_prefixed_serializes_once(self, message_module):
del message_module
class CountingMessage(message.Message):
def __init__(self):
self.serialize_count = 0
def SerializeToString(self, deterministic=None):
self.serialize_count += 1
return b'abc'
def ByteSize(self):
raise AssertionError('serialize_length_prefixed should not call ByteSize')
msg = CountingMessage()
out = io.BytesIO()
proto.serialize_length_prefixed(msg, out)
self.assertEqual(b'\x03abc', out.getvalue())
self.assertEqual(1, msg.serialize_count)
def test_byte_size(self, message_module):
msg = message_module.TestAllTypes()
self.assertEqual(0, proto.byte_size(msg))

View file

@ -64,9 +64,10 @@ def serialize_length_prefixed(message: _MESSAGE, output: io.BytesIO) -> None:
message: The protocol buffer message that should be serialized.
output: BytesIO or custom buffered IO that data should be written to.
"""
size = message.ByteSize()
payload = serialize(message)
size = len(payload)
encoder._VarintEncoder()(output.write, size)
out_size = output.write(serialize(message))
out_size = output.write(payload)
if out_size != size:
raise TypeError(