blob: e03477fe23e947d07fb3e709d4bbcb67c5254c91 [file] [log] [blame]
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://github.com/jskeet/dotnet-protobufs/
// Original C++/Java/Python code:
// http://code.google.com/p/protobuf/
//
// 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.
#endregion
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Google.ProtocolBuffers.Collections;
namespace Google.ProtocolBuffers
{
/// <summary>
/// Represents a single field in an UnknownFieldSet.
///
/// An UnknownField consists of five lists of values. The lists correspond
/// to the five "wire types" used in the protocol buffer binary format.
/// The wire type of each field can be determined from the encoded form alone,
/// without knowing the field's declared type. So, we are able to parse
/// unknown values at least this far and separate them. Normally, only one
/// of the five lists will contain any values, since it is impossible to
/// define a valid message type that declares two different types for the
/// same field number. However, the code is designed to allow for the case
/// where the same unknown field number is encountered using multiple different
/// wire types.
///
/// UnknownField is an immutable class. To construct one, you must use an
/// UnknownField.Builder.
/// </summary>
public sealed class UnknownField
{
public const string UnknownFieldName = "unknown_field";
private static readonly UnknownField defaultInstance = CreateBuilder().Build();
private readonly ReadOnlyCollection<ulong> varintList;
private readonly ReadOnlyCollection<uint> fixed32List;
private readonly ReadOnlyCollection<ulong> fixed64List;
private readonly ReadOnlyCollection<ByteString> lengthDelimitedList;
private readonly ReadOnlyCollection<UnknownFieldSet> groupList;
private UnknownField(ReadOnlyCollection<ulong> varintList,
ReadOnlyCollection<uint> fixed32List,
ReadOnlyCollection<ulong> fixed64List,
ReadOnlyCollection<ByteString> lengthDelimitedList,
ReadOnlyCollection<UnknownFieldSet> groupList)
{
this.varintList = varintList;
this.fixed32List = fixed32List;
this.fixed64List = fixed64List;
this.lengthDelimitedList = lengthDelimitedList;
this.groupList = groupList;
}
public static UnknownField DefaultInstance
{
get { return defaultInstance; }
}
/// <summary>
/// The list of varint values for this field.
/// </summary>
public IList<ulong> VarintList
{
get { return varintList; }
}
/// <summary>
/// The list of fixed32 values for this field.
/// </summary>
public IList<uint> Fixed32List
{
get { return fixed32List; }
}
/// <summary>
/// The list of fixed64 values for this field.
/// </summary>
public IList<ulong> Fixed64List
{
get { return fixed64List; }
}
/// <summary>
/// The list of length-delimited values for this field.
/// </summary>
public IList<ByteString> LengthDelimitedList
{
get { return lengthDelimitedList; }
}
/// <summary>
/// The list of embedded group values for this field. These
/// are represented using UnknownFieldSets rather than Messages
/// since the group's type is presumably unknown.
/// </summary>
public IList<UnknownFieldSet> GroupList
{
get { return groupList; }
}
public override bool Equals(object other)
{
if (ReferenceEquals(this, other))
{
return true;
}
UnknownField otherField = other as UnknownField;
return otherField != null
&& Lists.Equals(varintList, otherField.varintList)
&& Lists.Equals(fixed32List, otherField.fixed32List)
&& Lists.Equals(fixed64List, otherField.fixed64List)
&& Lists.Equals(lengthDelimitedList, otherField.lengthDelimitedList)
&& Lists.Equals(groupList, otherField.groupList);
}
public override int GetHashCode()
{
int hash = 43;
hash = hash*47 + Lists.GetHashCode(varintList);
hash = hash*47 + Lists.GetHashCode(fixed32List);
hash = hash*47 + Lists.GetHashCode(fixed64List);
hash = hash*47 + Lists.GetHashCode(lengthDelimitedList);
hash = hash*47 + Lists.GetHashCode(groupList);
return hash;
}
/// <summary>
/// Constructs a new Builder.
/// </summary>
public static Builder CreateBuilder()
{
return new Builder();
}
/// <summary>
/// Constructs a new Builder and initializes it to a copy of <paramref name="copyFrom"/>.
/// </summary>
public static Builder CreateBuilder(UnknownField copyFrom)
{
return new Builder().MergeFrom(copyFrom);
}
/// <summary>
/// Serializes the field, including the field number, and writes it to
/// <paramref name="output"/>.
/// </summary>
public void WriteTo(int fieldNumber, ICodedOutputStream output)
{
foreach (ulong value in varintList)
{
output.WriteUnknownField(fieldNumber, WireFormat.WireType.Varint, value);
}
foreach (uint value in fixed32List)
{
output.WriteUnknownField(fieldNumber, WireFormat.WireType.Fixed32, value);
}
foreach (ulong value in fixed64List)
{
output.WriteUnknownField(fieldNumber, WireFormat.WireType.Fixed64, value);
}
foreach (ByteString value in lengthDelimitedList)
{
output.WriteUnknownBytes(fieldNumber, value);
}
foreach (UnknownFieldSet value in groupList)
{
#pragma warning disable 0612
output.WriteUnknownGroup(fieldNumber, value);
#pragma warning restore 0612
}
}
/// <summary>
/// Computes the number of bytes required to encode this field, including field
/// number.
/// </summary>
public int GetSerializedSize(int fieldNumber)
{
int result = 0;
foreach (ulong value in varintList)
{
result += CodedOutputStream.ComputeUInt64Size(fieldNumber, value);
}
foreach (uint value in fixed32List)
{
result += CodedOutputStream.ComputeFixed32Size(fieldNumber, value);
}
foreach (ulong value in fixed64List)
{
result += CodedOutputStream.ComputeFixed64Size(fieldNumber, value);
}
foreach (ByteString value in lengthDelimitedList)
{
result += CodedOutputStream.ComputeBytesSize(fieldNumber, value);
}
foreach (UnknownFieldSet value in groupList)
{
#pragma warning disable 0612
result += CodedOutputStream.ComputeUnknownGroupSize(fieldNumber, value);
#pragma warning restore 0612
}
return result;
}
/// <summary>
/// Serializes the length-delimited values of the field, including field
/// number, and writes them to <paramref name="output"/> using the MessageSet wire format.
/// </summary>
/// <param name="fieldNumber"></param>
/// <param name="output"></param>
public void WriteAsMessageSetExtensionTo(int fieldNumber, ICodedOutputStream output)
{
foreach (ByteString value in lengthDelimitedList)
{
output.WriteMessageSetExtension(fieldNumber, UnknownFieldName, value);
}
}
/// <summary>
/// Get the number of bytes required to encode this field, incuding field number,
/// using the MessageSet wire format.
/// </summary>
public int GetSerializedSizeAsMessageSetExtension(int fieldNumber)
{
int result = 0;
foreach (ByteString value in lengthDelimitedList)
{
result += CodedOutputStream.ComputeRawMessageSetExtensionSize(fieldNumber, value);
}
return result;
}
/// <summary>
/// Used to build instances of UnknownField.
/// </summary>
public sealed class Builder
{
private List<ulong> varintList;
private List<uint> fixed32List;
private List<ulong> fixed64List;
private List<ByteString> lengthDelimitedList;
private List<UnknownFieldSet> groupList;
/// <summary>
/// Builds the field. After building, the builder is reset to an empty
/// state. (This is actually easier than making it unusable.)
/// </summary>
public UnknownField Build()
{
return new UnknownField(MakeReadOnly(ref varintList),
MakeReadOnly(ref fixed32List),
MakeReadOnly(ref fixed64List),
MakeReadOnly(ref lengthDelimitedList),
MakeReadOnly(ref groupList));
}
/// <summary>
/// Merge the values in <paramref name="other" /> into this field. For each list
/// of values, <paramref name="other"/>'s values are append to the ones in this
/// field.
/// </summary>
public Builder MergeFrom(UnknownField other)
{
varintList = AddAll(varintList, other.VarintList);
fixed32List = AddAll(fixed32List, other.Fixed32List);
fixed64List = AddAll(fixed64List, other.Fixed64List);
lengthDelimitedList = AddAll(lengthDelimitedList, other.LengthDelimitedList);
groupList = AddAll(groupList, other.GroupList);
return this;
}
/// <summary>
/// Returns a new list containing all of the given specified values from
/// both the <paramref name="current"/> and <paramref name="extras"/> lists.
/// If <paramref name="current" /> is null and <paramref name="extras"/> is empty,
/// null is returned. Otherwise, either a new list is created (if <paramref name="current" />
/// is null) or the elements of <paramref name="extras"/> are added to <paramref name="current" />.
/// </summary>
private static List<T> AddAll<T>(List<T> current, IList<T> extras)
{
if (extras.Count == 0)
{
return current;
}
if (current == null)
{
current = new List<T>(extras);
}
else
{
current.AddRange(extras);
}
return current;
}
/// <summary>
/// Clears the contents of this builder.
/// </summary>
public Builder Clear()
{
varintList = null;
fixed32List = null;
fixed64List = null;
lengthDelimitedList = null;
groupList = null;
return this;
}
/// <summary>
/// Adds a varint value.
/// </summary>
[CLSCompliant(false)]
public Builder AddVarint(ulong value)
{
varintList = Add(varintList, value);
return this;
}
/// <summary>
/// Adds a fixed32 value.
/// </summary>
[CLSCompliant(false)]
public Builder AddFixed32(uint value)
{
fixed32List = Add(fixed32List, value);
return this;
}
/// <summary>
/// Adds a fixed64 value.
/// </summary>
[CLSCompliant(false)]
public Builder AddFixed64(ulong value)
{
fixed64List = Add(fixed64List, value);
return this;
}
/// <summary>
/// Adds a length-delimited value.
/// </summary>
public Builder AddLengthDelimited(ByteString value)
{
lengthDelimitedList = Add(lengthDelimitedList, value);
return this;
}
/// <summary>
/// Adds an embedded group.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public Builder AddGroup(UnknownFieldSet value)
{
groupList = Add(groupList, value);
return this;
}
/// <summary>
/// Adds <paramref name="value"/> to the <paramref name="list"/>, creating
/// a new list if <paramref name="list"/> is null. The list is returned - either
/// the original reference or the new list.
/// </summary>
private static List<T> Add<T>(List<T> list, T value)
{
if (list == null)
{
list = new List<T>();
}
list.Add(value);
return list;
}
/// <summary>
/// Returns a read-only version of the given IList, and clears
/// the field used for <paramref name="list"/>. If the value
/// is null, an empty list is produced using Lists.Empty.
/// </summary>
/// <returns></returns>
private static ReadOnlyCollection<T> MakeReadOnly<T>(ref List<T> list)
{
ReadOnlyCollection<T> ret = list == null ? Lists<T>.Empty : new ReadOnlyCollection<T>(list);
list = null;
return ret;
}
}
}
}