Skip to content

Commit

Permalink
Leverage newer Java for Either, add flatMap.
Browse files Browse the repository at this point in the history
  • Loading branch information
LambdAurora committed Feb 12, 2025
1 parent 9227b7b commit 9f91839
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 17 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Yumi Commons

![Java 17](https://img.shields.io/badge/language-Java%2017-9B599A.svg?style=flat-square)
![Java 17](https://img.shields.io/badge/language-Java%2017-9115ff.svg?style=flat-square)
[![GitHub license](https://img.shields.io/github/license/YumiProject/yumi-commons?style=flat-square)](https://raw.githubusercontent.com/YumiProject/yumi-commons/main/LICENSE)
![Version](https://img.shields.io/github/v/tag/YumiProject/yumi-commons?label=version&style=flat-square)
![Maven Central](https://img.shields.io/maven-central/v/dev.yumi.commons/yumi-commons?style=flat-square&label=Maven%20Central)
<!--![Version](https://img.shields.io/github/v/tag/YumiProject/yumi-commons?label=version&style=flat-square)-->

A set of common utilities to use as libraries.

Expand Down
2 changes: 1 addition & 1 deletion build_logic/src/main/kotlin/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ data class Developer(val name: String, val email: String)

object Constants {
const val GROUP = "dev.yumi.commons"
const val VERSION = "1.0.0-alpha.3"
const val VERSION = "1.0.0-alpha.4"
const val JAVA_VERSION = 17

const val PROJECT_NAME = "Yumi Commons"
Expand Down
64 changes: 50 additions & 14 deletions libraries/core/src/main/java/dev/yumi/commons/Either.java
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,28 @@ default void ifRight(@NotNull Consumer<? super R> action) {}
*/
<NL, NR> Either<NL, NR> map(@NotNull Function<? super L, ? extends NL> leftMapper, @NotNull Function<? super R, ? extends NR> rightMapper);

/**
* If this either represents a left value,
* returns an {@code Either} given by the given mapping function,
* otherwise returns itself.
*
* @param mapper the mapping function to apply to the value, if this either represents a left value
* @param <NL> the type to map the left value to
* @return an {@code Either} describing the result of applying the mapping function to the value this holds
*/
<NL> Either<NL, R> flatMapLeft(@NotNull Function<? super L, ? extends Either<NL, R>> mapper);

/**
* If this either represents a right value,
* returns an {@code Either} given by the given mapping function,
* otherwise returns itself.
*
* @param mapper the mapping function to apply to the value, if this either represents a right value
* @param <NR> the type to map the right value to
* @return an {@code Either} describing the result of applying the mapping function to the value this holds
*/
<NR> Either<L, NR> flatMapRight(@NotNull Function<? super R, ? extends Either<L, NR>> mapper);

/**
* Folds this {@code Either} into a singular value.
*
Expand All @@ -195,16 +217,11 @@ default void ifRight(@NotNull Consumer<? super R> action) {}
/**
* Represents the left value of an {@link Either}.
*
* @param value the left value
* @param <L> the type of the left value
* @param <R> the type of the right value
*/
final class Left<L, R> implements Either<L, R> {
private final L value;

private Left(L value) {
this.value = value;
}

record Left<L, R>(L value) implements Either<L, R> {
@Override
public L getLeft() {
return this.value;
Expand Down Expand Up @@ -266,6 +283,18 @@ public <NL, NR> Either<NL, NR> map(@NotNull Function<? super L, ? extends NL> le
return new Left<>(leftMapper.apply(this.value));
}

@Override
public <NL> Either<NL, R> flatMapLeft(@NotNull Function<? super L, ? extends Either<NL, R>> mapper) {
return mapper.apply(this.value);
}

@SuppressWarnings("unchecked")
@Contract(value = "_ -> this", pure = true)
@Override
public <NR> Either<L, NR> flatMapRight(@NotNull Function<? super R, ? extends Either<L, NR>> mapper) {
return (Either<L, NR>) this;
}

@Override
public <U> U fold(@NotNull Function<? super L, ? extends U> leftMapper, @NotNull Function<? super R, ? extends U> rightMapper) {
return leftMapper.apply(this.value);
Expand Down Expand Up @@ -300,16 +329,11 @@ public String toString() {
/**
* Represents the right value of an {@link Either}.
*
* @param value the right value
* @param <L> the type of the left value
* @param <R> the type of the right value
*/
final class Right<L, R> implements Either<L, R> {
private final R value;

private Right(R value) {
this.value = value;
}

record Right<L, R>(R value) implements Either<L, R> {
@Contract(value = "-> fail", pure = true)
@Override
public L getLeft() {
Expand Down Expand Up @@ -371,6 +395,18 @@ public <NL, NR> Either<NL, NR> map(@NotNull Function<? super L, ? extends NL> le
return new Right<>(rightMapper.apply(this.value));
}

@SuppressWarnings("unchecked")
@Contract(value = "_ -> this", pure = true)
@Override
public <NL> Either<NL, R> flatMapLeft(@NotNull Function<? super L, ? extends Either<NL, R>> mapper) {
return (Either<NL, R>) this;
}

@Override
public <NR> Either<L, NR> flatMapRight(@NotNull Function<? super R, ? extends Either<L, NR>> mapper) {
return mapper.apply(this.value);
}

@Override
public <U> U fold(@NotNull Function<? super L, ? extends U> leftMapper, @NotNull Function<? super R, ? extends U> rightMapper) {
return rightMapper.apply(this.value);
Expand Down
19 changes: 19 additions & 0 deletions libraries/core/src/test/java/dev/yumi/commons/test/EitherTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,25 @@ public void testMap() {
}, value -> value + " Earth!"));
}

@Test
public void testFlatMap() {
var left = Either.left(1L);
var right = Either.right("Hello");

assertEquals(Either.left(2), left.flatMapLeft(value -> Either.left(value.intValue() + 1)));
assertSame(left, left.flatMapRight(o -> {
throw new AssertionError("mapRight on Either.Left should not call mapper function.");
}), "mapRight on Either.Left should return itself.");

assertSame(right, right.flatMapLeft(o -> {
throw new AssertionError("mapLeft on Either.Right should not call mapper function.");
}), "mapLeft on Either.Right should return itself.");
assertEquals(Either.right("Hello World!"), right.flatMapRight(value -> Either.right(value + " World!")));

assertEquals(Either.right("Hello 1!"), left.flatMapLeft(value -> Either.right("Hello " + value + "!")));
assertEquals(Either.left(5), right.flatMapRight(value -> Either.left(value.length())));
}

@Test
public void testFold() {
var left = Either.left(1L);
Expand Down

0 comments on commit 9f91839

Please sign in to comment.