diff --git a/src/BizHawk.Common/BinaryQuickSerializer.cs b/src/BizHawk.Common/BinaryQuickSerializer.cs deleted file mode 100644 index fcb487708d..0000000000 --- a/src/BizHawk.Common/BinaryQuickSerializer.cs +++ /dev/null @@ -1,194 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Reflection.Emit; -using System.Runtime.InteropServices; - -using BizHawk.Common.CollectionExtensions; - -namespace BizHawk.Common -{ - // fields are serialized/deserialized in their memory order as reported by Marshal.OffsetOf - // to do anything useful, passed targets should be [StructLayout.Sequential] or [StructLayout.Explicit] - public static class BinaryQuickSerializer - { - private static MethodInfo FromExpression(Expression e) - => e is MethodCallExpression caller - ? caller.Method - : throw new ArgumentException(message: "Expression must be a method call", paramName: nameof(e)); - - private static MethodInfo Method(Expression> f) - { - return FromExpression(f.Body); - } - - private static readonly Dictionary Readhandlers = new Dictionary(); - private static readonly Dictionary Writehandlers = new Dictionary(); - - private static void AddR(Expression> f) - { - var method = Method(f); - if (!typeof(T).IsAssignableFrom(method.ReturnType)) - { - throw new InvalidOperationException("Type mismatch"); - } - - Readhandlers.Add(typeof(T), method); - } - - private static void AddW(Expression> f) - { - var method = Method(f); - if (!method.GetParameters()[0].ParameterType.IsAssignableFrom(typeof(T))) - { - throw new InvalidOperationException("Type mismatch"); - } - - Writehandlers.Add(typeof(T), Method(f)); - } - - static BinaryQuickSerializer() - { - AddR(r => r.ReadBoolean()); - AddW(r => r.Write(false)); - - AddR(r => r.ReadSByte()); - AddW(r => r.Write((sbyte)0)); - - AddR(r => r.ReadByte()); - AddW(r => r.Write((byte)0U)); - - AddR(r => r.ReadInt16()); - AddW(r => r.Write((short)0)); - - AddR(r => r.ReadUInt16()); - AddW(r => r.Write((ushort)0U)); - - AddR(r => r.ReadInt32()); - AddW(r => r.Write(0)); - - AddR(r => r.ReadUInt32()); - AddW(r => r.Write(0U)); - - AddR(r => r.ReadInt64()); - AddW(r => r.Write(0L)); - - AddR(r => r.ReadUInt64()); - AddW(r => r.Write(0UL)); - } - - private delegate void Reader(object target, BinaryReader r); - private delegate void Writer(object target, BinaryWriter w); - - private class SerializationFactory - { - public Type Type; - public Reader Read; - public Writer Write; - - public SerializationFactory(Type type, Reader read, Writer write) - { - Type = type; - Read = read; - Write = write; - } - } - - private static SerializationFactory CreateFactory(Type t) - { - var fields = DeepEquality.GetAllFields(t) - ////.OrderBy(fi => (int)fi.GetManagedOffset()) // [StructLayout.Sequential] doesn't work with this - .OrderBy(fi => (int)Marshal.OffsetOf(t, fi.Name)) - .ToList(); - - var rmeth = new DynamicMethod($"{t.Name}_r", null, new[] { typeof(object), typeof(BinaryReader) }, true); - var wmeth = new DynamicMethod($"{t.Name}_w", null, new[] { typeof(object), typeof(BinaryWriter) }, true); - - { - var il = rmeth.GetILGenerator(); - var target = il.DeclareLocal(t); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Castclass, t); - il.Emit(OpCodes.Stloc, target); - - foreach (var field in fields) - { - il.Emit(OpCodes.Ldloc, target); - il.Emit(OpCodes.Ldarg_1); - if (!Readhandlers.TryGetValue(field.FieldType, out var m)) - { - throw new InvalidOperationException($"(R) Can't handle nested type {field.FieldType}"); - } - - il.Emit(OpCodes.Callvirt, m); - il.Emit(OpCodes.Stfld, field); - } - - il.Emit(OpCodes.Ret); - } - - { - var il = wmeth.GetILGenerator(); - var target = il.DeclareLocal(t); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Castclass, t); - il.Emit(OpCodes.Stloc, target); - - foreach (var field in fields) - { - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Ldloc, target); - il.Emit(OpCodes.Ldfld, field); - if (!Writehandlers.TryGetValue(field.FieldType, out var m)) - { - throw new InvalidOperationException($"(W) Can't handle nested type {field.FieldType}"); - } - - il.Emit(OpCodes.Callvirt, m); - } - - il.Emit(OpCodes.Ret); - } - - return new SerializationFactory( - t, - (Reader) rmeth.CreateDelegate(typeof(Reader)), - (Writer) wmeth.CreateDelegate(typeof(Writer))); - } - - private static readonly IDictionary Serializers = - new ConcurrentDictionary(); - - private static SerializationFactory GetFactory(Type t) - => Serializers.GetValueOrPut(t, CreateFactory); - - public static T Create(BinaryReader r) - where T : new() - { - T target = new T(); - Read(target, r); - return target; - } - - public static object Create(Type t, BinaryReader r) - { - object target = Activator.CreateInstance(t); - Read(target, r); - return target; - } - - public static void Read(object target, BinaryReader r) - { - GetFactory(target.GetType()).Read(target, r); - } - - public static void Write(object target, BinaryWriter w) - { - GetFactory(target.GetType()).Write(target, w); - } - } -} diff --git a/src/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.IStatable.cs b/src/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.IStatable.cs index 377491cb64..d778c2504a 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.IStatable.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.IStatable.cs @@ -5,17 +5,16 @@ using Newtonsoft.Json; using BizHawk.Common; using BizHawk.Emulation.Common; using System.Runtime.InteropServices; +using BizHawk.Common.IOExtensions; namespace BizHawk.Emulation.Cores.WonderSwan { partial class WonderSwan: ITextStatable { private void InitIStatable() - { - savebuff = new byte[BizSwan.bizswan_binstatesize(Core)]; - } + => savebuff = new byte[BizSwan.bizswan_binstatesize(Core)]; - private readonly JsonSerializer ser = new JsonSerializer { Formatting = Formatting.Indented }; + private readonly JsonSerializer ser = new() { Formatting = Formatting.Indented }; [StructLayout(LayoutKind.Sequential)] private class TextStateData @@ -31,6 +30,7 @@ namespace BizHawk.Emulation.Cores.WonderSwan LagCount = d.LagCount; Frame = d.Frame; } + private void SaveTextStateData(TextStateData d) { d.IsLagFrame = IsLagFrame; @@ -51,10 +51,17 @@ namespace BizHawk.Emulation.Cores.WonderSwan public void LoadStateText(TextReader reader) { var s = (TextState)ser.Deserialize(reader, typeof(TextState)); - s.Prepare(); - var ff = s.GetFunctionPointersLoad(); - BizSwan.bizswan_txtstateload(Core, ref ff); - LoadTextStateData(s.ExtraData); + if (s is not null) + { + s.Prepare(); + var ff = s.GetFunctionPointersLoad(); + BizSwan.bizswan_txtstateload(Core, ref ff); + LoadTextStateData(s.ExtraData); + } + else + { + throw new InvalidOperationException("Failed to deserialize state"); + } } private byte[] savebuff; @@ -64,26 +71,37 @@ namespace BizHawk.Emulation.Cores.WonderSwan public void SaveStateBinary(BinaryWriter writer) { if (!BizSwan.bizswan_binstatesave(Core, savebuff, savebuff.Length)) + { throw new InvalidOperationException($"{nameof(BizSwan.bizswan_binstatesave)}() returned false!"); + } + writer.Write(savebuff.Length); writer.Write(savebuff); - var d = new TextStateData(); - SaveTextStateData(d); - BinaryQuickSerializer.Write(d, writer); + // other variables + writer.Write(IsLagFrame); + writer.Write(LagCount); + writer.Write(Frame); } public void LoadStateBinary(BinaryReader reader) { - int length = reader.ReadInt32(); + var length = reader.ReadInt32(); if (length != savebuff.Length) + { throw new InvalidOperationException("Save buffer size mismatch!"); + } + reader.Read(savebuff, 0, length); if (!BizSwan.bizswan_binstateload(Core, savebuff, savebuff.Length)) + { throw new InvalidOperationException($"{nameof(BizSwan.bizswan_binstateload)}() returned false!"); + } - var d = BinaryQuickSerializer.Create(reader); - LoadTextStateData(d); + // other variables + IsLagFrame = reader.ReadBoolean(); + LagCount = reader.ReadInt32(); + Frame = reader.ReadInt32(); } } }