Commit 9512207e authored by Ben Lambell's avatar Ben Lambell

Serialize enumerators (kind of), functions, and private methods

parent 4f7341d7
using Recurse.Common.Utils;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
namespace Recurse.Persist.Serializables
{
public abstract class SerializableDelegate<TDelegate> : Equatable, ISerializable
{
private const BindingFlags GetMethodBindingFlags
= BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
private object Target => Delegate.Target;
private Type DelegateType => Delegate.GetType();
private Type ReflectedType => Delegate.Method.ReflectedType;
private string Name => Delegate.Method.Name;
......@@ -30,13 +36,14 @@ namespace Recurse.Persist.Serializables
public SerializableDelegate(SerializationInfo info, StreamingContext context)
{
var reflectedType = (Type)info.GetValue(nameof(ReflectedType), typeof(Type));
var delegateType = (Type)info.GetValue(nameof(DelegateType), typeof(Type));
var name = info.GetString(nameof(Name));
var target = info.GetValue(nameof(Target), reflectedType);
Delegate = Delegate.CreateDelegate(
typeof(TDelegate),
delegateType,
target,
reflectedType.GetMethod(name, ArgumentTypes));
reflectedType.GetMethod(name, GetMethodBindingFlags, null, ArgumentTypes, null));
}
public SerializableDelegate(Delegate @delegate)
......@@ -51,6 +58,7 @@ namespace Recurse.Persist.Serializables
{
info.AddValue(nameof(Target), Target, ReflectedType);
info.AddValue(nameof(ReflectedType), ReflectedType);
info.AddValue(nameof(DelegateType), DelegateType);
info.AddValue(nameof(Name), Name);
}
}
......
/*
* Copyright (c) 2017 Ben Lambell.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using System.Collections;
using System.Collections.Generic;
namespace Recurse.Persist.Test
{
public abstract class SerializableEnumerable<T> : IEnumerable<T>
{
public IEnumerator<T> GetEnumerator() => new SerializableEnumerator<T>(Start);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
protected abstract Result Start();
[Serializable]
protected class Result : SerializableEnumeratorState<T>
{
public Result(T value, Func<Result> next) : base(value, next)
{
}
}
}
}
/*
* Copyright (c) 2017 Ben Lambell.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using System.Collections;
using System.Collections.Generic;
namespace Recurse.Persist.Test
{
[Serializable]
public class SerializableEnumerator<T> : IEnumerator<T>
{
private readonly SerializableEnumeratorState<T> _start;
private SerializableEnumeratorState<T> _current;
public T Current => _current != null ? _current.Value : default(T);
object IEnumerator.Current => Current;
public SerializableEnumerator(Func<SerializableEnumeratorState<T>> start)
{
_start = new SerializableEnumeratorState<T>(default(T), start);
_current = _start;
}
public void Dispose()
{
}
public bool MoveNext()
{
_current = _current?.Next?.Invoke();
return _current != null;
}
public void Reset()
{
_current = _start;
}
}
}
/*
* Copyright (c) 2017 Ben Lambell.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using Recurse.Persist.Serializables;
namespace Recurse.Persist.Test
{
[Serializable]
public class SerializableEnumeratorState<T>
{
public T Value { get; }
public SerializableFunc<SerializableEnumeratorState<T>> Next { get; }
public SerializableEnumeratorState(T value, Func<SerializableEnumeratorState<T>> next) : this(value)
{
Next = new SerializableFunc<SerializableEnumeratorState<T>>(next);
}
public SerializableEnumeratorState(T value)
{
Value = value;
}
}
}
using System;
using System.Runtime.Serialization;
namespace Recurse.Persist.Serializables
{
public static class SerializableFunc
{
public static SerializableFunc<TResult> Get<TResult>(Func<TResult> func)
=> func != null ? new SerializableFunc<TResult>(func) : null;
public static SerializableFunc<T, TResult> Get<T, TResult>(Func<T, TResult> func)
=> func != null ? new SerializableFunc<T, TResult>(func) : null;
}
[Serializable]
public class SerializableFunc<TResult> : SerializableDelegate<Func<TResult>>
{
new protected Func<TResult> Delegate => (Func<TResult>)base.Delegate;
protected override Type[] ArgumentTypes => new Type[0];
public SerializableFunc(Func<TResult> func) : base(func)
{
}
public SerializableFunc(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
public TResult Invoke() => Delegate.Invoke();
}
[Serializable]
public class SerializableFunc<T, TResult> : SerializableDelegate<Func<T, TResult>>
{
new protected Func<T, TResult> Delegate => (Func<T, TResult>)base.Delegate;
protected override Type[] ArgumentTypes => new[] { typeof(T) };
public SerializableFunc(Func<T, TResult> func) : base(func)
{
}
public SerializableFunc(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
public TResult Invoke(T T1) => Delegate.Invoke(T1);
}
}
......@@ -23,6 +23,7 @@ namespace Recurse.Persist.Test
Assert.AreEqual(action1, action2);
}
[Test]
public static void CanSerializeSerializableDelegates()
{
......@@ -63,17 +64,71 @@ namespace Recurse.Persist.Test
Assert.AreEqual(result, action);
}
[Test]
public static void CanSerializePrivateAction()
{
var action = SerializableAction.Get(new InstanceClass().CreatePrivateAction);
var result = Deserialize.Execute(action);
// Cannot compare result with target, as serialization and deserialization
// means they actually refer to different objects' method calls
}
[Test]
public static void CanSerializePrivateStaticAction()
{
var action = SerializableAction.Get(StaticClass.CreatePrivateAction);
var result = Deserialize.Execute(action);
Assert.AreEqual(result, action);
}
[Test]
public static void CanSerializeFunctionWithNoArguments()
{
var func = SerializableFunc.Get(StaticClass.FuncWithoutArguments);
var result = Deserialize.Execute(func);
Assert.AreEqual(result, func);
}
[Test]
public static void CanSerializeFunctionWithArguments()
{
var func = SerializableFunc.Get<int, int>(StaticClass.FuncWithArguments);
var result = Deserialize.Execute(func);
Assert.AreEqual(result, func);
}
private static class StaticClass
{
public static int FuncWithoutArguments() => 0;
public static int FuncWithArguments(int x) => 0;
public static Action<int> CreatePrivateAction => PrivateReceiveValue;
public static void StaticReceiveValue(int value)
{
}
private static void PrivateReceiveValue(int value)
{
}
}
[Serializable]
private class InstanceClass
{
public Action<int> CreatePrivateAction => PrivateReceiveValue;
public static void StaticReceiveValue(int value)
{
......@@ -83,6 +138,11 @@ namespace Recurse.Persist.Test
{
}
private void PrivateReceiveValue(int value)
{
}
}
}
}
/*
* Copyright (c) 2017 Ben Lambell.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using NUnit.Framework;
namespace Recurse.Persist.Test
{
public static class SerializedEnumeratorTests
{
[Test]
public static void CanSerializeEnumerator()
{
var owner = new SerializableEnumerable();
var enumerator = owner.GetEnumerator();
Assume.That(enumerator.MoveNext());
var result = Deserialize.Execute(enumerator);
Assert.AreEqual(1, result.Current);
Assert.IsTrue(result.MoveNext());
Assert.AreEqual(2, result.Current);
}
[Serializable]
public class SerializableEnumerable : SerializableEnumerable<int>
{
private int _value = 1;
protected override Result Start()
{
return new Result(_value++, Start);
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment