using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; namespace VersionedSerialization.Generator.Utils; [DebuggerDisplay("Length = {Length}")] [DebuggerTypeProxy(typeof(ImmutableEquatableArray<>.DebugView))] public sealed class ImmutableEquatableArray : IEquatable>, IReadOnlyList, IList, IList where T : IEquatable { public static ImmutableEquatableArray Empty { get; } = new([]); private readonly T[] _values; public ref readonly T this[int index] => ref _values[index]; public int Length => _values.Length; private ImmutableEquatableArray(T[] values) => _values = values; public bool Equals(ImmutableEquatableArray? other) => ReferenceEquals(this, other) || ((ReadOnlySpan)_values).SequenceEqual(other?._values); public override bool Equals(object? obj) => obj is ImmutableEquatableArray other && Equals(other); public override int GetHashCode() { var hash = 0; foreach (var value in _values) { hash = HashCode.Combine(hash, value.GetHashCode()); } return hash; } public Enumerator GetEnumerator() => new(_values); public struct Enumerator { private readonly T[] _values; private int _index; internal Enumerator(T[] values) { _values = values; _index = -1; } public bool MoveNext() => ++_index < _values.Length; public readonly ref T Current => ref _values[_index]; } [EditorBrowsable(EditorBrowsableState.Never)] internal static ImmutableEquatableArray UnsafeCreateFromArray(T[] values) => new(values); #region Explicit interface implementations IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_values).GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_values).GetEnumerator(); bool ICollection.IsReadOnly => true; bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; T IReadOnlyList.this[int index] => _values[index]; T IList.this[int index] { get => _values[index]; set => throw new InvalidOperationException(); } object? IList.this[int index] { get => _values[index]; set => throw new InvalidOperationException(); } void ICollection.CopyTo(T[] array, int arrayIndex) => _values.CopyTo(array, arrayIndex); void ICollection.CopyTo(Array array, int index) => _values.CopyTo(array, index); int IList.IndexOf(T item) => _values.AsSpan().IndexOf(item); int IList.IndexOf(object? value) => ((IList)_values).IndexOf(value); bool ICollection.Contains(T item) => _values.AsSpan().IndexOf(item) >= 0; bool IList.Contains(object? value) => ((IList)_values).Contains(value); bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; int IReadOnlyCollection.Count => Length; int ICollection.Count => Length; int ICollection.Count => Length; void ICollection.Add(T item) => throw new InvalidOperationException(); bool ICollection.Remove(T item) => throw new InvalidOperationException(); void ICollection.Clear() => throw new InvalidOperationException(); void IList.Insert(int index, T item) => throw new InvalidOperationException(); void IList.RemoveAt(int index) => throw new InvalidOperationException(); int IList.Add(object? value) => throw new InvalidOperationException(); void IList.Clear() => throw new InvalidOperationException(); void IList.Insert(int index, object? value) => throw new InvalidOperationException(); void IList.Remove(object? value) => throw new InvalidOperationException(); void IList.RemoveAt(int index) => throw new InvalidOperationException(); #endregion private sealed class DebugView(ImmutableEquatableArray array) { [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] Items => array.ToArray(); } } public static class ImmutableEquatableArray { public static ImmutableEquatableArray ToImmutableEquatableArray(this IEnumerable values) where T : IEquatable => values is ICollection { Count: 0 } ? ImmutableEquatableArray.Empty : ImmutableEquatableArray.UnsafeCreateFromArray(values.ToArray()); public static ImmutableEquatableArray Create(ReadOnlySpan values) where T : IEquatable => values.IsEmpty ? ImmutableEquatableArray.Empty : ImmutableEquatableArray.UnsafeCreateFromArray(values.ToArray()); }