diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/ConsoleLuaLibrary.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/ConsoleLuaLibrary.cs index c18334dd31..a3cf1e885f 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/ConsoleLuaLibrary.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/ConsoleLuaLibrary.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Linq; using System.Text; @@ -66,23 +67,9 @@ namespace BizHawk.Client.EmuHawk { static string SerializeTable(LuaTable lti) { - var keyObjs = lti.Keys; - var valueObjs = lti.Values; - if (keyObjs.Count != valueObjs.Count) - { - throw new ArgumentException(message: "each value must be paired with one key, they differ in number", paramName: nameof(lti)); - } - - var values = new object[keyObjs.Count]; - var kvpIndex = 0; - foreach (var valueObj in valueObjs) - { - values[kvpIndex++] = valueObj; - } - - return string.Concat(keyObjs.Cast() - .Select((kObj, i) => $"\"{kObj}\": \"{values[i]}\"\n") - .Order()); + var entries = ((IEnumerator>) lti.GetEnumerator()).AsEnumerable() + .ToArray(); + return string.Concat(entries.Select(static kvp => $"\"{kvp.Key}\": \"{kvp.Value}\"\n").Order()); } if (!Tools.Has()) diff --git a/src/BizHawk.Common/Extensions/CollectionExtensions.cs b/src/BizHawk.Common/Extensions/CollectionExtensions.cs index 775be9d8f4..354fa32e31 100644 --- a/src/BizHawk.Common/Extensions/CollectionExtensions.cs +++ b/src/BizHawk.Common/Extensions/CollectionExtensions.cs @@ -10,6 +10,30 @@ namespace BizHawk.Common.CollectionExtensions public static class CollectionExtensions #pragma warning restore MA0104 { + private struct EnumeratorAsEnumerable : IEnumerable + { + private IEnumerator? _wrapped; + + public EnumeratorAsEnumerable(IEnumerator wrapped) + => _wrapped = wrapped; + + public override bool Equals(object? other) + => other is EnumeratorAsEnumerable wrapper && object.Equals(_wrapped, wrapper._wrapped); + + public IEnumerator GetEnumerator() + { + var temp = _wrapped ?? throw new InvalidOperationException("double enumeration (or `default`/zeroed struct)"); + _wrapped = null; + return temp; + } + + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); + + public override int GetHashCode() + => _wrapped?.GetHashCode() ?? default; + } + private const string ERR_MSG_IMMUTABLE_LIST = "immutable list passed to mutating method"; private const string WARN_NONGENERIC = "use generic overload"; @@ -119,6 +143,9 @@ namespace BizHawk.Common.CollectionExtensions foreach (var item in collection) list.Add(item); } + public static IEnumerable AsEnumerable(this IEnumerator enumerator) + => new EnumeratorAsEnumerable(enumerator); + /// /// Contains method for arrays which does not need Linq, but rather uses Array.IndexOf /// similar to ICollection's Contains