001/**
002 * Powerunit - A JDK1.8 test framework
003 * Copyright (C) 2014 Mathieu Boretti.
004 *
005 * This file is part of Powerunit
006 *
007 * Powerunit is free software: you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as published by
009 * the Free Software Foundation, either version 3 of the License, or
010 * (at your option) any later version.
011 *
012 * Powerunit is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with Powerunit. If not, see <http://www.gnu.org/licenses/>.
019 */
020package ch.powerunit.extensions.exceptions;
021
022import static ch.powerunit.extensions.exceptions.Constants.verifyExceptionMapper;
023import static ch.powerunit.extensions.exceptions.Constants.verifyFunction;
024
025import java.util.function.Function;
026import java.util.function.Supplier;
027import java.util.function.ToIntBiFunction;
028
029/**
030 * Represents a function that accepts two arguments and produces an int-valued
031 * result. This is the {@code int}-producing primitive specialization for
032 * {@link BiFunctionWithException}.
033 * <h3>General contract</h3>
034 * <ul>
035 * <li><b>{@link #applyAsInt(Object, Object) int applyAsInt(T t, U u) throws
036 * E}</b>&nbsp;-&nbsp;The functional method.</li>
037 * <li><b>uncheck</b>&nbsp;-&nbsp;Return a {@code ToIntBiFunction<T, U>}</li>
038 * <li><b>lift</b>&nbsp;-&nbsp;Return a {@code ToIntBiFunction<T, U>}</li>
039 * <li><b>ignore</b>&nbsp;-&nbsp;Return a {@code ToIntBiFunction<T, U>}</li>
040 * </ul>
041 *
042 * @see ToIntBiFunction
043 * @param <T>
044 *            the type of the first argument to the function
045 * @param <U>
046 *            the type of the second argument to the function
047 * @param <E>
048 *            the type of the potential exception of the function
049 */
050@FunctionalInterface
051public interface ToIntBiFunctionWithException<T, U, E extends Exception>
052                extends PrimitiveReturnExceptionHandlerSupport<ToIntBiFunction<T, U>, ToIntBiFunctionWithException<T, U, E>>,
053                IntDefaultValue {
054
055        /**
056         * Applies this function to the given arguments.
057         *
058         * @param t
059         *            the first function argument
060         * @param u
061         *            the second function argument
062         * @return the function result
063         * @throws E
064         *             any exception
065         * @see ToIntBiFunction#applyAsInt(Object, Object)
066         */
067        int applyAsInt(T t, U u) throws E;
068
069        @Override
070        default ToIntBiFunction<T, U> uncheckOrIgnore(boolean uncheck) {
071                return (t, u) -> {
072                        try {
073                                return applyAsInt(t, u);
074                        } catch (Exception e) {
075                                PrimitiveReturnExceptionHandlerSupport.handleException(uncheck, e, exceptionMapper());
076                                return defaultValue();
077                        }
078                };
079        }
080
081        /**
082         * Returns a function that always throw exception.
083         *
084         * @param exceptionBuilder
085         *            the supplier to create the exception
086         * @param <T>
087         *            the type of the first argument to the function
088         * @param <U>
089         *            the type of the second argument to the function
090         * @param <E>
091         *            the type of the exception
092         * @return a function that always throw exception
093         */
094        static <T, U, E extends Exception> ToIntBiFunctionWithException<T, U, E> failing(Supplier<E> exceptionBuilder) {
095                return (t, u) -> {
096                        throw exceptionBuilder.get();
097                };
098        }
099
100        /**
101         * Converts a {@code ToIntBiFunctionWithException} to a {@code ToIntBiFunction}
102         * that wraps exception to {@code RuntimeException}.
103         *
104         * @param function
105         *            to be unchecked
106         * @param <T>
107         *            the type of the first argument to the function
108         * @param <U>
109         *            the type of the second argument to the function
110         * @param <E>
111         *            the type of the potential exception
112         * @return the unchecked function
113         * @see #uncheck()
114         * @see #unchecked(ToIntBiFunctionWithException, Function)
115         * @throws NullPointerException
116         *             if function is null
117         */
118        static <T, U, E extends Exception> ToIntBiFunction<T, U> unchecked(ToIntBiFunctionWithException<T, U, E> function) {
119                return verifyFunction(function).uncheck();
120        }
121
122        /**
123         * Converts a {@code ToIntBiFunctionWithException} to a {@code ToIntBiFunction}
124         * that wraps exception to {@code RuntimeException} by using the provided
125         * mapping function.
126         *
127         * @param function
128         *            the be unchecked
129         * @param exceptionMapper
130         *            a function to convert the exception to the runtime exception.
131         * @param <T>
132         *            the type of the first argument to the function
133         * @param <U>
134         *            the type of the second argument to the function
135         * @param <E>
136         *            the type of the potential exception
137         * @return the unchecked function
138         * @see #uncheck()
139         * @see #unchecked(ToIntBiFunctionWithException)
140         * @throws NullPointerException
141         *             if function or exceptionMapper is null
142         */
143        static <T, U, E extends Exception> ToIntBiFunction<T, U> unchecked(ToIntBiFunctionWithException<T, U, E> function,
144                        Function<Exception, RuntimeException> exceptionMapper) {
145                verifyFunction(function);
146                verifyExceptionMapper(exceptionMapper);
147                return new ToIntBiFunctionWithException<T, U, E>() {
148
149                        @Override
150                        public int applyAsInt(T t, U u) throws E {
151                                return function.applyAsInt(t, u);
152                        }
153
154                        @Override
155                        public Function<Exception, RuntimeException> exceptionMapper() {
156                                return exceptionMapper;
157                        }
158
159                }.uncheck();
160        }
161
162        /**
163         * Converts a {@code ToIntBiFunctionWithException} to a lifted
164         * {@code ToIntBiFunction} returning {@code 0} in case of exception.
165         *
166         * @param function
167         *            to be lifted
168         * @param <T>
169         *            the type of the first argument to the function
170         * @param <U>
171         *            the type of the second argument to the function
172         * @param <E>
173         *            the type of the potential exception
174         * @return the lifted function
175         * @see #lift()
176         * @throws NullPointerException
177         *             if function is null
178         */
179        static <T, U, E extends Exception> ToIntBiFunction<T, U> lifted(ToIntBiFunctionWithException<T, U, E> function) {
180                return verifyFunction(function).lift();
181        }
182
183        /**
184         * Converts a {@code ToIntBiFunctionWithException} to a lifted
185         * {@code ToIntBiFunction} returning {@code 0} in case of exception.
186         *
187         * @param function
188         *            to be lifted
189         * @param <T>
190         *            the type of the first argument to the function
191         * @param <U>
192         *            the type of the second argument to the function
193         * @param <E>
194         *            the type of the potential exception
195         * @return the lifted function
196         * @see #ignore()
197         * @throws NullPointerException
198         *             if function is null
199         */
200        static <T, U, E extends Exception> ToIntBiFunction<T, U> ignored(ToIntBiFunctionWithException<T, U, E> function) {
201                return verifyFunction(function).ignore();
202        }
203
204        /**
205         * Converts a {@code ToIntBiFunctionWithException} to a lifted
206         * {@code ToIntBiFunction} returning a default value in case of exception.
207         *
208         * @param function
209         *            to be lifted
210         * @param defaultValue
211         *            value in case of exception
212         * @param <T>
213         *            the type of the first argument to the function
214         * @param <U>
215         *            the type of the second argument to the function
216         * @param <E>
217         *            the type of the potential exception
218         * @return the lifted function
219         * @see #ignore()
220         * @see #ignored(ToIntBiFunctionWithException)
221         * @throws NullPointerException
222         *             if function is null
223         * @since 3.0.0
224         */
225        static <T, U, E extends Exception> ToIntBiFunction<T, U> ignored(ToIntBiFunctionWithException<T, U, E> function,
226                        int defaultValue) {
227                verifyFunction(function);
228                return new ToIntBiFunctionWithException<T, U, E>() {
229
230                        @Override
231                        public int applyAsInt(T t, U u) throws E {
232                                return function.applyAsInt(t, u);
233                        }
234
235                        @Override
236                        public int defaultValue() {
237                                return defaultValue;
238                        }
239
240                }.ignore();
241        }
242
243}