src/main/java/org/michailov/async/WhenReady.java
private static <S, R> CompletableFuture<R> startApplyLoopAsync(WhenReadyMode mode, Predicate<S> ready, Predicate<S> done, Function<S, R> action, S state, AsyncOptions asyncOptions) {
        Util.ensureArgumentNotNull("ready", ready);
        Util.ensureArgumentNotNull("done", done);
        Util.ensureArgumentNotNull("action", action);
        Util.ensureArgumentNotNull("asyncOptions", asyncOptions);
        
        // Create the future that will be returned to the caller.
        CompletableFuture<R> future = new CompletableFuture<R>();
        WhenReadyArguments<S, R> args = new WhenReadyArguments<S, R>(mode, ready, done, action, state, asyncOptions);
        
        // Schedule a timeout completion in case the operation starts executing on time, but takes too long. 
        if (args.timeoutMillis > 0) {
            Executor.executeAfter(() -> {
                    if (!future.isDone()) {
                        future.completeExceptionally(new TimeoutException(TIMEOUT_MESSAGE));
                    }
                }, args.timeoutMillis);
        }
        
        return startApplyLoopAsync(future, args);
    }
/**
     * Private entry point for all {@link #applyAsync} and {@link #startApplyLoop} overloads.
     */
Private entry point for all  #applyAsync and  #startApplyLoop overloads.
Private entry point for all #applyAsync and #startApplyLoop overloads .
private static <S, R> CompletableFuture<R> startApplyLoopAsync(WhenReadyMode mode, Predicate<S> ready, Predicate<S> done, Function<S, R> action, S state, AsyncOptions asyncOptions) {
        Util.ensureArgumentNotNull("ready", ready);
        Util.ensureArgumentNotNull("done", done);
        Util.ensureArgumentNotNull("action", action);
        Util.ensureArgumentNotNull("asyncOptions", asyncOptions);
        CompletableFuture<R> future = new CompletableFuture<R>();
        WhenReadyArguments<S, R> args = new WhenReadyArguments<S, R>(mode, ready, done, action, state, asyncOptions);
        if (args.timeoutMillis > 0) {
            Executor.executeAfter(() -> {
                    if (!future.isDone()) {
                        future.completeExceptionally(new TimeoutException(TIMEOUT_MESSAGE));
                    }
                }, args.timeoutMillis);
        }
        return startApplyLoopAsync(future, args);
    }
private static < S , R > CompletableFuture < R > startApplyLoopAsync ( WhenReadyMode mode , Predicate < S > ready , Predicate < S > done , Function < S , R > action , S state , AsyncOptions asyncOptions ) { Util . ensureArgumentNotNull ( "ready" , ready ) ; Util . ensureArgumentNotNull ( "done" , done ) ; Util . ensureArgumentNotNull ( "action" , action ) ; Util . ensureArgumentNotNull ( "asyncOptions" , asyncOptions ) ; CompletableFuture < R > future = new CompletableFuture < R > ( ) ; WhenReadyArguments < S , R > args = new WhenReadyArguments < S , R > ( mode , ready , done , action , state , asyncOptions ) ; if ( args . timeoutMillis > 0 ) { Executor . executeAfter ( ( ) -> { if ( ! future . isDone ( ) ) { future . completeExceptionally ( new TimeoutException ( TIMEOUT_MESSAGE ) ) ; } } , args . timeoutMillis ) ; } return startApplyLoopAsync ( future , args ) ; }
Private entry point for all {@link #applyAsync} and {@link #startApplyLoop} overloads.
Private entry point for all { @link #applyAsync } and { @link #startApplyLoop } overloads .
// Create the future that will be returned to the caller.
 // Schedule a timeout completion in case the operation starts executing on time, but takes too long. 
