// -----------------------------------------------------------------------
//
// Copyright 2015 MIT Licence. See licence.md for more information.
//
// -----------------------------------------------------------------------
namespace Perspex.Utilities
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
///
/// Provides utilities for working with types at runtime.
///
internal static class TypeUtilities
{
private static readonly Dictionary> Conversions = new Dictionary>()
{
{ typeof(decimal), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char) } },
{ typeof(double), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } },
{ typeof(float), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } },
{ typeof(ulong), new List { typeof(byte), typeof(ushort), typeof(uint), typeof(char) } },
{ typeof(long), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(char) } },
{ typeof(uint), new List { typeof(byte), typeof(ushort), typeof(char) } },
{ typeof(int), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(char) } },
{ typeof(ushort), new List { typeof(byte), typeof(char) } },
{ typeof(short), new List { typeof(byte) } }
};
///
/// Try to cast a value to a type, using implicit conversions if possible.
///
/// The type to cast to.
/// The value to cast.
/// If sucessful, contains the cast value.
/// True if the cast was sucessful, otherwise false.
public static bool TryCast(Type to, object value, out object result)
{
Contract.Requires(to != null);
if (value == null)
{
var t = to.GetTypeInfo();
result = null;
return !t.IsValueType || (t.IsGenericType && (t.GetGenericTypeDefinition() == typeof(Nullable<>)));
}
var from = value.GetType();
if (value == PerspexProperty.UnsetValue)
{
result = value;
return true;
}
else if (to.GetTypeInfo().IsAssignableFrom(from.GetTypeInfo()))
{
result = value;
return true;
}
else if (Conversions.ContainsKey(to) && Conversions[to].Contains(from))
{
result = Convert.ChangeType(value, to);
return true;
}
else
{
var cast = from.GetTypeInfo()
.GetDeclaredMethods("op_Implicit")
.FirstOrDefault(m => m.ReturnType == to);
if (cast != null)
{
result = cast.Invoke(null, new[] { value });
return true;
}
}
result = null;
return false;
}
}
}