content: // 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 com.google.protobuf.Descriptors.Descriptor;
  import com.google.protobuf.Descriptors.EnumValueDescriptor;
  import com.google.protobuf.Descriptors.FieldDescriptor;
  import java.io.IOException;
  import java.util.Collections;
  import java.util.Map;
  import java.util.TreeMap;
  
  /**
   * Implements MapEntry messages.
   *
   * In reflection API, map fields will be treated as repeated message fields and
   * each map entry is accessed as a message. This MapEntry class is used to
   * represent these map entry messages in reflection API.
   *
   * Protobuf internal. Users shouldn't use this class.
   */
  public final class MapEntry<K, V> extends AbstractMessage {
  
    private static final class Metadata<K, V> extends MapEntryLite.Metadata<K, V> {
  
      public final Descriptor descriptor;
      public final Parser<MapEntry<K, V>> parser;
  
      public Metadata(
          Descriptor descriptor,
          MapEntry<K, V> defaultInstance,
          WireFormat.FieldType keyType,
          WireFormat.FieldType valueType) {
        super(keyType, defaultInstance.key, valueType, defaultInstance.value);
        this.descriptor = descriptor;
        this.parser = new AbstractParser<MapEntry<K, V>>() {
  
          @Override
          public MapEntry<K, V> parsePartialFrom(
              CodedInputStream input, ExtensionRegistryLite extensionRegistry)
              throws InvalidProtocolBufferException {
            return new MapEntry<K, V>(Metadata.this, input, extensionRegistry);
          }
        };
      }
    }
  
    private final K key;
    private final V value;
    private final Metadata<K, V> metadata;
  
    /** Create a default MapEntry instance. */
    private MapEntry(
        Descriptor descriptor,
        WireFormat.FieldType keyType, K defaultKey,
        WireFormat.FieldType valueType, V defaultValue) {
      this.key = defaultKey;
      this.value = defaultValue;
      this.metadata = new Metadata<K, V>(descriptor, this, keyType, valueType);
    }
  
    /** Create a MapEntry with the provided key and value. */
    @SuppressWarnings("unchecked")
    private MapEntry(Metadata metadata, K key, V value) {
      this.key = key;
      this.value = value;
      this.metadata = metadata;
    }
  
    /** Parsing constructor. */
    private MapEntry(
        Metadata<K, V> metadata,
        CodedInputStream input,
        ExtensionRegistryLite extensionRegistry)
        throws InvalidProtocolBufferException {
      try {
        this.metadata = metadata;
        Map.Entry<K, V> entry = MapEntryLite.parseEntry(input, metadata, extensionRegistry);
        this.key = entry.getKey();
        this.value = entry.getValue();
      } catch (InvalidProtocolBufferException e) {
        throw e.setUnfinishedMessage(this);
      } catch (IOException e) {
        throw new InvalidProtocolBufferException(e).setUnfinishedMessage(this);
      }
    }
  
    /**
     * Create a default MapEntry instance. A default MapEntry instance should be
     * created only once for each map entry message type. Generated code should
     * store the created default instance and use it later to create new MapEntry
     * messages of the same type.
     */
    public static <K, V> MapEntry<K, V> newDefaultInstance(
        Descriptor descriptor,
        WireFormat.FieldType keyType, K defaultKey,
        WireFormat.FieldType valueType, V defaultValue) {
      return new MapEntry<K, V>(
          descriptor, keyType, defaultKey, valueType, defaultValue);
    }
  
    public K getKey() {
      return key;
    }
  
    public V getValue() {
      return value;
    }
  
    private volatile int cachedSerializedSize = -1;
  
    @Override
    public int getSerializedSize() {
      if (cachedSerializedSize != -1) {
        return cachedSerializedSize;
      }
  
      int size = MapEntryLite.computeSerializedSize(metadata, key, value);
      cachedSerializedSize = size;
      return size;
    }
  
    @Override
    public void writeTo(CodedOutputStream output) throws IOException {
      MapEntryLite.writeTo(output, metadata, key, value);
    }
  
    @Override
    public boolean isInitialized() {
      return isInitialized(metadata, value);
    }
  
    @Override
    public Parser<MapEntry<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, true, true);
    }
  
    @Override
    public MapEntry<K, V> getDefaultInstanceForType() {
      return new MapEntry<K, V>(metadata, metadata.defaultKey, metadata.defaultValue);
    }
  
    @Override
    public Descriptor getDescriptorForType() {
      return metadata.descriptor;
    }
  
    @Override
    public Map<FieldDescriptor, Object> getAllFields() {
      TreeMap<FieldDescriptor, Object> result = new TreeMap<FieldDescriptor, Object>();
      for (final FieldDescriptor field : metadata.descriptor.getFields()) {
        if (hasField(field)) {
          result.put(field, getField(field));
        }
      }
      return Collections.unmodifiableMap(result);
    }
  
    private void checkFieldDescriptor(FieldDescriptor field) {
      if (field.getContainingType() != metadata.descriptor) {
        throw new RuntimeException(
            "Wrong FieldDescriptor \"" + field.getFullName()
            + "\" used in message \"" + metadata.descriptor.getFullName());
      }
    }
  
    @Override
    public boolean hasField(FieldDescriptor field) {
      checkFieldDescriptor(field);;
      // A MapEntry always contains two fields.
      return true;
    }
  
    @Override
    public Object getField(FieldDescriptor field) {
      checkFieldDescriptor(field);
      Object result = field.getNumber() == 1 ? getKey() : getValue();
      // Convert enums to EnumValueDescriptor.
      if (field.getType() == FieldDescriptor.Type.ENUM) {
        result = field.getEnumType().findValueByNumberCreatingIfUnknown(
            (java.lang.Integer) result);
      }
      return result;
    }
  
    @Override
    public int getRepeatedFieldCount(FieldDescriptor field) {
      throw new RuntimeException(
          "There is no repeated field in a map entry message.");
    }
  
    @Override
    public Object getRepeatedField(FieldDescriptor field, int index) {
      throw new RuntimeException(
          "There is no repeated field in a map entry message.");
    }
  
    @Override
    public UnknownFieldSet getUnknownFields() {
      return UnknownFieldSet.getDefaultInstance();
    }
  
    /**
     * Builder to create {@link MapEntry} messages.
     */
    public static class Builder<K, V>
        extends AbstractMessage.Builder<Builder<K, V>> {
      private final Metadata<K, V> metadata;
      private K key;
      private V value;
      private boolean hasKey;
      private boolean hasValue;
  
      private Builder(Metadata<K, V> metadata) {
        this(metadata, metadata.defaultKey, metadata.defaultValue, false, false);
      }
  
      private Builder(Metadata<K, V> metadata, K key, V value, boolean hasKey, boolean hasValue) {
        this.metadata = metadata;
        this.key = key;
        this.value = value;
        this.hasKey = hasKey;
        this.hasValue = hasValue;
      }
  
      public K getKey() {
        return key;
      }
  
      public V getValue() {
        return value;
      }
  
      public Builder<K, V> setKey(K key) {
        this.key = key;
        this.hasKey = true;
        return this;
      }
  
      public Builder<K, V> clearKey() {
        this.key = metadata.defaultKey;
        this.hasKey = false;
        return this;
      }
  
      public Builder<K, V> setValue(V value) {
        this.value = value;
        this.hasValue = true;
        return this;
      }
  
      public Builder<K, V> clearValue() {
        this.value = metadata.defaultValue;
        this.hasValue = false;
        return this;
      }
  
      @Override
      public MapEntry<K, V> build() {
        MapEntry<K, V> result = buildPartial();
        if (!result.isInitialized()) {
          throw newUninitializedMessageException(result);
        }
        return result;
      }
  
      @Override
      public MapEntry<K, V> buildPartial() {
        return new MapEntry<K, V>(metadata, key, value);
      }
  
      @Override
      public Descriptor getDescriptorForType() {
        return metadata.descriptor;
      }
  
      private void checkFieldDescriptor(FieldDescriptor field) {
        if (field.getContainingType() != metadata.descriptor) {
          throw new RuntimeException(
              "Wrong FieldDescriptor \"" + field.getFullName()
              + "\" used in message \"" + metadata.descriptor.getFullName());
        }
      }
  
      @Override
      public Message.Builder newBuilderForField(FieldDescriptor field) {
        checkFieldDescriptor(field);;
        // This method should be called for message fields and in a MapEntry
        // message only the value field can possibly be a message field.
        if (field.getNumber() != 2
            || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
          throw new RuntimeException(
              "\"" + field.getFullName() + "\" is not a message value field.");
        }
        return ((Message) value).newBuilderForType();
      }
  
      @SuppressWarnings("unchecked")
      @Override
      public Builder<K, V> setField(FieldDescriptor field, Object value) {
        checkFieldDescriptor(field);
        if (field.getNumber() == 1) {
          setKey((K) value);
        } else {
          if (field.getType() == FieldDescriptor.Type.ENUM) {
            value = ((EnumValueDescriptor) value).getNumber();
          } else if (field.getType() == FieldDescriptor.Type.MESSAGE) {
            if (value != null && !metadata.defaultValue.getClass().isInstance(value)) {
              // The value is not the exact right message type.  However, if it
              // is an alternative implementation of the same type -- e.g. a
              // DynamicMessage -- we should accept it.  In this case we can make
              // a copy of the message.
              value =
                  ((Message) metadata.defaultValue).toBuilder().mergeFrom((Message) value).build();
            }
          }
          setValue((V) value);
        }
        return this;
      }
  
      @Override
      public Builder<K, V> clearField(FieldDescriptor field) {
        checkFieldDescriptor(field);
        if (field.getNumber() == 1) {
          clearKey();
        } else {
          clearValue();
        }
        return this;
      }
  
      @Override
      public Builder<K, V> setRepeatedField(FieldDescriptor field, int index,
          Object value) {
        throw new RuntimeException(
            "There is no repeated field in a map entry message.");
      }
  
      @Override
      public Builder<K, V> addRepeatedField(FieldDescriptor field, Object value) {
        throw new RuntimeException(
            "There is no repeated field in a map entry message.");
      }
  
      @Override
      public Builder<K, V> setUnknownFields(UnknownFieldSet unknownFields) {
        // Unknown fields are discarded for MapEntry message.
        return this;
      }
  
      @Override
      public MapEntry<K, V> getDefaultInstanceForType() {
        return new MapEntry<K, V>(metadata, metadata.defaultKey, metadata.defaultValue);
      }
  
      @Override
      public boolean isInitialized() {
        return MapEntry.isInitialized(metadata, value);
      }
  
      @Override
      public Map<FieldDescriptor, Object> getAllFields() {
        final TreeMap<FieldDescriptor, Object> result = new TreeMap<FieldDescriptor, Object>();
        for (final FieldDescriptor field : metadata.descriptor.getFields()) {
          if (hasField(field)) {
            result.put(field, getField(field));
          }
        }
        return Collections.unmodifiableMap(result);
      }
  
      @Override
      public boolean hasField(FieldDescriptor field) {
        checkFieldDescriptor(field);
        return field.getNumber() == 1 ? hasKey : hasValue;
      }
  
      @Override
      public Object getField(FieldDescriptor field) {
        checkFieldDescriptor(field);
        Object result = field.getNumber() == 1 ? getKey() : getValue();
        // Convert enums to EnumValueDescriptor.
        if (field.getType() == FieldDescriptor.Type.ENUM) {
          result = field.getEnumType().findValueByNumberCreatingIfUnknown((Integer) result);
        }
        return result;
      }
  
      @Override
      public int getRepeatedFieldCount(FieldDescriptor field) {
        throw new RuntimeException(
            "There is no repeated field in a map entry message.");
      }
  
      @Override
      public Object getRepeatedField(FieldDescriptor field, int index) {
        throw new RuntimeException(
            "There is no repeated field in a map entry message.");
      }
  
      @Override
      public UnknownFieldSet getUnknownFields() {
        return UnknownFieldSet.getDefaultInstance();
      }
  
      @Override
      @SuppressWarnings("unchecked")
      public Builder<K, V> clone() {
        return new Builder(metadata, key, value, hasKey, hasValue);
      }
    }
  
    private static <V> boolean isInitialized(Metadata metadata, V value) {
      if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
        return ((MessageLite) value).isInitialized();
      }
      return true;
    }
    
    /** Returns the metadata only for experimental runtime. */
    final Metadata<K, V> getMetadata() {
      return metadata;
    }
  }
  