From b1550bfde08640849082cf91ddac08c87d0c0426 Mon Sep 17 00:00:00 2001 From: Bjarne Koll Date: Fri, 8 Oct 2021 16:18:14 +0200 Subject: [PATCH] Add TriState toBoolean helper methods While the TriState enum already has helper methods to quickly convert a boolean into a TriState (both nullable wrappers and their primitive counterparts), helper methods to convert a TriState back into a boolean representation are currently missing. This commit introduces two methods that do exactly that, one allowing a straight forward conversion to a Boolean as it can represent a TriState through its nullability as well as another method that discards the TriState#NOT_SET by accepting a supplier that will be used to map a not set tri-state. --- .../net/kyori/adventure/util/TriState.java | 55 +++++++++++++++++++ .../kyori/adventure/util/TriStateTest.java | 38 +++++++++++++ 2 files changed, 93 insertions(+) diff --git a/api/src/main/java/net/kyori/adventure/util/TriState.java b/api/src/main/java/net/kyori/adventure/util/TriState.java index 01b7b2424..4fc8ebef6 100644 --- a/api/src/main/java/net/kyori/adventure/util/TriState.java +++ b/api/src/main/java/net/kyori/adventure/util/TriState.java @@ -23,6 +23,7 @@ */ package net.kyori.adventure.util; +import java.util.function.BooleanSupplier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -51,6 +52,60 @@ public enum TriState { */ TRUE; + /** + * Converts this tri-state back into a {@link Boolean}. + * + * @return the boolean representing this tri-state. {@link #NOT_SET} will be represented by {@code null}. + * @since 4.10.0 + */ + public @Nullable Boolean toBoolean() { + switch (this) { + case TRUE: return Boolean.TRUE; + case FALSE: return Boolean.FALSE; + default: return null; + } + } + + /** + * Converts this tri-state back into a {@code boolean}. + * + *

As the {@link #NOT_SET} state cannot be represented by the boolean type, this + * method maps the {@link #NOT_SET} state to other passed boolean value. + * This method may hence also be viewed as an equivalent to {@link + * java.util.Optional#orElse(Object)}.

+ * + * @param other the boolean value that should be returned if this tri-state is {@link #NOT_SET}. + * @return the boolean representing the tri-state or the boolean passed if this state is {@link #NOT_SET}. + * @since 4.10.0 + */ + public boolean toBooleanOrElse(final boolean other) { + switch (this) { + case TRUE: return true; + case FALSE: return false; + default: return other; + } + } + + /** + * Converts this tri-state back into a {@code boolean}. + * + *

As the {@link #NOT_SET} state cannot be represented by the boolean type, this + * method maps the {@link #NOT_SET} state to the suppliers result. + * This method may hence also be viewed as an equivalent to {@link + * java.util.Optional#orElseGet(java.util.function.Supplier)}.

+ * + * @param supplier the supplier that will be executed to produce the value that should be returned if this tri-state is {@link #NOT_SET}. + * @return the boolean representing the tri-state or the result of the passed supplier if this state is {@link #NOT_SET}. + * @since 4.10.0 + */ + public boolean toBooleanOrElseGet(final @NotNull BooleanSupplier supplier) { + switch (this) { + case TRUE: return true; + case FALSE: return false; + default: return supplier.getAsBoolean(); + } + } + /** * Gets a state from a {@code boolean}. * diff --git a/api/src/test/java/net/kyori/adventure/util/TriStateTest.java b/api/src/test/java/net/kyori/adventure/util/TriStateTest.java index 98c6c2bc0..d956c6a60 100644 --- a/api/src/test/java/net/kyori/adventure/util/TriStateTest.java +++ b/api/src/test/java/net/kyori/adventure/util/TriStateTest.java @@ -23,9 +23,14 @@ */ package net.kyori.adventure.util; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; class TriStateTest { @Test @@ -40,4 +45,37 @@ void testByBooleanBoxed() { assertEquals(TriState.FALSE, TriState.byBoolean(Boolean.FALSE)); assertEquals(TriState.TRUE, TriState.byBoolean(Boolean.TRUE)); } + + @Test + void testToBoolean() { + assertEquals(true, TriState.TRUE.toBoolean()); + assertEquals(false, TriState.FALSE.toBoolean()); + assertNull(TriState.NOT_SET.toBoolean()); + } + + @Test + void testToBooleanOrElse() { + assertTrue(TriState.TRUE.toBooleanOrElse(false)); + assertFalse(TriState.FALSE.toBooleanOrElse(true)); + + assertTrue(TriState.NOT_SET.toBooleanOrElse(true)); + assertFalse(TriState.NOT_SET.toBooleanOrElse(false)); + } + + @Test + void testToBooleanOrElseGet() { + final AtomicInteger atomicCounter = new AtomicInteger(0); + final Function supplierCounter = b -> { + atomicCounter.incrementAndGet(); + return b; + }; + + assertTrue(TriState.TRUE.toBooleanOrElseGet(() -> supplierCounter.apply(false))); + assertFalse(TriState.FALSE.toBooleanOrElseGet(() -> supplierCounter.apply(true))); + + assertTrue(TriState.NOT_SET.toBooleanOrElseGet(() -> supplierCounter.apply(true))); + assertFalse(TriState.NOT_SET.toBooleanOrElseGet(() -> supplierCounter.apply(false))); + + assertEquals(2, atomicCounter.get()); // Ensure that the supplier was only called twice for the two test cases. + } }