Newer
Older
vavr-effect / src / main / java / com / github / tonivade / vavr / effect / CallStack.java
/*
 * Copyright (c) 2024-2025, Antonio Gabriel Muñoz Conejo <me at tonivade dot es>
 * Distributed under the terms of the MIT License
 */
package com.github.tonivade.vavr.effect;

import org.jspecify.annotations.Nullable;

import io.vavr.PartialFunction;
import io.vavr.control.Option;

final class CallStack<T> {

  @Nullable
  private StackItem<T> top = new StackItem<>();

  void push() {
    if (top != null) {
      top.push();
    }
  }

  void pop() {
    if (top == null) {
      return;
    }
    if (top.count() > 0) {
      top.pop();
    } else {
      top = top.prev();
    }
  }

  void add(PartialFunction<? super Throwable, ? extends IO<? extends T>> mapError) {
    if (top == null) {
      return;
    }
    if (top.count() > 0) {
      top.pop();
      top = new StackItem<>(top);
    }
    top.add(mapError);
  }

  Option<IO<T>> tryHandle(Throwable error) {
    while (top != null) {
      top.reset();
      Option<IO<T>> result = top.tryHandle(error);

      if (result.isDefined()) {
        return result;
      } else {
        top = top.prev();
      }
    }
    return Option.none();
  }

  // XXX: https://www.baeldung.com/java-sneaky-throws
  @SuppressWarnings("unchecked")
  <X extends Throwable, R> R sneakyThrow(Throwable t) throws X {
    throw (X) t;
  }
}