package moe.nea.pcj; import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.function.Function; public sealed interface Result permits Result.Ok, Result.Fail { default boolean isOk() { return error().isEmpty(); } Optional value(); Optional partial(); default Optional valueOrPartial() { return value().or(this::partial); } Optional error(); default Result map(Function mapper) { return flatMap(mapper.andThen(Result::ok)); } default Result flatMap(Function> mapper) { return flatMapBoth(mapper, Result::fail); } Result flatMapBoth( Function> mapGood, Function> mapBad); Result appendError(Bad error); record Ok(Good okValue) implements Result { @Override public Result appendError(Bad error) { return Result.partial(okValue, error); } @Override public Optional partial() { return Optional.empty(); } @Override public Optional value() { return Optional.of(okValue); } @Override public Optional error() { return Optional.empty(); } @Override public Result flatMapBoth(Function> mapGood, Function> mapBad) { return mapGood.apply(okValue); } } record Fail(@Nullable Good partialValue, Bad badValue) implements Result { @Override public Optional value() { return Optional.empty(); } @Override public Optional partial() { return Optional.ofNullable(partialValue); } @Override public Optional error() { return Optional.of(badValue); } @Override public Result flatMapBoth(Function> mapGood, Function> mapBad) { if (partialValue != null) { var nextPartial = mapGood.apply(partialValue); return nextPartial.appendError(badValue); } return mapBad.apply(badValue); } @Override public Result appendError(Bad error) { return Result.partial(partialValue, AppendableError.concatError(badValue, error)); } } static Result ok(Good value) { return new Ok<>(value); } static Result.Fail fail(Bad error) { return new Fail<>(null, error); } static Result.Fail partial(@Nullable Good partial, Bad error) { return new Fail<>(partial, error); } }