package org.tinyj.lava;

/**
 * Unchecked exception wrapping a checked exception.
 */
public final class WrappedCheckedException extends RuntimeException {

  /**
   * {@link WrappedCheckedException} cannot be instantiated directly. Use
   * {@code wrapCheckedException(Exception)} instead.
   *
   * @param e the wrapped checked exception
   */
  private WrappedCheckedException(Exception e) { super(assertCheckedException(e)); }

  /**
   * @param e {@link Exception} to wrap
   * @return {@code e} if {@code e} is {@code null} or a {@link RuntimeException},
   *     a {@link WrappedCheckedException} wrapping {@code e} otherwise
   */
  public static RuntimeException wrapCheckedException(Exception e) {
    return e == null || e instanceof RuntimeException ? (RuntimeException) e
                                                      : new WrappedCheckedException(e);
  }

  /**
   * @param e {@link Exception} to unwrap
   * @return {@code e} if {@code e} is not a {@link WrappedCheckedException} or
   *     {@code e.getCause()} otherwise
   */
  public static Exception unwrapCheckedException(Exception e) {
    return e instanceof WrappedCheckedException ? (Exception) e.getCause() : e;
  }

  /**
   * Execute {@code task}, wrap and rethrow any checked exception raised during
   * execution.
   *
   * @param task {@link LavaRunnable} to execute
   * @throws RuntimeException Checked exception raised during {@code task.checkedRun()}
   *     will be wrapped in a {@link WrappedCheckedException}
   */
  public static void wrapCheckedException(LavaRunnable<?> task) {
    try {
      task.checkedRun();
    } catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
      throw new WrappedCheckedException(e);
    }
  }

  /**
   * Execute {@code task}, wrap and rethrow any checked exception raised during
   * execution. The result of {@code task.checkedGet()} is passed to the caller.
   *
   * @param task {@link LavaSupplier} to execute
   * @return Value returned by {@code task.checkedGet()}
   * @throws RuntimeException checked exception raised during {@code task.checkedGet()}
   *     will be wrapped in a {@link WrappedCheckedException}
   */
  public static <R> R wrapCheckedException(LavaSupplier<R, ?> task) {
    try {
      return task.checkedGet();
    } catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
      throw new WrappedCheckedException(e);
    }
  }

  /**
   * Raise {@code e}. If {@code e} is a checked exception a {@link WrappedCheckedException}
   * wrapping {@code e} is raised instead.
   */
  public static <R> R raiseUnchecked(Exception e) {
    throw wrapCheckedException(e);
  }

  private static Exception assertCheckedException(Exception cause) {
    assert cause != null && !(cause instanceof RuntimeException);
    return cause;
  }
}

@@ -2658,16 +2658,419 @@
 );%0A  %7D%0A%0A
+  /**%0A   * Raise %7B@code e%7D if %7B@code e%7D is a unchecked exception or an instance of %7B@code limit%7D.%0A   * Otherwise raise a %7B@link WrappedCheckedException%7D wrapping %7B@code e%7D instead.%0A   */%0A  public static %3CE extends Exception%3E void raiseCheckedLimit(Exception e, Class%3C? extends E%3E limit) throws E %7B%0A    if (limit.isInstance(e)) %7B%0A      throw limit.cast(e);%0A    %7D else throw wrapCheckedException(e);%0A  %7D%0A%0A
   privat

Add `raiseCheckedLimit` to `WrappedCheckedException`