Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2965_CancelablePersistence/HeuristicLab.ExtLibs/HeuristicLab.ProtobufCS/2.4.1/ProtobufCS/src/ProtocolBuffers/FieldSet.cs @ 16723

Last change on this file since 16723 was 8295, checked in by abeham, 12 years ago

#1897:

  • Removed protocol buffers 0.9.1
  • Added protocol buffers 2.4.1
  • Updated proto processing command
File size: 24.5 KB
Line 
1#region Copyright notice and license
2
3// Protocol Buffers - Google's data interchange format
4// Copyright 2008 Google Inc.  All rights reserved.
5// http://github.com/jskeet/dotnet-protobufs/
6// Original C++/Java/Python code:
7// http://code.google.com/p/protobuf/
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions are
11// met:
12//
13//     * Redistributions of source code must retain the above copyright
14// notice, this list of conditions and the following disclaimer.
15//     * Redistributions in binary form must reproduce the above
16// copyright notice, this list of conditions and the following disclaimer
17// in the documentation and/or other materials provided with the
18// distribution.
19//     * Neither the name of Google Inc. nor the names of its
20// contributors may be used to endorse or promote products derived from
21// this software without specific prior written permission.
22//
23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35#endregion
36
37using System;
38using System.Collections;
39using System.Collections.Generic;
40using Google.ProtocolBuffers.Collections;
41using Google.ProtocolBuffers.Descriptors;
42
43namespace Google.ProtocolBuffers
44{
45    public interface IFieldDescriptorLite : IComparable<IFieldDescriptorLite>
46    {
47        bool IsRepeated { get; }
48        bool IsRequired { get; }
49        bool IsPacked { get; }
50        bool IsExtension { get; }
51        bool MessageSetWireFormat { get; } //field.ContainingType.Options.MessageSetWireFormat
52        int FieldNumber { get; }
53        string Name { get; }
54        string FullName { get; }
55        IEnumLiteMap EnumType { get; }
56        FieldType FieldType { get; }
57        MappedType MappedType { get; }
58        object DefaultValue { get; }
59    }
60
61    /// <summary>
62    /// A class which represents an arbitrary set of fields of some message type.
63    /// This is used to implement DynamicMessage, and also to represent extensions
64    /// in GeneratedMessage. This class is internal, since outside users should probably
65    /// be using DynamicMessage.
66    ///
67    /// As in the Java implementation, this class goes against the rest of the framework
68    /// in terms of mutability. Instead of having a mutable Builder class and an immutable
69    /// FieldSet class, FieldSet just has a MakeImmutable() method. This is safe so long as
70    /// all callers are careful not to let a mutable FieldSet escape into the open. This would
71    /// be impossible to guarantee if this were a public class, of course.
72    ///
73    /// All repeated fields are stored as IList[object] even
74    /// TODO(jonskeet): Finish this comment!
75    /// </summary>
76    internal sealed class FieldSet
77    {
78        private static readonly FieldSet defaultInstance =
79            new FieldSet(new Dictionary<IFieldDescriptorLite, object>()).MakeImmutable();
80
81        private IDictionary<IFieldDescriptorLite, object> fields;
82
83        private FieldSet(IDictionary<IFieldDescriptorLite, object> fields)
84        {
85            this.fields = fields;
86        }
87
88        public static FieldSet CreateInstance()
89        {
90            // Use SortedList to keep fields in the canonical order
91            return new FieldSet(new SortedList<IFieldDescriptorLite, object>());
92        }
93
94        /// <summary>
95        /// Makes this FieldSet immutable, and returns it for convenience. Any
96        /// mutable repeated fields are made immutable, as well as the map itself.
97        /// </summary>
98        internal FieldSet MakeImmutable()
99        {
100            // First check if we have any repeated values
101            bool hasRepeats = false;
102            foreach (object value in fields.Values)
103            {
104                IList<object> list = value as IList<object>;
105                if (list != null && !list.IsReadOnly)
106                {
107                    hasRepeats = true;
108                    break;
109                }
110            }
111
112            if (hasRepeats)
113            {
114                var tmp = new SortedList<IFieldDescriptorLite, object>();
115                foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields)
116                {
117                    IList<object> list = entry.Value as IList<object>;
118                    tmp[entry.Key] = list == null ? entry.Value : Lists.AsReadOnly(list);
119                }
120                fields = tmp;
121            }
122
123            fields = Dictionaries.AsReadOnly(fields);
124
125            return this;
126        }
127
128        /// <summary>
129        /// Returns the default, immutable instance with no fields defined.
130        /// </summary>
131        internal static FieldSet DefaultInstance
132        {
133            get { return defaultInstance; }
134        }
135
136        /// <summary>
137        /// Returns an immutable mapping of fields. Note that although the mapping itself
138        /// is immutable, the entries may not be (i.e. any repeated values are represented by
139        /// mutable lists). The behaviour is not specified if the contents are mutated.
140        /// </summary>
141        internal IDictionary<IFieldDescriptorLite, object> AllFields
142        {
143            get { return Dictionaries.AsReadOnly(fields); }
144        }
145
146#if !LITE
147        /// <summary>
148        /// Force coercion to full descriptor dictionary.
149        /// </summary>
150        internal IDictionary<FieldDescriptor, object> AllFieldDescriptors
151        {
152            get
153            {
154                SortedList<FieldDescriptor, object> copy =
155                    new SortedList<FieldDescriptor, object>();
156                foreach (KeyValuePair<IFieldDescriptorLite, object> fd in fields)
157                {
158                    copy.Add((FieldDescriptor) fd.Key, fd.Value);
159                }
160                return Dictionaries.AsReadOnly(copy);
161            }
162        }
163#endif
164
165        /// <summary>
166        /// See <see cref="IMessageLite.HasField"/>.
167        /// </summary>
168        public bool HasField(IFieldDescriptorLite field)
169        {
170            if (field.IsRepeated)
171            {
172                throw new ArgumentException("HasField() can only be called on non-repeated fields.");
173            }
174
175            return fields.ContainsKey(field);
176        }
177
178        /// <summary>
179        /// Clears all fields.
180        /// </summary>
181        internal void Clear()
182        {
183            fields.Clear();
184        }
185
186        /// <summary>
187        /// See <see cref="IMessageLite.Item(IFieldDescriptorLite)"/>
188        /// </summary>
189        /// <remarks>
190        /// If the field is not set, the behaviour when fetching this property varies by field type:
191        /// <list>
192        /// <item>For singular message values, null is returned.</item>
193        /// <item>For singular non-message values, the default value of the field is returned.</item>
194        /// <item>For repeated values, an empty immutable list is returned. This will be compatible
195        /// with IList[object], regardless of the type of the repeated item.</item>
196        /// </list>
197        /// This method returns null if the field is a singular message type
198        /// and is not set; in this case it is up to the caller to fetch the
199        /// message's default instance. For repeated fields of message types,
200        /// an empty collection is returned. For repeated fields of non-message
201        /// types, null is returned.
202        /// <para />
203        /// When setting this property, any list values are copied, and each element is checked
204        /// to ensure it is of an appropriate type.
205        /// </remarks>
206        ///
207        internal object this[IFieldDescriptorLite field]
208        {
209            get
210            {
211                object result;
212                if (fields.TryGetValue(field, out result))
213                {
214                    return result;
215                }
216                if (field.MappedType == MappedType.Message)
217                {
218                    if (field.IsRepeated)
219                    {
220                        return new List<object>();
221                    }
222                    else
223                    {
224                        return null;
225                    }
226                }
227                return field.DefaultValue;
228            }
229            set
230            {
231                if (field.IsRepeated)
232                {
233                    List<object> list = value as List<object>;
234                    if (list == null)
235                    {
236                        throw new ArgumentException("Wrong object type used with protocol message reflection.");
237                    }
238
239                    // Wrap the contents in a new list so that the caller cannot change
240                    // the list's contents after setting it.
241                    List<object> newList = new List<object>(list);
242                    foreach (object element in newList)
243                    {
244                        VerifyType(field, element);
245                    }
246                    value = newList;
247                }
248                else
249                {
250                    VerifyType(field, value);
251                }
252                fields[field] = value;
253            }
254        }
255
256        /// <summary>
257        /// See <see cref="IMessageLite.Item(IFieldDescriptorLite,int)" />
258        /// </summary>
259        internal object this[IFieldDescriptorLite field, int index]
260        {
261            get
262            {
263                if (!field.IsRepeated)
264                {
265                    throw new ArgumentException(
266                        "Indexer specifying field and index can only be called on repeated fields.");
267                }
268
269                return ((IList<object>) this[field])[index];
270            }
271            set
272            {
273                if (!field.IsRepeated)
274                {
275                    throw new ArgumentException(
276                        "Indexer specifying field and index can only be called on repeated fields.");
277                }
278                VerifyType(field, value);
279                object list;
280                if (!fields.TryGetValue(field, out list))
281                {
282                    throw new ArgumentOutOfRangeException();
283                }
284                ((IList<object>) list)[index] = value;
285            }
286        }
287
288        /// <summary>
289        /// See <see cref="IBuilder{TMessage, TBuilder}.AddRepeatedField" />
290        /// </summary>
291        internal void AddRepeatedField(IFieldDescriptorLite field, object value)
292        {
293            if (!field.IsRepeated)
294            {
295                throw new ArgumentException("AddRepeatedField can only be called on repeated fields.");
296            }
297            VerifyType(field, value);
298            object list;
299            if (!fields.TryGetValue(field, out list))
300            {
301                list = new List<object>();
302                fields[field] = list;
303            }
304            ((IList<object>) list).Add(value);
305        }
306
307        /// <summary>
308        /// Returns an enumerator for the field map. Used to write the fields out.
309        /// </summary>
310        internal IEnumerator<KeyValuePair<IFieldDescriptorLite, object>> GetEnumerator()
311        {
312            return fields.GetEnumerator();
313        }
314
315        /// <summary>
316        /// See <see cref="IMessageLite.IsInitialized" />
317        /// </summary>
318        /// <remarks>
319        /// Since FieldSet itself does not have any way of knowing about
320        /// required fields that aren't actually present in the set, it is up
321        /// to the caller to check for genuinely required fields. This property
322        /// merely checks that any messages present are themselves initialized.
323        /// </remarks>
324        internal bool IsInitialized
325        {
326            get
327            {
328                foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields)
329                {
330                    IFieldDescriptorLite field = entry.Key;
331                    if (field.MappedType == MappedType.Message)
332                    {
333                        if (field.IsRepeated)
334                        {
335                            foreach (IMessageLite message in (IEnumerable) entry.Value)
336                            {
337                                if (!message.IsInitialized)
338                                {
339                                    return false;
340                                }
341                            }
342                        }
343                        else
344                        {
345                            if (!((IMessageLite) entry.Value).IsInitialized)
346                            {
347                                return false;
348                            }
349                        }
350                    }
351                }
352                return true;
353            }
354        }
355
356        /// <summary>
357        /// Verifies whether all the required fields in the specified message
358        /// descriptor are present in this field set, as well as whether
359        /// all the embedded messages are themselves initialized.
360        /// </summary>
361        internal bool IsInitializedWithRespectTo(IEnumerable typeFields)
362        {
363            foreach (IFieldDescriptorLite field in typeFields)
364            {
365                if (field.IsRequired && !HasField(field))
366                {
367                    return false;
368                }
369            }
370            return IsInitialized;
371        }
372
373        /// <summary>
374        /// See <see cref="IBuilder{TMessage, TBuilder}.ClearField" />
375        /// </summary>
376        public void ClearField(IFieldDescriptorLite field)
377        {
378            fields.Remove(field);
379        }
380
381        /// <summary>
382        /// See <see cref="IMessageLite.GetRepeatedFieldCount" />
383        /// </summary>
384        public int GetRepeatedFieldCount(IFieldDescriptorLite field)
385        {
386            if (!field.IsRepeated)
387            {
388                throw new ArgumentException("GetRepeatedFieldCount() can only be called on repeated fields.");
389            }
390
391            return ((IList<object>) this[field]).Count;
392        }
393
394#if !LITE
395        /// <summary>
396        /// See <see cref="IBuilder{TMessage, TBuilder}.MergeFrom(IMessageLite)" />
397        /// </summary>
398        public void MergeFrom(IMessage other)
399        {
400            foreach (KeyValuePair<FieldDescriptor, object> fd in other.AllFields)
401            {
402                MergeField(fd.Key, fd.Value);
403            }
404        }
405#endif
406
407        /// <summary>
408        /// Implementation of both <c>MergeFrom</c> methods.
409        /// </summary>
410        /// <param name="otherFields"></param>
411        public void MergeFrom(FieldSet other)
412        {
413            // Note:  We don't attempt to verify that other's fields have valid
414            //   types.  Doing so would be a losing battle.  We'd have to verify
415            //   all sub-messages as well, and we'd have to make copies of all of
416            //   them to insure that they don't change after verification (since
417            //   the IMessageLite interface itself cannot enforce immutability of
418            //   implementations).
419            // TODO(jonskeet):  Provide a function somewhere called MakeDeepCopy()
420            //   which allows people to make secure deep copies of messages.
421
422            foreach (KeyValuePair<IFieldDescriptorLite, object> entry in other.fields)
423            {
424                MergeField(entry.Key, entry.Value);
425            }
426        }
427
428        private void MergeField(IFieldDescriptorLite field, object mergeValue)
429        {
430            object existingValue;
431            fields.TryGetValue(field, out existingValue);
432            if (field.IsRepeated)
433            {
434                if (existingValue == null)
435                {
436                    existingValue = new List<object>();
437                    fields[field] = existingValue;
438                }
439                IList<object> list = (IList<object>) existingValue;
440                foreach (object otherValue in (IEnumerable) mergeValue)
441                {
442                    list.Add(otherValue);
443                }
444            }
445            else if (field.MappedType == MappedType.Message && existingValue != null)
446            {
447                IMessageLite existingMessage = (IMessageLite) existingValue;
448                IMessageLite merged = existingMessage.WeakToBuilder()
449                    .WeakMergeFrom((IMessageLite) mergeValue)
450                    .WeakBuild();
451                this[field] = merged;
452            }
453            else
454            {
455                this[field] = mergeValue;
456            }
457        }
458
459        /// <summary>
460        /// See <see cref="IMessageLite.WriteTo(CodedOutputStream)" />.
461        /// </summary>
462        public void WriteTo(ICodedOutputStream output)
463        {
464            foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields)
465            {
466                WriteField(entry.Key, entry.Value, output);
467            }
468        }
469
470        /// <summary>
471        /// Writes a single field to a CodedOutputStream.
472        /// </summary>
473        public void WriteField(IFieldDescriptorLite field, Object value, ICodedOutputStream output)
474        {
475            if (field.IsExtension && field.MessageSetWireFormat)
476            {
477                output.WriteMessageSetExtension(field.FieldNumber, field.Name, (IMessageLite) value);
478            }
479            else
480            {
481                if (field.IsRepeated)
482                {
483                    IEnumerable valueList = (IEnumerable) value;
484                    if (field.IsPacked)
485                    {
486                        output.WritePackedArray(field.FieldType, field.FieldNumber, field.Name, valueList);
487                    }
488                    else
489                    {
490                        output.WriteArray(field.FieldType, field.FieldNumber, field.Name, valueList);
491                    }
492                }
493                else
494                {
495                    output.WriteField(field.FieldType, field.FieldNumber, field.Name, value);
496                }
497            }
498        }
499
500        /// <summary>
501        /// See <see cref="IMessageLite.SerializedSize" />. It's up to the caller to
502        /// cache the resulting size if desired.
503        /// </summary>
504        public int SerializedSize
505        {
506            get
507            {
508                int size = 0;
509                foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields)
510                {
511                    IFieldDescriptorLite field = entry.Key;
512                    object value = entry.Value;
513
514                    if (field.IsExtension && field.MessageSetWireFormat)
515                    {
516                        size += CodedOutputStream.ComputeMessageSetExtensionSize(field.FieldNumber, (IMessageLite) value);
517                    }
518                    else
519                    {
520                        if (field.IsRepeated)
521                        {
522                            IEnumerable valueList = (IEnumerable) value;
523                            if (field.IsPacked)
524                            {
525                                int dataSize = 0;
526                                foreach (object element in valueList)
527                                {
528                                    dataSize += CodedOutputStream.ComputeFieldSizeNoTag(field.FieldType, element);
529                                }
530                                size += dataSize + CodedOutputStream.ComputeTagSize(field.FieldNumber) +
531                                        CodedOutputStream.ComputeRawVarint32Size((uint) dataSize);
532                            }
533                            else
534                            {
535                                foreach (object element in valueList)
536                                {
537                                    size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber,
538                                                                               element);
539                                }
540                            }
541                        }
542                        else
543                        {
544                            size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, value);
545                        }
546                    }
547                }
548                return size;
549            }
550        }
551
552        /// <summary>
553        /// Verifies that the given object is of the correct type to be a valid
554        /// value for the given field.
555        /// </summary>
556        /// <remarks>
557        /// For repeated fields, this checks if the object is of the right
558        /// element type, not whether it's a list.
559        /// </remarks>
560        /// <exception cref="ArgumentException">The value is not of the right type.</exception>
561        /// <exception cref="ArgumentNullException">The value is null.</exception>
562        private static void VerifyType(IFieldDescriptorLite field, object value)
563        {
564            ThrowHelper.ThrowIfNull(value, "value");
565            bool isValid = false;
566            switch (field.MappedType)
567            {
568                case MappedType.Int32:
569                    isValid = value is int;
570                    break;
571                case MappedType.Int64:
572                    isValid = value is long;
573                    break;
574                case MappedType.UInt32:
575                    isValid = value is uint;
576                    break;
577                case MappedType.UInt64:
578                    isValid = value is ulong;
579                    break;
580                case MappedType.Single:
581                    isValid = value is float;
582                    break;
583                case MappedType.Double:
584                    isValid = value is double;
585                    break;
586                case MappedType.Boolean:
587                    isValid = value is bool;
588                    break;
589                case MappedType.String:
590                    isValid = value is string;
591                    break;
592                case MappedType.ByteString:
593                    isValid = value is ByteString;
594                    break;
595                case MappedType.Enum:
596                    IEnumLite enumValue = value as IEnumLite;
597                    isValid = enumValue != null && field.EnumType.IsValidValue(enumValue);
598                    break;
599                case MappedType.Message:
600                    IMessageLite messageValue = value as IMessageLite;
601                    isValid = messageValue != null;
602#if !LITE
603                    if (isValid && messageValue is IMessage && field is FieldDescriptor)
604                    {
605                        isValid = ((IMessage) messageValue).DescriptorForType == ((FieldDescriptor) field).MessageType;
606                    }
607#endif
608                    break;
609            }
610
611            if (!isValid)
612            {
613                // When chaining calls to SetField(), it can be hard to tell from
614                // the stack trace which exact call failed, since the whole chain is
615                // considered one line of code.  So, let's make sure to include the
616                // field name and other useful info in the exception.
617                string message = "Wrong object type used with protocol message reflection.";
618#if !LITE
619                FieldDescriptor fieldinfo =
620                    field as FieldDescriptor;
621                if (fieldinfo != null)
622                {
623                    message += "Message type \"" + fieldinfo.ContainingType.FullName;
624                    message += "\", field \"" + (fieldinfo.IsExtension ? fieldinfo.FullName : fieldinfo.Name);
625                    message += "\", value was type \"" + value.GetType().Name + "\".";
626                }
627#endif
628                throw new ArgumentException(message);
629            }
630        }
631    }
632}
Note: See TracBrowser for help on using the repository browser.