/// <summary>
 /// Creates a new instance of a <see cref="PropertyDrawer{TValue, TAttribute}"/> that can act as a property drawer
 /// for a given field.
 /// </summary>
 /// <param name="constraints">Constraints that filter the candidate property drawer types.</param>
 /// <typeparam name="TValue">The type of the value</typeparam>
 /// <typeparam name="TAttribute">The attribute type the value was tagged with</typeparam>
 /// <returns>The property drawer instance or null</returns>
 public static PropertyDrawer <TValue, TAttribute> GetPropertyDrawer <TValue, TAttribute>(
     params IInspectorConstraint[] constraints)
     where TAttribute : UnityEngine.PropertyAttribute
 {
     return((PropertyDrawer <TValue, TAttribute>)GetInspector <TValue>(
                InspectorConstraint.Combine(InspectorConstraint.AssignableTo <IPropertyDrawer <TAttribute> >(),
                                            constraints)));
 }
        /// <summary>
        /// Creates a new instance of a <see cref="PropertyInspector{TValue,TAttribute}"/> that can act as a property drawer
        /// for a given field.
        /// </summary>
        /// <param name="property"></param>
        /// <param name="constraints">Constraints that filter the candidate property drawer types.</param>
        /// <typeparam name="TValue">The type of the value</typeparam>
        /// <returns>The property drawer instance or null</returns>
        static IInspector <TValue> GetAttributeInspector <TValue>(IProperty property, params IInspectorConstraint[] constraints)
        {
            foreach (var attribute in property.GetAttributes <UnityEngine.PropertyAttribute>() ??
                     Array.Empty <UnityEngine.PropertyAttribute>())
            {
                var drawer    = typeof(IPropertyDrawer <>).MakeGenericType(attribute.GetType());
                var inspector = GetInspectorWithConstraints <TValue>(InspectorConstraint.Combine(InspectorConstraint.AssignableTo(drawer), constraints));
                if (null != inspector)
                {
                    return(inspector);
                }
            }

            return(null);
        }
        internal static IInspector <TValue> GetBestInspectorType <TValue>(IProperty property)
        {
            var inspector = default(IInspector <TValue>);

            foreach (var drawerAttribute in property.GetAttributes <UnityEngine.PropertyAttribute>() ?? Array.Empty <UnityEngine.PropertyAttribute>())
            {
                var drawer = typeof(IPropertyDrawer <>).MakeGenericType(drawerAttribute.GetType());
                inspector = GetPropertyDrawer <TValue>(InspectorConstraint.AssignableTo(drawer));
                if (null != inspector)
                {
                    break;
                }
            }
            return(inspector ?? GetRootInspector <TValue>());
        }
        internal static IInspector <TValue> GetPropertyDrawer <TValue>(IEnumerable <Attribute> attributes)
        {
            foreach (var drawerAttribute in attributes)
            {
                if (!(drawerAttribute is PropertyAttribute))
                {
                    continue;
                }

                var drawer    = typeof(IPropertyDrawer <>).MakeGenericType(drawerAttribute.GetType());
                var inspector = GetPropertyDrawer <TValue>(InspectorConstraint.AssignableTo(drawer));
                if (null != inspector)
                {
                    return(inspector);
                }
            }

            return(null);
        }
 /// <summary>
 /// Creates a new instance of a <see cref="PropertyInspector{TValue,TAttribute}"/> that can act as a property drawer
 /// for a given field.
 /// </summary>
 /// <param name="constraints">Constraints that filter the candidate property drawer types.</param>
 /// <typeparam name="TValue">The type of the value</typeparam>
 /// <typeparam name="TAttribute">The attribute type the value was tagged with</typeparam>
 /// <returns>The property drawer instance or null</returns>
 static PropertyInspector <TValue> GetPropertyInspector <TValue>(params IInspectorConstraint[] constraints)
 {
     return((PropertyInspector <TValue>)GetInspectorWithConstraints <TValue>(InspectorConstraint.Combine(InspectorConstraint.AssignableTo <IPropertyDrawer>(), constraints)));
 }
 /// <summary>
 /// Creates a new instance of a <see cref="Inspector{TValue}"/> that can act as a root inspector.
 /// </summary>
 /// <param name="constraints">Constraints that filter the candidate inspector types.</param>
 /// <typeparam name="TValue">The type of the value</typeparam>
 /// <returns>The inspector instance or null</returns>
 static IInspector <TValue> GetInspector <TValue>(params IInspectorConstraint[] constraints)
 {
     return(GetInspectorWithConstraints <TValue>(InspectorConstraint.Combine(InspectorConstraint.AssignableTo <IRootInspector>(), constraints)));
 }
 /// <summary>
 /// Creates a new instance of a <see cref="IInspector{TValue}"/> that can act as a root inspector.
 /// </summary>
 /// <param name="constraints">Constraints that filter the candidate inspector types.</param>
 /// <typeparam name="TValue">The type of the value</typeparam>
 /// <returns>The inspector instance or null</returns>
 public static Inspector <TValue> GetRootInspector <TValue>(params IInspectorConstraint[] constraints)
 {
     return(GetInspector <TValue>(
                InspectorConstraint.Combine(InspectorConstraint.Not.AssignableTo <IPropertyDrawer>(), constraints)));
 }