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.IntBinaryOperator;
027import java.util.function.Supplier;
028
029/**
030 * Represents an operation upon two {@code int}-valued operands, may thrown
031 * exception and producing an {@code int}-valued result. This is the primitive
032 * type specialization of {@link BinaryOperatorWithException} for {@code int}.
033 * <h3>General contract</h3>
034 * <ul>
035 * <li><b>{@link #applyAsInt(int, int) int applyAsInt(int left, int right)
036 * throws E}</b>&nbsp;-&nbsp;The functional method.</li>
037 * <li><b>uncheck</b>&nbsp;-&nbsp;Return a {@code IntBinaryOperator}</li>
038 * <li><b>lift</b>&nbsp;-&nbsp;Return a {@code IntBinaryOperator}</li>
039 * <li><b>ignore</b>&nbsp;-&nbsp;Return a {@code IntBinaryOperator}</li>
040 * </ul>
041 *
042 * @see IntBinaryOperator
043 * @param <E>
044 *            the type of the potential exception of the function
045 */
046@FunctionalInterface
047public interface IntBinaryOperatorWithException<E extends Exception> extends
048                PrimitiveReturnExceptionHandlerSupport<IntBinaryOperator, IntBinaryOperatorWithException<E>>, IntDefaultValue {
049
050        /**
051         * Applies this operator to the given operands.
052         *
053         * @param left
054         *            the first operand
055         * @param right
056         *            the second operand
057         * @return the operator result
058         * @throws E
059         *             any exception
060         * @see IntBinaryOperator#applyAsInt(int, int)
061         */
062        int applyAsInt(int left, int right) throws E;
063
064        @Override
065        default IntBinaryOperator uncheckOrIgnore(boolean uncheck) {
066                return (left, right) -> {
067                        try {
068                                return applyAsInt(left, right);
069                        } catch (Exception e) {
070                                PrimitiveReturnExceptionHandlerSupport.handleException(uncheck, e, exceptionMapper());
071                                return defaultValue();
072                        }
073                };
074        }
075
076        /**
077         * Returns a function that always throw exception.
078         *
079         * @param exceptionBuilder
080         *            the supplier to create the exception
081         * @param <E>
082         *            the type of the exception
083         * @return a function that always throw exception
084         */
085        static <E extends Exception> IntBinaryOperatorWithException<E> failing(Supplier<E> exceptionBuilder) {
086                return (left, right) -> {
087                        throw exceptionBuilder.get();
088                };
089        }
090
091        /**
092         * Converts a {@code IntBinaryOperatorWithException} to a
093         * {@code IntBinaryOperator} that convert exception to {@code RuntimeException}.
094         *
095         * @param function
096         *            to be unchecked
097         * @param <E>
098         *            the type of the potential exception
099         * @return the unchecked function
100         * @see #uncheck()
101         * @see #unchecked(IntBinaryOperatorWithException, Function)
102         * @throws NullPointerException
103         *             if function is null
104         */
105        static <E extends Exception> IntBinaryOperator unchecked(IntBinaryOperatorWithException<E> function) {
106                return verifyFunction(function).uncheck();
107        }
108
109        /**
110         * Converts a {@code IntBinaryOperatorWithException} to a
111         * {@code IntBinaryOperator} that convert exception to {@code RuntimeException}
112         * by using the provided mapping function.
113         *
114         * @param function
115         *            the be unchecked
116         * @param exceptionMapper
117         *            a function to convert the exception to the runtime exception.
118         * @param <E>
119         *            the type of the potential exception
120         * @return the unchecked function
121         * @see #uncheck()
122         * @see #unchecked(IntBinaryOperatorWithException)
123         * @throws NullPointerException
124         *             if function or exceptionMapper is null
125         */
126        static <E extends Exception> IntBinaryOperator unchecked(IntBinaryOperatorWithException<E> function,
127                        Function<Exception, RuntimeException> exceptionMapper) {
128                verifyFunction(function);
129                verifyExceptionMapper(exceptionMapper);
130                return new IntBinaryOperatorWithException<E>() {
131
132                        @Override
133                        public int applyAsInt(int left, int right) throws E {
134                                return function.applyAsInt(left, right);
135                        }
136
137                        @Override
138                        public Function<Exception, RuntimeException> exceptionMapper() {
139                                return exceptionMapper;
140                        }
141
142                }.uncheck();
143        }
144
145        /**
146         * Converts a {@code IntBinaryOperatorWithException} to a lifted
147         * {@code IntBinaryOperator} with {@code 0} as return value in case of
148         * exception.
149         *
150         * @param function
151         *            to be lifted
152         * @param <E>
153         *            the type of the potential exception
154         * @return the lifted function
155         * @see #lift()
156         * @throws NullPointerException
157         *             if function is null
158         */
159        static <E extends Exception> IntBinaryOperator lifted(IntBinaryOperatorWithException<E> function) {
160                return verifyFunction(function).lift();
161        }
162
163        /**
164         * Converts a {@code IntBinaryOperatorWithException} to a lifted
165         * {@code IntBinaryOperator} with {@code 0} as return value in case of
166         * exception.
167         *
168         * @param function
169         *            to be lifted
170         * @param <E>
171         *            the type of the potential exception
172         * @return the lifted function
173         * @see #ignore()
174         * @throws NullPointerException
175         *             if function is null
176         */
177        static <E extends Exception> IntBinaryOperator ignored(IntBinaryOperatorWithException<E> function) {
178                return verifyFunction(function).ignore();
179        }
180
181        /**
182         * Converts a {@code IntBinaryOperatorWithException} to a lifted
183         * {@code IntBinaryOperator} with a default value as return value in case of
184         * exception.
185         *
186         * @param function
187         *            to be lifted
188         * @param defaultValue
189         *            value in case of exception
190         * @param <E>
191         *            the type of the potential exception
192         * @return the lifted function
193         * @see #ignore()
194         * @see #ignored(IntBinaryOperatorWithException)
195         * @throws NullPointerException
196         *             if function is null
197         * @since 3.0.0
198         */
199        static <E extends Exception> IntBinaryOperator ignored(IntBinaryOperatorWithException<E> function,
200                        int defaultValue) {
201                verifyFunction(function);
202                return new IntBinaryOperatorWithException<E>() {
203
204                        @Override
205                        public int applyAsInt(int left, int right) throws E {
206                                return function.applyAsInt(left, right);
207                        }
208
209                        @Override
210                        public int defaultValue() {
211                                return defaultValue;
212                        }
213
214                }.ignore();
215        }
216
217}