Skip to content

Instantly share code, notes, and snippets.

@reniris
Last active April 23, 2018 16:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reniris/78eeb527e6a9a9c111ad760b2a439075 to your computer and use it in GitHub Desktop.
Save reniris/78eeb527e6a9a9c111ad760b2a439075 to your computer and use it in GitHub Desktop.
ReactivePropertySlimResolver
using System;
using System.Collections.Generic;
using System.Reactive;
using System.Reflection;
using System.Text;
using MessagePack.Formatters;
using Reactive.Bindings;
namespace MessagePack.ReactivePropertyExtension
{
public class ReactivePropertySlimResolver : IFormatterResolver
{
public static IFormatterResolver Instance = new ReactivePropertySlimResolver();
ReactivePropertySlimResolver()
{
}
public IMessagePackFormatter<T> GetFormatter<T>()
{
return FormatterCache<T>.formatter;
}
static class FormatterCache<T>
{
public static readonly IMessagePackFormatter<T> formatter;
static FormatterCache()
{
formatter = (IMessagePackFormatter<T>)ReactivePropertySlimResolverGetFormatterHelper.GetFormatter(typeof(T));
}
}
}
internal static class ReactivePropertySlimResolverGetFormatterHelper
{
static readonly Dictionary<Type, Type> formatterMap = new Dictionary<Type, Type>()
{
{typeof(ReactivePropertySlim<>), typeof(ReactivePropertySlimFormatter<>)},
};
internal static object GetFormatter(Type t)
{
var ti = t.GetTypeInfo();
if (ti.IsGenericType)
{
var genericType = ti.GetGenericTypeDefinition();
if (formatterMap.TryGetValue(genericType, out Type formatterType))
{
return CreateInstance(formatterType, ti.GenericTypeArguments);
}
}
return null;
}
static object CreateInstance(Type genericType, Type[] genericTypeArguments, params object[] arguments)
{
return Activator.CreateInstance(genericType.MakeGenericType(genericTypeArguments), arguments);
}
}
}
using MessagePack.Formatters;
using Reactive.Bindings;
using System;
using System.Collections.Generic;
using System.Text;
namespace MessagePack.ReactivePropertyExtension
{
// [Mode, Value]
public class ReactivePropertySlimFormatter<T> : IMessagePackFormatter<ReactivePropertySlim<T>>
{
public int Serialize(ref byte[] bytes, int offset, ReactivePropertySlim<T> value, IFormatterResolver formatterResolver)
{
if (value == null)
{
return MessagePackBinary.WriteNil(ref bytes, offset);
}
else
{
var startOffset = offset;
offset += MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 2);
offset += MessagePackBinary.WriteInt32(ref bytes, offset, ReactivePropertySlimModeMapper.ToReactivePropertySlimModeInt(value));
offset += formatterResolver.GetFormatterWithVerify<T>().Serialize(ref bytes, offset, value.Value, formatterResolver);
return offset - startOffset;
}
}
public ReactivePropertySlim<T> Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize)
{
if (MessagePackBinary.IsNil(bytes, offset))
{
readSize = 1;
return null;
}
else
{
var startOffset = offset;
var length = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize);
offset += readSize;
if (length != 2) throw new InvalidOperationException("Invalid ReactivePropertySlim data.");
var mode = (ReactivePropertyMode)MessagePackBinary.ReadInt32(bytes, offset, out readSize);
offset += readSize;
var v = formatterResolver.GetFormatterWithVerify<T>().Deserialize(bytes, offset, formatterResolver, out readSize);
offset += readSize;
readSize = offset - startOffset;
return new ReactivePropertySlim<T>(v, mode);
}
}
}
public static class ReactivePropertySlimModeMapper
{
internal static int ToReactivePropertySlimModeInt<T>(global::Reactive.Bindings.ReactivePropertySlim<T> reactiveProperty)
{
var mode = ReactivePropertyMode.None;
if (reactiveProperty.IsDistinctUntilChanged)
{
mode |= ReactivePropertyMode.DistinctUntilChanged;
}
if (reactiveProperty.IsRaiseLatestValueOnSubscribe)
{
mode |= ReactivePropertyMode.RaiseLatestValueOnSubscribe;
}
return (int)mode;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment