Commit 8f721f5d authored by Jon Skeet's avatar Jon Skeet

Experimental (and currently unused) behaviour to determine whether or not a…

Experimental (and currently unused) behaviour to determine whether or not a message has any required fields.
parent b01135c4
......@@ -221,6 +221,10 @@ namespace Google.ProtocolBuffers.Descriptors {
foreach (FieldDescriptor extension in extensions) {
extension.CrossLink();
}
foreach (MessageDescriptor message in messageTypes) {
message.CheckRequiredFields();
}
}
/// <summary>
......
......@@ -28,6 +28,7 @@ namespace Google.ProtocolBuffers.Descriptors {
private readonly IList<EnumDescriptor> enumTypes;
private readonly IList<FieldDescriptor> fields;
private readonly IList<FieldDescriptor> extensions;
private bool hasRequiredFields;
internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex)
: base(proto, file, ComputeFullName(file, parent, proto.Name), typeIndex) {
......@@ -83,6 +84,16 @@ namespace Google.ProtocolBuffers.Descriptors {
get { return enumTypes; }
}
/// <summary>
/// Returns a pre-computed result as to whether this message
/// has required fields. This includes optional fields which are
/// message types which in turn have required fields, and any
/// extension fields.
/// </summary>
internal bool HasRequiredFields {
get { return hasRequiredFields; }
}
/// <summary>
/// Determines if the given field number is an extension.
/// </summary>
......@@ -131,5 +142,45 @@ namespace Google.ProtocolBuffers.Descriptors {
extension.CrossLink();
}
}
internal void CheckRequiredFields() {
IDictionary<MessageDescriptor, byte> alreadySeen = new Dictionary<MessageDescriptor, byte>();
hasRequiredFields = CheckRequiredFields(alreadySeen);
}
private bool CheckRequiredFields(IDictionary<MessageDescriptor,byte> alreadySeen) {
if (alreadySeen.ContainsKey(this)) {
// The type is already in the cache. This means that either:
// a. The type has no required fields.
// b. We are in the midst of checking if the type has required fields,
// somewhere up the stack. In this case, we know that if the type
// has any required fields, they'll be found when we return to it,
// and the whole call to HasRequiredFields() will return true.
// Therefore, we don't have to check if this type has required fields
// here.
return false;
}
alreadySeen[this] = 0; // Value is irrelevant; we want set semantics
// If the type allows extensions, an extension with message type could contain
// required fields, so we have to be conservative and assume such an
// extension exists.
if (Proto.ExtensionRangeCount != 0) {
return true;
}
foreach (FieldDescriptor field in Fields) {
if (field.IsRequired) {
return true;
}
if (field.MappedType == MappedType.Message) {
if (field.MessageType.CheckRequiredFields(alreadySeen)) {
return true;
}
}
}
return false;
}
}
}
......@@ -68,6 +68,9 @@ namespace Google.ProtocolBuffers {
public override bool IsInitialized {
get {
/* if (!DescriptorForType.HasRequiredFields) {
return true;
}*/
// Check that all required fields are present.
foreach (FieldDescriptor field in DescriptorForType.Fields) {
if (field.IsRequired && !HasField(field)) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment