Skip to content

Commit

Permalink
Reimplement Slots as a true wrapper, and expose raw slot values via (…
Browse files Browse the repository at this point in the history
…Raw).
  • Loading branch information
int19h committed Dec 21, 2018
1 parent 3ed5a46 commit 3d87c20
Showing 1 changed file with 98 additions and 61 deletions.
159 changes: 98 additions & 61 deletions WarBender/Slots.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using WarBender.Modules;

namespace WarBender {
public class Slots : LengthPrefixedCollection<long>, IList, IEnumerable<object> {
[Browsable(false)]
public new IRecord Parent => (IRecord)((IDataObject)this).Parent;
public class Slots : IDataObject, ICollection, IList<object> {
private IReadOnlyList<SlotDefinition> _slotDefinitions;

[Browsable(false)]
public LengthPrefixedCollection<long> Raw => this;
public Slots() {
}

private IReadOnlyList<SlotDefinition> _slotDefinitions;
[ParenthesizePropertyName(true)]
public LengthPrefixedCollection<long> Raw { get; } = new LengthPrefixedCollection<long>();

public IReadOnlyList<SlotDefinition> SlotDefinitions {
get {
Expand All @@ -27,83 +29,118 @@ public IReadOnlyList<SlotDefinition> SlotDefinitions {
}
}

protected override void SetParent(IDataObject parent) {
public IDataObjectChild WithParent(IDataObject parent, int index = -1) {
if (!(parent is IRecord)) {
throw new InvalidOperationException($"{nameof(Slots)} must have a record as parent");
throw new ArgumentOutOfRangeException(nameof(parent));
}

_slotDefinitions = null;
base.SetParent(parent);
var raw = ((IDataObject)Raw).WithParent(parent, index);
Trace.Assert(Raw == raw);
return this;
}

protected override void OnItemAdded(long item, int index) {
base.OnItemAdded(item, index);
if (_slotDefinitions != null && Count > _slotDefinitions.Count) {
_slotDefinitions = null;
}
}
public string GetKeyOfIndex(int index) => index < SlotDefinitions.Count ? SlotDefinitions[index].Name : null;

public override string GetKeyOfIndex(int index) => SlotDefinitions[index].Name;
private static long RawValue(object value) =>
value == null ? -1 :
value is IRecord record ? record.Index :
value is IEntityReference eref ? eref.Index :
value is IConvertible conv ? conv.ToInt64(CultureInfo.InvariantCulture) :
value is Color color ? color.ToArgb() :
throw new ArgumentOutOfRangeException("value");

public new object this[int index] {
get {
var raw = Raw[index];
var slotType = SlotDefinitions[index].Type;

object slot;
if (typeof(Color) == slotType) {
slot = Color.FromArgb((int)raw);
} else if (slotType.IsEnum) {
slot = Enum.ToObject(slotType, raw);
} else if (typeof(IEntity).IsAssignableFrom(slotType)) {
slotType = typeof(EntityReference<,>).MakeGenericType(slotType, typeof(int));
slot = Activator.CreateInstance(slotType, (int)raw);
} else {
slot = ((IConvertible)raw).ToType(slotType, null);
}
private object TypedValue(long value, int index) {
if (index >= SlotDefinitions.Count) {
return value;
}

if (slot is IDataObjectChild child) {
slot = child.WithParent(this, index);
}
var raw = Raw[index];
var slotType = SlotDefinitions[index].Type;

object slot;
if (typeof(Color) == slotType) {
slot = Color.FromArgb((int)raw);
} else if (slotType.IsEnum) {
slot = Enum.ToObject(slotType, raw);
} else if (typeof(IEntity).IsAssignableFrom(slotType)) {
slotType = typeof(EntityReference<,>).MakeGenericType(slotType, typeof(int));
slot = Activator.CreateInstance(slotType, (int)raw);
} else {
slot = ((IConvertible)raw).ToType(slotType, null);
}

return slot;
if (slot is IDataObjectChild child) {
slot = child.WithParent(this, index);
}
set =>
Raw[index] = RawValue(value);

return slot;
}

public new object this[string key] {
get => this[GetIndexOfKey(key)];
set => this[GetIndexOfKey(key)] = value;
public object this[int index] {
get => TypedValue(Raw[index], index);
set => Raw[index] = RawValue(value);
}

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<object> GetEnumerator() => Raw.Select((x, i) => TypedValue(x, i)).GetEnumerator();

public int Add(object value) => ((ICollection)Raw).Add(RawValue(value));

public int GetLength() => Raw.GetLength();

public bool Contains(object value) => Raw.Contains(RawValue(value));

public void Clear() => Raw.Clear();

public int IndexOf(object value) =>Raw.IndexOf(RawValue(value));

public void Insert(int index, object value) => ((ICollection)Raw).Insert(index, RawValue(value));

public new IEnumerator<object> GetEnumerator() {
for (int i = 0; i < Count; ++i) {
yield return this[i];
public void Remove(object value) => ((ICollection)Raw).Remove(RawValue(value));

public void RemoveAt(int index) => Raw.RemoveAt(index);

public void CopyTo(Array array, int index) {
foreach (var value in this) {
array.SetValue(value, index++);
}
}

int IList.Add(object value) {
Raw.Add(RawValue(value));
return Count - 1;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

bool IList.Contains(object value) => Raw.Contains(RawValue(value));
void ICollection<object>.Add(object item) => Add(RawValue(item));

int IList.IndexOf(object value) => Raw.IndexOf(RawValue(value));
public void CopyTo(object[] array, int arrayIndex) => CopyTo(array, arrayIndex);

void IList.Insert(int index, object value) => Raw.Insert(index, RawValue(value));
bool ICollection<object>.Remove(object item) => Raw.Remove(RawValue(item));

void IList.Remove(object value) => Raw.Remove(RawValue(value));
[ParenthesizePropertyName(true)]
public long SizeInBytes => Raw.SizeInBytes;

private static long RawValue(object value) =>
value == null ? -1 :
value is IRecord record ? record.Index :
value is IEntityReference eref ? eref.Index :
value is IConvertible conv ? conv.ToInt64(CultureInfo.InvariantCulture) :
value is Color color ? color.ToArgb() :
throw new ArgumentOutOfRangeException("value");
IDataObject IDataObjectChild.Parent => Raw.Parent;

[Browsable(false)]
IRecord Parent => (IRecord)Raw.Parent;

[Browsable(false)]
public Type ItemType => Raw.ItemType;

[Browsable(false)]
public bool IsReadOnly => ((ICollection)Raw).IsReadOnly;

[Browsable(false)]
public bool IsFixedSize => ((ICollection)Raw).IsFixedSize;

[ParenthesizePropertyName(true)]
public int Count => Raw.Count;

[Browsable(false)]
public object SyncRoot => ((ICollection)Raw).SyncRoot;

[Browsable(false)]
public bool IsSynchronized => ((ICollection)Raw).IsSynchronized;

public void ReadFrom(BinaryReader reader) => Raw.ReadFrom(reader);

public void WriteTo(BinaryWriter writer) => Raw.WriteTo(writer);
}
}

0 comments on commit 3d87c20

Please sign in to comment.