|
@@ -39,6 +39,20 @@ using Google.ProtocolBuffers.Collections;
|
|
|
using Google.ProtocolBuffers.Descriptors;
|
|
|
|
|
|
namespace Google.ProtocolBuffers {
|
|
|
+
|
|
|
+ public interface IFieldDescriptorLite : IComparable<IFieldDescriptorLite> {
|
|
|
+ bool IsRepeated { get; }
|
|
|
+ bool IsRequired { get; }
|
|
|
+ bool IsPacked { get; }
|
|
|
+ bool IsExtension { get; }
|
|
|
+ bool MessageSetWireFormat { get; } //field.ContainingType.Options.MessageSetWireFormat
|
|
|
+ int FieldNumber { get; }
|
|
|
+ IEnumLiteMap EnumType { get; }
|
|
|
+ FieldType FieldType { get; }
|
|
|
+ MappedType MappedType { get; }
|
|
|
+ object DefaultValue { get; }
|
|
|
+ }
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// A class which represents an arbitrary set of fields of some message type.
|
|
|
/// This is used to implement DynamicMessage, and also to represent extensions
|
|
@@ -56,17 +70,17 @@ namespace Google.ProtocolBuffers {
|
|
|
/// </summary>
|
|
|
internal sealed class FieldSet {
|
|
|
|
|
|
- private static readonly FieldSet defaultInstance = new FieldSet(new Dictionary<FieldDescriptor, object>()).MakeImmutable();
|
|
|
+ private static readonly FieldSet defaultInstance = new FieldSet(new Dictionary<IFieldDescriptorLite, object>()).MakeImmutable();
|
|
|
|
|
|
- private IDictionary<FieldDescriptor, object> fields;
|
|
|
+ private IDictionary<IFieldDescriptorLite, object> fields;
|
|
|
|
|
|
- private FieldSet(IDictionary<FieldDescriptor, object> fields) {
|
|
|
+ private FieldSet(IDictionary<IFieldDescriptorLite, object> fields) {
|
|
|
this.fields = fields;
|
|
|
}
|
|
|
|
|
|
public static FieldSet CreateInstance() {
|
|
|
// Use SortedList to keep fields in the canonical order
|
|
|
- return new FieldSet(new SortedList<FieldDescriptor, object>());
|
|
|
+ return new FieldSet(new SortedList<IFieldDescriptorLite, object>());
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
@@ -85,8 +99,8 @@ namespace Google.ProtocolBuffers {
|
|
|
}
|
|
|
|
|
|
if (hasRepeats) {
|
|
|
- var tmp = new SortedList<FieldDescriptor, object>();
|
|
|
- foreach (KeyValuePair<FieldDescriptor, object> entry in fields) {
|
|
|
+ var tmp = new SortedList<IFieldDescriptorLite, object>();
|
|
|
+ foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
|
|
|
IList<object> list = entry.Value as IList<object>;
|
|
|
tmp[entry.Key] = list == null ? entry.Value : Lists.AsReadOnly(list);
|
|
|
}
|
|
@@ -110,14 +124,26 @@ namespace Google.ProtocolBuffers {
|
|
|
/// is immutable, the entries may not be (i.e. any repeated values are represented by
|
|
|
/// mutable lists). The behaviour is not specified if the contents are mutated.
|
|
|
/// </summary>
|
|
|
- internal IDictionary<FieldDescriptor, object> AllFields {
|
|
|
+ internal IDictionary<IFieldDescriptorLite, object> AllFields {
|
|
|
get { return Dictionaries.AsReadOnly(fields); }
|
|
|
}
|
|
|
-
|
|
|
+#if !LITE
|
|
|
+ /// <summary>
|
|
|
+ /// Force coercion to full descriptor dictionary.
|
|
|
+ /// </summary>
|
|
|
+ internal IDictionary<Descriptors.FieldDescriptor, object> AllFieldDescriptors {
|
|
|
+ get {
|
|
|
+ SortedList<Descriptors.FieldDescriptor, object> copy = new SortedList<Google.ProtocolBuffers.Descriptors.FieldDescriptor, object>();
|
|
|
+ foreach (KeyValuePair<IFieldDescriptorLite, object> fd in fields)
|
|
|
+ copy.Add((Descriptors.FieldDescriptor)fd.Key, fd.Value);
|
|
|
+ return Dictionaries.AsReadOnly(copy);
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
/// <summary>
|
|
|
- /// See <see cref="IMessage.HasField"/>.
|
|
|
+ /// See <see cref="IMessageLite.HasField"/>.
|
|
|
/// </summary>
|
|
|
- public bool HasField(FieldDescriptor field) {
|
|
|
+ public bool HasField(IFieldDescriptorLite field) {
|
|
|
if (field.IsRepeated) {
|
|
|
throw new ArgumentException("HasField() can only be called on non-repeated fields.");
|
|
|
}
|
|
@@ -133,7 +159,7 @@ namespace Google.ProtocolBuffers {
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// See <see cref="IMessage.Item(FieldDescriptor)"/>
|
|
|
+ /// See <see cref="IMessageLite.Item(IFieldDescriptorLite)"/>
|
|
|
/// </summary>
|
|
|
/// <remarks>
|
|
|
/// If the field is not set, the behaviour when fetching this property varies by field type:
|
|
@@ -153,7 +179,7 @@ namespace Google.ProtocolBuffers {
|
|
|
/// to ensure it is of an appropriate type.
|
|
|
/// </remarks>
|
|
|
///
|
|
|
- internal object this[FieldDescriptor field] {
|
|
|
+ internal object this[IFieldDescriptorLite field] {
|
|
|
get {
|
|
|
object result;
|
|
|
if (fields.TryGetValue(field, out result)) {
|
|
@@ -191,9 +217,9 @@ namespace Google.ProtocolBuffers {
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// See <see cref="IMessage.Item(FieldDescriptor,int)" />
|
|
|
+ /// See <see cref="IMessageLite.Item(IFieldDescriptorLite,int)" />
|
|
|
/// </summary>
|
|
|
- internal object this[FieldDescriptor field, int index] {
|
|
|
+ internal object this[IFieldDescriptorLite field, int index] {
|
|
|
get {
|
|
|
if (!field.IsRepeated) {
|
|
|
throw new ArgumentException("Indexer specifying field and index can only be called on repeated fields.");
|
|
@@ -217,7 +243,7 @@ namespace Google.ProtocolBuffers {
|
|
|
/// <summary>
|
|
|
/// See <see cref="IBuilder{TMessage, TBuilder}.AddRepeatedField" />
|
|
|
/// </summary>
|
|
|
- internal void AddRepeatedField(FieldDescriptor field, object value) {
|
|
|
+ internal void AddRepeatedField(IFieldDescriptorLite field, object value) {
|
|
|
if (!field.IsRepeated) {
|
|
|
throw new ArgumentException("AddRepeatedField can only be called on repeated fields.");
|
|
|
}
|
|
@@ -233,12 +259,12 @@ namespace Google.ProtocolBuffers {
|
|
|
/// <summary>
|
|
|
/// Returns an enumerator for the field map. Used to write the fields out.
|
|
|
/// </summary>
|
|
|
- internal IEnumerator<KeyValuePair<FieldDescriptor, object>> GetEnumerator() {
|
|
|
+ internal IEnumerator<KeyValuePair<IFieldDescriptorLite, object>> GetEnumerator() {
|
|
|
return fields.GetEnumerator();
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// See <see cref="IMessage.IsInitialized" />
|
|
|
+ /// See <see cref="IMessageLite.IsInitialized" />
|
|
|
/// </summary>
|
|
|
/// <remarks>
|
|
|
/// Since FieldSet itself does not have any way of knowing about
|
|
@@ -248,17 +274,17 @@ namespace Google.ProtocolBuffers {
|
|
|
/// </remarks>
|
|
|
internal bool IsInitialized {
|
|
|
get {
|
|
|
- foreach (KeyValuePair<FieldDescriptor, object> entry in fields) {
|
|
|
- FieldDescriptor field = entry.Key;
|
|
|
+ foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
|
|
|
+ IFieldDescriptorLite field = entry.Key;
|
|
|
if (field.MappedType == MappedType.Message) {
|
|
|
if (field.IsRepeated) {
|
|
|
- foreach(IMessage message in (IEnumerable) entry.Value) {
|
|
|
+ foreach(IMessageLite message in (IEnumerable) entry.Value) {
|
|
|
if (!message.IsInitialized) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
- if (!((IMessage) entry.Value).IsInitialized) {
|
|
|
+ if (!((IMessageLite)entry.Value).IsInitialized) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
@@ -273,8 +299,8 @@ namespace Google.ProtocolBuffers {
|
|
|
/// descriptor are present in this field set, as well as whether
|
|
|
/// all the embedded messages are themselves initialized.
|
|
|
/// </summary>
|
|
|
- internal bool IsInitializedWithRespectTo(MessageDescriptor type) {
|
|
|
- foreach (FieldDescriptor field in type.Fields) {
|
|
|
+ internal bool IsInitializedWithRespectTo(IEnumerable typeFields) {
|
|
|
+ foreach (IFieldDescriptorLite field in typeFields) {
|
|
|
if (field.IsRequired && !HasField(field)) {
|
|
|
return false;
|
|
|
}
|
|
@@ -285,14 +311,14 @@ namespace Google.ProtocolBuffers {
|
|
|
/// <summary>
|
|
|
/// See <see cref="IBuilder{TMessage, TBuilder}.ClearField" />
|
|
|
/// </summary>
|
|
|
- public void ClearField(FieldDescriptor field) {
|
|
|
+ public void ClearField(IFieldDescriptorLite field) {
|
|
|
fields.Remove(field);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// See <see cref="IMessage.GetRepeatedFieldCount" />
|
|
|
+ /// See <see cref="IMessageLite.GetRepeatedFieldCount" />
|
|
|
/// </summary>
|
|
|
- public int GetRepeatedFieldCount(FieldDescriptor field) {
|
|
|
+ public int GetRepeatedFieldCount(IFieldDescriptorLite field) {
|
|
|
if (!field.IsRepeated) {
|
|
|
throw new ArgumentException("GetRepeatedFieldCount() can only be called on repeated fields.");
|
|
|
}
|
|
@@ -300,64 +326,63 @@ namespace Google.ProtocolBuffers {
|
|
|
return ((IList<object>) this[field]).Count;
|
|
|
}
|
|
|
|
|
|
+#if !LITE
|
|
|
+ /// <summary>
|
|
|
+ /// See <see cref="IBuilder{TMessage, TBuilder}.MergeFrom(IMessageLite)" />
|
|
|
+ /// </summary>
|
|
|
+ public void MergeFrom(IMessage other) {
|
|
|
+ foreach (KeyValuePair<Descriptors.FieldDescriptor, object> fd in other.AllFields)
|
|
|
+ MergeField(fd.Key, fd.Value);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Implementation of both <c>MergeFrom</c> methods.
|
|
|
/// </summary>
|
|
|
/// <param name="otherFields"></param>
|
|
|
- private void MergeFields(IEnumerable<KeyValuePair<FieldDescriptor, object>> otherFields) {
|
|
|
+ public void MergeFrom(FieldSet other) {
|
|
|
// Note: We don't attempt to verify that other's fields have valid
|
|
|
// types. Doing so would be a losing battle. We'd have to verify
|
|
|
// all sub-messages as well, and we'd have to make copies of all of
|
|
|
// them to insure that they don't change after verification (since
|
|
|
- // the IMessage interface itself cannot enforce immutability of
|
|
|
+ // the IMessageLite interface itself cannot enforce immutability of
|
|
|
// implementations).
|
|
|
// TODO(jonskeet): Provide a function somewhere called MakeDeepCopy()
|
|
|
// which allows people to make secure deep copies of messages.
|
|
|
|
|
|
- foreach (KeyValuePair<FieldDescriptor, object> entry in otherFields) {
|
|
|
- FieldDescriptor field = entry.Key;
|
|
|
- object existingValue;
|
|
|
- fields.TryGetValue(field, out existingValue);
|
|
|
- if (field.IsRepeated) {
|
|
|
- if (existingValue == null) {
|
|
|
- existingValue = new List<object>();
|
|
|
- fields[field] = existingValue;
|
|
|
- }
|
|
|
- IList<object> list = (IList<object>) existingValue;
|
|
|
- foreach (object otherValue in (IEnumerable) entry.Value) {
|
|
|
- list.Add(otherValue);
|
|
|
- }
|
|
|
- } else if (field.MappedType == MappedType.Message && existingValue != null) {
|
|
|
- IMessage existingMessage = (IMessage)existingValue;
|
|
|
- IMessage merged = existingMessage.WeakToBuilder()
|
|
|
- .WeakMergeFrom((IMessage) entry.Value)
|
|
|
- .WeakBuild();
|
|
|
- this[field] = merged;
|
|
|
- } else {
|
|
|
- this[field] = entry.Value;
|
|
|
- }
|
|
|
+ foreach (KeyValuePair<IFieldDescriptorLite, object> entry in other.fields) {
|
|
|
+ MergeField(entry.Key, entry.Value);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// See <see cref="IBuilder{TMessage, TBuilder}.MergeFrom(IMessage)" />
|
|
|
- /// </summary>
|
|
|
- public void MergeFrom(IMessage other) {
|
|
|
- MergeFields(other.AllFields);
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Like <see cref="MergeFrom(IMessage)"/>, but merges from another <c>FieldSet</c>.
|
|
|
- /// </summary>
|
|
|
- public void MergeFrom(FieldSet other) {
|
|
|
- MergeFields(other.fields);
|
|
|
+ private void MergeField(IFieldDescriptorLite field, object mergeValue) {
|
|
|
+ object existingValue;
|
|
|
+ fields.TryGetValue(field, out existingValue);
|
|
|
+ if (field.IsRepeated) {
|
|
|
+ if (existingValue == null) {
|
|
|
+ existingValue = new List<object>();
|
|
|
+ fields[field] = existingValue;
|
|
|
+ }
|
|
|
+ IList<object> list = (IList<object>) existingValue;
|
|
|
+ foreach (object otherValue in (IEnumerable)mergeValue) {
|
|
|
+ list.Add(otherValue);
|
|
|
+ }
|
|
|
+ } else if (field.MappedType == MappedType.Message && existingValue != null) {
|
|
|
+ IMessageLite existingMessage = (IMessageLite)existingValue;
|
|
|
+ IMessageLite merged = existingMessage.WeakToBuilder()
|
|
|
+ .WeakMergeFrom((IMessageLite)mergeValue)
|
|
|
+ .WeakBuild();
|
|
|
+ this[field] = merged;
|
|
|
+ } else {
|
|
|
+ this[field] = mergeValue;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// See <see cref="IMessage.WriteTo(CodedOutputStream)" />.
|
|
|
+ /// See <see cref="IMessageLite.WriteTo(CodedOutputStream)" />.
|
|
|
/// </summary>
|
|
|
public void WriteTo(CodedOutputStream output) {
|
|
|
- foreach (KeyValuePair<FieldDescriptor, object> entry in fields) {
|
|
|
+ foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
|
|
|
WriteField(entry.Key, entry.Value, output);
|
|
|
}
|
|
|
}
|
|
@@ -365,9 +390,9 @@ namespace Google.ProtocolBuffers {
|
|
|
/// <summary>
|
|
|
/// Writes a single field to a CodedOutputStream.
|
|
|
/// </summary>
|
|
|
- public void WriteField(FieldDescriptor field, Object value, CodedOutputStream output) {
|
|
|
- if (field.IsExtension && field.ContainingType.Options.MessageSetWireFormat) {
|
|
|
- output.WriteMessageSetExtension(field.FieldNumber, (IMessage) value);
|
|
|
+ public void WriteField(IFieldDescriptorLite field, Object value, CodedOutputStream output) {
|
|
|
+ if (field.IsExtension && field.MessageSetWireFormat) {
|
|
|
+ output.WriteMessageSetExtension(field.FieldNumber, (IMessageLite) value);
|
|
|
} else {
|
|
|
if (field.IsRepeated) {
|
|
|
IEnumerable valueList = (IEnumerable) value;
|
|
@@ -395,18 +420,18 @@ namespace Google.ProtocolBuffers {
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// See <see cref="IMessage.SerializedSize" />. It's up to the caller to
|
|
|
+ /// See <see cref="IMessageLite.SerializedSize" />. It's up to the caller to
|
|
|
/// cache the resulting size if desired.
|
|
|
/// </summary>
|
|
|
public int SerializedSize {
|
|
|
get {
|
|
|
int size = 0;
|
|
|
- foreach (KeyValuePair<FieldDescriptor, object> entry in fields) {
|
|
|
- FieldDescriptor field = entry.Key;
|
|
|
+ foreach (KeyValuePair<IFieldDescriptorLite, object> entry in fields) {
|
|
|
+ IFieldDescriptorLite field = entry.Key;
|
|
|
object value = entry.Value;
|
|
|
|
|
|
- if (field.IsExtension && field.ContainingType.Options.MessageSetWireFormat) {
|
|
|
- size += CodedOutputStream.ComputeMessageSetExtensionSize(field.FieldNumber, (IMessage)value);
|
|
|
+ if (field.IsExtension && field.MessageSetWireFormat) {
|
|
|
+ size += CodedOutputStream.ComputeMessageSetExtensionSize(field.FieldNumber, (IMessageLite)value);
|
|
|
} else {
|
|
|
if (field.IsRepeated) {
|
|
|
IEnumerable valueList = (IEnumerable)value;
|
|
@@ -440,7 +465,7 @@ namespace Google.ProtocolBuffers {
|
|
|
/// </remarks>
|
|
|
/// <exception cref="ArgumentException">The value is not of the right type.</exception>
|
|
|
/// <exception cref="ArgumentNullException">The value is null.</exception>
|
|
|
- private static void VerifyType(FieldDescriptor field, object value) {
|
|
|
+ private static void VerifyType(IFieldDescriptorLite field, object value) {
|
|
|
ThrowHelper.ThrowIfNull(value, "value");
|
|
|
bool isValid = false;
|
|
|
switch (field.MappedType) {
|
|
@@ -454,12 +479,15 @@ namespace Google.ProtocolBuffers {
|
|
|
case MappedType.String: isValid = value is string; break;
|
|
|
case MappedType.ByteString: isValid = value is ByteString; break;
|
|
|
case MappedType.Enum:
|
|
|
- EnumValueDescriptor enumValue = value as EnumValueDescriptor;
|
|
|
- isValid = enumValue != null && enumValue.EnumDescriptor == field.EnumType;
|
|
|
+ IEnumLite enumValue = value as IEnumLite;
|
|
|
+ isValid = enumValue != null && field.EnumType.IsValidValue(enumValue);
|
|
|
break;
|
|
|
case MappedType.Message:
|
|
|
- IMessage messageValue = value as IMessage;
|
|
|
- isValid = messageValue != null && messageValue.DescriptorForType == field.MessageType;
|
|
|
+ IMessageLite messageValue = value as IMessageLite;
|
|
|
+ isValid = messageValue != null;
|
|
|
+#if !LITE
|
|
|
+ isValid = isValid && ((IMessage)messageValue).DescriptorForType == ((Google.ProtocolBuffers.Descriptors.FieldDescriptor)field).MessageType;
|
|
|
+#endif
|
|
|
break;
|
|
|
}
|
|
|
|
|
@@ -468,10 +496,16 @@ namespace Google.ProtocolBuffers {
|
|
|
// the stack trace which exact call failed, since the whole chain is
|
|
|
// considered one line of code. So, let's make sure to include the
|
|
|
// field name and other useful info in the exception.
|
|
|
- throw new ArgumentException("Wrong object type used with protocol message reflection. "
|
|
|
- + "Message type \"" + field.ContainingType.FullName
|
|
|
- + "\", field \"" + (field.IsExtension ? field.FullName : field.Name)
|
|
|
- + "\", value was type \"" + value.GetType().Name + "\".");
|
|
|
+ string message = "Wrong object type used with protocol message reflection.";
|
|
|
+#if !LITE
|
|
|
+ Google.ProtocolBuffers.Descriptors.FieldDescriptor fieldinfo = field as Google.ProtocolBuffers.Descriptors.FieldDescriptor;
|
|
|
+ if (fieldinfo != null) {
|
|
|
+ message += "Message type \"" + fieldinfo.ContainingType.FullName;
|
|
|
+ message += "\", field \"" + (fieldinfo.IsExtension ? fieldinfo.FullName : fieldinfo.Name);
|
|
|
+ message += "\", value was type \"" + value.GetType().Name + "\".";
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ throw new ArgumentException(message);
|
|
|
}
|
|
|
}
|
|
|
}
|