Add javadocs and fix some checkstyles

This commit is contained in:
Ben Woo 2023-09-10 23:00:15 +08:00
parent 6f9f9085fd
commit 99846b5567
No known key found for this signature in database
GPG Key ID: FB2A3645536E12C8
4 changed files with 304 additions and 37 deletions

View File

@ -43,7 +43,7 @@ public class MVWorldListener implements InjectableListener {
return;
}
worldManager.unloadWorld(event.getWorld()).onFailure(failure -> {
if (failure.getFailureReason() != UnloadWorldResult.Failure.WORLD_ALREADY_UNLOADING) {
if (failure.getFailureReason() != UnloadWorldResult.WORLD_ALREADY_UNLOADING) {
Logging.severe("Failed to unload world: " + failure);
}
});
@ -60,7 +60,7 @@ public class MVWorldListener implements InjectableListener {
.peek(world -> {
Logging.fine("Loading world: " + world.getName());
worldManager.loadWorld(world).onFailure(failure -> {
if (failure.getFailureReason() != LoadWorldResult.Failure.WORLD_ALREADY_LOADING) {
if (failure.getFailureReason() != LoadWorldResult.WORLD_ALREADY_LOADING) {
Logging.severe("Failed to load world: " + failure);
}
});

View File

@ -7,35 +7,98 @@ import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
public interface Attempt<T, F extends FailureReason> {
/**
* Represents an attempt to process a value that can fail with a reason that has a localized message.
*
* @param <T> The type of the value.
* @param <F> The type of failure reason.
*/
public sealed interface Attempt<T, F extends FailureReason> permits Attempt.Success, Attempt.Failure {
/**
* Creates a new success attempt.
*
* @param value The value.
* @param <T> The type of the value.
* @param <F> The type of failure reason.
* @return The new success attempt.
*/
static <T, F extends FailureReason> Attempt<T, F> success(T value) {
return new Success<>(value);
}
/**
* Creates a new failure attempt.
*
* @param failureReason The reason for failure.
* @param messageReplacements The replacements for the failure message.
* @param <T> The type of the value.
* @param <F> The type of failure reason.
* @return The new failure attempt.
*/
static <T, F extends FailureReason> Attempt<T, F> failure(
F failureReason, MessageReplacement... messageReplacements) {
return new Failure<>(failureReason, Message.of(failureReason, "Failed!", messageReplacements));
}
/**
* Creates a new failure attempt with a custom message.
*
* @param failureReason The reason for failure.
* @param message The custom message for failure. This will override the default message.
* @param <T> The type of the value.
* @param <F> The type of failure reason.
* @return The new failure attempt.
*/
static <T, F extends FailureReason> Attempt<T, F> failure(F failureReason, Message message) {
return new Failure<>(failureReason, message);
}
/**
* Gets the value of this attempt. Exceptions will be thrown if this is a failure attempt.
*
* @return The value.
*/
T get();
/**
* Gets the reason for failure. Exceptions will be thrown if this is a success attempt.
*
* @return The reason for failure.
*/
F getFailureReason();
/**
* Gets the message for failure. Exceptions will be thrown if this is a success attempt.
*
* @return The message for failure.
*/
Message getFailureMessage();
/**
* Returns whether this attempt is a success.
*
* @return Whether this attempt is a success.
*/
default boolean isSuccess() {
return this instanceof Success;
}
/**
* Returns whether this attempt is a failure.
*
* @return Whether this attempt is a failure.
*/
default boolean isFailure() {
return this instanceof Failure;
}
/**
* Peeks at the value if this is a success attempt.
*
* @param consumer The consumer with the value.
* @return This attempt.
*/
default Attempt<T, F> peek(Consumer<T> consumer) {
if (this instanceof Success) {
consumer.accept(get());
@ -43,6 +106,13 @@ public interface Attempt<T, F extends FailureReason> {
return this;
}
/**
* Maps the value to another value if this is a success attempt.
*
* @param mapper The mapper.
* @param <U> The type of the new value.
* @return The new attempt.
*/
default <U> Attempt<U, F> map(Function<? super T, ? extends U> mapper) {
if (this instanceof Success) {
return new Success<>(mapper.apply(get()));
@ -51,6 +121,13 @@ public interface Attempt<T, F extends FailureReason> {
}
}
/**
* Maps the value to another attempt if this is a success attempt.
*
* @param mapper The mapper.
* @param <U> The type of the new value.
* @return The new attempt.
*/
default <U> Attempt<U, F> map(Supplier<? extends U> mapper) {
if (this instanceof Success) {
return new Success<>(mapper.get());
@ -59,6 +136,13 @@ public interface Attempt<T, F extends FailureReason> {
}
}
/**
* Maps the value to another attempt with the same fail reason if this is a success attempt.
*
* @param mapper The mapper.
* @param <U> The type of the new value.
* @return The new attempt.
*/
default <U> Attempt<U, F> mapAttempt(Function<? super T, Attempt<U, F>> mapper) {
if (this instanceof Success) {
return mapper.apply(get());
@ -67,6 +151,13 @@ public interface Attempt<T, F extends FailureReason> {
}
}
/**
* Maps the value to another attempt with the same fail reason if this is a success attempt.
*
* @param mapper The mapper.
* @param <U> The type of the new value.
* @return The new attempt.
*/
default <U> Attempt<U, F> mapAttempt(Supplier<Attempt<U, F>> mapper) {
if (this instanceof Success) {
return mapper.get();
@ -75,6 +166,13 @@ public interface Attempt<T, F extends FailureReason> {
}
}
/**
* Maps to another attempt with a different fail reason.
*
* @param failureReason The new fail reason.
* @param <UF> The type of the new fail reason.
* @return The new attempt.
*/
default <UF extends FailureReason> Attempt<T, UF> transform(UF failureReason) {
if (this instanceof Success) {
return new Success<>(get());
@ -83,14 +181,14 @@ public interface Attempt<T, F extends FailureReason> {
}
}
default <NF extends FailureReason> Attempt<T, NF> convertReason(NF failure) {
if (this instanceof Success) {
return new Success<>(get());
} else {
return new Failure<>(failure, getFailureMessage());
}
}
/**
* Calls either the failure or success function depending on the result type.
*
* @param failureMapper The failure function.
* @param successMapper The success function.
* @param <N> The type of the new value.
* @return The result of the function.
*/
default <N> N fold(Function<Failure<T, F>, N> failureMapper, Function<T, N> successMapper) {
if (this instanceof Success) {
return successMapper.apply(get());
@ -99,6 +197,12 @@ public interface Attempt<T, F extends FailureReason> {
}
}
/**
* Calls the given runnable if this is a success attempt.
*
* @param runnable The runnable.
* @return This attempt.
*/
default Attempt<T, F> onSuccess(Runnable runnable) {
if (this instanceof Success) {
runnable.run();
@ -106,6 +210,12 @@ public interface Attempt<T, F extends FailureReason> {
return this;
}
/**
* Calls the given consumer if this is a success attempt.
*
* @param consumer The consumer with the value.
* @return This attempt.
*/
default Attempt<T, F> onSuccess(Consumer<T> consumer) {
if (this instanceof Success) {
consumer.accept(get());
@ -113,6 +223,12 @@ public interface Attempt<T, F extends FailureReason> {
return this;
}
/**
* Calls the given consumer if this is a failure attempt.
*
* @param runnable The runnable.
* @return This attempt.
*/
default Attempt<T, F> onFailure(Runnable runnable) {
if (this instanceof Failure) {
runnable.run();
@ -120,6 +236,12 @@ public interface Attempt<T, F extends FailureReason> {
return this;
}
/**
* Calls the given consumer if this is a failure attempt.
*
* @param consumer The consumer with the failure instance.
* @return This attempt.
*/
default Attempt<T, F> onFailure(Consumer<Failure<T, F>> consumer) {
if (this instanceof Failure) {
consumer.accept((Failure<T, F>) this);
@ -127,6 +249,12 @@ public interface Attempt<T, F extends FailureReason> {
return this;
}
/**
* Calls the given runnable if this is a failure attempt.
*
* @param consumer The consumer with the failure reason.
* @return This attempt.
*/
default Attempt<T, F> onFailureReason(Consumer<F> consumer) {
if (this instanceof Failure) {
consumer.accept(getFailureReason());
@ -134,7 +262,13 @@ public interface Attempt<T, F extends FailureReason> {
return this;
}
class Success<T, F extends FailureReason> implements Attempt<T, F> {
/**
* Represents a successful attempt with a value.
*
* @param <T> The type of the value.
* @param <F> The type of failure reason.
*/
final class Success<T, F extends FailureReason> implements Attempt<T, F> {
private final T value;
Success(T value) {
@ -148,12 +282,12 @@ public interface Attempt<T, F extends FailureReason> {
@Override
public F getFailureReason() {
throw new IllegalStateException("Attempt is a success!");
throw new UnsupportedOperationException("No failure reason as attempt is a success");
}
@Override
public Message getFailureMessage() {
throw new IllegalStateException("Attempt is a success!");
throw new UnsupportedOperationException("No failure message as attempt is a success");
}
@Override
@ -164,7 +298,13 @@ public interface Attempt<T, F extends FailureReason> {
}
}
class Failure<T, F extends FailureReason> implements Attempt<T, F> {
/**
* Represents a failed attempt with a reason.
*
* @param <T> The type of the value.
* @param <F> The type of failure reason.
*/
final class Failure<T, F extends FailureReason> implements Attempt<T, F> {
private final F failureReason;
private final Message message;
@ -175,7 +315,7 @@ public interface Attempt<T, F extends FailureReason> {
@Override
public T get() {
throw new IllegalStateException("Attempt is a failure!");
throw new UnsupportedOperationException("No value as attempt is a failure");
}
@Override

View File

@ -8,42 +8,123 @@ import java.util.NoSuchElementException;
import java.util.function.Consumer;
import java.util.function.Function;
public sealed interface Result<S extends SuccessReason, F extends FailureReason> permits Result.Success, Result.Failure {
/**
* Represents result of an operation with a reason for success or failure that has localized messages.
*
* @param <S> The type of success reason.
* @param <F> The type of failure reason.
*/
public sealed interface Result<S extends SuccessReason, F extends FailureReason>
permits Result.Success, Result.Failure {
/**
* Creates a new success result.
*
* @param successReason The reason for success.
* @param replacements The replacements for the success message.
* @param <F> The type of failure reason.
* @param <S> The type of success reason.
* @return The new success result.
*/
static <F extends FailureReason, S extends SuccessReason> Result<S, F> success(
S successReason, MessageReplacement...replacements) {
S successReason, MessageReplacement... replacements) {
return new Success<>(successReason, replacements);
}
/**
* Creates a new success result.
*
* @param successReason The reason for success.
* @param message The custom message for success. This will override the default message.
* @param <F> The type of failure reason.
* @param <S> The type of success reason.
* @return The new success result.
*/
static <F extends FailureReason, S extends SuccessReason> Result<S, F> success(S successReason, Message message) {
return new Success<>(successReason, message);
}
/**
* Creates a new failure result.
*
* @param failureReason The reason for failure.
* @param replacements The replacements for the failure message.
* @param <F> The type of failure reason.
* @param <S> The type of success reason.
* @return The new failure result.
*/
static <F extends FailureReason, S extends SuccessReason> Result<S, F> failure(
F failureReason, MessageReplacement...replacements) {
F failureReason, MessageReplacement... replacements) {
return new Failure<>(failureReason, replacements);
}
/**
* Creates a new failure result.
*
* @param failureReason The reason for failure.
* @param message The custom message for failure. This will override the default message.
* @param <F> The type of failure reason.
* @param <S> The type of success reason.
* @return The new failure result.
*/
static <F extends FailureReason, S extends SuccessReason> Result<S, F> failure(F failureReason, Message message) {
return new Failure<>(failureReason, message);
}
/**
* Returns whether this result is a success.
*
* @return Whether this result is a success.
*/
boolean isSuccess();
/**
* Returns whether this result is a failure.
*
* @return Whether this result is a failure.
*/
boolean isFailure();
/**
* Returns the reason for success.
*
* @return The reason for success.
*/
S getSuccessReason();
/**
* Returns the reason for failure.
*
* @return The reason for failure.
*/
F getFailureReason();
/**
* Returns the message for the reason of this result.
*
* @return The message for the reason.
*/
@NotNull Message getReasonMessage();
default Result<S, F> onSuccess(Consumer<Success<F, S>> consumer) {
/**
* Executes the given consumer if this result is a success.
*
* @param consumer The consumer with success object.
* @return This result.
*/
default Result<S, F> onSuccess(Consumer<Success<S, F>> consumer) {
if (this instanceof Success) {
consumer.accept((Success<F, S>) this);
consumer.accept((Success<S, F>) this);
}
return this;
}
/**
* Executes the given consumer if this result is a failure.
*
* @param consumer The consumer with failure object.
* @return This result.
*/
default Result<S, F> onFailure(Consumer<Failure<S, F>> consumer) {
if (this instanceof Failure) {
consumer.accept((Failure<S, F>) this);
@ -51,6 +132,13 @@ public sealed interface Result<S extends SuccessReason, F extends FailureReason>
return this;
}
/**
* Executes the given consumer if this result is a success and the success reason matches the given reason.
*
* @param successReason The success reason to match.
* @param consumer The consumer with success reason.
* @return This result.
*/
default Result<S, F> onSuccessReason(S successReason, Consumer<S> consumer) {
if (this.isSuccess() && this.getSuccessReason() == successReason) {
consumer.accept(this.getSuccessReason());
@ -58,6 +146,13 @@ public sealed interface Result<S extends SuccessReason, F extends FailureReason>
return this;
}
/**
* Executes the given consumer if this result is a failure and the failure reason matches the given reason.
*
* @param failureReason The failure reason to match.
* @param consumer The consumer with failure reason.
* @return This result.
*/
default Result<S, F> onFailureReason(F failureReason, Consumer<F> consumer) {
if (this.isFailure() && this.getFailureReason() == failureReason) {
consumer.accept(this.getFailureReason());
@ -65,13 +160,25 @@ public sealed interface Result<S extends SuccessReason, F extends FailureReason>
return this;
}
default Result<S, F> onSuccessThen(Function<Success<F, S>, Result<S, F>> function) {
/**
* Executes the given function if this result is a success and returns the result of the function.
*
* @param function The function with success object.
* @return The result of the function.
*/
default Result<S, F> onSuccessThen(Function<Success<S, F>, Result<S, F>> function) {
if (this instanceof Success) {
return function.apply((Success<F, S>) this);
return function.apply((Success<S, F>) this);
}
return this;
}
/**
* Executes the given function if this result is a failure and returns the result of the function.
*
* @param function The function with failure object.
* @return The result of the function.
*/
default Result<S, F> onFailureThen(Function<Failure<S, F>, Result<S, F>> function) {
if (this instanceof Failure) {
return function.apply((Failure<S, F>) this);
@ -79,25 +186,39 @@ public sealed interface Result<S extends SuccessReason, F extends FailureReason>
return this;
}
default <R> R fold(Function<Failure<S, F>, R> failureFunc, Function<Success<F, S>, R> successFunc) {
/**
* Executes either the failure or success function depending on the result type.
*
* @param failureFunc The function with success reason.
* @param successFunc The function with success reason.
* @param <R> The type of the result.
* @return The result of the function.
*/
default <R> R fold(Function<Failure<S, F>, R> failureFunc, Function<Success<S, F>, R> successFunc) {
if (this instanceof Failure) {
return failureFunc.apply((Failure<S, F>) this);
} else if (this instanceof Success) {
return successFunc.apply((Success<F, S>) this);
return successFunc.apply((Success<S, F>) this);
}
throw new IllegalStateException("Unknown result type: " + this.getClass().getName());
}
final class Success<F extends FailureReason, S extends SuccessReason> implements Result<S, F> {
/**
* The class for a successful result.
*
* @param <F> The type of failure reason.
* @param <S> The type of success reason.
*/
final class Success<S extends SuccessReason, F extends FailureReason> implements Result<S, F> {
private final S successReason;
private final Message message;
public Success(S successReason, Message message) {
Success(S successReason, Message message) {
this.successReason = successReason;
this.message = message;
}
public Success(S successReason, MessageReplacement[] replacements) {
Success(S successReason, MessageReplacement[] replacements) {
this.successReason = successReason;
this.message = Message.of(successReason, "Success!", replacements);
}
@ -119,7 +240,7 @@ public sealed interface Result<S extends SuccessReason, F extends FailureReason>
@Override
public F getFailureReason() {
throw new NoSuchElementException("No reason for failure");
throw new UnsupportedOperationException("No reason for success");
}
@Override
@ -135,18 +256,24 @@ public sealed interface Result<S extends SuccessReason, F extends FailureReason>
}
}
/**
* The class for a failed result.
*
* @param <S> The type of success reason.
* @param <F> The type of failure reason.
*/
final class Failure<S extends SuccessReason, F extends FailureReason> implements Result<S, F> {
private final F failureReason;
private final Message message;
public Failure(F failureReason, Message message) {
Failure(F failureReason, Message message) {
this.failureReason = failureReason;
this.message = message;
}
public Failure(F failureReason, MessageReplacement[] replacements) {
Failure(F failureReason, MessageReplacement[] replacements) {
this.failureReason = failureReason;
this.message = Message.of(failureReason, "Success!", replacements);
this.message = Message.of(failureReason, "Failed!", replacements);
}
@Override
@ -161,7 +288,7 @@ public sealed interface Result<S extends SuccessReason, F extends FailureReason>
@Override
public S getSuccessReason() {
throw new NoSuchElementException("No reason for failure");
throw new UnsupportedOperationException("No reason for failure");
}
@Override

View File

@ -488,7 +488,7 @@ public class WorldManager {
public Attempt<String, DeleteWorldResult> deleteWorld(@NotNull MultiverseWorld world) {
return getLoadedWorld(world).fold(
() -> loadWorld(world)
.convertReason(DeleteWorldResult.LOAD_FAILED)
.transform(DeleteWorldResult.LOAD_FAILED)
.mapAttempt(this::deleteWorld),
this::deleteWorld);
}
@ -535,7 +535,7 @@ public class WorldManager {
.worldName(validatedOptions.newWorldName())
.environment(validatedOptions.world().getEnvironment())
.generator(validatedOptions.world().getGenerator());
return importWorld(importWorldOptions).convertReason(CloneWorldResult.IMPORT_FAILED);
return importWorld(importWorldOptions).transform(CloneWorldResult.IMPORT_FAILED);
})
.onSuccess(newWorld -> {
cloneWorldTransferData(options, newWorld);
@ -616,8 +616,8 @@ public class WorldManager {
.worldType(world.getWorldType().getOrElse(WorldType.NORMAL));
return deleteWorld(world)
.convertReason(RegenWorldResult.DELETE_FAILED)
.mapAttempt(() -> createWorld(createWorldOptions).convertReason(RegenWorldResult.CREATE_FAILED))
.transform(RegenWorldResult.DELETE_FAILED)
.mapAttempt(() -> createWorld(createWorldOptions).transform(RegenWorldResult.CREATE_FAILED))
.onSuccess(newWorld -> {
dataTransfer.pasteAllTo(newWorld);
saveWorldsConfig();