Skip to content

Commit

Permalink
Library changes (initialized extension)
Browse files Browse the repository at this point in the history
  • Loading branch information
ObsidianMinor committed Sep 8, 2018
1 parent 659c6db commit 72f2e08
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 45 deletions.
8 changes: 0 additions & 8 deletions csharp/src/Google.Protobuf/Collections/MapField.cs
Expand Up @@ -285,14 +285,6 @@ public void Clear()
map.Clear();
}

/// <summary>
/// Determines whether all map message values are initialized
/// </summary>
public bool IsInitialized()
{
return list.All(kvp => kvp.Value is IMessage2 message ? message.IsInitialized() : true);
}

/// <summary>
/// Determines whether map contains an entry equivalent to the given key/value pair.
/// </summary>
Expand Down
22 changes: 0 additions & 22 deletions csharp/src/Google.Protobuf/Collections/RepeatedField.cs
Expand Up @@ -292,28 +292,6 @@ public bool Remove(T item)
/// </summary>
public bool IsReadOnly => false;

/// <summary>
/// Gets a value indicating whether the elements in the collection are all initialized
/// </summary>
public bool IsInitialized()
{
for (int i = 0; i < count; i++)
{
T value = array[i];
if (value is IMessage2 message)
{
if (!message.IsInitialized())
return false;
}
else
{
return true;
}
}

return true;
}

/// <summary>
/// Adds all of the specified values into this collection.
/// </summary>
Expand Down
12 changes: 0 additions & 12 deletions csharp/src/Google.Protobuf/IMessage.cs
Expand Up @@ -69,18 +69,6 @@ public interface IMessage
MessageDescriptor Descriptor { get; }
}

/// <summary>
/// Interface for a Protocol Buffers message, supporting
/// proto2 operations required for serialization
/// </summary>
public interface IMessage2 : IMessage
{
/// <summary>
/// Checks if all required fields have values set
/// </summary>
bool IsInitialized();
}

/// <summary>
/// Generic interface for a Protocol Buffers message,
/// where the type parameter is expected to be the same type as
Expand Down
72 changes: 72 additions & 0 deletions csharp/src/Google.Protobuf/MessageExtensions.cs
Expand Up @@ -30,7 +30,10 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

using Google.Protobuf.Reflection;
using System.Collections;
using System.IO;
using System.Linq;

namespace Google.Protobuf
{
Expand Down Expand Up @@ -140,6 +143,75 @@ public static ByteString ToByteString(this IMessage message)
return ByteString.AttachBytes(message.ToByteArray());
}

/// <summary>
/// Checks if all required fields in a message have values set. For proto3 messages, this returns true
/// </summary>
public static bool IsInitialized(this IMessage message)
{
if (message.Descriptor.File.Proto.Syntax != "proto2")
{
return true;
}

return message.Descriptor
.Fields
.InDeclarationOrder()
.Where(f => f.IsRequired || f.IsRepeated || f.IsMap || f.MessageType != null)
.All(f =>
{
if (f.MessageType != null)
{
if (f.Accessor.HasValue(message))
{
var field = (IMessage)f.Accessor.GetValue(message);
return field.IsInitialized();
}
else
{
return false;
}
}
else if (f.IsRepeated)
{
IList list = (IList)f.Accessor.GetValue(message);
foreach (IMessage item in list)
{
if (item is null)
{
return true;
}
else if (!item.IsInitialized())
{
return false;
}
}
return true;
}
else if (f.IsMap)
{
IDictionary list = (IDictionary)f.Accessor.GetValue(message);
foreach (IMessage item in list.Values)
{
if (item is null)
{
return true;
}
else if (!item.IsInitialized())
{
return false;
}
}
return true;
}
else
{
return f.Accessor.HasValue(message);
}
});
}

// Implementations allowing unknown fields to be discarded.
internal static void MergeFrom(this IMessage message, byte[] data, bool discardUnknownFields)
{
Expand Down
2 changes: 1 addition & 1 deletion csharp/src/Google.Protobuf/MessageParser.cs
Expand Up @@ -175,7 +175,7 @@ internal void MergeFrom(IMessage message, CodedInputStream codedInput)

internal static void CheckMergedRequiredFields(IMessage message)
{
if (message is IMessage2 proto2 && !proto2.IsInitialized())
if (!message.IsInitialized())
throw new InvalidOperationException("Parsed message does not contain all required fields");
}

Expand Down
5 changes: 5 additions & 0 deletions csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
Expand Up @@ -183,6 +183,11 @@ private static FieldType GetFieldTypeFromProtoType(FieldDescriptorProto.Types.Ty
/// </summary>
public bool IsRepeated => Proto.Label == FieldDescriptorProto.Types.Label.Repeated;

/// <summary>
/// Returns <c>true</c> if this field is a required field; <c>false</c> otherwise.
/// </summary>
public bool IsRequired => Proto.Label == FieldDescriptorProto.Types.Label.Required;

/// <summary>
/// Returns <c>true</c> if this field is a map field; <c>false</c> otherwise.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs
Expand Up @@ -52,7 +52,7 @@ public interface IFieldAccessor
void Clear(IMessage message);

/// <summary>
/// Indicates whether the field in the specified message is set. For proto3 fields and repeated fields, this throws an <see cref="InvalidOperationException"/>
/// Indicates whether the field in the specified message is set. For proto3 fields, this throws an <see cref="InvalidOperationException"/>
/// </summary>
bool HasValue(IMessage message);

Expand Down
Expand Up @@ -53,7 +53,7 @@ public override void Clear(IMessage message)

public override bool HasValue(IMessage message)
{
throw new NotImplementedException();
throw new InvalidOperationException("HasValue is not implemented for repeated fields");
}

public override void SetValue(IMessage message, object value)
Expand Down

0 comments on commit 72f2e08

Please sign in to comment.