diff --git a/BizHawk.Common/DeepEquality.cs b/BizHawk.Common/DeepEquality.cs
index 820cd2f696..04aa0359b9 100644
--- a/BizHawk.Common/DeepEquality.cs
+++ b/BizHawk.Common/DeepEquality.cs
@@ -34,7 +34,7 @@ namespace BizHawk.Common
///
///
///
- private static IEnumerable GetAllFields(Type t)
+ public static IEnumerable GetAllFields(Type t)
{
while (t != null)
{
diff --git a/BizHawk.Emulation.Common/BinaryQuickSerializer.cs b/BizHawk.Emulation.Common/BinaryQuickSerializer.cs
new file mode 100644
index 0000000000..97b791ac44
--- /dev/null
+++ b/BizHawk.Emulation.Common/BinaryQuickSerializer.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Linq.Expressions;
+using System.IO;
+using BizHawk.Common;
+using BizHawk.Common.ReflectionExtensions;
+using System.Collections.Concurrent;
+using System.Runtime.InteropServices;
+
+namespace BizHawk.Emulation.Common
+{
+ public class BinaryQuickSerializer
+ {
+ // 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]
+
+ #region reflection infrastructure
+ private static MethodInfo FromExpression(Expression e)
+ {
+ var caller = e as MethodCallExpression;
+ if (caller == null)
+ throw new ArgumentException("Expression must be a method call");
+ return caller.Method;
+ }
+
+ private static MethodInfo Method(Expression f)
+ {
+ return FromExpression(f.Body);
+ }
+ private static MethodInfo Method(Expression> f)
+ {
+ return FromExpression(f.Body);
+ }
+
+ private static Dictionary readhandlers = new Dictionary();
+ private static 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)0));
+
+ AddR(r => r.ReadInt16());
+ AddW(r => r.Write((short)0));
+
+ AddR(r => r.ReadUInt16());
+ AddW(r => r.Write((ushort)0));
+
+ AddR(r => r.ReadInt32());
+ AddW(r => r.Write((int)0));
+
+ AddR(r => r.ReadUInt32());
+ AddW(r => r.Write((uint)0));
+
+ AddR(r => r.ReadInt64());
+ AddW(r => r.Write((long)0));
+
+ AddR(r => r.ReadUInt64());
+ AddW(r => r.Write((ulong)0));
+
+ }
+
+ 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;
+ }
+
+ private static SerializationFactory CreateSer(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();
+
+ foreach (var field in DeepEquality.GetAllFields(t))
+ {
+ Console.WriteLine("{0} @{1}", field.Name, field.GetManagedOffset());
+ }
+
+ 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);
+ MethodInfo m;
+ if (!readhandlers.TryGetValue(field.FieldType, out m))
+ throw new InvalidOperationException("(R) Can't handle nested type " + field.FieldType);
+ il.Emit(OpCodes.Callvirt, m);
+ il.Emit(OpCodes.Stfld, field);
+ Console.WriteLine("(R) {0} {1}: {2}", field.Name, field.FieldType, m);
+ }
+ 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);
+ MethodInfo m;
+ if (!writehandlers.TryGetValue(field.FieldType, out m))
+ throw new InvalidOperationException("(W) Can't handle nested type " + field.FieldType);
+ il.Emit(OpCodes.Callvirt, m);
+ Console.WriteLine("(W) {0} {1}: {2}", field.Name, field.FieldType, m);
+ }
+ il.Emit(OpCodes.Ret);
+ }
+
+ return new SerializationFactory
+ {
+ Type = t,
+ Read = (Reader)rmeth.CreateDelegate(typeof(Reader)),
+ Write = (Writer)wmeth.CreateDelegate(typeof(Writer))
+ };
+ }
+ #endregion
+
+ private static IDictionary sers =
+ new ConcurrentDictionary();
+
+ private static SerializationFactory GetFactory(Type t)
+ {
+ SerializationFactory f;
+ if (!sers.TryGetValue(t, out f))
+ {
+ f = CreateSer(t);
+ sers[t] = f;
+ }
+ return f;
+ }
+
+ 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/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj
index 4c7ff0f34a..d3ffcfb00f 100644
--- a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj
+++ b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj
@@ -60,6 +60,7 @@
+
diff --git a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs
index b625a091fc..3cbe563dd0 100644
--- a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs
+++ b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs
@@ -268,13 +268,6 @@ namespace BizHawk.Emulation.Cores.WonderSwan
writer.Write(savebuff.Length);
writer.Write(savebuff);
- // other variables
- /*
- writer.Write(IsLagFrame);
- writer.Write(LagCount);
- writer.Write(Frame);
- */
-
var d = new TextStateData();
SaveTextStateData(d);
BinaryQuickSerializer.Write(d, writer);
@@ -289,10 +282,9 @@ namespace BizHawk.Emulation.Cores.WonderSwan
if (!BizSwan.bizswan_binstateload(Core, savebuff, savebuff.Length))
throw new InvalidOperationException("bizswan_binstateload() returned false!");
- // other variables
- IsLagFrame = reader.ReadBoolean();
- LagCount = reader.ReadInt32();
- Frame = reader.ReadInt32();
+ var d = new TextStateData();
+ BinaryQuickSerializer.Read(d, reader);
+ LoadTextStateData(d);
}
public byte[] SaveStateBinary()
@@ -602,7 +594,6 @@ namespace BizHawk.Emulation.Cores.WonderSwan
public void DiscardSamples()
{
sbuffcontains = 0;
- new DiscSystem.Disc().Dispose();
}
#endregion