blob: 0d6eed6357a828c88b6102b99b839e1cd290bc37 [file] [log] [blame]
Austin Schuh40c16522018-10-28 20:27:54 -07001#region Copyright notice and license
2// Protocol Buffers - Google's data interchange format
3// Copyright 2017 Google Inc. All rights reserved.
4// https://developers.google.com/protocol-buffers/
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31#endregion
32
33using System;
34using System.Collections.Generic;
35using System.Collections.ObjectModel;
36using Google.Protobuf.Collections;
37
38namespace Google.Protobuf
39{
40 /// <summary>
41 /// Represents a single field in an UnknownFieldSet.
42 ///
43 /// An UnknownField consists of four lists of values. The lists correspond
44 /// to the four "wire types" used in the protocol buffer binary format.
45 /// Normally, only one of the four lists will contain any values, since it
46 /// is impossible to define a valid message type that declares two different
47 /// types for the same field number. However, the code is designed to allow
48 /// for the case where the same unknown field number is encountered using
49 /// multiple different wire types.
50 ///
51 /// </summary>
52 internal sealed class UnknownField
53 {
54 private List<ulong> varintList;
55 private List<uint> fixed32List;
56 private List<ulong> fixed64List;
57 private List<ByteString> lengthDelimitedList;
58
59 /// <summary>
60 /// Creates a new UnknownField.
61 /// </summary>
62 public UnknownField()
63 {
64 }
65
66 /// <summary>
67 /// Checks if two unknown field are equal.
68 /// </summary>
69 public override bool Equals(object other)
70 {
71 if (ReferenceEquals(this, other))
72 {
73 return true;
74 }
75 UnknownField otherField = other as UnknownField;
76 return otherField != null
77 && Lists.Equals(varintList, otherField.varintList)
78 && Lists.Equals(fixed32List, otherField.fixed32List)
79 && Lists.Equals(fixed64List, otherField.fixed64List)
80 && Lists.Equals(lengthDelimitedList, otherField.lengthDelimitedList);
81 }
82
83 /// <summary>
84 /// Get the hash code of the unknown field.
85 /// </summary>
86 public override int GetHashCode()
87 {
88 int hash = 43;
89 hash = hash * 47 + Lists.GetHashCode(varintList);
90 hash = hash * 47 + Lists.GetHashCode(fixed32List);
91 hash = hash * 47 + Lists.GetHashCode(fixed64List);
92 hash = hash * 47 + Lists.GetHashCode(lengthDelimitedList);
93 return hash;
94 }
95
96 /// <summary>
97 /// Serializes the field, including the field number, and writes it to
98 /// <paramref name="output"/>
99 /// </summary>
100 /// <param name="fieldNumber">The unknown field number.</param>
101 /// <param name="output">The CodedOutputStream to write to.</param>
102 internal void WriteTo(int fieldNumber, CodedOutputStream output)
103 {
104 if (varintList != null)
105 {
106 foreach (ulong value in varintList)
107 {
108 output.WriteTag(fieldNumber, WireFormat.WireType.Varint);
109 output.WriteUInt64(value);
110 }
111 }
112 if (fixed32List != null)
113 {
114 foreach (uint value in fixed32List)
115 {
116 output.WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
117 output.WriteFixed32(value);
118 }
119 }
120 if (fixed64List != null)
121 {
122 foreach (ulong value in fixed64List)
123 {
124 output.WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
125 output.WriteFixed64(value);
126 }
127 }
128 if (lengthDelimitedList != null)
129 {
130 foreach (ByteString value in lengthDelimitedList)
131 {
132 output.WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
133 output.WriteBytes(value);
134 }
135 }
136 }
137
138 /// <summary>
139 /// Computes the number of bytes required to encode this field, including field
140 /// number.
141 /// </summary>
142 internal int GetSerializedSize(int fieldNumber)
143 {
144 int result = 0;
145 if (varintList != null)
146 {
147 result += CodedOutputStream.ComputeTagSize(fieldNumber) * varintList.Count;
148 foreach (ulong value in varintList)
149 {
150 result += CodedOutputStream.ComputeUInt64Size(value);
151 }
152 }
153 if (fixed32List != null)
154 {
155 result += CodedOutputStream.ComputeTagSize(fieldNumber) * fixed32List.Count;
156 result += CodedOutputStream.ComputeFixed32Size(1) * fixed32List.Count;
157 }
158 if (fixed64List != null)
159 {
160 result += CodedOutputStream.ComputeTagSize(fieldNumber) * fixed64List.Count;
161 result += CodedOutputStream.ComputeFixed64Size(1) * fixed64List.Count;
162 }
163 if (lengthDelimitedList != null)
164 {
165 result += CodedOutputStream.ComputeTagSize(fieldNumber) * lengthDelimitedList.Count;
166 foreach (ByteString value in lengthDelimitedList)
167 {
168 result += CodedOutputStream.ComputeBytesSize(value);
169 }
170 }
171 return result;
172 }
173
174 /// <summary>
175 /// Merge the values in <paramref name="other" /> into this field. For each list
176 /// of values, <paramref name="other"/>'s values are append to the ones in this
177 /// field.
178 /// </summary>
179 internal UnknownField MergeFrom(UnknownField other)
180 {
181 varintList = AddAll(varintList, other.varintList);
182 fixed32List = AddAll(fixed32List, other.fixed32List);
183 fixed64List = AddAll(fixed64List, other.fixed64List);
184 lengthDelimitedList = AddAll(lengthDelimitedList, other.lengthDelimitedList);
185 return this;
186 }
187
188 /// <summary>
189 /// Returns a new list containing all of the given specified values from
190 /// both the <paramref name="current"/> and <paramref name="extras"/> lists.
191 /// If <paramref name="current" /> is null and <paramref name="extras"/> is empty,
192 /// null is returned. Otherwise, either a new list is created (if <paramref name="current" />
193 /// is null) or the elements of <paramref name="extras"/> are added to <paramref name="current" />.
194 /// </summary>
195 private static List<T> AddAll<T>(List<T> current, IList<T> extras)
196 {
197 if (extras.Count == 0)
198 {
199 return current;
200 }
201 if (current == null)
202 {
203 current = new List<T>(extras);
204 }
205 else
206 {
207 current.AddRange(extras);
208 }
209 return current;
210 }
211
212 /// <summary>
213 /// Adds a varint value.
214 /// </summary>
215 internal UnknownField AddVarint(ulong value)
216 {
217 varintList = Add(varintList, value);
218 return this;
219 }
220
221 /// <summary>
222 /// Adds a fixed32 value.
223 /// </summary>
224 internal UnknownField AddFixed32(uint value)
225 {
226 fixed32List = Add(fixed32List, value);
227 return this;
228 }
229
230 /// <summary>
231 /// Adds a fixed64 value.
232 /// </summary>
233 internal UnknownField AddFixed64(ulong value)
234 {
235 fixed64List = Add(fixed64List, value);
236 return this;
237 }
238
239 /// <summary>
240 /// Adds a length-delimited value.
241 /// </summary>
242 internal UnknownField AddLengthDelimited(ByteString value)
243 {
244 lengthDelimitedList = Add(lengthDelimitedList, value);
245 return this;
246 }
247
248 /// <summary>
249 /// Adds <paramref name="value"/> to the <paramref name="list"/>, creating
250 /// a new list if <paramref name="list"/> is null. The list is returned - either
251 /// the original reference or the new list.
252 /// </summary>
253 private static List<T> Add<T>(List<T> list, T value)
254 {
255 if (list == null)
256 {
257 list = new List<T>();
258 }
259 list.Add(value);
260 return list;
261 }
262 }
263}