All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.artkonr.result.FlagResult Maven / Gradle / Ivy

package io.github.artkonr.result;

import lombok.NonNull;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * A {@link BaseResult result} container that carries no value.
 * @param  error type
 */
public class FlagResult extends BaseResult {

    /**
     * Runs a specified {@link Wrap.Runnable}, catches an expected exception
     *  and returns it as a {@link FlagResult}.
     * 

The expected exception can be any {@link Exception} type, * this method internally checks if the caught exception type * matches the expected type or its subtype. Normally, the client * code should pass the narrowest type possible. *

If no error is thrown by the supplied function, the call * resolves to {@code OK}. * @param errType expected type * @param action fallible action * @return result of the invocation * @param error type * @throws IllegalArgumentException if either of the arguments not provided * @throws IllegalStateException if the exception during invocation is not * of an expected type or its subtype */ public static FlagResult wrap(@NonNull Class errType, @NonNull Wrap.Runnable action) { try { action.run(); return FlagResult.ok(); } catch (Exception exception) { if (errType.isAssignableFrom(exception.getClass())) { @SuppressWarnings("unchecked") E cast = (E) exception; return FlagResult.err(cast); } else { throw BaseResult.unexpectedWrappedException(errType, exception); } } } /** * Creates a new instance from an existing {@link BaseResult result}. * The {@code OK}/{@code ERR} state is taken from the source entity. *

Note: as {@link FlagResult} doesn't contain a value in {@code OK} * state, any value carried by the source {@code OK} result is dropped. * @param source source {@link BaseResult result} * @return new instance * @param error type * @throws IllegalArgumentException if no argument provided */ public static FlagResult from(@NonNull BaseResult source) { if (source.isOk()) { return FlagResult.ok(); } else { return FlagResult.err(source.error); } } /** * Creates an {@code OK} item with no value. * @return new {@code OK} instance * @param error type */ public static FlagResult ok() { return new FlagResult<>(null); } /** * Creates an {@code ERR} item with the provided error. * @param error error * @return new {@code ERR} instance * @param error type * @throws IllegalArgumentException if no argument provided */ public static FlagResult err(@NonNull E error) { return new FlagResult<>(error); } /** * Joins a {@link Collection} of {@link BaseResult any result} objects into * a single {@link FlagResult}. *

The eventual {@link FlagResult} will have the {@code OK} state * iff. all {@link BaseResult source results} are {@code OK}. Otherwise, * the internal error of the fist occurring {@code ERR} result is taken. *

As {@link Collection} does not specify the ordering, the eventual * {@link FlagResult} is not guaranteed to contain the same internal * error state every time. *

Null-safe: should the input contain {@code null} items, * this method will remove them. * @param results collection of {@link BaseResult results} * @return results joined into a {@link FlagResult} * @param error type * @throws IllegalArgumentException if no argument provided */ public static FlagResult join(@NonNull Collection> results) { return join(results, TakeFrom.HEAD); } /** * Joins a {@link Collection} of {@link BaseResult any result} objects into * a single {@link FlagResult}. *

The eventual {@link FlagResult} will have the {@code OK} state * iff. all {@link BaseResult source results} are {@code OK}. Otherwise, * the internal error of is taken as described by {@link TakeFrom}. *

As {@link Collection} does not specify the ordering, the eventual * {@link FlagResult} is not guaranteed to contain the same internal * error state every time. *

Null-safe: should the input contain {@code null} items, * this method will remove them. * @param results collection of {@link BaseResult results} * @param rule fusing rule * @return results joined into a {@link FlagResult} * @param error type * @throws IllegalArgumentException if no argument provided */ public static FlagResult join(@NonNull Collection> results, @NonNull TakeFrom rule) { List> errored = results.stream() .filter(Objects::nonNull) .filter(BaseResult::isErr) .toList(); if (!errored.isEmpty()) { BaseResult picked = switch (rule) { case HEAD -> errored.get(0); case TAIL -> errored.get(errored.size() - 1); }; return FlagResult.err(picked.error); } else { return FlagResult.ok(); } } /** * Converts {@code this} {@link FlagResult} into a {@link Result * value result} with a given item if {@code this} result is * {@code OK}; simply carriers internal error state otherwise. * @param item item to populate the result with * @return new {@link Result} instance * @param type of {@code OK} item * @throws IllegalArgumentException if no argument provided */ public Result populate(@NonNull V item) { if (isOk()) { return Result.ok(item); } else { return Result.err(error); } } /** * Produces a new {@link FlagResult} out of {@code this} * and another {@link FlagResult}. *

The eventual {@link FlagResult} will have {@code OK} * state iff. both instances are {@code OK}; {@code ERR} * state is assumed otherwise, with the error taken from * the only {@code ERR} from the pair or from {@code this} * instance if both are {@code ERR}. *

In order to be fuse-able, the fused items must contain * the same error type. * @param another fuse with * @return a new {@link FlagResult} * @throws IllegalArgumentException if no argument provided */ public FlagResult fuse(@NonNull FlagResult another) { return fuse(another, TakeFrom.HEAD); } /** * Produces a new {@link FlagResult} out of {@code this} * and another {@link FlagResult}. *

The eventual {@link FlagResult} will have {@code OK} * state iff. both instances are {@code OK}; {@code ERR} * state is assumed otherwise, with the error taken from * the only {@code ERR} from the pair. If both instances * are {@code ERR}, the {@link TakeFrom rule arg} allows * to point which of the {@code ERR} items passes the * error on. *

In order to be fuse-able, the fused items must contain * the same error type. * @param another fuse with * @param rule fusing rule * @return a new {@link FlagResult} * @throws IllegalArgumentException if no argument provided */ public FlagResult fuse(@NonNull FlagResult another, @NonNull TakeFrom rule) { return rule.takeError(this, another) .map(FlagResult::err) .orElseGet(FlagResult::ok); } /** * {@inheritDoc} * @param remap callback * @return mapped {@link FlagResult} * @param new error type * @throws IllegalArgumentException if no argument provided or * if the callback function returns {@code null} */ @Override public FlagResult mapErr(@NonNull Function remap) { if (isErr()) { return FlagResult.err(remap.apply(error)); } else { return FlagResult.ok(); } } /** * Converts an {@code OK} result into {@code ERR} * using the specified factory if {@code this} * instance is {@code OK}. Recreates {@code this} * with its internal error state otherwise. *

Note: the resulting type parameter is up-cast * to the most generic type supported: {@link Exception}. * @param factory exception factory * @return converted instance * @throws IllegalArgumentException if no argument provided or if * the factory function returns {@code null} */ @Override public FlagResult taint(@NonNull Supplier factory) { if (isOk()) { return err(factory.get()); } else { return err(error); } } /** * Wraps the internal {@code ERR} state into a {@link * Failure wrapping exception} and throws if {@code * this} instance is an {@code ERR}. * @throws Failure result wrapping exception */ public void unwrap() { if (isErr()) { throw new Failure(error); } } /** * Builds a text representation. * @return text representation */ @Override public String toString() { return "FlagResult[" + (isOk() ? "ok" : "err=" + error) + ']'; } /** * Checks if {@code this} equals {@code that}. * @param that that * @return comparison result */ @Override public boolean equals(Object that) { if (this == that) return true; if (that == null || getClass() != that.getClass()) return false; FlagResult result = (FlagResult) that; return Objects.equals(error, result.error); } /** * Computes hashcode. * @return computed hashcode */ @Override public int hashCode() { if (isOk()) { return 31; } else { return 31 * error.hashCode(); } } /** * Internal constructor. *

Setting the argument to {@code null} must * follow the class contract. * @param error nullable error value */ protected FlagResult(E error) { super(error); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy