blob: 12c64abbb4af3473c18c518795f1b5a39c187332 [file] [log] [blame]
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.IOException;
/**
* Implements the lite version of map entry messages.
*
* This class serves as an utility class to help do serialization/parsing of
* map entries. It's used in generated code and also in the full version
* MapEntry message.
*
* Protobuf internal. Users shouldn't use.
*/
public class MapEntryLite<K, V>
extends AbstractMessageLite<MapEntryLite<K, V>, MapEntryLite.Builder<K, V>> {
private static class Metadata<K, V> {
public final MapEntryLite<K, V> defaultInstance;
public final WireFormat.FieldType keyType;
public final WireFormat.FieldType valueType;
public final Parser<MapEntryLite<K, V>> parser;
public Metadata(
MapEntryLite<K, V> defaultInstance,
WireFormat.FieldType keyType,
WireFormat.FieldType valueType) {
this.defaultInstance = defaultInstance;
this.keyType = keyType;
this.valueType = valueType;
final Metadata<K, V> finalThis = this;
this.parser = new AbstractParser<MapEntryLite<K, V>>() {
@Override
public MapEntryLite<K, V> parsePartialFrom(
CodedInputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return new MapEntryLite<K, V>(finalThis, input, extensionRegistry);
}
};
}
}
private static final int KEY_FIELD_NUMBER = 1;
private static final int VALUE_FIELD_NUMBER = 2;
private final Metadata<K, V> metadata;
private final K key;
private final V value;
/** Creates a default MapEntryLite message instance. */
private MapEntryLite(
WireFormat.FieldType keyType, K defaultKey,
WireFormat.FieldType valueType, V defaultValue) {
this.metadata = new Metadata<K, V>(this, keyType, valueType);
this.key = defaultKey;
this.value = defaultValue;
}
/** Creates a new MapEntryLite message. */
private MapEntryLite(Metadata<K, V> metadata, K key, V value) {
this.metadata = metadata;
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
/**
* Creates a default MapEntryLite message instance.
*
* This method is used by generated code to create the default instance for
* a map entry message. The created default instance should be used to create
* new map entry messages of the same type. For each map entry message, only
* one default instance should be created.
*/
public static <K, V> MapEntryLite<K, V> newDefaultInstance(
WireFormat.FieldType keyType, K defaultKey,
WireFormat.FieldType valueType, V defaultValue) {
return new MapEntryLite<K, V>(
keyType, defaultKey, valueType, defaultValue);
}
@Override
public void writeTo(CodedOutputStream output) throws IOException {
writeField(KEY_FIELD_NUMBER, metadata.keyType, key, output);
writeField(VALUE_FIELD_NUMBER, metadata.valueType, value, output);
}
private void writeField(
int number, WireFormat.FieldType type, Object value,
CodedOutputStream output) throws IOException {
output.writeTag(number, type.getWireType());
FieldSet.writeElementNoTag(output, type, value);
}
private volatile int cachedSerializedSize = -1;
@Override
public int getSerializedSize() {
if (cachedSerializedSize != -1) {
return cachedSerializedSize;
}
int size = 0;
size += getFieldSize(KEY_FIELD_NUMBER, metadata.keyType, key);
size += getFieldSize(VALUE_FIELD_NUMBER, metadata.valueType, value);
cachedSerializedSize = size;
return size;
}
private int getFieldSize(
int number, WireFormat.FieldType type, Object value) {
return CodedOutputStream.computeTagSize(number)
+ FieldSet.computeElementSizeNoTag(type, value);
}
/** Parsing constructor. */
private MapEntryLite(
Metadata<K, V> metadata,
CodedInputStream input,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
K key = metadata.defaultInstance.key;
V value = metadata.defaultInstance.value;
while (true) {
int tag = input.readTag();
if (tag == 0) {
break;
}
if (tag == WireFormat.makeTag(
KEY_FIELD_NUMBER, metadata.keyType.getWireType())) {
key = mergeField(
input, extensionRegistry, metadata.keyType, key);
} else if (tag == WireFormat.makeTag(
VALUE_FIELD_NUMBER, metadata.valueType.getWireType())) {
value = mergeField(
input, extensionRegistry, metadata.valueType, value);
} else {
if (!input.skipField(tag)) {
break;
}
}
}
this.metadata = metadata;
this.key = key;
this.value = value;
} catch (InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(this);
} catch (IOException e) {
throw new InvalidProtocolBufferException(e.getMessage())
.setUnfinishedMessage(this);
}
}
@SuppressWarnings("unchecked")
private <T> T mergeField(
CodedInputStream input, ExtensionRegistryLite extensionRegistry,
WireFormat.FieldType type, T value) throws IOException {
switch (type) {
case MESSAGE:
MessageLite.Builder subBuilder = ((MessageLite) value).toBuilder();
input.readMessage(subBuilder, extensionRegistry);
return (T) subBuilder.buildPartial();
case ENUM:
return (T) (java.lang.Integer) input.readEnum();
case GROUP:
throw new RuntimeException("Groups are not allowed in maps.");
default:
return (T) FieldSet.readPrimitiveField(input, type, true);
}
}
@Override
public Parser<MapEntryLite<K, V>> getParserForType() {
return metadata.parser;
}
@Override
public Builder<K, V> newBuilderForType() {
return new Builder<K, V>(metadata);
}
@Override
public Builder<K, V> toBuilder() {
return new Builder<K, V>(metadata, key, value);
}
@Override
public MapEntryLite<K, V> getDefaultInstanceForType() {
return metadata.defaultInstance;
}
@Override
public boolean isInitialized() {
if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
return ((MessageLite) value).isInitialized();
}
return true;
}
/**
* Builder used to create {@link MapEntryLite} messages.
*/
public static class Builder<K, V>
extends AbstractMessageLite.Builder<MapEntryLite<K, V>, Builder<K, V>> {
private final Metadata<K, V> metadata;
private K key;
private V value;
private Builder(Metadata<K, V> metadata) {
this.metadata = metadata;
this.key = metadata.defaultInstance.key;
this.value = metadata.defaultInstance.value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public Builder<K, V> setKey(K key) {
this.key = key;
return this;
}
public Builder<K, V> setValue(V value) {
this.value = value;
return this;
}
public Builder<K, V> clearKey() {
this.key = metadata.defaultInstance.key;
return this;
}
public Builder<K, V> clearValue() {
this.value = metadata.defaultInstance.value;
return this;
}
@Override
public Builder<K, V> clear() {
this.key = metadata.defaultInstance.key;
this.value = metadata.defaultInstance.value;
return this;
}
@Override
public MapEntryLite<K, V> build() {
MapEntryLite<K, V> result = buildPartial();
if (!result.isInitialized()) {
throw newUninitializedMessageException(result);
}
return result;
}
@Override
public MapEntryLite<K, V> buildPartial() {
return new MapEntryLite<K, V>(metadata, key, value);
}
@Override
public MessageLite getDefaultInstanceForType() {
return metadata.defaultInstance;
}
@Override
public boolean isInitialized() {
if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
return ((MessageLite) value).isInitialized();
}
return true;
}
private Builder(Metadata<K, V> metadata, K key, V value) {
this.metadata = metadata;
this.key = key;
this.value = value;
}
@Override
public Builder<K, V> clone() {
return new Builder<K, V>(metadata, key, value);
}
@Override
public Builder<K, V> mergeFrom(
CodedInputStream input, ExtensionRegistryLite extensionRegistry)
throws IOException {
MapEntryLite<K, V> entry =
new MapEntryLite<K, V>(metadata, input, extensionRegistry);
this.key = entry.key;
this.value = entry.value;
return this;
}
@Override
protected Builder<K, V> internalMergeFrom(MapEntryLite<K, V> message) {
throw new UnsupportedOperationException();
}
}
}