def _ion_equals(a, b, timestamp_comparison_func, recursive_comparison_func):
    """Compares a and b according to the description of the ion_equals method."""
    for a, b in ((a, b), (b, a)):  # Ensures that operand order does not matter.
        if isinstance(a, _IonNature):
            if isinstance(b, _IonNature):
                # Both operands have _IonNature. Their IonTypes and annotations must be equivalent.
                eq = a.ion_type is b.ion_type and _annotations_eq(a, b)
            else:
                # Only one operand has _IonNature. It cannot be equivalent to the other operand if it has annotations.
                eq = not a.ion_annotations
            if eq:
                if isinstance(a, IonPyList):
                    return _sequences_eq(a, b, recursive_comparison_func)
                elif isinstance(a, IonPyDict):
                    return _structs_eq(a, b, recursive_comparison_func)
                elif isinstance(a, IonPyTimestamp):
                    return timestamp_comparison_func(a, b)
                elif isinstance(a, IonPyNull):
                    return isinstance(b, IonPyNull) or (b is None and a.ion_type is IonType.NULL)
                elif isinstance(a, IonPySymbol) or (isinstance(a, IonPyText) and a.ion_type is IonType.SYMBOL):
                    return _symbols_eq(a, b)
                elif isinstance(a, IonPyDecimal):
                    return _decimals_eq(a, b)
                elif isinstance(a, IonPyFloat):
                    return _floats_eq(a, b)
                else:
                    return a == b
            return False
    # Reaching this point means that neither operand has _IonNature.
    for a, b in ((a, b), (b, a)):  # Ensures that operand order does not matter.
        if isinstance(a, list):
            return _sequences_eq(a, b, recursive_comparison_func)
        elif isinstance(a, dict):
            return _structs_eq(a, b, recursive_comparison_func)
        elif isinstance(a, datetime):
            return timestamp_comparison_func(a, b)
        elif isinstance(a, SymbolToken):
            return _symbols_eq(a, b)
        elif isinstance(a, Decimal):
            return _decimals_eq(a, b)
        elif isinstance(a, float):
            return _floats_eq(a, b)
    return a == b
Compares a and b according to the description of the ion_equals method.