Review changes
* Add Syntax enum and make file syntax checks check the enum * Made IsPacked a normal get method without ternary op * Moved IFieldAccessor.HasValue to IFieldPresenceAccessor * Change naming of GetIsExtensionsInitialized * Fixed stray text in summary text
This commit is contained in:
parent
29d5186867
commit
47f2017cf3
@ -101,7 +101,7 @@ namespace Google.Protobuf.Reflection
|
||||
{
|
||||
IMessage message = SampleMessages.CreateFullTestAllTypes();
|
||||
var fields = message.Descriptor.Fields;
|
||||
Assert.Throws<InvalidOperationException>(() => fields[TestProtos.TestAllTypes.SingleBoolFieldNumber].Accessor.HasValue(message));
|
||||
Assert.Throws<InvalidOperationException>(() => (fields[TestProtos.TestAllTypes.SingleBoolFieldNumber].Accessor as IFieldPresenceAccessor).HasValue(message));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -109,7 +109,7 @@ namespace Google.Protobuf.Reflection
|
||||
{
|
||||
IMessage message = new Proto2.TestAllTypes();
|
||||
var fields = message.Descriptor.Fields;
|
||||
var accessor = fields[Proto2.TestAllTypes.OptionalBoolFieldNumber].Accessor;
|
||||
var accessor = fields[Proto2.TestAllTypes.OptionalBoolFieldNumber].Accessor as IFieldPresenceAccessor;
|
||||
|
||||
Assert.False(accessor.HasValue(message));
|
||||
|
||||
|
@ -148,12 +148,12 @@ namespace Google.Protobuf
|
||||
/// </summary>
|
||||
public static bool IsInitialized(this IMessage message)
|
||||
{
|
||||
if (message.Descriptor.File.Proto.Syntax == "proto3")
|
||||
if (message.Descriptor.File.Syntax == Syntax.Proto3)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!message.Descriptor.GetIsExtensionsInitialized(message))
|
||||
if (!message.Descriptor.IsExtensionsInitialized(message))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -183,7 +183,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
else if (f.FieldType == FieldType.Message || f.FieldType == FieldType.Group)
|
||||
{
|
||||
if (f.Accessor.HasValue(message))
|
||||
if ((f.Accessor as IFieldPresenceAccessor).HasValue(message))
|
||||
{
|
||||
return ((IMessage)f.Accessor.GetValue(message)).IsInitialized();
|
||||
}
|
||||
@ -194,7 +194,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
else if (f.IsRequired)
|
||||
{
|
||||
return f.Accessor.HasValue(message);
|
||||
return (f.Accessor as IFieldPresenceAccessor).HasValue(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -201,7 +201,20 @@ namespace Google.Protobuf.Reflection
|
||||
/// <summary>
|
||||
/// Returns <c>true</c> if this field is a packed, repeated field; <c>false</c> otherwise.
|
||||
/// </summary>
|
||||
public bool IsPacked => File.Proto.Syntax != "proto3" ? Proto.Options?.Packed ?? false : !Proto.Options.HasPacked || Proto.Options.Packed;
|
||||
public bool IsPacked
|
||||
{
|
||||
get
|
||||
{
|
||||
if (File.Syntax != Syntax.Proto3)
|
||||
{
|
||||
return Proto.Options?.Packed ?? false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return !Proto.Options.HasPacked || Proto.Options.Packed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <c>true</c> if this field extends another message type; <c>false</c> otherwise.
|
||||
|
@ -42,6 +42,25 @@ using static Google.Protobuf.Reflection.SourceCodeInfo.Types;
|
||||
|
||||
namespace Google.Protobuf.Reflection
|
||||
{
|
||||
/// <summary>
|
||||
/// The syntax of a .proto file
|
||||
/// </summary>
|
||||
public enum Syntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Proto2 syntax
|
||||
/// </summary>
|
||||
Proto2,
|
||||
/// <summary>
|
||||
/// Proto3 syntax
|
||||
/// </summary>
|
||||
Proto3,
|
||||
/// <summary>
|
||||
/// An unknown declared syntax
|
||||
/// </summary>
|
||||
Unknown
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes a .proto file, including everything defined within.
|
||||
/// IDescriptor is implemented such that the File property returns this descriptor,
|
||||
@ -87,6 +106,19 @@ namespace Google.Protobuf.Reflection
|
||||
Extensions = new ExtensionCollection(this, generatedCodeInfo?.Extensions);
|
||||
|
||||
declarations = new Lazy<Dictionary<IDescriptor, DescriptorDeclaration>>(CreateDeclarationMap, LazyThreadSafetyMode.ExecutionAndPublication);
|
||||
|
||||
if (!proto.HasSyntax || proto.Syntax == "proto2")
|
||||
{
|
||||
Syntax = Syntax.Proto2;
|
||||
}
|
||||
else if (proto.Syntax == "proto3")
|
||||
{
|
||||
Syntax = Syntax.Proto3;
|
||||
}
|
||||
else
|
||||
{
|
||||
Syntax = Syntax.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<IDescriptor, DescriptorDeclaration> CreateDeclarationMap()
|
||||
@ -217,6 +249,11 @@ namespace Google.Protobuf.Reflection
|
||||
/// </value>
|
||||
internal FileDescriptorProto Proto { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The syntax of the file
|
||||
/// </summary>
|
||||
public Syntax Syntax { get; }
|
||||
|
||||
/// <value>
|
||||
/// The file name.
|
||||
/// </value>
|
||||
|
@ -51,11 +51,6 @@ namespace Google.Protobuf.Reflection
|
||||
/// </summary>
|
||||
void Clear(IMessage message);
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the field in the specified message is set. For proto3 fields, this throws an <see cref="InvalidOperationException"/>
|
||||
/// </summary>
|
||||
bool HasValue(IMessage message);
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the field value. For repeated values, this will be an
|
||||
/// <see cref="IList"/> implementation. For map values, this will be an
|
||||
@ -73,4 +68,15 @@ namespace Google.Protobuf.Reflection
|
||||
/// <exception cref="InvalidOperationException">The field is not a "simple" field.</exception>
|
||||
void SetValue(IMessage message, object value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows field presence to be checked reflectively. This is implemented for all single field accessors
|
||||
/// </summary>
|
||||
public interface IFieldPresenceAccessor : IFieldAccessor
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether the field in the specified message is set. For proto3 fields, this throws an <see cref="InvalidOperationException"/>
|
||||
/// </summary>
|
||||
bool HasValue(IMessage message);
|
||||
}
|
||||
}
|
@ -136,7 +136,7 @@ namespace Google.Protobuf.Reflection
|
||||
|
||||
internal DescriptorProto Proto { get; }
|
||||
|
||||
internal bool GetIsExtensionsInitialized(IMessage message)
|
||||
internal bool IsExtensionsInitialized(IMessage message)
|
||||
{
|
||||
if (Proto.ExtensionRange.Count == 0)
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ namespace Google.Protobuf.Reflection
|
||||
|
||||
/// <summary>
|
||||
/// Empty Type[] used when calling GetProperty to force property instead of indexer fetching.
|
||||
/// </summary>getFieldFunc
|
||||
/// </summary>
|
||||
internal static readonly Type[] EmptyTypes = new Type[0];
|
||||
|
||||
/// <summary>
|
||||
|
@ -39,7 +39,7 @@ namespace Google.Protobuf.Reflection
|
||||
/// <summary>
|
||||
/// Accessor for single fields.
|
||||
/// </summary>
|
||||
internal sealed class SingleFieldAccessor : FieldAccessorBase
|
||||
internal sealed class SingleFieldAccessor : FieldAccessorBase, IFieldPresenceAccessor
|
||||
{
|
||||
// All the work here is actually done in the constructor - it creates the appropriate delegates.
|
||||
// There are various cases to consider, based on the property type (message, string/bytes, or "genuine" primitive)
|
||||
@ -57,7 +57,7 @@ namespace Google.Protobuf.Reflection
|
||||
throw new ArgumentException("Not all required properties/methods available");
|
||||
}
|
||||
setValueDelegate = ReflectionUtil.CreateActionIMessageObject(property.GetSetMethod());
|
||||
if (descriptor.File.Proto.Syntax == "proto3")
|
||||
if (descriptor.File.Syntax == Syntax.Proto3)
|
||||
{
|
||||
hasDelegate = message => {
|
||||
throw new InvalidOperationException("HasValue is not implemented for proto3 fields");
|
||||
|
Loading…
Reference in New Issue
Block a user