using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Serialization;
using JetBrains.Diagnostics;
using JetBrains.Rd.Base;
using JetBrains.Rd.Impl;
using JetBrains.Util;
using JetBrains.Util.Util;
namespace JetBrains.Rd.Reflection
{
public class ScalarSerializer : IScalarSerializers
{
///
/// Types catalog required for providing information about statically discovered types during concrete serializer
/// construction for sake of possibility for Rd serializers to lookup real type by representing RdId
///
private readonly ITypesCatalog? myTypesCatalog;
///
/// Black listed type. Any attempt to create serializer for these types should throw exception.
/// Used to prevent attempts to pass an object which is well-known as non-serializable.
/// For example, any component of tree-like structure or object graph should not be passed to
/// serializer
///
/// This predicate should return true only for blacklisted type
///
private readonly Predicate myBlackListChecker;
public ScalarSerializer(ITypesCatalog? typesCatalog, Predicate? blackListChecker = null)
{
myTypesCatalog = typesCatalog;
myBlackListChecker = blackListChecker ?? (_ => false);
}
///
/// Creates static serializers for type
///
///
///
///
public SerializerPair CreateSerializer(Type type, ISerializersSource serializers)
{
if (type == typeof(IntPtr))
{
throw new ArgumentException($"Unable to serialize {type.ToString(true)}. Platform-specific types cannot be serialized.");
}
if (typeof(Delegate).IsAssignableFrom(type))
{
throw new ArgumentException($"Unable to serialize {type.ToString(true)}. Delegates cannot be serialized.");
}
if (myBlackListChecker(type))
{
Assertion.Fail($"Attempt to create serializer for black-listed type: {type.ToString(true)}");
}
var typeInfo = type.GetTypeInfo();
var builtIn = BuiltInSerializers.TryGet(typeInfo, t1 => serializers.GetOrRegisterSerializerPair(t1, true));
if (builtIn != null)
{
myTypesCatalog?.AddType(type);
return builtIn;
}
else if (type.IsEnum)
{
var serializer = ReflectionUtil.InvokeGenericThis(this, nameof(CreateEnumSerializer), type);
return (SerializerPair) serializer!;
}
else if (ReflectionSerializerVerifier.IsValueTuple(typeInfo))
{
return (SerializerPair) ReflectionUtil.InvokeGenericThis(this, nameof(CreateValueTupleSerializer), type, new object?[] { serializers })!;
}
else if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))
{
var genericTypeArgument = typeInfo.GetGenericArguments()[0];
var nullableSerializer = (SerializerPair) ReflectionUtil.InvokeGenericThis(this, nameof(RegisterNullable), genericTypeArgument, new object?[] { serializers })!;
return nullableSerializer;
// return CreateGenericSerializer(member, typeInfo, implementingType, implementingTypeInfo);
}
else
{
myTypesCatalog?.AddType(type);
var serializer = ReflectionUtil.InvokeGenericThis(this, nameof(CreateCustomScalar), type, new object[] { serializers });
return (SerializerPair) serializer!;
}
}
private SerializerPair CreateCustomScalar(ISerializersSource serializers)
{
if (Mode.IsAssertion)
ReflectionSerializerVerifier.AssertValidScalar(typeof(T).GetTypeInfo());
TypeInfo typeInfo = typeof(T).GetTypeInfo();
var allowNullable = ReflectionSerializerVerifier.CanBeNull(typeInfo);
var memberInfos = SerializerReflectionUtil.GetSerializableFields(typeInfo);
var memberSetters = memberInfos.Select(ReflectionUtil.GetSetter).ToArray();
var memberGetters = memberInfos.Select(ReflectionUtil.GetGetter).ToArray();
// todo: consider using IL emit
CtxReadDelegate