diff options
author | Jon Skeet <skeet@pobox.com> | 2008-08-14 20:35:21 +0100 |
---|---|---|
committer | Jon Skeet <skeet@pobox.com> | 2008-08-14 20:35:21 +0100 |
commit | 575083ae9c3ecb17e14ae29aa20b784940fcdfd1 (patch) | |
tree | a8b536c9b8e2982e9e904e25b8489404cd727155 /csharp/ProtocolBuffers/ExtendableMessage.cs | |
parent | 1353315dede3e22266df73fca8dd421119597e46 (diff) | |
download | protobuf-575083ae9c3ecb17e14ae29aa20b784940fcdfd1.tar.gz protobuf-575083ae9c3ecb17e14ae29aa20b784940fcdfd1.tar.bz2 protobuf-575083ae9c3ecb17e14ae29aa20b784940fcdfd1.zip |
Initial support for services and extensions. Incomplete, but enough to get generated unit test files to compile.
Diffstat (limited to 'csharp/ProtocolBuffers/ExtendableMessage.cs')
-rw-r--r-- | csharp/ProtocolBuffers/ExtendableMessage.cs | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/csharp/ProtocolBuffers/ExtendableMessage.cs b/csharp/ProtocolBuffers/ExtendableMessage.cs new file mode 100644 index 00000000..cf43b03b --- /dev/null +++ b/csharp/ProtocolBuffers/ExtendableMessage.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Google.ProtocolBuffers.Descriptors; +using Google.ProtocolBuffers.Collections; + +namespace Google.ProtocolBuffers { + public abstract class ExtendableMessage<TMessage,TBuilder> : GeneratedMessage<TMessage,TBuilder> + where TMessage : GeneratedMessage<TMessage, TBuilder> + where TBuilder : IBuilder<TMessage> { + + protected ExtendableMessage() {} + private readonly FieldSet extensions = FieldSet.CreateFieldSet(); + + /// <summary> + /// Checks if a singular extension is present. + /// </summary> + public bool HasExtension(GeneratedExtension<TMessage, TBuilder> extension) { + return extensions.HasField(extension.Descriptor); + } + + /// <summary> + /// Returns the number of elements in a repeated extension. + /// </summary> + public int GetExtensionCount<TExtension>(GeneratedExtension<TMessage, IList<TExtension>> extension) { + return extensions.GetRepeatedFieldCount(extension.Descriptor); + } + + /// <summary> + /// Returns the value of an extension. + /// </summary> + public TExtension GetExtension<TExtension>(GeneratedExtension<TMessage, TExtension> extension) { + object value = extensions[extension.Descriptor]; + if (value == null) { + return (TExtension) extension.MessageDefaultInstance; + } else { + return (TExtension) extension.FromReflectionType(value); + } + } + + /// <summary> + /// Returns one element of a repeated extension. + /// </summary> + public TExtension GetExtension<TExtension>(GeneratedExtension<TMessage, IList<TExtension>> extension, int index) { + return (TExtension) extension.SingularFromReflectionType(extensions[extension.Descriptor, index]); + } + + /// <summary> + /// Called by subclasses to check if all extensions are initialized. + /// </summary> + protected bool ExtensionsAreInitialized { + get { return extensions.IsInitialized; } + } + + #region Reflection + public override IDictionary<FieldDescriptor, object> AllFields { + get { + IDictionary<FieldDescriptor, object> result = GetMutableFieldMap(); + foreach(KeyValuePair<FieldDescriptor, object> entry in extensions.AllFields) { + result[entry.Key] = entry.Value; + } + return Dictionaries.AsReadOnly(result); + } + } + + public override bool HasField(FieldDescriptor field) { + if (field.IsExtension) { + VerifyContainingType(field); + return extensions.HasField(field); + } else { + return base.HasField(field); + } + } + + public override object this[FieldDescriptor field] { + get { + if (field.IsExtension) { + VerifyContainingType(field); + object value = extensions[field]; + if (value == null) { + // Lacking an ExtensionRegistry, we have no way to determine the + // extension's real type, so we return a DynamicMessage. + // TODO(jonskeet): Work out what this means + return DynamicMessage.GetDefaultInstance(field.MessageType); + } else { + return value; + } + } else { + return base[field]; + } + } + } + + public override int GetRepeatedFieldCount(FieldDescriptor field) { + if (field.IsExtension) { + VerifyContainingType(field); + return extensions.GetRepeatedFieldCount(field); + } else { + return base.GetRepeatedFieldCount(field); + } + } + + public override object this[FieldDescriptor field, int index] { + get { + if (field.IsExtension) { + VerifyContainingType(field); + return extensions[field, index]; + } else { + return base[field, index]; + } + } + } + + private void VerifyContainingType(FieldDescriptor field) { + if (field.ContainingType != DescriptorForType) { + throw new ArgumentException("FieldDescriptor does not match message type."); + } + } + #endregion + + /// <summary> + /// Used by subclasses to serialize extensions. Extension ranges may be + /// interleaves with field numbers, but we must write them in canonical + /// (sorted by field number) order. This class helps us to write individual + /// ranges of extensions at once. + /// + /// TODO(jonskeet): See if we can improve this in terms of readability. + /// </summary> + protected class ExtensionWriter { + readonly IEnumerator<KeyValuePair<FieldDescriptor, object>> iterator; + readonly FieldSet extensions; + KeyValuePair<FieldDescriptor, object>? next = null; + + internal ExtensionWriter(ExtendableMessage<TMessage, TBuilder> message) { + extensions = message.extensions; + iterator = message.extensions.GetEnumerator(); + if (iterator.MoveNext()) { + next = iterator.Current; + } + } + + public void WriteUntil(int end, CodedOutputStream output) { + while (next != null && next.Value.Key.FieldNumber < end) { + extensions.WriteField(next.Value.Key, next.Value.Value, output); + if (iterator.MoveNext()) { + next = iterator.Current; + } else { + next = null; + } + } + } + } + + protected ExtensionWriter CreateExtensionWriter(ExtendableMessage<TMessage, TBuilder> message) { + return new ExtensionWriter(message); + } + + /// <summary> + /// Called by subclasses to compute the size of extensions. + /// </summary> + protected int ExtensionsSerializedSize { + get { return extensions.SerializedSize; } + } + } +} |