|
|
|
@ -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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|