Utility method to check if a parser is able to convert a given type to the given type, either in
        * strict mode : provided_type and desired_type must be equal to this converter's from_type and to_type
        respectively (or the to_type does not match but this converter is generic
        * inference mode (non-strict) : provided_type may be a subclass of from_type, and to_type may be a subclass
        of desired_type

        If a custom function was provided at construction time, it is called to enable converters to reject some
        conversions based on source and/or dest type provided.

        :param strict: a boolean indicating if matching should be in strict mode or not
        :param from_type:
        :param to_type:
        :return: a tuple of 3 booleans : (does match?, strict source match? (None if no match), strict dest match?
        (None if no match))

def is_able_to_convert_detailed(self, strict: bool, from_type: Type[Any], to_type: Type[Any]) \
            -> Tuple[bool, bool, bool]:
        """
        Utility method to check if a parser is able to convert a given type to the given type, either in
        * strict mode : provided_type and desired_type must be equal to this converter's from_type and to_type
        respectively (or the to_type does not match but this converter is generic
        * inference mode (non-strict) : provided_type may be a subclass of from_type, and to_type may be a subclass
        of desired_type

        If a custom function was provided at construction time, it is called to enable converters to reject some
        conversions based on source and/or dest type provided.

        :param strict: a boolean indicating if matching should be in strict mode or not
        :param from_type:
        :param to_type:
        :return: a tuple of 3 booleans : (does match?, strict source match? (None if no match), strict dest match?
        (None if no match))
        """
        # (1) first handle the easy joker+joker case
        if from_type is JOKER and to_type is JOKER:
            return True, None, None

        # Don't validate types -- this is called too often at the initial RootParser instance creation time,
        # and this is quite 'internal' so the risk is very low
        #
        # check_var(strict, var_types=bool, var_name='strict')
        # if from_type is not JOKER:
        #     check_var(from_type, var_types=type, var_name='from_type')
        # if to_type is not JOKER:
        #     check_var(to_type, var_types=type, var_name='to_type')

        # -- first call custom checker if provided
        if self.is_able_to_convert_func is not None:
            # TODO Maybe one day, rather push the JOKER to the function ? not sure that it will be more explicit..
            if not self.is_able_to_convert_func(strict,
                                                from_type=None if from_type is JOKER else from_type,
                                                to_type=None if to_type is JOKER else to_type):
                return False, None, None

        # -- from_type strict match
        if (from_type is JOKER) or (from_type is self.from_type) or is_any_type(from_type):
            # -- check to type strict
            if (to_type is JOKER) or self.is_generic() or (to_type is self.to_type):
                return True, True, True  # strict to_type match
            # -- check to type non-strict
            elif (not strict) and issubclass(self.to_type, to_type):
                return True, True, False  # approx to_type match

        # -- from_type non-strict match
        elif (not strict) and issubclass(from_type, self.from_type):
            # -- check to type strict
            if (to_type is JOKER) or self.is_generic() or (to_type is self.to_type):
                return True, False, True  # exact to_type match
            # -- check to type non-strict
            elif (not strict) and issubclass(self.to_type, to_type):
                return True, False, False  # approx to_type match

        # -- otherwise no match
        return False, None, None