using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using MiraAPI.GameOptions.Attributes;
namespace MiraAPI.GameOptions;
///
/// A fixed-size array created specifically for modded options that automatically synchronizes with option attributes.
///
/// The type of the values that the array holds.
[CollectionBuilder(typeof(ModdedArrayBuilder), nameof(ModdedArrayBuilder.Create))]
public sealed class ModdedArray : IList, IReadOnlyList, IList
{
private readonly T[] items;
private int version;
///
public int Count => items.Length;
///
public bool IsReadOnly => false;
///
bool IList.IsFixedSize => true;
///
bool ICollection.IsSynchronized => false;
///
object ICollection.SyncRoot => items.SyncRoot;
///
/// Initializes a new instance of the class with the provided capacity.
///
/// The capacity of the list.
public ModdedArray(int capacity)
{
items = new T[capacity];
}
///
/// Initializes a new instance of the class with initial values.
///
/// The initial collection of values to initialise with.
public ModdedArray(IEnumerable collection)
{
items = [.. collection];
}
///
/// Initializes a new instance of the class with initial values.
///
/// The initial span of values to initialise with.
public ModdedArray(Span span)
{
items = [.. span];
}
///
/// Initializes a new instance of the class with initial values.
///
/// The initial span of values to initialise with.
public ModdedArray(ReadOnlySpan span)
{
items = [.. span];
}
///
/// Gets or sets the element at the specified index, syncing with the attribute if registered.
///
/// The index of the value.
public T this[int index]
{
get
{
if (ModdedOptionsManager.ListInstanceCache.TryGetValue(this, out var attribute))
{
items[index] = attribute is ITypedOptionList typedAttr
? typedAttr.GetValueUnboxed(index)
: (T)attribute.GetValue(index);
}
return items[index];
}
set
{
if (ModdedOptionsManager.ListInstanceCache.TryGetValue(this, out var attribute))
{
if (attribute is ITypedOptionList typedAttr)
typedAttr.SetValueUnboxed(index, value);
else
attribute.SetValue(index, value!);
items[index] = attribute is ITypedOptionList typedAttr2
? typedAttr2.GetValueUnboxed(index)
: (T)attribute.GetValue(index);
}
else
{
items[index] = value;
}
version++;
}
}
///
object? IList.this[int index]
{
get => this[index];
set => this[index] = (T)value!;
}
///
public bool Contains(T item)
{
return Array.IndexOf(items, item) >= 0;
}
///
public void CopyTo(T[] array, int arrayIndex)
{
items.CopyTo(array, arrayIndex);
}
///
public int IndexOf(T item)
{
return Array.IndexOf(items, item);
}
///
public Enumerator GetEnumerator()
{
return new(this);
}
///
bool IList.Contains(object? value)
{
return ((IList)items).Contains(value);
}
///
int IList.IndexOf(object? value)
{
return ((IList)items).IndexOf(value);
}
///
void ICollection.CopyTo(Array array, int index)
{
items.CopyTo(array, index);
}
///
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
///
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
///
int IList.Add(object? value)
{
throw new NotSupportedException("ModdedArray is of a fixed size.");
}
///
void IList.Clear()
{
throw new NotSupportedException("ModdedArray is of a fixed size.");
}
///
void IList.Insert(int index, object? value)
{
throw new NotSupportedException("ModdedArray is of a fixed size.");
}
///
void IList.Remove(object? value)
{
throw new NotSupportedException("ModdedArray is of a fixed size.");
}
///
void IList.RemoveAt(int index)
{
throw new NotSupportedException("ModdedArray is of a fixed size.");
}
///
void IList.Insert(int index, T item)
{
throw new NotSupportedException("ModdedArray is of a fixed size.");
}
///
void IList.RemoveAt(int index)
{
throw new NotSupportedException("ModdedArray is of a fixed size.");
}
///
void ICollection.Add(T item)
{
throw new NotSupportedException("ModdedArray is of a fixed size.");
}
///
void ICollection.Clear()
{
throw new NotSupportedException("ModdedArray is of a fixed size.");
}
///
bool ICollection.Remove(T item)
{
throw new NotSupportedException("ModdedArray is of a fixed size.");
}
///
/// Enumerates the elements of a .
///
public struct Enumerator : IEnumerator
{
private readonly ModdedArray array;
private readonly int version;
private int index;
private T? current;
internal Enumerator(ModdedArray moddedArray)
{
array = moddedArray;
version = moddedArray.version;
index = 0;
current = default;
}
///
public readonly T Current => current!;
///
readonly object? IEnumerator.Current
{
get
{
if (index == 0 || index == array.Count + 1)
throw new InvalidOperationException("Enumeration has not started or has already finished.");
return Current;
}
}
///
public readonly void Dispose()
{
}
///
public bool MoveNext()
{
if (version != array.version)
throw new InvalidOperationException("Collection was modified; enumeration operation may not execute.");
if ((uint)index < (uint)array.Count)
{
current = array[index];
index++;
return true;
}
index = array.Count + 1;
current = default;
return false;
}
///
public void Reset()
{
if (version != array.version)
throw new InvalidOperationException("Collection was modified; enumeration operation may not execute.");
index = 0;
current = default;
}
}
}
///
/// Provides a builder for to support C# 12 collection expressions.
///
public static class ModdedArrayBuilder
{
///
/// Creates a new from a span of values.
///
/// The the type of the values.
/// The values to initialise with.
/// The instance initialised with the provided values.
public static ModdedArray Create(ReadOnlySpan values)
{
return new(values);
}
}