blob: fc2ccb6c0272e8d64cb35a59af31e1535aa6611e [file] [log] [blame]
csharptest980ba8d2010-11-07 16:30:39 -06001#region Copyright notice and license
2// Protocol Buffers - Google's data interchange format
3// Copyright 2008 Google Inc. All rights reserved.
4// http://github.com/jskeet/dotnet-protobufs/
5// Original C++/Java/Python code:
6// http://code.google.com/p/protobuf/
7//
8// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
11//
12// * Redistributions of source code must retain the above copyright
13// notice, this list of conditions and the following disclaimer.
14// * Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following disclaimer
16// in the documentation and/or other materials provided with the
17// distribution.
18// * Neither the name of Google Inc. nor the names of its
19// contributors may be used to endorse or promote products derived from
20// this software without specific prior written permission.
21//
22// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33#endregion
34
35using System;
36using System.Collections.Generic;
37namespace Google.ProtocolBuffers {
38 public abstract class ExtendableMessageLite<TMessage, TBuilder> : GeneratedMessageLite<TMessage, TBuilder>
39 where TMessage : GeneratedMessageLite<TMessage, TBuilder>
40 where TBuilder : GeneratedBuilderLite<TMessage, TBuilder> {
41
42 protected ExtendableMessageLite() { }
43 private readonly FieldSet extensions = FieldSet.CreateInstance();
44
45 /// <summary>
46 /// Access for the builder.
47 /// </summary>
48 internal FieldSet Extensions {
49 get { return extensions; }
50 }
51
52 /// <summary>
53 /// Checks if a singular extension is present.
54 /// </summary>
55 public bool HasExtension<TExtension>(GeneratedExtensionLite<TMessage, TExtension> extension) {
56 VerifyExtensionContainingType(extension);
57 return extensions.HasField(extension.Descriptor);
58 }
59
60 /// <summary>
61 /// Returns the number of elements in a repeated extension.
62 /// </summary>
63 public int GetExtensionCount<TExtension>(GeneratedExtensionLite<TMessage, IList<TExtension>> extension) {
64 VerifyExtensionContainingType(extension);
65 return extensions.GetRepeatedFieldCount(extension.Descriptor);
66 }
67
68 /// <summary>
69 /// Returns the value of an extension.
70 /// </summary>
71 public TExtension GetExtension<TExtension>(GeneratedExtensionLite<TMessage, TExtension> extension) {
72 VerifyExtensionContainingType(extension);
73 object value = extensions[extension.Descriptor];
74 if (value == null) {
75 return extension.DefaultValue;
76 } else {
csharptest80824a52010-11-07 17:25:47 -060077 return (TExtension)extension.FromReflectionType(value);
csharptest980ba8d2010-11-07 16:30:39 -060078 }
79 }
80
81 /// <summary>
82 /// Returns one element of a repeated extension.
83 /// </summary>
84 public TExtension GetExtension<TExtension>(GeneratedExtensionLite<TMessage, IList<TExtension>> extension, int index) {
85 VerifyExtensionContainingType(extension);
csharptest80824a52010-11-07 17:25:47 -060086 return (TExtension)extension.SingularFromReflectionType(extensions[extension.Descriptor, index]);
csharptest980ba8d2010-11-07 16:30:39 -060087 }
88
89 /// <summary>
90 /// Called to check if all extensions are initialized.
91 /// </summary>
92 protected bool ExtensionsAreInitialized {
93 get { return extensions.IsInitialized; }
94 }
95
96 public override bool IsInitialized {
97 get {
98 return ExtensionsAreInitialized;
99 }
100 }
101
102 /// <summary>
103 /// Used by subclasses to serialize extensions. Extension ranges may be
104 /// interleaves with field numbers, but we must write them in canonical
105 /// (sorted by field number) order. This class helps us to write individual
106 /// ranges of extensions at once.
107 ///
108 /// TODO(jonskeet): See if we can improve this in terms of readability.
109 /// </summary>
110 protected class ExtensionWriter {
111 readonly IEnumerator<KeyValuePair<IFieldDescriptorLite, object>> iterator;
112 readonly FieldSet extensions;
113 KeyValuePair<IFieldDescriptorLite, object>? next = null;
114
115 internal ExtensionWriter(ExtendableMessageLite<TMessage, TBuilder> message) {
116 extensions = message.extensions;
117 iterator = message.extensions.GetEnumerator();
118 if (iterator.MoveNext()) {
119 next = iterator.Current;
120 }
121 }
122
123 public void WriteUntil(int end, CodedOutputStream output) {
124 while (next != null && next.Value.Key.FieldNumber < end) {
125 extensions.WriteField(next.Value.Key, next.Value.Value, output);
126 if (iterator.MoveNext()) {
127 next = iterator.Current;
128 } else {
129 next = null;
130 }
131 }
132 }
133 }
134
135 protected ExtensionWriter CreateExtensionWriter(ExtendableMessageLite<TMessage, TBuilder> message) {
136 return new ExtensionWriter(message);
137 }
138
139 /// <summary>
140 /// Called by subclasses to compute the size of extensions.
141 /// </summary>
142 protected int ExtensionsSerializedSize {
143 get { return extensions.SerializedSize; }
144 }
145
146 internal void VerifyExtensionContainingType<TExtension>(GeneratedExtensionLite<TMessage, TExtension> extension) {
147 if (!ReferenceEquals(extension.ContainingTypeDefaultInstance, DefaultInstanceForType)) {
148 // This can only happen if someone uses unchecked operations.
149 throw new ArgumentException(
150 String.Format("Extension is for type \"{0}\" which does not match message type \"{1}\".",
151 extension.ContainingTypeDefaultInstance, DefaultInstanceForType
152 ));
153 }
154 }
155 }
156}