def METHOD_NAME(array: Union[np.ndarray, pd.Series, pd.Index]) -> Tuple[np.dtype, dict]:
    """
    Determine encoding type and schema hint from an array.  This allows more
    flexible casting than may be possible by using just the dtype, as it can
    account for category types and array values.
    """
    if (
        not isinstance(array, np.ndarray)
        and not isinstance(array, pd.Series)
        and not isinstance(array, pd.Index)
        and not hasattr(array, "dtype")
    ):
        raise TypeError("Unsupported data type.")
    dtype = array.dtype
    res = _get_type_info_from_dtype(dtype)
    if res is not None:
        return res
    if dtype.kind == "O":
        if dtype.name == "category":
            # Sometimes CategoricalDType can be encoded as int or float without further fuss.
            # Do not specify the categories in the schema - let the client-side figure it out
            # on its own.  Utilize Series.to_numpy() to do casting that handles categorical
            # NA/NaN (missing or undefined) categories.
            if dtype.categories.dtype.kind in ["f", "i", "u"]:
                return (
                    METHOD_NAME(array.to_numpy())[0],
                    {"type": "categorical"},
                )
            else:
                return (np.dtype(str), {"type": "categorical", "categories": dtype.categories.to_list()})
        # all other extension types are str-encoded
        return (np.dtype(str), {"type": "string"})
    if dtype.kind in ["i", "u"] and _can_cast_array_values_to_int32(array):
        return (np.int32, {"type": "int32"})
    if dtype.kind == "f":
        _float64_warning(array.dtype)
        return (np.float32, {"type": "float32"})
    raise TypeError(f"Annotations of type {dtype} are unsupported.")