Skip to content

Commit

Permalink
Add Equals to DynamicData (#35733)
Browse files Browse the repository at this point in the history
* Implement equality

* Update API and a few more tests

* Remove

* Add TryGetXx to MJE to prevent exceptions thrown from Equals

* Update tests to show intended use of == for nullable value types.

* Updates to docs per pr fb

* pr fb
  • Loading branch information
annelo-msft committed Apr 24, 2023
1 parent 5146c89 commit 02800a3
Show file tree
Hide file tree
Showing 9 changed files with 340 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ public sealed partial class DynamicData : System.Dynamic.IDynamicMetaObjectProvi
{
internal DynamicData() { }
public void Dispose() { }
public override bool Equals(object? obj) { throw null; }
public override int GetHashCode() { throw null; }
public static bool operator ==(Azure.Core.Dynamic.DynamicData? left, object? right) { throw null; }
public static implicit operator bool (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static implicit operator double (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static implicit operator int (Azure.Core.Dynamic.DynamicData value) { throw null; }
Expand All @@ -130,6 +133,7 @@ public sealed partial class DynamicData : System.Dynamic.IDynamicMetaObjectProvi
public static implicit operator float? (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static implicit operator float (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static implicit operator string (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static bool operator !=(Azure.Core.Dynamic.DynamicData? left, object? right) { throw null; }
System.Dynamic.DynamicMetaObject System.Dynamic.IDynamicMetaObjectProvider.GetMetaObject(System.Linq.Expressions.Expression parameter) { throw null; }
public override string ToString() { throw null; }
}
Expand Down Expand Up @@ -196,7 +200,11 @@ public sealed partial class MutableJsonDocument : System.IDisposable
public void Set(string value) { }
public Azure.Core.Json.MutableJsonElement SetProperty(string name, object value) { throw null; }
public override string ToString() { throw null; }
public bool TryGetDouble(out double value) { throw null; }
public bool TryGetInt32(out int value) { throw null; }
public bool TryGetInt64(out long value) { throw null; }
public bool TryGetProperty(string name, out Azure.Core.Json.MutableJsonElement value) { throw null; }
public bool TryGetSingle(out float value) { throw null; }
[System.Diagnostics.DebuggerDisplayAttribute("{Current,nq}")]
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public partial struct ArrayEnumerator : System.Collections.Generic.IEnumerable<Azure.Core.Json.MutableJsonElement>, System.Collections.Generic.IEnumerator<Azure.Core.Json.MutableJsonElement>, System.Collections.IEnumerable, System.Collections.IEnumerator, System.IDisposable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ public sealed partial class DynamicData : System.Dynamic.IDynamicMetaObjectProvi
{
internal DynamicData() { }
public void Dispose() { }
public override bool Equals(object? obj) { throw null; }
public override int GetHashCode() { throw null; }
public static bool operator ==(Azure.Core.Dynamic.DynamicData? left, object? right) { throw null; }
public static implicit operator bool (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static implicit operator double (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static implicit operator int (Azure.Core.Dynamic.DynamicData value) { throw null; }
Expand All @@ -130,6 +133,7 @@ public sealed partial class DynamicData : System.Dynamic.IDynamicMetaObjectProvi
public static implicit operator float? (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static implicit operator float (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static implicit operator string (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static bool operator !=(Azure.Core.Dynamic.DynamicData? left, object? right) { throw null; }
System.Dynamic.DynamicMetaObject System.Dynamic.IDynamicMetaObjectProvider.GetMetaObject(System.Linq.Expressions.Expression parameter) { throw null; }
public override string ToString() { throw null; }
}
Expand Down Expand Up @@ -196,7 +200,11 @@ public sealed partial class MutableJsonDocument : System.IDisposable
public void Set(string value) { }
public Azure.Core.Json.MutableJsonElement SetProperty(string name, object value) { throw null; }
public override string ToString() { throw null; }
public bool TryGetDouble(out double value) { throw null; }
public bool TryGetInt32(out int value) { throw null; }
public bool TryGetInt64(out long value) { throw null; }
public bool TryGetProperty(string name, out Azure.Core.Json.MutableJsonElement value) { throw null; }
public bool TryGetSingle(out float value) { throw null; }
[System.Diagnostics.DebuggerDisplayAttribute("{Current,nq}")]
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public partial struct ArrayEnumerator : System.Collections.Generic.IEnumerable<Azure.Core.Json.MutableJsonElement>, System.Collections.Generic.IEnumerator<Azure.Core.Json.MutableJsonElement>, System.Collections.IEnumerable, System.Collections.IEnumerator, System.IDisposable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ public sealed partial class DynamicData : System.Dynamic.IDynamicMetaObjectProvi
{
internal DynamicData() { }
public void Dispose() { }
public override bool Equals(object? obj) { throw null; }
public override int GetHashCode() { throw null; }
public static bool operator ==(Azure.Core.Dynamic.DynamicData? left, object? right) { throw null; }
public static implicit operator bool (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static implicit operator double (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static implicit operator int (Azure.Core.Dynamic.DynamicData value) { throw null; }
Expand All @@ -130,6 +133,7 @@ public sealed partial class DynamicData : System.Dynamic.IDynamicMetaObjectProvi
public static implicit operator float? (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static implicit operator float (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static implicit operator string (Azure.Core.Dynamic.DynamicData value) { throw null; }
public static bool operator !=(Azure.Core.Dynamic.DynamicData? left, object? right) { throw null; }
System.Dynamic.DynamicMetaObject System.Dynamic.IDynamicMetaObjectProvider.GetMetaObject(System.Linq.Expressions.Expression parameter) { throw null; }
public override string ToString() { throw null; }
}
Expand Down Expand Up @@ -196,7 +200,11 @@ public sealed partial class MutableJsonDocument : System.IDisposable
public void Set(string value) { }
public Azure.Core.Json.MutableJsonElement SetProperty(string name, object value) { throw null; }
public override string ToString() { throw null; }
public bool TryGetDouble(out double value) { throw null; }
public bool TryGetInt32(out int value) { throw null; }
public bool TryGetInt64(out long value) { throw null; }
public bool TryGetProperty(string name, out Azure.Core.Json.MutableJsonElement value) { throw null; }
public bool TryGetSingle(out float value) { throw null; }
[System.Diagnostics.DebuggerDisplayAttribute("{Current,nq}")]
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public partial struct ArrayEnumerator : System.Collections.Generic.IEnumerable<Azure.Core.Json.MutableJsonElement>, System.Collections.Generic.IEnumerator<Azure.Core.Json.MutableJsonElement>, System.Collections.IEnumerable, System.Collections.IEnumerator, System.IDisposable
Expand Down
40 changes: 40 additions & 0 deletions sdk/core/Azure.Core.Experimental/src/DynamicData.Operators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,46 @@ public partial class DynamicData
}
}

/// <summary>
/// Determines whether the specified <see cref="DynamicData"/> and <see cref="object"/> have the same value.
/// </summary>
/// <remarks>
/// This operator calls through to <see cref="DynamicData.Equals(object?)"/> when DynamicData is on the left-hand
/// side of the operation. <see cref="DynamicData.Equals(object?)"/> has value semantics when the DynamicData represents
/// a JSON primitive, i.e. string, bool, number, or null, and reference semantics otherwise, i.e. for objects and arrays.
///
/// Please note that if DynamicData is on the right-hand side of a <c>==</c> operation, this operator will not be invoked.
/// Because of this the result of a <c>==</c> comparison with <c>null</c> on the left and a DynamicData instance on the right will return <c>false</c>.
/// </remarks>
/// <param name="left">The <see cref="DynamicData"/> to compare.</param>
/// <param name="right">The <see cref="object"/> to compare.</param>
/// <returns><c>true</c> if the value of <paramref name="left"/> is the same as the value of <paramref name="right"/>; otherwise, <c>false</c>.</returns>
public static bool operator ==(DynamicData? left, object? right)
{
if (left is null)
{
return right is null;
}

return left.Equals(right);
}

/// <summary>
/// Determines whether the specified <see cref="DynamicData"/> and <see cref="object"/> have different values.
/// </summary>
/// <remarks>
/// This operator calls through to <see cref="DynamicData.Equals(object?)"/> when DynamicData is on the left-hand
/// side of the operation. <see cref="DynamicData.Equals(object?)"/> has value semantics when the DynamicData represents
/// a JSON primitive, i.e. string, bool, number, or null, and reference semantics otherwise, i.e. for objects and arrays.
///
/// Please note that if DynamicData is on the right-hand side of a <c>!=</c> operation, this operator will not be invoked.
/// Because of this the result of a <c>!=</c> comparison with <c>null</c> on the left and a DynamicData instance on the right will return <c>true</c>.
/// </remarks>
/// <param name="left">The <see cref="DynamicData"/> to compare.</param>
/// <param name="right">The <see cref="object"/> to compare.</param>
/// <returns><c>true</c> if the value of <paramref name="left"/> is different from the value of <paramref name="right"/>; otherwise, <c>false</c>.</returns>
public static bool operator !=(DynamicData? left, object? right) => !(left == right);

private static string GetInvalidCastExceptionText(Type target, MutableJsonElement element)
{
return $"Unable to cast element to '{target}'. Element has kind '{element.ValueKind}'.";
Expand Down
90 changes: 90 additions & 0 deletions sdk/core/Azure.Core.Experimental/src/DynamicData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,96 @@ public void Dispose()
_element.DisposeRoot();
}

/// <inheritdoc/>
public override bool Equals(object? obj)
{
if (obj is null)
{
return _element.ValueKind == JsonValueKind.Null;
}

if (_element.ValueKind == JsonValueKind.Null)
{
return obj is DynamicData d && Equals(d);
}

return obj switch
{
string s =>
_element.ValueKind == JsonValueKind.String &&
_element.GetString() == s,

bool b =>
(_element.ValueKind == JsonValueKind.True ||
_element.ValueKind == JsonValueKind.False) &&
_element.GetBoolean() == b,

double d =>
_element.ValueKind == JsonValueKind.Number &&
_element.TryGetDouble(out double od) && d == od,

float f =>
_element.ValueKind == JsonValueKind.Number &&
_element.TryGetSingle(out float of) && f == of,

long l =>
_element.ValueKind == JsonValueKind.Number &&
_element.TryGetInt64(out long ol) && l == ol,

int i =>
_element.ValueKind == JsonValueKind.Number &&
_element.TryGetInt32(out int oi) && i == oi,

DynamicData data => Equals(data),

_ => base.Equals(obj),
};
}

internal bool Equals(DynamicData other)
{
if (other is null)
{
return _element.ValueKind == JsonValueKind.Null;
}

if (_element.ValueKind != other._element.ValueKind)
{
return false;
}

return _element.ValueKind switch
{
JsonValueKind.String => _element.GetString() == other._element.GetString(),
JsonValueKind.Number => NumberEqual(other),
JsonValueKind.True => true,
JsonValueKind.False => true,
JsonValueKind.Null => true,
_ => base.Equals(other)
};
}

private bool NumberEqual(DynamicData other)
{
if (_element.TryGetDouble(out double d))
{
return other._element.TryGetDouble(out double od) && d == od;
}

if (_element.TryGetInt64(out long l))
{
return other._element.TryGetInt64(out long ol) && l == ol;
}

return false;
}

/// <inheritdoc/>
public override int GetHashCode()
{
return _element.GetHashCode();
}

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay => _element.DebuggerDisplay;

Expand Down
Loading

0 comments on commit 02800a3

Please sign in to comment.