001/*
002 * ============================================================================
003 * Copyright © 2002-2026 by Thomas Thrien.
004 * All Rights Reserved.
005 * ============================================================================
006 *
007 * Licensed to the public under the agreements of the GNU Lesser General Public
008 * License, version 3.0 (the "License"). You may obtain a copy of the License at
009 *
010 *      http://www.gnu.org/licenses/lgpl.html
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015 * License for the specific language governing permissions and limitations
016 * under the License.
017 */
018
019package org.tquadrat.foundation.function;
020
021import static org.apiguardian.api.API.Status.STABLE;
022
023import java.util.function.BiConsumer;
024import java.util.function.BiFunction;
025import java.util.function.BinaryOperator;
026import java.util.function.Consumer;
027import java.util.function.Function;
028import java.util.function.Predicate;
029import java.util.function.Supplier;
030
031import org.apiguardian.api.API;
032import org.tquadrat.foundation.annotation.ClassVersion;
033import org.tquadrat.foundation.annotation.UtilityClass;
034import org.tquadrat.foundation.exception.LambdaContainerException;
035import org.tquadrat.foundation.exception.PrivateConstructorForStaticClassCalledError;
036import org.tquadrat.foundation.function.tce.TCEBiConsumer;
037import org.tquadrat.foundation.function.tce.TCEBiFunction;
038import org.tquadrat.foundation.function.tce.TCEBinaryOperator;
039import org.tquadrat.foundation.function.tce.TCEConsumer;
040import org.tquadrat.foundation.function.tce.TCEFunction;
041import org.tquadrat.foundation.function.tce.TCEPredicate;
042import org.tquadrat.foundation.function.tce.TCESupplier;
043import org.tquadrat.foundation.function.tce.TCETriConsumer;
044import org.tquadrat.foundation.function.tce.TCETriFunction;
045
046/**
047 *  <p>{@summary Some helper methods for the use with lambdas and functional
048 *  interfaces.}</p>
049 *
050 *  <h2>TCE Wrapper</h2>
051 *  <p>The methods of the
052 *  {@linkplain java.lang.FunctionalInterface functional interfaces}
053 *  in the package
054 *  {@link java.util.function}
055 *  do not declare any checked exceptions - for good reasons, of course. But
056 *  sometimes, it would be nice to have that capability.</p>
057 *  <p>Using the wrapper methods in this class, you can achieve that like
058 *  this:</p>
059 *  <div class="source-container"><pre>&hellip;
060 *  import static org.tquadrat.foundation.function.Functions.*;
061 *  &hellip;
062 *
063 *  &hellip;
064 *  Appendable appendable = &hellip;
065 *  Consumer appender = wrapConsumer( s -&gt; appendable.append( s ) );
066 *  &hellip;
067 *
068 *  &hellip;
069 *  try
070 *  {
071 *    appender.accept( "&hellip;" );
072 *  }
073 *  catch( LambdaContainerException e )
074 *  {
075 *    throw (IOException) e.getCause();
076 *  }
077 *  &hellip;</pre></div>
078 *  <p>A
079 *  {@link RuntimeException}
080 *  that might be thrown by a wrapped function will not be packaged into a
081 *  {@link LambdaContainerException}.</p>
082 *  <p>&quot;<i>TCE</i>&quot; stands for &quot;<b>T</b>hrows <b>C</b>hecked
083 *  <b>E</b>xception&quot;.</p>
084 *
085 *  @author Thomas Thrien - thomas.thrien@tquadrat.org
086 *  @version $Id: Functions.java 1295 2026-10-18 12:34:27Z tquadrat $
087 *  @since 0.0.5
088 *
089 *  @UMLGraph.link
090 */
091@UtilityClass
092@ClassVersion( sourceVersion = "$Id: Functions.java 1295 2026-10-18 12:34:27Z tquadrat $" )
093public final class Functions
094{
095        /*--------------*\
096    ====** Constructors **=====================================================
097        \*--------------*/
098    /**
099     * <p>{@summary {@noInstance}}</p>
100     */
101    private Functions() { throw new PrivateConstructorForStaticClassCalledError( Functions.class ); }
102
103        /*---------*\
104    ====** Methods **==========================================================
105        \*---------*/
106    /**
107     *  <p>{@summary Wraps an instance of
108     *  {@link TCEBiConsumer}
109     *  to an instance of
110     *  {@link BiConsumer}
111     *  that throws an instance of
112     *  {@link LambdaContainerException}
113     *  with the causing exception, in case the wrapped instance emitted a
114     *  {@linkplain Exception checked exception}.}</p>
115     *
116     *  @param  <T1> The type of the first argument taken by the consumer.
117     *  @param  <T2> The type of the second argument taken by the consumer.
118     *  @param  consumer    The consumer to wrap.
119     *  @return The wrapped consumer.
120     */
121    @API( status = STABLE, since = "0.0.5" )
122    public static final <T1,T2> BiConsumer<T1,T2> wrapBiConsumer( final TCEBiConsumer<? super T1, ? super T2> consumer )
123    {
124        final BiConsumer<T1,T2> retValue = ( arg1, arg2) ->
125        {
126            try
127            {
128                consumer.accept( arg1, arg2 );
129            }
130            catch( final RuntimeException e ) { throw e; }
131            catch( final Exception e )
132            {
133                throw new LambdaContainerException( e );
134            }
135        };
136
137        //---* Done *----------------------------------------------------------
138        return retValue;
139    }   //  wrapBiConsumer()
140
141    /**
142     *  <p>{@summary Wraps an instance of
143     *  {@link TCEBiFunction}
144     *  to an instance of
145     *  {@link BiFunction}
146     *  that throws an instance of
147     *  {@link LambdaContainerException}
148     *  with the causing exception, in case the wrapped instance emitted a
149     *  {@linkplain Exception checked exception}.}</p>
150     *
151     *  @param  <T1>    The type of the first argument to the function.
152     *  @param  <T2>    The type of the second argument to the function.
153     *  @param  <R> The type of the result of the function.
154     *  @param  function    The function to wrap.
155     *  @return The wrapped function.
156     */
157    @API( status = STABLE, since = "0.0.5" )
158    public static final <T1,T2,R> BiFunction<T1,T2,R> wrapBiFunction( final TCEBiFunction<? super T1, ? super T2, ? extends R> function )
159    {
160        final BiFunction<T1,T2,R> retValue = (arg1,arg2) ->
161        {
162            try
163            {
164                return function.apply( arg1, arg2 );
165            }
166            catch( final RuntimeException e ) { throw e; }
167            catch( final Exception e )
168            {
169                throw new LambdaContainerException( e );
170            }
171        };
172
173        //---* Done *----------------------------------------------------------
174        return retValue;
175    }   //  wrapBiFunction()
176
177    /**
178     *  <p>{@summary Wraps an instance of
179     *  {@link TCEBinaryOperator}
180     *  to an instance of
181     *  {@link BinaryOperator}
182     *  that throws an instance of
183     *  {@link LambdaContainerException}
184     *  with the causing exception, in case the wrapped instance emitted a
185     *  {@linkplain Exception checked exception}.}</p>
186     *
187     *  @param  <T> The type of the operands and result of the operator.
188     *  @param  function    The function to wrap.
189     *  @return The wrapped function.
190     */
191    @API( status = STABLE, since = "0.0.5" )
192    public static final <T> BinaryOperator<T> wrapBinaryOperator( final TCEBinaryOperator<T> function )
193    {
194        final BinaryOperator<T> retValue = (arg1,arg2) ->
195        {
196            try
197            {
198                return function.apply( arg1, arg2 );
199            }
200            catch( final RuntimeException e ) { throw e; }
201            catch( final Exception e )
202            {
203                throw new LambdaContainerException( e );
204            }
205        };
206
207        //---* Done *----------------------------------------------------------
208        return retValue;
209    }   //  wrapBinaryOperator()
210
211    /**
212     *  <p>{@summary Wraps an instance of
213     *  {@link TCEConsumer}
214     *  to an instance of
215     *  {@link Consumer}
216     *  that throws an instance of
217     *  {@link LambdaContainerException}
218     *  with the causing exception, in case the wrapped instance emitted a
219     *  {@linkplain Exception checked exception}.}</p>
220     *
221     *  @param  <T> The type of arguments taken by the consumer.
222     *  @param  consumer    The consumer to wrap.
223     *  @return The wrapped consumer.
224     */
225    @API( status = STABLE, since = "0.0.5" )
226    public static final <T> Consumer<T> wrapConsumer( final TCEConsumer<? super T> consumer )
227    {
228        final Consumer<T> retValue = arg ->
229        {
230            try
231            {
232                consumer.accept( arg );
233            }
234            catch( final RuntimeException e ) { throw e; }
235            catch( final Exception e )
236            {
237                throw new LambdaContainerException( e );
238            }
239        };
240
241        //---* Done *----------------------------------------------------------
242        return retValue;
243    }   //  wrapConsumer()
244
245    /**
246     *  <p>{@summary Wraps an instance of
247     *  {@link TCEFunction}
248     *  to an instance of
249     *  {@link Function}
250     *  that throws an instance of
251     *  {@link LambdaContainerException}
252     *  with the causing exception, in case the wrapped instance emitted a
253     *  {@linkplain Exception checked exception}.}</p>
254     *
255     *  @param  <T> The type of the input to the function.
256     *  @param  <R> The type of the result of the function.
257     *  @param  function    The function to wrap.
258     *  @return The wrapped function.
259     */
260    @API( status = STABLE, since = "0.0.5" )
261    public static final <T,R> Function<T,R> wrapFunction( final TCEFunction<? super T, ? extends R> function )
262    {
263        final Function<T,R> retValue = arg ->
264        {
265            try
266            {
267                return function.apply( arg );
268            }
269            catch( final RuntimeException e ) { throw e; }
270            catch( final Exception e )
271            {
272                throw new LambdaContainerException( e );
273            }
274        };
275
276        //---* Done *----------------------------------------------------------
277        return retValue;
278    }   //  wrapFunction()
279
280    /**
281     *  <p>{@summary Wraps an instance of
282     *  {@link TCEPredicate}
283     *  to an instance of
284     *  {@link Predicate}
285     *  that throws an instance of
286     *  {@link LambdaContainerException}
287     *  with the causing exception, in case the wrapped instance emitted a
288     *  {@linkplain Exception checked exception}.}</p>
289     *
290     *  @param  <T> The type of the input to the predicate.
291     *  @param  predicate   The predicate to wrap.
292     *  @return The wrapped predicate.
293     */
294    @API( status = STABLE, since = "0.0.5" )
295    public static final <T> Predicate<T> wrapPredicate( final TCEPredicate<? super T> predicate )
296    {
297        final Predicate<T> retValue = arg ->
298        {
299            try
300            {
301                return predicate.test( arg );
302            }
303            catch( final RuntimeException e ) { throw e; }
304            catch( final Exception e )
305            {
306                throw new LambdaContainerException( e );
307            }
308        };
309
310        //---* Done *----------------------------------------------------------
311        return retValue;
312    }   //  wrapPredicate()
313
314    /**
315     *  <p>{@summary Wraps an instance of
316     *  {@link TCESupplier}
317     *  to an instance of
318     *  {@link Supplier}
319     *  that throws an instance of
320     *  {@link LambdaContainerException}
321     *  with the causing exception, in case the wrapped instance emitted a
322     *  {@linkplain Exception checked exception}.}</p>
323     *
324     *  @param  <T> The type of results supplied by the supplier.
325     *  @param  supplier    The supplier to wrap.
326     *  @return The wrapped supplier.
327     */
328    @API( status = STABLE, since = "0.0.5" )
329    public static final <T> Supplier<T> wrapSupplier( final TCESupplier<? extends T> supplier )
330    {
331        final Supplier<T> retValue = () ->
332        {
333            try
334            {
335                return supplier.get();
336            }
337            catch( final RuntimeException e ) { throw e; }
338            catch( final Exception e )
339            {
340                throw new LambdaContainerException( e );
341            }
342        };
343
344        //---* Done *----------------------------------------------------------
345        return retValue;
346    }   //  wrapSupplier()
347
348    /**
349     *  <p>{@summary Wraps an instance of
350     *  {@link TCETriConsumer}
351     *  to an instance of
352     *  {@link TriConsumer}
353     *  that throws an instance of
354     *  {@link LambdaContainerException}
355     *  with the causing exception, in case the wrapped instance emitted a
356     *  {@linkplain Exception checked exception}.}</p>
357     *
358     *  @param  <T1> The type of the first argument taken by the consumer.
359     *  @param  <T2> The type of the second argument taken by the consumer.
360     *  @param  <T3> The type of the third argument taken by the consumer.
361     *  @param  consumer    The consumer to wrap.
362     *  @return The wrapped consumer.
363     */
364    @API( status = STABLE, since = "0.0.5" )
365    public static final <T1,T2,T3> TriConsumer<T1,T2,T3> wrapTriConsumer( final TCETriConsumer<? super T1, ? super T2, ? super T3> consumer )
366    {
367        final TriConsumer<T1,T2,T3> retValue = (arg1, arg2, arg3) ->
368        {
369            try
370            {
371                consumer.accept( arg1, arg2, arg3 );
372            }
373            catch( final RuntimeException e ) { throw e; }
374            catch( final Exception e )
375            {
376                throw new LambdaContainerException( e );
377            }
378        };
379
380        //---* Done *----------------------------------------------------------
381        return retValue;
382    }   //  wrapTriConsumer()
383
384    /**
385     *  <p>{@summary Wraps an instance of
386     *  {@link TCETriFunction}
387     *  to an instance of
388     *  {@link TriFunction}
389     *  that throws an instance of
390     *  {@link LambdaContainerException}
391     *  with the causing exception, in case the wrapped instance emitted a
392     *  {@linkplain Exception checked exception}.}</p>
393     *
394     *  @param  <T1> The type of the first argument taken by the function.
395     *  @param  <T2> The type of the second argument taken by the function.
396     *  @param  <T3> The type of the third argument taken by the function.
397     *  @param  <R> The type of the result of the function.
398     *  @param  function    The function to wrap.
399     *  @return The wrapped function.
400     */
401    @API( status = STABLE, since = "0.0.5" )
402    public static final <T1,T2,T3,R> TriFunction<T1,T2,T3,R> wrapTriFunction( final TCETriFunction<? super T1, ? super T2, ? super T3, ? extends R> function )
403    {
404        final TriFunction<T1,T2,T3,R> retValue = (arg1, arg2, arg3) ->
405        {
406            try
407            {
408                return function.apply( arg1, arg2, arg3 );
409            }
410            catch( final RuntimeException e ) { throw e; }
411            catch( final Exception e )
412            {
413                throw new LambdaContainerException( e );
414            }
415        };
416
417        //---* Done *----------------------------------------------------------
418        return retValue;
419    }   //  wrapTriFunction()
420}
421//  class Functions
422
423/*
424 *  End of File
425 */