const isFailureSymbol = Symbol('isFailure');
/**
 * Represents a failure or error if you will. Use function {@link Fail} to create
 * a failure instance.
 */
export type Failure<T> = { readonly isFailure: true } & T;

/**
 * Helper to return a non failure result
 * @param result Result to return.
 */
export function Ok<T>(result: T): T {
    return result;
}

/**
 * Helper to return a {@link Fail} result.
 * @param failure The failure to return
 */
export function Fail<T>(failure: T): Failure<T> {
    const tmp = failure as any;
    tmp[isFailureSymbol] = true;
    return tmp;
}

/**
 * Checks if a value is a {@link Failure} or not. A {@link Failure} is a value that was created
 * with the {@link Fail} function.
 * @param resultOrFailure value to check if it is a {@link Fail}'ure nor not.
 */
export function isFailure<E>(resultOrFailure: unknown | Failure<E> | undefined | null): resultOrFailure is Failure<E> {
    return resultOrFailure != null && (resultOrFailure as any)[isFailureSymbol] === true;
}
