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

import java.util.function.Function;
import java.util.function.IntUnaryOperator;

/**
 * This functional interface represents operation inverted to {@link IntUnaryOperator}.
 * Strictly speaking, inverted operation does not require to be separate interface,
 * but we want to declare method other than "apply" and be able to implement both methods in IntProjectionFunction
 *
 * It is specialization of CoFunction for integer types.
 * It avoids uneccessary boxing and unboxing
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public interface IntCoFunction extends CoFunction<Integer, Integer> {

    @Override
    default Integer invert(Integer value) {
        return invert(value.intValue());
    }

    /**
     * non-generic version of {@link #invert(Integer)} method
     * @param value value
     * @return value
     */
    int invert(int value);

    /**
     * Returns identity function
     *
     * @return function
     */
    static IntCoFunction identity() {
        return v -> v;
    }

    /**
     * Converts specified function into IntCoFunction interface.
     * Obviously, it does not change operation, it just changes interface.
     *
     * @param f f
     * @return functional
     */
    static IntCoFunction inverted(IntUnaryOperator f) {
        return v -> f.applyAsInt(v);
    }

    /**
     * Converts specified inverted function into IntUnaryOperator.
     * Obviously, it does not change operation, it just changes interface.
     *
     * @param f f
     * @return functional
     */
    static IntUnaryOperator inverted(IntCoFunction f) {
        return v -> f.invert(v);
    }
    
}
