Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ProtobufCS/2.4.1/ProtobufCS/src/ProtocolBuffers/Descriptors/MessageDescriptor.cs @ 8295

Last change on this file since 8295 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: 11.3 KB
Line 
1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// http://github.com/jskeet/dotnet-protobufs/
4// Original C++/Java/Python code:
5// http://code.google.com/p/protobuf/
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are
9// met:
10//
11//     * Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//     * Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following disclaimer
15// in the documentation and/or other materials provided with the
16// distribution.
17//     * Neither the name of Google Inc. nor the names of its
18// contributors may be used to endorse or promote products derived from
19// this software without specific prior written permission.
20//
21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32using System;
33using System.Collections.Generic;
34using Google.ProtocolBuffers.DescriptorProtos;
35
36namespace Google.ProtocolBuffers.Descriptors
37{
38    /// <summary>
39    /// Describes a message type.
40    /// </summary>
41    public sealed class MessageDescriptor : IndexedDescriptorBase<DescriptorProto, MessageOptions>
42    {
43        private readonly MessageDescriptor containingType;
44        private readonly IList<MessageDescriptor> nestedTypes;
45        private readonly IList<EnumDescriptor> enumTypes;
46        private readonly IList<FieldDescriptor> fields;
47        private readonly IList<FieldDescriptor> extensions;
48        private bool hasRequiredFields;
49
50        internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex)
51            : base(proto, file, ComputeFullName(file, parent, proto.Name), typeIndex)
52        {
53            containingType = parent;
54
55            nestedTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.NestedTypeList,
56                                                                (type, index) =>
57                                                                new MessageDescriptor(type, file, this, index));
58
59            enumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumTypeList,
60                                                              (type, index) =>
61                                                              new EnumDescriptor(type, file, this, index));
62
63            // TODO(jonskeet): Sort fields first?
64            fields = DescriptorUtil.ConvertAndMakeReadOnly(proto.FieldList,
65                                                           (field, index) =>
66                                                           new FieldDescriptor(field, file, this, index, false));
67
68            extensions = DescriptorUtil.ConvertAndMakeReadOnly(proto.ExtensionList,
69                                                               (field, index) =>
70                                                               new FieldDescriptor(field, file, this, index, true));
71
72            file.DescriptorPool.AddSymbol(this);
73        }
74
75        /// <value>
76        /// If this is a nested type, get the outer descriptor, otherwise null.
77        /// </value>
78        public MessageDescriptor ContainingType
79        {
80            get { return containingType; }
81        }
82
83        /// <value>
84        /// An unmodifiable list of this message type's fields.
85        /// </value>
86        public IList<FieldDescriptor> Fields
87        {
88            get { return fields; }
89        }
90
91        /// <value>
92        /// An unmodifiable list of this message type's extensions.
93        /// </value>
94        public IList<FieldDescriptor> Extensions
95        {
96            get { return extensions; }
97        }
98
99        /// <value>
100        /// An unmodifiable list of this message type's nested types.
101        /// </value>
102        public IList<MessageDescriptor> NestedTypes
103        {
104            get { return nestedTypes; }
105        }
106
107        /// <value>
108        /// An unmodifiable list of this message type's enum types.
109        /// </value>
110        public IList<EnumDescriptor> EnumTypes
111        {
112            get { return enumTypes; }
113        }
114
115        /// <summary>
116        /// Returns a pre-computed result as to whether this message
117        /// has required fields. This includes optional fields which are
118        /// message types which in turn have required fields, and any
119        /// extension fields.
120        /// </summary>
121        internal bool HasRequiredFields
122        {
123            get { return hasRequiredFields; }
124        }
125
126        /// <summary>
127        /// Determines if the given field number is an extension.
128        /// </summary>
129        public bool IsExtensionNumber(int number)
130        {
131            foreach (DescriptorProto.Types.ExtensionRange range in Proto.ExtensionRangeList)
132            {
133                if (range.Start <= number && number < range.End)
134                {
135                    return true;
136                }
137            }
138            return false;
139        }
140
141        /// <summary>
142        /// Finds a field by field name.
143        /// </summary>
144        /// <param name="name">The unqualified name of the field (e.g. "foo").</param>
145        /// <returns>The field's descriptor, or null if not found.</returns>
146        public FieldDescriptor FindFieldByName(String name)
147        {
148            return File.DescriptorPool.FindSymbol<FieldDescriptor>(FullName + "." + name);
149        }
150
151        /// <summary>
152        /// Finds a field by field number.
153        /// </summary>
154        /// <param name="number">The field number within this message type.</param>
155        /// <returns>The field's descriptor, or null if not found.</returns>
156        public FieldDescriptor FindFieldByNumber(int number)
157        {
158            return File.DescriptorPool.FindFieldByNumber(this, number);
159        }
160
161        /// <summary>
162        /// Finds a field by its property name, as it would be generated by protogen.
163        /// </summary>
164        /// <param name="propertyName">The property name within this message type.</param>
165        /// <returns>The field's descriptor, or null if not found.</returns>
166        public FieldDescriptor FindFieldByPropertyName(string propertyName)
167        {
168            // For reasonably short messages, this will be more efficient than a dictionary
169            // lookup. It also means we don't need to do things lazily with locks etc.
170            foreach (FieldDescriptor field in Fields)
171            {
172                if (field.CSharpOptions.PropertyName == propertyName)
173                {
174                    return field;
175                }
176            }
177            return null;
178        }
179
180        /// <summary>
181        /// Finds a nested descriptor by name. The is valid for fields, nested
182        /// message types and enums.
183        /// </summary>
184        /// <param name="name">The unqualified name of the descriptor, e.g. "Foo"</param>
185        /// <returns>The descriptor, or null if not found.</returns>
186        public T FindDescriptor<T>(string name)
187            where T : class, IDescriptor
188        {
189            return File.DescriptorPool.FindSymbol<T>(FullName + "." + name);
190        }
191
192        /// <summary>
193        /// Looks up and cross-links all fields, nested types, and extensions.
194        /// </summary>
195        internal void CrossLink()
196        {
197            foreach (MessageDescriptor message in nestedTypes)
198            {
199                message.CrossLink();
200            }
201
202            foreach (FieldDescriptor field in fields)
203            {
204                field.CrossLink();
205            }
206
207            foreach (FieldDescriptor extension in extensions)
208            {
209                extension.CrossLink();
210            }
211        }
212
213        internal void CheckRequiredFields()
214        {
215            IDictionary<MessageDescriptor, byte> alreadySeen = new Dictionary<MessageDescriptor, byte>();
216            hasRequiredFields = CheckRequiredFields(alreadySeen);
217        }
218
219        private bool CheckRequiredFields(IDictionary<MessageDescriptor, byte> alreadySeen)
220        {
221            if (alreadySeen.ContainsKey(this))
222            {
223                // The type is already in the cache. This means that either:
224                // a. The type has no required fields.
225                // b. We are in the midst of checking if the type has required fields,
226                //    somewhere up the stack.  In this case, we know that if the type
227                //    has any required fields, they'll be found when we return to it,
228                //    and the whole call to HasRequiredFields() will return true.
229                //    Therefore, we don't have to check if this type has required fields
230                //    here.
231                return false;
232            }
233            alreadySeen[this] = 0; // Value is irrelevant; we want set semantics
234
235            // If the type allows extensions, an extension with message type could contain
236            // required fields, so we have to be conservative and assume such an
237            // extension exists.
238            if (Proto.ExtensionRangeCount != 0)
239            {
240                return true;
241            }
242
243            foreach (FieldDescriptor field in Fields)
244            {
245                if (field.IsRequired)
246                {
247                    return true;
248                }
249                if (field.MappedType == MappedType.Message)
250                {
251                    if (field.MessageType.CheckRequiredFields(alreadySeen))
252                    {
253                        return true;
254                    }
255                }
256            }
257            return false;
258        }
259
260        /// <summary>
261        /// See FileDescriptor.ReplaceProto
262        /// </summary>
263        internal override void ReplaceProto(DescriptorProto newProto)
264        {
265            base.ReplaceProto(newProto);
266
267            for (int i = 0; i < nestedTypes.Count; i++)
268            {
269                nestedTypes[i].ReplaceProto(newProto.GetNestedType(i));
270            }
271
272            for (int i = 0; i < enumTypes.Count; i++)
273            {
274                enumTypes[i].ReplaceProto(newProto.GetEnumType(i));
275            }
276
277            for (int i = 0; i < fields.Count; i++)
278            {
279                fields[i].ReplaceProto(newProto.GetField(i));
280            }
281
282            for (int i = 0; i < extensions.Count; i++)
283            {
284                extensions[i].ReplaceProto(newProto.GetExtension(i));
285            }
286        }
287    }
288}
Note: See TracBrowser for help on using the repository browser.