123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
- using System;
- using System.Collections.Generic;
- using UnityEngine;
- namespace Animancer
- {
- /// <summary>An object which can be converted to another type.</summary>
- /// https://kybernetik.com.au/animancer/api/Animancer/IConvertable_1
- public interface IConvertable<out T>
- {
- /************************************************************************************************************************/
- /// <summary>Returns the equivalent of this object as <typeparamref name="T"/>.</summary>
- T Convert();
- /************************************************************************************************************************/
- }
- /// <summary>Utility methods for <see cref="IConvertable{T}"/>.</summary>
- /// https://kybernetik.com.au/animancer/api/Animancer/ConvertableUtilities
- public static partial class ConvertableUtilities
- {
- /************************************************************************************************************************/
- /// <summary>
- /// Custom conversion functions used as a fallback
- /// for types that can't implement <see cref="IConvertable{T}"/>.
- /// </summary>
- public static readonly Dictionary<Type, Func<object, Type, object>>
- CustomConverters = new();
- /************************************************************************************************************************/
- /// <summary>Tries to convert the `original` to <typeparamref name="T"/>.</summary>
- /// <remarks>
- /// <list type="bullet">
- /// <item>If the `original` is already a <typeparamref name="T"/> then it's returned directly.</item>
- /// <item>Or if it's an <see cref="IConvertable{T}"/> then <see cref="IConvertable{T}.Convert"/> is used.</item>
- /// <item>Otherwise, this method throws an <see cref="ArgumentException"/>.</item>
- /// </list>
- /// </remarks>
- public static T ConvertOrThrow<T>(object original)
- {
- if (TryConvert<T>(original, out var converted))
- return converted;
- throw new ArgumentException(
- $"Unable to convert '{AnimancerUtilities.ToStringOrNull(original)}'" +
- $" to '{typeof(T).GetNameCS()}'.");
- }
- /************************************************************************************************************************/
- /// <summary>Tries to convert the `original` to <typeparamref name="T"/>.</summary>
- /// <remarks>
- /// <list type="bullet">
- /// <item>If the `original` is already a <typeparamref name="T"/> then it's returned directly.</item>
- /// <item>Or if it's an <see cref="IConvertable{T}"/> then <see cref="IConvertable{T}.Convert"/> is used.</item>
- /// <item>Otherwise, this method returns the <c>default(T)</c>.</item>
- /// </list>
- /// </remarks>
- public static T ConvertOrDefault<T>(object original)
- {
- TryConvert<T>(original, out var converted);
- return converted;
- }
- /************************************************************************************************************************/
- /// <summary>Tries to convert the `original` to <typeparamref name="T"/>.</summary>
- /// <remarks>
- /// <list type="bullet">
- /// <item>If the `original` is already a <typeparamref name="T"/> then it's returned directly.</item>
- /// <item>Or if it's an <see cref="IConvertable{T}"/> then <see cref="IConvertable{T}.Convert"/> is used.</item>
- /// <item>Otherwise, this method returns <c>false</c>.</item>
- /// </list>
- /// </remarks>
- public static bool TryConvert<T>(object original, out T converted)
- {
- if (original is null)
- {
- converted = default;
- return converted == null;// True for value type, false for reference type.
- }
- if (original is T t)
- {
- converted = t;
- return true;
- }
- if (original is IConvertable<T> convertable)
- {
- converted = convertable.Convert();
- return true;
- }
- if (CustomConverters.TryGetValue(original.GetType(), out var converter))
- {
- converted = (T)converter(original, typeof(T));
- return converted != null;
- }
- converted = default;
- return false;
- }
- /************************************************************************************************************************/
- /// <summary>Initializes the inbuilt custom converters.</summary>
- static ConvertableUtilities()
- {
- CustomConverters.Add(typeof(GameObject), TryGetComponent);
- }
- /************************************************************************************************************************/
- /// <summary>Tries to get a component if the `original` is a <see cref="GameObject"/>.</summary>
- private static object TryGetComponent(object original, Type type)
- {
- if (original is GameObject gameObject &&
- gameObject.TryGetComponent(type, out var component))
- return component;
- return null;
- }
- /************************************************************************************************************************/
- }
- }
|