001/* 002 * ============================================================================ 003 * Copyright © 2002-2026 by Thomas Thrien. 004 * All Rights Reserved. 005 * ============================================================================ 006 * Licensed to the public under the agreements of the GNU Lesser General Public 007 * License, version 3.0 (the "License"). You may obtain a copy of the License at 008 * 009 * http://www.gnu.org/licenses/lgpl.html 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 014 * License for the specific language governing permissions and limitations 015 * under the License. 016 */ 017 018package org.tquadrat.foundation.lang; 019 020import org.apiguardian.api.API; 021import org.tquadrat.foundation.annotation.ClassVersion; 022 023import java.util.Optional; 024import java.util.function.Consumer; 025import java.util.function.Function; 026 027import static org.apiguardian.api.API.Status.STABLE; 028import static org.tquadrat.foundation.lang.Objects.isNull; 029import static org.tquadrat.foundation.lang.Objects.nonNull; 030import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument; 031 032/** 033 * <p>{Instances of this record are meant to be used as the return values for 034 * methods that should either return a proper result, or an error code.}</p> 035 * <p>A sample use case may look like this:</p> 036 * <div class="source-container"><pre>… 037 * public final Status<Result,ErrorCode> processInput( final InputStream input ) {…} 038 * … 039 * 040 * … 041 * private final Throwable errorHandler( ErrorCode ) {…} 042 * … 043 * 044 * … 045 * public final Result execute( final File inputFile ) throws Throwable 046 * { 047 * ErrorHandler<ErrorCode> errorHandler = this::errorHandler; 048 * try( var inputStream = new FileInputStream( inputFile ) ) 049 * { 050 * return processInput( inputStream ).getOrElse( errorHandler ); 051 * } 052 * } 053 * …</pre></div> 054 * 055 * @extauthor Thomas Thrien - thomas.thrien@tquadrat.org 056 * @version $Id: Status.java 1163 2026-03-20 15:28:33Z tquadrat $ 057 * @since 0.1.0 058 * 059 * @UMLGraph.link 060 * 061 * @param <V> The type of the result value. 062 * @param <C> The type of the error code. 063 * @param result The result value; can be {@code null}. 064 * @param errorCode The error code; a value of {@code null} indicates a 065 * success. 066 */ 067@SuppressWarnings( {"ProhibitedExceptionDeclared", "ProhibitedExceptionThrown"} ) 068@ClassVersion( sourceVersion = "$Id: Status.java 1163 2026-03-20 15:28:33Z tquadrat $" ) 069@API( status = STABLE, since = "0.1.0" ) 070public record Status<V,C>( V result, C errorCode ) 071{ 072 /*---------*\ 073 ====** Methods **========================================================== 074 \*---------*/ 075 /** 076 * Returns the result in case of a success, otherwise executes the given 077 * error handler and throws the exception determined by it. 078 * 079 * @param errorHandler The error handler. 080 * @return The result. 081 * @throws RuntimeException Any exception that is determined by the 082 * error handler. 083 * 084 * @since 0.2.1 085 */ 086 @API( status = STABLE, since = "0.2.1" ) 087 public final V getOrElseThrow( final ErrorHandler<? super C> errorHandler ) throws RuntimeException 088 { 089 requireNonNullArgument( errorHandler, "errorHandler" ); 090 091 if( isFailure() ) throw errorHandler.handleError( errorCode ); 092 093 //---* Done *---------------------------------------------------------- 094 return result; 095 } // getOrElseThrow() 096 097 /** 098 * Returns whether this {@code Status} instance indicates a failure. 099 * 100 * @return {@code true} if the status indicates a failure, {@code false} 101 * otherwise. 102 */ 103 public final boolean isFailure() { return nonNull( errorCode ); } 104 105 /** 106 * Returns whether this {@code Status} instance indicates a success. 107 * 108 * @return {@code true} if the status indicates a success, {@code false} 109 * otherwise. 110 */ 111 public final boolean isSuccess() { return isNull( errorCode ); } 112 113 /** 114 * Performs the given conversion on success, otherwise returns 115 * {@link Optional#empty()}. 116 * 117 * @param <R> The type of the conversion result. 118 * @param conversion The conversion. 119 * @return An instance of 120 * {@link Optional} 121 * that holds the converted result in case of a success, or it will 122 * be 123 * {@linkplain Optional#empty() empty} 124 * otherwise. 125 * 126 * @note As the result can be {@code null}, too (or the result of the 127 * conversion is {@code null}), an empty return value does not 128 * necessarily indicate a failure. 129 */ 130 public final <R> Optional<R> map( final Function<? super V,? extends R> conversion ) 131 { 132 requireNonNullArgument( conversion, "conversion" ); 133 134 final Optional<R> retValue = Optional.ofNullable( isSuccess() ? conversion.apply( result ) : null ); 135 136 //---* Done *---------------------------------------------------------- 137 return retValue; 138 } // map() 139 140 /** 141 * Performs the given action on success, otherwise does nothing. 142 * 143 * @param action The action. 144 */ 145 public final void onSuccess( final Consumer<? super V> action ) 146 { 147 requireNonNullArgument( action, "action" ); 148 if( isSuccess() ) action.accept( result ); 149 } // onSuccess() 150 151 /** 152 * Performs the given action on success, otherwise throws the exception 153 * determined by the error handler. 154 * 155 * @param action The action. 156 * @param errorHandler The error handler. 157 * @throws RuntimeException Any exception that is determined by the 158 * error handler. 159 */ 160 public final void onSuccess( final Consumer<? super V> action, final ErrorHandler<? super C> errorHandler ) throws RuntimeException 161 { 162 requireNonNullArgument( action, "action" ); 163 requireNonNullArgument( errorHandler, "errorHandler" ); 164 165 if( isFailure() ) throw errorHandler.handleError( errorCode ); 166 action.accept( result ); 167 } // onSuccess() 168 169 /** 170 * Performs the given conversion on success, otherwise throws the 171 * exception determined by the error handler. 172 * 173 * @param <R> The type of the conversion result. 174 * @param conversion The conversion. 175 * @param errorHandler The error handler. 176 * @return The converted result. 177 * @throws RuntimeException Any exception that is determined by the 178 * error handler. 179 */ 180 public final <R> R onSuccess( final Function<? super V,R> conversion, final ErrorHandler<? super C> errorHandler ) throws RuntimeException 181 { 182 requireNonNullArgument( conversion, "conversion" ); 183 requireNonNullArgument( errorHandler, "errorHandler" ); 184 185 if( isFailure() ) throw errorHandler.handleError( errorCode ); 186 final var retValue = conversion.apply( result ); 187 188 //---* Done *---------------------------------------------------------- 189 return retValue; 190 } // onSuccess() 191} 192// record Status 193 194/* 195 * End of File 196 */