Protocol Buffers - Google's data interchange format (grpc依赖)
https://developers.google.com/protocol-buffers/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
390 lines
13 KiB
390 lines
13 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.IO; |
|
using System.Text; |
|
using Google.ProtocolBuffers.Descriptors; |
|
|
|
namespace Google.ProtocolBuffers { |
|
|
|
/// <summary> |
|
/// An implementation of IMessage that can represent arbitrary types, given a MessageaDescriptor. |
|
/// TODO: Implement appropriate generics. |
|
/// </summary> |
|
public class DynamicMessage : AbstractMessage { |
|
|
|
private readonly MessageDescriptor type; |
|
private readonly FieldSet fields; |
|
private readonly UnknownFieldSet unknownFields; |
|
private int memoizedSize = -1; |
|
|
|
/// <summary> |
|
/// Creates a DynamicMessage with the given FieldSet. |
|
/// </summary> |
|
/// <param name="type"></param> |
|
/// <param name="fields"></param> |
|
/// <param name="unknownFields"></param> |
|
private DynamicMessage(MessageDescriptor type, FieldSet fields, UnknownFieldSet unknownFields) { |
|
this.type = type; |
|
this.fields = fields; |
|
this.unknownFields = unknownFields; |
|
} |
|
|
|
/// <summary> |
|
/// Returns a DynamicMessage representing the default instance of the given type. |
|
/// </summary> |
|
/// <param name="type"></param> |
|
/// <returns></returns> |
|
public static DynamicMessage GetDefaultInstance(MessageDescriptor type) { |
|
return new DynamicMessage(type, FieldSet.DefaultInstance, UnknownFieldSet.DefaultInstance); |
|
} |
|
|
|
/// <summary> |
|
/// Parses a message of the given type from the given stream. |
|
/// </summary> |
|
public static DynamicMessage ParseFrom(MessageDescriptor type, CodedInputStream input) { |
|
IBuilder builder = CreateBuilder(type); |
|
Builder dynamicBuilder = (Builder)builder.MergeFrom(input); |
|
return dynamicBuilder.BuildParsed(); |
|
|
|
} |
|
|
|
/// <summary> |
|
/// Parse a message of the given type from the given stream and extension registry. |
|
/// </summary> |
|
/// <param name="type"></param> |
|
/// <param name="input"></param> |
|
/// <param name="extensionRegistry"></param> |
|
/// <returns></returns> |
|
public static DynamicMessage ParseFrom(MessageDescriptor type, CodedInputStream input, ExtensionRegistry extensionRegistry) { |
|
IBuilder builder = CreateBuilder(type); |
|
Builder dynamicBuilder = (Builder) builder.MergeFrom(input, extensionRegistry); |
|
return dynamicBuilder.BuildParsed(); |
|
} |
|
|
|
/// <summary> |
|
/// Parses a message of the given type from the given stream. |
|
/// </summary> |
|
public static DynamicMessage ParseFrom(MessageDescriptor type, Stream input) { |
|
IBuilder builder = CreateBuilder(type); |
|
Builder dynamicBuilder = (Builder)builder.MergeFrom(input); |
|
return dynamicBuilder.BuildParsed(); |
|
} |
|
|
|
/// <summary> |
|
/// Parse a message of the given type from the given stream and extension registry. |
|
/// </summary> |
|
/// <param name="type"></param> |
|
/// <param name="input"></param> |
|
/// <param name="extensionRegistry"></param> |
|
/// <returns></returns> |
|
public static DynamicMessage ParseFrom(MessageDescriptor type, Stream input, ExtensionRegistry extensionRegistry) { |
|
IBuilder builder = CreateBuilder(type); |
|
Builder dynamicBuilder = (Builder)builder.MergeFrom(input, extensionRegistry); |
|
return dynamicBuilder.BuildParsed(); |
|
} |
|
|
|
/// <summary> |
|
/// Parse <paramref name="data"/> as a message of the given type and return it. |
|
/// </summary> |
|
public static DynamicMessage ParseFrom(MessageDescriptor type, ByteString data) { |
|
IBuilder builder = CreateBuilder(type); |
|
Builder dynamicBuilder = (Builder)builder.MergeFrom(data); |
|
return dynamicBuilder.BuildParsed(); |
|
} |
|
|
|
/// <summary> |
|
/// Parse <paramref name="data"/> as a message of the given type and return it. |
|
/// </summary> |
|
public static DynamicMessage ParseFrom(MessageDescriptor type, ByteString data, ExtensionRegistry extensionRegistry) { |
|
IBuilder builder = CreateBuilder(type); |
|
Builder dynamicBuilder = (Builder)builder.MergeFrom(data, extensionRegistry); |
|
return dynamicBuilder.BuildParsed(); |
|
|
|
} |
|
|
|
/// <summary> |
|
/// Parse <paramref name="data"/> as a message of the given type and return it. |
|
/// </summary> |
|
public static DynamicMessage ParseFrom(MessageDescriptor type, byte[] data) { |
|
IBuilder builder = CreateBuilder(type); |
|
Builder dynamicBuilder = (Builder)builder.MergeFrom(data); |
|
return dynamicBuilder.BuildParsed(); |
|
} |
|
|
|
/// <summary> |
|
/// Parse <paramref name="data"/> as a message of the given type and return it. |
|
/// </summary> |
|
public static DynamicMessage ParseFrom(MessageDescriptor type, byte[] data, ExtensionRegistry extensionRegistry) { |
|
IBuilder builder = CreateBuilder(type); |
|
Builder dynamicBuilder = (Builder)builder.MergeFrom(data, extensionRegistry); |
|
return dynamicBuilder.BuildParsed(); |
|
} |
|
|
|
/// <summary> |
|
/// Constructs a builder for the given type. |
|
/// </summary> |
|
public static Builder CreateBuilder(MessageDescriptor type) { |
|
return new Builder(type); |
|
} |
|
|
|
/// <summary> |
|
/// Constructs a builder for a message of the same type as <paramref name="prototype"/>, |
|
/// and initializes it with the same contents. |
|
/// </summary> |
|
/// <param name="prototype"></param> |
|
/// <returns></returns> |
|
public static Builder CreateBuilder(IMessage prototype) { |
|
return (Builder) new Builder(prototype.DescriptorForType).MergeFrom(prototype); |
|
} |
|
|
|
// ----------------------------------------------------------------- |
|
// Implementation of IMessage interface. |
|
|
|
public override MessageDescriptor DescriptorForType { |
|
get { return type; } |
|
} |
|
|
|
protected override IMessage DefaultInstanceForTypeImpl { |
|
get { return GetDefaultInstance(type); } |
|
} |
|
|
|
public override IDictionary<FieldDescriptor, object> AllFields { |
|
get { return fields.AllFields; } |
|
} |
|
|
|
public override bool HasField(FieldDescriptor field) { |
|
VerifyContainingType(field); |
|
return fields.HasField(field); |
|
} |
|
|
|
public override object this[FieldDescriptor field] { |
|
get { |
|
VerifyContainingType(field); |
|
object result = fields[field]; |
|
if (result == null) { |
|
result = GetDefaultInstance(field.MessageType); |
|
} |
|
return result; |
|
} |
|
} |
|
|
|
public override int GetRepeatedFieldCount(FieldDescriptor field) { |
|
VerifyContainingType(field); |
|
return fields.GetRepeatedFieldCount(field); |
|
} |
|
|
|
public override object this[FieldDescriptor field, int index] { |
|
get { |
|
VerifyContainingType(field); |
|
return fields[field, index]; |
|
} |
|
} |
|
|
|
public override UnknownFieldSet UnknownFields { |
|
get { return unknownFields; } |
|
} |
|
|
|
public bool Initialized { |
|
get { return fields.IsInitializedWithRespectTo(type); } |
|
} |
|
|
|
public override void WriteTo(CodedOutputStream output) { |
|
fields.WriteTo(output); |
|
if (type.Options.MessageSetWireFormat) { |
|
unknownFields.WriteAsMessageSetTo(output); |
|
} else { |
|
unknownFields.WriteTo(output); |
|
} |
|
} |
|
|
|
public override int SerializedSize { |
|
get { |
|
int size = memoizedSize; |
|
if (size != -1) return size; |
|
|
|
size = fields.SerializedSize; |
|
if (type.Options.MessageSetWireFormat) { |
|
size += unknownFields.SerializedSizeAsMessageSet; |
|
} else { |
|
size += unknownFields.SerializedSize; |
|
} |
|
|
|
memoizedSize = size; |
|
return size; |
|
} |
|
} |
|
|
|
protected override IBuilder CreateBuilderForTypeImpl() { |
|
return new Builder(type); |
|
} |
|
|
|
/// <summary> |
|
/// Verifies that the field is a field of this message. |
|
/// </summary> |
|
private void VerifyContainingType(FieldDescriptor field) { |
|
if (field.ContainingType != type) { |
|
throw new ArgumentException("FieldDescriptor does not match message type."); |
|
} |
|
} |
|
|
|
public class Builder : AbstractBuilder { |
|
private readonly MessageDescriptor type; |
|
private FieldSet fields; |
|
private UnknownFieldSet unknownFields; |
|
|
|
internal Builder(MessageDescriptor type) { |
|
this.type = type; |
|
this.fields = FieldSet.CreateFieldSet(); |
|
this.unknownFields = UnknownFieldSet.DefaultInstance; |
|
} |
|
|
|
public DynamicMessage Build() { |
|
return (DynamicMessage)((IBuilder)this).Build(); |
|
} |
|
|
|
public override IBuilder Clear() { |
|
fields.Clear(); |
|
return this; |
|
} |
|
|
|
public override IBuilder MergeFrom(IMessage other) { |
|
if (other.DescriptorForType != type) { |
|
throw new ArgumentException("MergeFrom(IMessage) can only merge messages of the same type."); |
|
} |
|
fields.MergeFrom(other); |
|
return this; |
|
} |
|
|
|
protected override IMessage BuildImpl() { |
|
if (!IsInitialized) { |
|
throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields)); |
|
} |
|
return BuildPartialImpl(); |
|
} |
|
|
|
/// <summary> |
|
/// Helper for DynamicMessage.ParseFrom() methods to call. Throws |
|
/// InvalidProtocolBufferException |
|
/// </summary> |
|
/// <returns></returns> |
|
internal DynamicMessage BuildParsed() { |
|
if (!IsInitialized) { |
|
throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields)).AsInvalidProtocolBufferException(); |
|
} |
|
return (DynamicMessage) BuildPartialImpl(); |
|
} |
|
|
|
protected override IMessage BuildPartialImpl() { |
|
fields.MakeImmutable(); |
|
DynamicMessage result = new DynamicMessage(type, fields, unknownFields); |
|
fields = null; |
|
unknownFields = null; |
|
return result; |
|
} |
|
|
|
protected override IBuilder CloneImpl() { |
|
Builder result = new Builder(type); |
|
result.fields.MergeFrom(fields); |
|
return result; |
|
} |
|
|
|
public override bool IsInitialized { |
|
get { return fields.IsInitializedWithRespectTo(type); } |
|
} |
|
|
|
protected override IBuilder MergeFromImpl(CodedInputStream input, ExtensionRegistry extensionRegistry) { |
|
UnknownFieldSet.Builder unknownFieldsBuilder = UnknownFieldSet.CreateBuilder(unknownFields); |
|
FieldSet.MergeFrom(input, unknownFieldsBuilder, extensionRegistry, this); |
|
unknownFields = unknownFieldsBuilder.Build(); |
|
return this; |
|
} |
|
|
|
public override MessageDescriptor DescriptorForType { |
|
get { return type; } |
|
} |
|
|
|
protected override IMessage DefaultInstanceForTypeImpl { |
|
get { return GetDefaultInstance(type); } |
|
} |
|
|
|
public override IDictionary<FieldDescriptor, object> AllFields { |
|
get { return fields.AllFields; } |
|
} |
|
|
|
public override IBuilder CreateBuilderForField(FieldDescriptor field) { |
|
VerifyContainingType(field); |
|
if (field.MappedType != MappedType.Message) { |
|
throw new ArgumentException("CreateBuilderForField is only valid for fields with message type."); |
|
} |
|
return new Builder(field.MessageType); |
|
} |
|
|
|
public override bool HasField(FieldDescriptor field) { |
|
VerifyContainingType(field); |
|
return fields.HasField(field); |
|
} |
|
|
|
public override object this[FieldDescriptor field, int index] { |
|
get { |
|
VerifyContainingType(field); |
|
return fields[field, index]; |
|
} |
|
set { |
|
VerifyContainingType(field); |
|
fields[field, index] = value; |
|
} |
|
} |
|
|
|
public override object this[FieldDescriptor field] { |
|
get { |
|
VerifyContainingType(field); |
|
object result = fields[field]; |
|
if (result == null) { |
|
result = GetDefaultInstance(field.MessageType); |
|
} |
|
return result; |
|
} |
|
set { |
|
VerifyContainingType(field); |
|
fields[field] = value; |
|
} |
|
} |
|
|
|
protected override IBuilder ClearFieldImpl(FieldDescriptor field) { |
|
VerifyContainingType(field); |
|
fields.ClearField(field); |
|
return this; |
|
} |
|
|
|
public override int GetRepeatedFieldCount(FieldDescriptor field) { |
|
VerifyContainingType(field); |
|
return fields.GetRepeatedFieldCount(field); |
|
} |
|
|
|
protected override IBuilder AddRepeatedFieldImpl(FieldDescriptor field, object value) { |
|
VerifyContainingType(field); |
|
fields.AddRepeatedField(field, value); |
|
return this; |
|
} |
|
|
|
public override UnknownFieldSet UnknownFields { |
|
get { |
|
return unknownFields; |
|
} |
|
set { |
|
unknownFields = value; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Verifies that the field is a field of this message. |
|
/// </summary> |
|
/// <param name="field"></param> |
|
private void VerifyContainingType(FieldDescriptor field) { |
|
if (field.ContainingType != type) { |
|
throw new ArgumentException("FieldDescriptor does not match message type."); |
|
} |
|
} |
|
} |
|
} |
|
}
|
|
|