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