Skip to content

Commit

Permalink
feat: Add result/error return type (#1369)
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinWitt authored Dec 19, 2023
1 parent 572a9f7 commit 279eced
Show file tree
Hide file tree
Showing 3 changed files with 265 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package io.github.martinwitt.laughing_train.commons.result;

import static java.util.Objects.requireNonNull;

import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

class Error<T> implements Result<T> {

private final Throwable throwable;

Error(Throwable throwable) {
this.throwable = throwable;
}

@SuppressWarnings("unchecked")
private <E extends Throwable> T propagate(Throwable throwable) throws E {
throw (E) throwable;
}

@Override
public boolean isOk() {
return false;
}

@Override
public void ifOk(Consumer<? super T> consumer) {
// Do nothing when trying to consume the value of an Error result.
}

@Override
public boolean isError() {
return true;
}

@Override
public void ifError(Consumer<? super Throwable> consumer) {
requireNonNull(consumer, "The error consumer cannot be null");
consumer.accept(throwable);
}

@Override
public Result<T> switchIfError(Function<? super Throwable, ? extends Result<T>> fallbackMethod) {
requireNonNull(fallbackMethod, "The fallback method cannot be null");
return fallbackMethod.apply(throwable);
}

@Override
public <U> Result<U> map(Function<? super T, ? extends U> mapper) {
return new Error<>(throwable);
}

@Override
public <U> Result<U> flatMap(Function<? super T, ? extends Result<U>> mapper) {
return new Error<>(throwable);
}

@Override
public Result<T> mapError(Function<? super Throwable, ? extends Throwable> mapper) {
requireNonNull(mapper, "The error mapper cannot be null");
return new Error<>(mapper.apply(throwable));
}

@Override
public T get() {
return propagate(throwable);
}

@Override
public T getOrElse(Supplier<? extends T> supplier) {
requireNonNull(supplier);
return supplier.get();
}

@Override
public Throwable getError() {
return throwable;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (null == o || getClass() != o.getClass()) return false;
Error<?> error = (Error<?>) o;
return Objects.equals(throwable, error.throwable);
}

@Override
public int hashCode() {
return Objects.hash(throwable);
}

@Override
public String toString() {
return "Error{" + "throwable=" + throwable + '}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package io.github.martinwitt.laughing_train.commons.result;

import static java.util.Objects.requireNonNull;

import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

class Ok<T> implements Result<T> {

private final T value;

Ok(T value) {
this.value = value;
}

@Override
public boolean isOk() {
return true;
}

@Override
public void ifOk(Consumer<? super T> consumer) {
requireNonNull(consumer, "The value consumer cannot be null");
consumer.accept(value);
}

@Override
public boolean isError() {
return false;
}

@Override
public void ifError(Consumer<? super Throwable> consumer) {
// Do nothing when trying to consume the error of an Ok result.
}

@Override
public Result<T> switchIfError(Function<? super Throwable, ? extends Result<T>> fallbackMethod) {
return new Ok<>(value);
}

@Override
public <U> Result<U> map(Function<? super T, ? extends U> mapper) {
requireNonNull(mapper, "The value mapper cannot be null");
return new Ok<>(mapper.apply(value));
}

@Override
public <U> Result<U> flatMap(Function<? super T, ? extends Result<U>> mapper) {
requireNonNull(mapper, "The value flat-mapper cannot be null");
return mapper.apply(value);
}

@Override
public Result<T> mapError(Function<? super Throwable, ? extends Throwable> mapper) {
return new Ok<>(value);
}

@Override
public T get() {
return value;
}

@Override
public T getOrElse(Supplier<? extends T> supplier) {
return value;
}

@Override
public Throwable getError() {
throw new NoSuchElementException("Result contains a value: " + value.toString());
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (null == obj || getClass() != obj.getClass()) return false;
Ok<?> ok = (Ok<?>) obj;
return Objects.equals(value, ok.value);
}

@Override
public int hashCode() {
return Objects.hash(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package io.github.martinwitt.laughing_train.commons.result;

import static java.util.Objects.nonNull;
import static java.util.Objects.requireNonNull;

import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

public interface Result<T> {

static <T> Result<T> ok(T value) {
requireNonNull(value, "The value of a Result cannot be null");
return new Ok<>(value);
}

static <T, E extends Throwable> Result<T> error(E throwable) {
requireNonNull(throwable, "The error of a Result cannot be null");
return new Error<>(throwable);
}

static <T> Result<T> of(Supplier<T> supplier) {
requireNonNull(supplier, "The value supplier cannot be null");

try {
return ok(supplier.get());
} catch (Exception error) {
return error(error);
}
}

@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
static <T> Result<T> of(Optional<T> optional) {
requireNonNull(optional, "The optional value cannot be null");

return optional
.map(Result::ok)
.orElseGet(
() ->
error(new NoSuchElementException("No value present when unwrapping the optional")));
}

static <T> Result<T> ofNullable(T value) {
return ofNullable(
value, () -> new NullPointerException("The result was initialized with a null value"));
}

static <T> Result<T> ofNullable(T value, Supplier<? extends Throwable> errorSupplier) {
requireNonNull(errorSupplier, "The error supplier cannot be null");

return nonNull(value) ? ok(value) : error(errorSupplier.get());
}

boolean isOk();

void ifOk(Consumer<? super T> consumer);

boolean isError();

void ifError(Consumer<? super Throwable> consumer);

Result<T> switchIfError(Function<? super Throwable, ? extends Result<T>> fallbackMethod);

<U> Result<U> map(Function<? super T, ? extends U> mapper);

<U> Result<U> flatMap(Function<? super T, ? extends Result<U>> mapper);

Result<T> mapError(Function<? super Throwable, ? extends Throwable> mapper);

T get();

T getOrElse(Supplier<? extends T> supplier);

Throwable getError();
}

0 comments on commit 279eced

Please sign in to comment.