1
# Protocol Buffers - Google's data interchange format
2
# Copyright 2008 Google Inc. All rights reserved.
3
# http://code.google.com/p/protobuf/
5
# Redistribution and use in source and binary forms, with or without
6
# modification, are permitted provided that the following conditions are
9
# * Redistributions of source code must retain the above copyright
10
# notice, this list of conditions and the following disclaimer.
11
# * Redistributions in binary form must reproduce the above
12
# copyright notice, this list of conditions and the following disclaimer
13
# in the documentation and/or other materials provided with the
15
# * Neither the name of Google Inc. nor the names of its
16
# contributors may be used to endorse or promote products derived from
17
# this software without specific prior written permission.
19
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
"""Contains container classes to represent different protocol buffer types.
33
This file defines container classes which represent categories of protocol
34
buffer field types which need extra maintenance. Currently these categories
36
- Repeated scalar fields - These are all repeated fields which aren't
37
composite (e.g. they are of simple types like int32, string, etc).
38
- Repeated composite fields - Repeated fields which are composite. This
39
includes groups and nested messages.
42
__author__ = 'petar@google.com (Petar Petrov)'
45
class BaseContainer(object):
47
"""Base container class."""
49
# Minimizes memory usage and disallows assignment to other attributes.
50
__slots__ = ['_message_listener', '_values']
52
def __init__(self, message_listener):
55
message_listener: A MessageListener implementation.
56
The RepeatedScalarFieldContainer will call this object's
57
TransitionToNonempty() method when it transitions from being empty to
60
self._message_listener = message_listener
63
def __getitem__(self, key):
64
"""Retrieves item by the specified key."""
65
return self._values[key]
68
"""Returns the number of elements in the container."""
69
return len(self._values)
71
def __ne__(self, other):
72
"""Checks if another instance isn't equal to this one."""
73
# The concrete classes should define __eq__.
74
return not self == other
77
class RepeatedScalarFieldContainer(BaseContainer):
79
"""Simple, type-checked, list-like container for holding repeated scalars."""
81
# Disallows assignment to other attributes.
82
__slots__ = ['_type_checker']
84
def __init__(self, message_listener, type_checker):
87
message_listener: A MessageListener implementation.
88
The RepeatedScalarFieldContainer will call this object's
89
TransitionToNonempty() method when it transitions from being empty to
91
type_checker: A type_checkers.ValueChecker instance to run on elements
92
inserted into this container.
94
super(RepeatedScalarFieldContainer, self).__init__(message_listener)
95
self._type_checker = type_checker
97
def append(self, elem):
98
"""Appends a scalar to the list. Similar to list.append()."""
99
self._type_checker.CheckValue(elem)
100
self._values.append(elem)
101
self._message_listener.ByteSizeDirty()
102
if len(self._values) == 1:
103
self._message_listener.TransitionToNonempty()
105
def remove(self, elem):
106
"""Removes a scalar from the list. Similar to list.remove()."""
107
self._values.remove(elem)
108
self._message_listener.ByteSizeDirty()
110
def __setitem__(self, key, value):
111
"""Sets the item on the specified position."""
112
# No need to call TransitionToNonempty(), since if we're able to
113
# set the element at this index, we were already nonempty before
114
# this method was called.
115
self._message_listener.ByteSizeDirty()
116
self._type_checker.CheckValue(value)
117
self._values[key] = value
119
def __eq__(self, other):
120
"""Compares the current instance with another one."""
123
# Special case for the same type which should be common and fast.
124
if isinstance(other, self.__class__):
125
return other._values == self._values
126
# We are presumably comparing against some other sequence type.
127
return other == self._values
130
class RepeatedCompositeFieldContainer(BaseContainer):
132
"""Simple, list-like container for holding repeated composite fields."""
134
# Disallows assignment to other attributes.
135
__slots__ = ['_message_descriptor']
137
def __init__(self, message_listener, message_descriptor):
139
Note that we pass in a descriptor instead of the generated directly,
140
since at the time we construct a _RepeatedCompositeFieldContainer we
141
haven't yet necessarily initialized the type that will be contained in the
145
message_listener: A MessageListener implementation.
146
The RepeatedCompositeFieldContainer will call this object's
147
TransitionToNonempty() method when it transitions from being empty to
149
message_descriptor: A Descriptor instance describing the protocol type
150
that should be present in this container. We'll use the
151
_concrete_class field of this descriptor when the client calls add().
153
super(RepeatedCompositeFieldContainer, self).__init__(message_listener)
154
self._message_descriptor = message_descriptor
157
"""Adds a new element to the list and returns it."""
158
new_element = self._message_descriptor._concrete_class()
159
new_element._SetListener(self._message_listener)
160
self._values.append(new_element)
161
self._message_listener.ByteSizeDirty()
162
self._message_listener.TransitionToNonempty()
165
def __delitem__(self, key):
166
"""Deletes the element on the specified position."""
167
self._message_listener.ByteSizeDirty()
168
del self._values[key]
170
def __eq__(self, other):
171
"""Compares the current instance with another one."""
174
if not isinstance(other, self.__class__):
175
raise TypeError('Can only compare repeated composite fields against '
176
'other repeated composite fields.')
177
return self._values == other._values
179
# TODO(robinson): Implement, document, and test slicing support.