/*
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */

package net.ranides.assira.functional.checked;

import net.ranides.assira.trace.ExceptionUtils;

import java.util.function.Supplier;

/**
 * This functional inferface represents {@link Supplier} which could throw checked exception
 *
 * @param <T> T
 * @param <E> E
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public interface CheckedSupplier<T,E extends Exception> {

    /**
     * Performs operation and returns produced result.
     *
     * @return result
     * @throws E on error
     */
    T get() throws E;

    /**
     * Performs operation and returns produced result.
     * Usafe method: it rethrows checked exceptions, but without declaring them.
     *
     * Please note, that javac does not allow to catch checked exception of specific type if they are not declared.
     * In such situations you can only catch very general "Exception" type.
     *
     * @return result
     */
    default T $get() {
        try {
            return get();
        } catch(Exception cause) {
            throw ExceptionUtils.rethrow(cause);
        }
    }

    /**
     * Converts this supplier into sneaky version, which rethrows checked exception, but without declaring it.
     * Please note, that code expecting ordinary Supplier is not prerared for handling checked throws
     * and could work incorrectly when exception happens.
     *
     * @param supplier supplier
     * @param <T> T
     * @param <E> E
     * @return Supplier
     */
    static  <T, E extends Exception> Supplier<T> sneaky(CheckedSupplier<T, E> supplier) {
        return supplier::$get;
    }

}
