/*
 * @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.io.IOException;
import java.util.function.Consumer;

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

    /**
     * Performs operation on given argument.
     *
     * @param value value
     * @throws E on error
     */
    void accept(T value) throws E;

    /**
     * Performs operation on given argument.
     * 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.
     *
     * @param value value
     */
    default void $accept(T value) {
        try {
            accept(value);
        } catch(Exception cause) {
            throw ExceptionUtils.rethrow(cause);
        }
    }

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

}
