Prevent a StackOverflowException when calling BundlePath.ToString

This commit is contained in:
ds5678 2024-12-16 20:19:32 -08:00
parent 95024da309
commit 4a84a657ec
2 changed files with 58 additions and 2 deletions

View File

@ -32,4 +32,25 @@ public class BundlePathTests
BundlePath parent = path.Parent;
Assert.That(parent.Path.ToArray(), Is.EquivalentTo((int[])[1, 2]));
}
[Test]
public void BundlePathsAreSequenceEqual()
{
BundlePath path1 = new([0, 0]);
BundlePath path2 = new([0, 0]);
Assert.That(path1, Is.EqualTo(path2));
}
[Test]
public void ToStringDoesNotThrow()
{
// At one point, ToString could cause a StackOverflowException because it was a record,
// and the generated PrintMembers method was calling Parent.ToString.
// This test prevents that from ever happening again.
Assert.DoesNotThrow(() =>
{
BundlePath bundlePath = default;
bundlePath.ToString();
});
}
}

View File

@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
namespace AssetRipper.GUI.Web.Paths;
public readonly record struct BundlePath : IPath<BundlePath>
public readonly struct BundlePath : IPath<BundlePath>, IEquatable<BundlePath>
{
private readonly int[]? _path;
@ -26,6 +26,9 @@ public readonly record struct BundlePath : IPath<BundlePath>
[JsonPropertyName("P")]
public ReadOnlyMemory<int> Path => _path;
[JsonIgnore]
public ReadOnlySpan<int> Span => _path;
[JsonIgnore]
public int Depth => Path.Length;
@ -72,7 +75,17 @@ public readonly record struct BundlePath : IPath<BundlePath>
return new ResourcePath(this, index);
}
public static implicit operator ReadOnlySpan<int>(BundlePath path) => path._path;
public static implicit operator ReadOnlySpan<int>(BundlePath path) => path.Span;
public static bool operator ==(BundlePath left, BundlePath right)
{
return left.Equals(right);
}
public static bool operator !=(BundlePath left, BundlePath right)
{
return !(left == right);
}
public string ToJson()
{
@ -83,4 +96,26 @@ public readonly record struct BundlePath : IPath<BundlePath>
{
return JsonSerializer.Deserialize(json, PathSerializerContext.Default.BundlePath);
}
public override string ToString() => ToJson();
public override bool Equals(object? obj)
{
return obj is BundlePath path && Equals(path);
}
public bool Equals(BundlePath other)
{
return Span.SequenceEqual(other.Span);
}
public override int GetHashCode()
{
HashCode code = new();
foreach (int item in Span)
{
code.Add(item);
}
return code.ToHashCode();
}
}