Merge branch 'main' into avm99963-monorail
Merged commit 34d8229ae2b51fb1a15bd208e6fe6185c94f6266
GitOrigin-RevId: 7ee0917f93a577e475f8e09526dd144d245593f4
diff --git a/third_party/protorpc/protobuf.py b/third_party/protorpc/protobuf.py
new file mode 100644
index 0000000..6de3bce
--- /dev/null
+++ b/third_party/protorpc/protobuf.py
@@ -0,0 +1,360 @@
+#!/usr/bin/env python
+#
+# Copyright 2010 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""Protocol buffer support for message types.
+
+For more details about protocol buffer encoding and decoding please see:
+
+ http://code.google.com/apis/protocolbuffers/docs/encoding.html
+
+Public Exceptions:
+ DecodeError: Raised when a decode error occurs from incorrect protobuf format.
+
+Public Functions:
+ encode_message: Encodes a message in to a protocol buffer string.
+ decode_message: Decode from a protocol buffer string to a message.
+"""
+import six
+
+__author__ = 'rafek@google.com (Rafe Kaplan)'
+
+
+import array
+
+from . import message_types
+from . import messages
+from . import util
+from .google_imports import ProtocolBuffer
+
+
+__all__ = ['ALTERNATIVE_CONTENT_TYPES',
+ 'CONTENT_TYPE',
+ 'encode_message',
+ 'decode_message',
+ ]
+
+CONTENT_TYPE = 'application/octet-stream'
+
+ALTERNATIVE_CONTENT_TYPES = ['application/x-google-protobuf']
+
+
+class _Encoder(ProtocolBuffer.Encoder):
+ """Extension of protocol buffer encoder.
+
+ Original protocol buffer encoder does not have complete set of methods
+ for handling required encoding. This class adds them.
+ """
+
+ # TODO(rafek): Implement the missing encoding types.
+ def no_encoding(self, value):
+ """No encoding available for type.
+
+ Args:
+ value: Value to encode.
+
+ Raises:
+ NotImplementedError at all times.
+ """
+ raise NotImplementedError()
+
+ def encode_enum(self, value):
+ """Encode an enum value.
+
+ Args:
+ value: Enum to encode.
+ """
+ self.putVarInt32(value.number)
+
+ def encode_message(self, value):
+ """Encode a Message in to an embedded message.
+
+ Args:
+ value: Message instance to encode.
+ """
+ self.putPrefixedString(encode_message(value))
+
+
+ def encode_unicode_string(self, value):
+ """Helper to properly pb encode unicode strings to UTF-8.
+
+ Args:
+ value: String value to encode.
+ """
+ if isinstance(value, six.text_type):
+ value = value.encode('utf-8')
+ self.putPrefixedString(value)
+
+
+class _Decoder(ProtocolBuffer.Decoder):
+ """Extension of protocol buffer decoder.
+
+ Original protocol buffer decoder does not have complete set of methods
+ for handling required decoding. This class adds them.
+ """
+
+ # TODO(rafek): Implement the missing encoding types.
+ def no_decoding(self):
+ """No decoding available for type.
+
+ Raises:
+ NotImplementedError at all times.
+ """
+ raise NotImplementedError()
+
+ def decode_string(self):
+ """Decode a unicode string.
+
+ Returns:
+ Next value in stream as a unicode string.
+ """
+ return self.getPrefixedString().decode('UTF-8')
+
+ def decode_boolean(self):
+ """Decode a boolean value.
+
+ Returns:
+ Next value in stream as a boolean.
+ """
+ return bool(self.getBoolean())
+
+
+# Number of bits used to describe a protocol buffer bits used for the variant.
+_WIRE_TYPE_BITS = 3
+_WIRE_TYPE_MASK = 7
+
+
+# Maps variant to underlying wire type. Many variants map to same type.
+_VARIANT_TO_WIRE_TYPE = {
+ messages.Variant.DOUBLE: _Encoder.DOUBLE,
+ messages.Variant.FLOAT: _Encoder.FLOAT,
+ messages.Variant.INT64: _Encoder.NUMERIC,
+ messages.Variant.UINT64: _Encoder.NUMERIC,
+ messages.Variant.INT32: _Encoder.NUMERIC,
+ messages.Variant.BOOL: _Encoder.NUMERIC,
+ messages.Variant.STRING: _Encoder.STRING,
+ messages.Variant.MESSAGE: _Encoder.STRING,
+ messages.Variant.BYTES: _Encoder.STRING,
+ messages.Variant.UINT32: _Encoder.NUMERIC,
+ messages.Variant.ENUM: _Encoder.NUMERIC,
+ messages.Variant.SINT32: _Encoder.NUMERIC,
+ messages.Variant.SINT64: _Encoder.NUMERIC,
+}
+
+
+# Maps variant to encoder method.
+_VARIANT_TO_ENCODER_MAP = {
+ messages.Variant.DOUBLE: _Encoder.putDouble,
+ messages.Variant.FLOAT: _Encoder.putFloat,
+ messages.Variant.INT64: _Encoder.putVarInt64,
+ messages.Variant.UINT64: _Encoder.putVarUint64,
+ messages.Variant.INT32: _Encoder.putVarInt32,
+ messages.Variant.BOOL: _Encoder.putBoolean,
+ messages.Variant.STRING: _Encoder.encode_unicode_string,
+ messages.Variant.MESSAGE: _Encoder.encode_message,
+ messages.Variant.BYTES: _Encoder.encode_unicode_string,
+ messages.Variant.UINT32: _Encoder.no_encoding,
+ messages.Variant.ENUM: _Encoder.encode_enum,
+ messages.Variant.SINT32: _Encoder.no_encoding,
+ messages.Variant.SINT64: _Encoder.no_encoding,
+}
+
+
+# Basic wire format decoders. Used for reading unknown values.
+_WIRE_TYPE_TO_DECODER_MAP = {
+ _Encoder.NUMERIC: _Decoder.getVarInt64,
+ _Encoder.DOUBLE: _Decoder.getDouble,
+ _Encoder.STRING: _Decoder.getPrefixedString,
+ _Encoder.FLOAT: _Decoder.getFloat,
+}
+
+
+# Map wire type to variant. Used to find a variant for unknown values.
+_WIRE_TYPE_TO_VARIANT_MAP = {
+ _Encoder.NUMERIC: messages.Variant.INT64,
+ _Encoder.DOUBLE: messages.Variant.DOUBLE,
+ _Encoder.STRING: messages.Variant.STRING,
+ _Encoder.FLOAT: messages.Variant.FLOAT,
+}
+
+
+# Wire type to name mapping for error messages.
+_WIRE_TYPE_NAME = {
+ _Encoder.NUMERIC: 'NUMERIC',
+ _Encoder.DOUBLE: 'DOUBLE',
+ _Encoder.STRING: 'STRING',
+ _Encoder.FLOAT: 'FLOAT',
+}
+
+
+# Maps variant to decoder method.
+_VARIANT_TO_DECODER_MAP = {
+ messages.Variant.DOUBLE: _Decoder.getDouble,
+ messages.Variant.FLOAT: _Decoder.getFloat,
+ messages.Variant.INT64: _Decoder.getVarInt64,
+ messages.Variant.UINT64: _Decoder.getVarUint64,
+ messages.Variant.INT32: _Decoder.getVarInt32,
+ messages.Variant.BOOL: _Decoder.decode_boolean,
+ messages.Variant.STRING: _Decoder.decode_string,
+ messages.Variant.MESSAGE: _Decoder.getPrefixedString,
+ messages.Variant.BYTES: _Decoder.getPrefixedString,
+ messages.Variant.UINT32: _Decoder.no_decoding,
+ messages.Variant.ENUM: _Decoder.getVarInt32,
+ messages.Variant.SINT32: _Decoder.no_decoding,
+ messages.Variant.SINT64: _Decoder.no_decoding,
+}
+
+
+def encode_message(message):
+ """Encode Message instance to protocol buffer.
+
+ Args:
+ Message instance to encode in to protocol buffer.
+
+ Returns:
+ String encoding of Message instance in protocol buffer format.
+
+ Raises:
+ messages.ValidationError if message is not initialized.
+ """
+ message.check_initialized()
+ encoder = _Encoder()
+
+ # Get all fields, from the known fields we parsed and the unknown fields
+ # we saved. Note which ones were known, so we can process them differently.
+ all_fields = [(field.number, field) for field in message.all_fields()]
+ all_fields.extend((key, None)
+ for key in message.all_unrecognized_fields()
+ if isinstance(key, six.integer_types))
+ all_fields.sort()
+ for field_num, field in all_fields:
+ if field:
+ # Known field.
+ value = message.get_assigned_value(field.name)
+ if value is None:
+ continue
+ variant = field.variant
+ repeated = field.repeated
+ else:
+ # Unrecognized field.
+ value, variant = message.get_unrecognized_field_info(field_num)
+ if not isinstance(variant, messages.Variant):
+ continue
+ repeated = isinstance(value, (list, tuple))
+
+ tag = ((field_num << _WIRE_TYPE_BITS) | _VARIANT_TO_WIRE_TYPE[variant])
+
+ # Write value to wire.
+ if repeated:
+ values = value
+ else:
+ values = [value]
+ for next in values:
+ encoder.putVarInt32(tag)
+ if isinstance(field, messages.MessageField):
+ next = field.value_to_message(next)
+ field_encoder = _VARIANT_TO_ENCODER_MAP[variant]
+ field_encoder(encoder, next)
+
+ buffer = encoder.buffer()
+ return buffer.tobytes()
+
+
+def decode_message(message_type, encoded_message):
+ """Decode protocol buffer to Message instance.
+
+ Args:
+ message_type: Message type to decode data to.
+ encoded_message: Encoded version of message as string.
+
+ Returns:
+ Decoded instance of message_type.
+
+ Raises:
+ DecodeError if an error occurs during decoding, such as incompatible
+ wire format for a field.
+ messages.ValidationError if merged message is not initialized.
+ """
+ message = message_type()
+ message_array = array.array('B')
+ message_array.frombytes(encoded_message)
+ try:
+ decoder = _Decoder(message_array, 0, len(message_array))
+
+ while decoder.avail() > 0:
+ # Decode tag and variant information.
+ encoded_tag = decoder.getVarInt32()
+ tag = encoded_tag >> _WIRE_TYPE_BITS
+ wire_type = encoded_tag & _WIRE_TYPE_MASK
+ try:
+ found_wire_type_decoder = _WIRE_TYPE_TO_DECODER_MAP[wire_type]
+ except:
+ raise messages.DecodeError('No such wire type %d' % wire_type)
+
+ if tag < 1:
+ raise messages.DecodeError('Invalid tag value %d' % tag)
+
+ try:
+ field = message.field_by_number(tag)
+ except KeyError:
+ # Unexpected tags are ok.
+ field = None
+ wire_type_decoder = found_wire_type_decoder
+ else:
+ expected_wire_type = _VARIANT_TO_WIRE_TYPE[field.variant]
+ if expected_wire_type != wire_type:
+ raise messages.DecodeError('Expected wire type %s but found %s' % (
+ _WIRE_TYPE_NAME[expected_wire_type],
+ _WIRE_TYPE_NAME[wire_type]))
+
+ wire_type_decoder = _VARIANT_TO_DECODER_MAP[field.variant]
+
+ value = wire_type_decoder(decoder)
+
+ # Save unknown fields and skip additional processing.
+ if not field:
+ # When saving this, save it under the tag number (which should
+ # be unique), and set the variant and value so we know how to
+ # interpret the value later.
+ variant = _WIRE_TYPE_TO_VARIANT_MAP.get(wire_type)
+ if variant:
+ message.set_unrecognized_field(tag, value, variant)
+ continue
+
+ # Special case Enum and Message types.
+ if isinstance(field, messages.EnumField):
+ try:
+ value = field.type(value)
+ except TypeError:
+ raise messages.DecodeError('Invalid enum value %s' % value)
+ elif isinstance(field, messages.MessageField):
+ value = decode_message(field.message_type, value)
+ value = field.value_from_message(value)
+
+ # Merge value in to message.
+ if field.repeated:
+ values = getattr(message, field.name)
+ if values is None:
+ setattr(message, field.name, [value])
+ else:
+ values.append(value)
+ else:
+ setattr(message, field.name, value)
+ except ProtocolBuffer.ProtocolBufferDecodeError as err:
+ raise messages.DecodeError('Decoding error: %s' % str(err))
+
+ message.check_initialized()
+ return message