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.verifyPredicate;
024import static java.util.Objects.requireNonNull;
025
026import java.util.function.DoublePredicate;
027import java.util.function.Function;
028import java.util.function.Supplier;
029
030/**
031 * Represents a predicate (boolean-valued function) of one {@code double}-valued
032 * argument that may throw exception. This is the {@code double}-consuming
033 * primitive type specialization of {@link PredicateWithException}.
034 * <h3>General contract</h3>
035 * <ul>
036 * <li><b>{@link #test(double) boolean test(double value) throws
037 * E}</b>&nbsp;-&nbsp;The functional method.</li>
038 * <li><b>uncheck</b>&nbsp;-&nbsp;Return a {@code DoublePredicate}</li>
039 * <li><b>lift</b>&nbsp;-&nbsp;Return a {@code DoublePredicate}</li>
040 * <li><b>ignore</b>&nbsp;-&nbsp;Return a {@code DoublePredicate}</li>
041 * </ul>
042 *
043 * @see DoublePredicate
044 * @param <E>
045 *            the type of the potential exception of the function
046 */
047@FunctionalInterface
048public interface DoublePredicateWithException<E extends Exception> extends
049                PrimitiveReturnExceptionHandlerSupport<DoublePredicate, DoublePredicateWithException<E>>, BooleanDefaultValue {
050
051        /**
052         * Evaluates this predicate on the given argument.
053         *
054         * @param value
055         *            the input argument
056         * @return {@code true} if the input argument matches the predicate, otherwise
057         *         {@code false}
058         * @throws E
059         *             any exception
060         * @see DoublePredicate#test(double)
061         */
062        boolean test(double value) throws E;
063
064        @Override
065        default DoublePredicate uncheckOrIgnore(boolean uncheck) {
066                return value -> {
067                        try {
068                                return test(value);
069                        } catch (Exception e) {
070                                PrimitiveReturnExceptionHandlerSupport.handleException(uncheck, e, exceptionMapper());
071                                return defaultValue();
072                        }
073                };
074        }
075
076        /**
077         * Returns a composed predicate that represents a short-circuiting logical AND
078         * of this predicate and another. When evaluating the composed predicate, if
079         * this predicate is {@code false}, then the {@code other} predicate is not
080         * evaluated.
081         *
082         * <p>
083         * Any exceptions thrown during evaluation of either predicate are relayed to
084         * the caller; if evaluation of this predicate throws an exception, the
085         * {@code other} predicate will not be evaluated.
086         *
087         * @param other
088         *            a predicate that will be logically-ANDed with this predicate
089         * @return a composed predicate that represents the short-circuiting logical AND
090         *         of this predicate and the {@code other} predicate
091         * @throws NullPointerException
092         *             if other is null
093         * @see #or(DoublePredicateWithException)
094         * @see #negate()
095         */
096        default DoublePredicateWithException<E> and(DoublePredicateWithException<? extends E> other) {
097                requireNonNull(other);
098                return t -> test(t) && other.test(t);
099        }
100
101        /**
102         * Returns a predicate that represents the logical negation of this predicate.
103         *
104         * @return a predicate that represents the logical negation of this predicate
105         * @see #and(DoublePredicateWithException)
106         * @see #or(DoublePredicateWithException)
107         */
108        default DoublePredicateWithException<E> negate() {
109                return t -> !test(t);
110        }
111
112        /**
113         * Negate a {@code DoublePredicateWithException}.
114         *
115         * @param predicate
116         *            to be negate
117         * @param <E>
118         *            the type of the potential exception
119         * @return the negated predicate
120         * @see #negate()
121         */
122        static <E extends Exception> DoublePredicateWithException<E> negate(DoublePredicateWithException<E> predicate) {
123                return verifyPredicate(predicate).negate();
124        }
125
126        /**
127         * Returns a composed predicate that represents a short-circuiting logical OR of
128         * this predicate and another. When evaluating the composed predicate, if this
129         * predicate is {@code true}, then the {@code other} predicate is not evaluated.
130         *
131         * <p>
132         * Any exceptions thrown during evaluation of either predicate are relayed to
133         * the caller; if evaluation of this predicate throws an exception, the
134         * {@code other} predicate will not be evaluated.
135         *
136         * @param other
137         *            a predicate that will be logically-ORed with this predicate
138         * @return a composed predicate that represents the short-circuiting logical OR
139         *         of this predicate and the {@code other} predicate
140         * @throws NullPointerException
141         *             if other is null
142         * @see #and(DoublePredicateWithException)
143         * @see #negate()
144         */
145        default DoublePredicateWithException<E> or(DoublePredicateWithException<? extends E> other) {
146                requireNonNull(other);
147                return t -> test(t) || other.test(t);
148        }
149
150        /**
151         * Returns a predicate that always throw exception.
152         *
153         * @param exceptionBuilder
154         *            the supplier to create the exception the type of the input object
155         *            to the function
156         * @param <E>
157         *            the type of the exception
158         * @return a predicate that always throw exception
159         */
160        static <E extends Exception> DoublePredicateWithException<E> failing(Supplier<E> exceptionBuilder) {
161                return t -> {
162                        throw exceptionBuilder.get();
163                };
164        }
165
166        /**
167         * Converts a {@code DoublePredicateWithException} to a {@code DoublePredicate}
168         * that wraps exception to {@code RuntimeException}.
169         *
170         * @param predicate
171         *            to be unchecked
172         * @param <E>
173         *            the type of the potential exception
174         * @return the unchecked predicate
175         * @see #uncheck()
176         * @see #unchecked(DoublePredicateWithException, Function)
177         * @throws NullPointerException
178         *             if predicate is null
179         */
180        static <E extends Exception> DoublePredicate unchecked(DoublePredicateWithException<E> predicate) {
181                return verifyPredicate(predicate).uncheck();
182        }
183
184        /**
185         * Converts a {@code PredicateWithException} to a {@code Predicate} that wraps
186         * exception to {@code RuntimeException} by using the provided mapping function.
187         *
188         * @param predicate
189         *            the be unchecked
190         * @param exceptionMapper
191         *            a function to convert the exception to the runtime exception.
192         * @param <E>
193         *            the type of the potential exception
194         * @return the unchecked predicate
195         * @see #uncheck()
196         * @see #unchecked(DoublePredicateWithException)
197         * @throws NullPointerException
198         *             if predicate or exceptionMapper is null
199         */
200        static <E extends Exception> DoublePredicate unchecked(DoublePredicateWithException<E> predicate,
201                        Function<Exception, RuntimeException> exceptionMapper) {
202                verifyPredicate(predicate);
203                verifyExceptionMapper(exceptionMapper);
204                return new DoublePredicateWithException<E>() {
205
206                        @Override
207                        public boolean test(double value) throws E {
208                                return predicate.test(value);
209                        }
210
211                        @Override
212                        public Function<Exception, RuntimeException> exceptionMapper() {
213                                return exceptionMapper;
214                        }
215
216                }.uncheck();
217        }
218
219        /**
220         * Converts a {@code DoublePredicateWithException} to a lifted
221         * {@code DoublePredicate} returning {@code false} in case of exception.
222         *
223         * @param predicate
224         *            to be lifted
225         * @param <E>
226         *            the type of the potential exception
227         * @return the lifted predicate
228         * @see #lift()
229         * @throws NullPointerException
230         *             if predicate is null
231         */
232        static <E extends Exception> DoublePredicate lifted(DoublePredicateWithException<E> predicate) {
233                return verifyPredicate(predicate).lift();
234        }
235
236        /**
237         * Converts a {@code DoublePredicateWithException} to a lifted
238         * {@code DoublePredicate} returning {@code false} in case of exception.
239         *
240         * @param predicate
241         *            to be lifted
242         * @param <E>
243         *            the type of the potential exception
244         * @return the lifted predicate
245         * @see #ignore()
246         * @throws NullPointerException
247         *             if predicate is null
248         */
249        static <E extends Exception> DoublePredicate ignored(DoublePredicateWithException<E> predicate) {
250                return verifyPredicate(predicate).ignore();
251        }
252
253        /**
254         * Converts a {@code DoublePredicateWithException} to a lifted
255         * {@code DoublePredicate} returning a default value in case of exception.
256         *
257         * @param predicate
258         *            to be lifted
259         * @param defaultValue
260         *            value in case of exception
261         * @param <E>
262         *            the type of the potential exception
263         * @return the lifted predicate
264         * @see #ignore()
265         * @see #ignored(DoublePredicateWithException)
266         * @throws NullPointerException
267         *             if predicate is null
268         * @since 3.0.0
269         */
270        static <E extends Exception> DoublePredicate ignored(DoublePredicateWithException<E> predicate,
271                        boolean defaultValue) {
272                verifyPredicate(predicate);
273                return new DoublePredicateWithException<E>() {
274
275                        @Override
276                        public boolean test(double value) throws E {
277                                return predicate.test(value);
278                        }
279
280                        @Override
281                        public boolean defaultValue() {
282                                return defaultValue;
283                        }
284
285                }.ignore();
286        }
287
288}