diff --git a/build.gradle b/build.gradle index 0e9c0c434..e22e3deb1 100644 --- a/build.gradle +++ b/build.gradle @@ -82,17 +82,23 @@ allprojects { } jacoco { - toolVersion = "0.8.10" + toolVersion = "0.8.11" + } + + javadoc.options { + addStringOption('-release', '21') } compileJava { options.compilerArgs << '-Xlint:unchecked' options.compilerArgs << '-Xlint:rawtypes' + options.release = 21 } compileTestJava { options.compilerArgs << '-Xlint:unchecked' options.compilerArgs << '-Xlint:rawtypes' + options.release = 21 } jacocoTestReport { @@ -107,8 +113,8 @@ allprojects { subprojects { java { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 withJavadocJar() withSourcesJar() @@ -128,7 +134,7 @@ subprojects { if (it.getName().contains("Java21")) { it.options.release = 21 } else { - it.options.release = 17 + it.options.release = 21 } } diff --git a/core/build.gradle b/core/build.gradle index 608269324..f5db065f9 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,30 +1,3 @@ -sourceSets { - java21 { - java { - srcDirs = ['src/main/java21'] - } - } -} - -java { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - - withJavadocJar() - withSourcesJar() -} - -compileJava21Java { - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 -} - -jar { - into('META-INF/versions/21') { - from sourceSets.java21.output - } - manifest.attributes('Multi-Release': 'true') -} dependencies { annotationProcessor projects.purefunProcessor diff --git a/core/src/main/java/com/github/tonivade/purefun/concurrent/DefaultExecutor.java b/core/src/main/java/com/github/tonivade/purefun/concurrent/DefaultExecutor.java deleted file mode 100644 index b1b78328d..000000000 --- a/core/src/main/java/com/github/tonivade/purefun/concurrent/DefaultExecutor.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c) 2018-2023, Antonio Gabriel Muñoz Conejo - * Distributed under the terms of the MIT License - */ -package com.github.tonivade.purefun.concurrent; - -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -final class DefaultExecutor { - - static final Executor EXECUTOR = Executors.newCachedThreadPool(); -} diff --git a/core/src/main/java/com/github/tonivade/purefun/concurrent/Future.java b/core/src/main/java/com/github/tonivade/purefun/concurrent/Future.java index 6943e346e..0a0955b28 100644 --- a/core/src/main/java/com/github/tonivade/purefun/concurrent/Future.java +++ b/core/src/main/java/com/github/tonivade/purefun/concurrent/Future.java @@ -69,7 +69,7 @@ @HigherKind public sealed interface Future extends FutureOf, Bindable { - Executor DEFAULT_EXECUTOR = DefaultExecutor.EXECUTOR; + Executor DEFAULT_EXECUTOR = Executors.newVirtualThreadPerTaskExecutor(); Try await(); Try await(Duration timeout); @@ -133,7 +133,7 @@ default Future recover(Function1 mapper) { Future recoverWith(Class type, Function1 mapper); Future fold( - Function1 failureMapper, + Function1 failureMapper, Function1 successMapper); default CompletableFuture toCompletableFuture() { @@ -233,41 +233,41 @@ static Future later(Executor executor, Producer producer) { return task(executor, producer::get); } - static Future bracket(Future acquire, + static Future bracket(Future acquire, Function1> use) { return bracket(DEFAULT_EXECUTOR, acquire, use); } - static Future bracket(Executor executor, - Future acquire, + static Future bracket(Executor executor, + Future acquire, Function1> use) { return FutureImpl.bracket(executor, acquire, use, AutoCloseable::close); } - static Future bracket(Future acquire, - Function1> use, + static Future bracket(Future acquire, + Function1> use, Consumer1 release) { return bracket(DEFAULT_EXECUTOR, acquire, use, release); } - static Future bracket(Executor executor, - Future acquire, - Function1> use, + static Future bracket(Executor executor, + Future acquire, + Function1> use, Consumer1 release) { return FutureImpl.bracket(executor, acquire, use, release); } // TODO static Future> traverse(Sequence> sequence) { - return sequence.foldLeft(success(ImmutableList.empty()), + return sequence.foldLeft(success(ImmutableList.empty()), (Future> xs, Future a) -> map2(xs, a, Sequence::append)); } - - static Future map2(Future fa, Future fb, + + static Future map2(Future fa, Future fb, Function2 mapper) { return fb.ap(fa.map(mapper.curried())); } - + static Future> tuple(Future fa, Future fb) { return map2(fa, fb, Tuple2::of); } @@ -287,7 +287,7 @@ final class FutureImpl implements Future { private final Propagate propagate; private final Promise promise; private final Cancellable cancellable; - + private final UUID uuid; private FutureImpl(Executor executor, Callback callback) { @@ -345,7 +345,7 @@ public Try await(Duration timeout) { public Future map(Function1 mapper) { return transform(value -> value.map(mapper)); } - + @Override public Future mapError(Function1 mapper) { return transform(value -> value.mapError(mapper)); @@ -360,11 +360,11 @@ public Future flatMap(Function1 Future andThen(Future next) { return flatMap(ignore -> next); } - + @Override public Future ap(Future> apply) { checkNonNull(apply); - return new FutureImpl<>(executor, + return new FutureImpl<>(executor, (p, c) -> promise.onComplete(try1 -> apply.onComplete( try2 -> p.tryComplete(Try.map2(try2, try1, Function1::apply)))), this::cancel); } @@ -406,7 +406,7 @@ public void cancel(boolean mayInterruptThread) { public Promise toPromise() { return promise; } - + @Override public String toString() { return "Future(" + uuid + ')'; @@ -447,7 +447,7 @@ static Future async(Executor executor, Consumer1>> consumer) { checkNonNull(executor); checkNonNull(consumer); - return new FutureImpl<>(executor, + return new FutureImpl<>(executor, (p, c) -> Future.later(executor, () -> { c.updateThread(); return consumer.asFunction().apply(p::tryComplete); @@ -494,7 +494,7 @@ static Executor delayedExecutor(Duration delay, Executor executor) { } interface Callback { - + void accept(Promise promise, Cancellable cancellable); } diff --git a/core/src/main/java/com/github/tonivade/purefun/data/Range.java b/core/src/main/java/com/github/tonivade/purefun/data/Range.java index 305869953..47b2cfc43 100644 --- a/core/src/main/java/com/github/tonivade/purefun/data/Range.java +++ b/core/src/main/java/com/github/tonivade/purefun/data/Range.java @@ -4,45 +4,25 @@ */ package com.github.tonivade.purefun.data; -import com.github.tonivade.purefun.Equal; import com.github.tonivade.purefun.Function1; import com.github.tonivade.purefun.Tuple; -import java.io.Serial; -import java.io.Serializable; import java.util.Iterator; -import java.util.Objects; import java.util.stream.IntStream; import java.util.stream.Stream; import static com.github.tonivade.purefun.Function1.identity; +import static com.github.tonivade.purefun.Precondition.check; +import static com.github.tonivade.purefun.Precondition.greaterThanOrEquals; import static com.github.tonivade.purefun.type.Validation.mapN; import static com.github.tonivade.purefun.type.Validation.requireGreaterThanOrEqual; import static com.github.tonivade.purefun.type.Validation.requireLowerThan; import static com.github.tonivade.purefun.type.Validation.requireLowerThanOrEqual; -public final class Range implements Iterable, Serializable { +public record Range(int begin, int end) implements Iterable { - @Serial - private static final long serialVersionUID = 7923835507243835436L; - - private static final Equal EQUAL = - Equal.of().comparing(x -> x.begin).comparing(x -> x.end); - - private final int begin; - private final int end; - - private Range(int begin, int end) { - this.begin = begin; - this.end = end; - } - - public int begin() { - return begin; - } - - public int end() { - return end; + public Range { + check(greaterThanOrEquals(end, begin)); } public boolean contains(int value) { @@ -76,16 +56,6 @@ public Iterator iterator() { return intStream().iterator(); } - @Override - public boolean equals(Object obj) { - return EQUAL.applyTo(this, obj); - } - - @Override - public int hashCode() { - return Objects.hash(begin, end); - } - @Override public String toString() { return String.format("Range(%d..%d)", begin, end); diff --git a/core/src/main/java/com/github/tonivade/purefun/type/Const.java b/core/src/main/java/com/github/tonivade/purefun/type/Const.java index 4fe994183..a8050bd01 100644 --- a/core/src/main/java/com/github/tonivade/purefun/type/Const.java +++ b/core/src/main/java/com/github/tonivade/purefun/type/Const.java @@ -6,28 +6,13 @@ import static com.github.tonivade.purefun.Precondition.checkNonNull; -import java.io.Serial; -import java.io.Serializable; -import java.util.Objects; -import com.github.tonivade.purefun.Equal; import com.github.tonivade.purefun.HigherKind; @HigherKind -public final class Const implements ConstOf, Serializable { +public record Const(T value) implements ConstOf { - @Serial - private static final long serialVersionUID = 7431389527943145565L; - - private static final Equal> EQUAL = Equal.>of().comparing(Const::get); - - private final T value; - - private Const(T value) { - this.value = checkNonNull(value); - } - - public T get() { - return value; + public Const { + checkNonNull(value); } @SuppressWarnings("unchecked") @@ -35,16 +20,6 @@ public Const retag() { return (Const) this; } - @Override - public int hashCode() { - return Objects.hash(value); - } - - @Override - public boolean equals(Object obj) { - return EQUAL.applyTo(this, obj); - } - @Override public String toString() { return "Const(" + value + ")"; diff --git a/core/src/main/java/com/github/tonivade/purefun/type/Either.java b/core/src/main/java/com/github/tonivade/purefun/type/Either.java index d099b4b93..53e0d0352 100644 --- a/core/src/main/java/com/github/tonivade/purefun/type/Either.java +++ b/core/src/main/java/com/github/tonivade/purefun/type/Either.java @@ -8,13 +8,9 @@ import static com.github.tonivade.purefun.Function1.identity; import static com.github.tonivade.purefun.Precondition.checkNonNull; -import java.io.Serial; -import java.io.Serializable; import java.util.NoSuchElementException; -import java.util.Objects; import java.util.stream.Stream; -import com.github.tonivade.purefun.Equal; import com.github.tonivade.purefun.Function1; import com.github.tonivade.purefun.Function2; import com.github.tonivade.purefun.HigherKind; @@ -51,12 +47,14 @@ static Either right(R value) { boolean isLeft(); boolean isRight(); + /** * Returns the left value if available. If not, it throws {@code NoSuchElementException} * @return the left value * @throws NoSuchElementException if left value is not available */ L getLeft(); + /** * Returns the right value if available. If not, it throws {@code NoSuchElementException} * @return the right value @@ -65,38 +63,38 @@ static Either right(R value) { R getRight(); default R get() { - if (isRight()) { - return getRight(); + if (this instanceof Right(var right)) { + return right; } throw new NoSuchElementException("get() on left"); } default Option left() { - if (isLeft()) { - return Option.some(getLeft()); + if (this instanceof Left(var left)) { + return Option.some(left); } return Option.none(); } default Option right() { - if (isRight()) { - return Option.some(getRight()); + if (this instanceof Right(var right)) { + return Option.some(right); } return Option.none(); } default Either swap() { - if (isRight()) { - return left(getRight()); - } - return right(getLeft()); + return switch (this) { + case Right(var right) -> left(right); + case Left(var left) -> right(left); + }; } default Either bimap(Function1 leftMapper, Function1 rightMapper) { - if (isRight()) { - return right(rightMapper.apply(getRight())); - } - return left(leftMapper.apply(getLeft())); + return switch (this) { + case Right(var right) -> right(rightMapper.apply(right)); + case Left(var left) -> left(leftMapper.apply(left)); + }; } @Override @@ -111,22 +109,22 @@ default Either mapLeft(Function1 map) { @Override @SuppressWarnings("unchecked") default Either flatMap(Function1, ? extends T>> map) { - if (isRight()) { - return map.andThen(EitherOf::narrowK).apply(getRight()); + if (this instanceof Right(var right)) { + return map.andThen(EitherOf::narrowK).apply(right); } return (Either) this; } @SuppressWarnings("unchecked") default Either flatMapLeft(Function1> map) { - if (isLeft()) { - return (Either) map.apply(getLeft()); + if (this instanceof Left(var left)) { + return (Either) map.apply(left); } return (Either) this; } default Option> filter(Matcher1 matcher) { - if (isRight() && matcher.match(getRight())) { + if (this instanceof Right(var right) && matcher.match(right)) { return Option.some(this); } return Option.none(); @@ -137,14 +135,17 @@ default Option> filterNot(Matcher1 matcher) { } default Either filterOrElse(Matcher1 matcher, Producer, R>> orElse) { - if (isLeft() || matcher.match(getRight())) { + if (this instanceof Left) { + return this; + } + if (this instanceof Right(var right) && matcher.match(right)) { return this; } return orElse.andThen(EitherOf::narrowK).get(); } default Either or(Producer, R>> orElse) { - if (isLeft()) { + if (this instanceof Left) { return orElse.andThen(EitherOf::narrowK).get(); } return this; @@ -167,10 +168,10 @@ default R getOrElse(Producer orElse) { } default T fold(Function1 leftMapper, Function1 rightMapper) { - if (isRight()) { - return rightMapper.apply(getRight()); - } - return leftMapper.apply(getLeft()); + return switch (this) { + case Right(var right) -> rightMapper.apply(right); + case Left(var left) -> leftMapper.apply(left); + }; } default Stream stream() { @@ -188,28 +189,21 @@ default Option toOption() { default Validation toValidation() { return fold(Validation::invalid, Validation::valid); } - + static A merge(Either either) { return either.fold(identity(), identity()); } static Either map2( - Either eitherA, Either eitherB, + Either eitherA, Either eitherB, Function2 mapper) { return eitherA.flatMap(a -> eitherB.map(b -> mapper.apply(a, b))); } - final class Left implements Either, Serializable { - - @Serial - private static final long serialVersionUID = 7040154642166638129L; - - private static final Equal> EQUAL = Equal.>of().comparing(Left::getLeft); + record Left(L value) implements Either { - private final L value; - - private Left(L value) { - this.value = checkNonNull(value); + public Left { + checkNonNull(value); } @Override @@ -232,33 +226,16 @@ public R getRight() { throw new NoSuchElementException("getRight() in left"); } - @Override - public int hashCode() { - return Objects.hash(value); - } - - @Override - public boolean equals(Object obj) { - return EQUAL.applyTo(this, obj); - } - @Override public String toString() { return "Left(" + value + ")"; } } - final class Right implements Either, Serializable { - - @Serial - private static final long serialVersionUID = 164989996450592091L; - - private static final Equal> EQUAL = Equal.>of().comparing(Right::getRight); - - private final R value; + record Right(R value) implements Either { - private Right(R value) { - this.value = checkNonNull(value); + public Right { + checkNonNull(value); } @Override @@ -281,16 +258,6 @@ public R getRight() { return value; } - @Override - public int hashCode() { - return Objects.hash(value); - } - - @Override - public boolean equals(Object obj) { - return EQUAL.applyTo(this, obj); - } - @Override public String toString() { return "Right(" + value + ")"; diff --git a/core/src/main/java/com/github/tonivade/purefun/type/Id.java b/core/src/main/java/com/github/tonivade/purefun/type/Id.java index ab552ca6b..b1be04da3 100644 --- a/core/src/main/java/com/github/tonivade/purefun/type/Id.java +++ b/core/src/main/java/com/github/tonivade/purefun/type/Id.java @@ -6,11 +6,6 @@ import static com.github.tonivade.purefun.Precondition.checkNonNull; -import java.io.Serial; -import java.io.Serializable; -import java.util.Objects; - -import com.github.tonivade.purefun.Equal; import com.github.tonivade.purefun.Function1; import com.github.tonivade.purefun.HigherKind; import com.github.tonivade.purefun.Kind; @@ -23,17 +18,10 @@ * @param the wrapped value */ @HigherKind -public final class Id implements IdOf, Bindable, Serializable { - - @Serial - private static final long serialVersionUID = -6295106408421985189L; - - private static final Equal> EQUAL = Equal.>of().comparing(Id::get); +public record Id(T value) implements IdOf, Bindable { - private final T value; - - private Id(T value) { - this.value = checkNonNull(value); + public Id { + checkNonNull(value); } @Override @@ -46,20 +34,6 @@ public Id flatMap(Function1> return map.andThen(IdOf::narrowK).apply(value); } - public T get() { - return value; - } - - @Override - public int hashCode() { - return Objects.hash(value); - } - - @Override - public boolean equals(Object obj) { - return EQUAL.applyTo(this, obj); - } - @Override public String toString() { return "Id(" + value + ")"; diff --git a/core/src/main/java/com/github/tonivade/purefun/type/Option.java b/core/src/main/java/com/github/tonivade/purefun/type/Option.java index 0eedded29..1b0b93845 100644 --- a/core/src/main/java/com/github/tonivade/purefun/type/Option.java +++ b/core/src/main/java/com/github/tonivade/purefun/type/Option.java @@ -9,21 +9,19 @@ import static com.github.tonivade.purefun.Producer.cons; import static java.util.Objects.nonNull; -import java.io.Serial; import java.io.Serializable; import java.util.NoSuchElementException; -import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; import com.github.tonivade.purefun.Consumer1; -import com.github.tonivade.purefun.Equal; import com.github.tonivade.purefun.Function1; import com.github.tonivade.purefun.Function2; import com.github.tonivade.purefun.HigherKind; import com.github.tonivade.purefun.Kind; import com.github.tonivade.purefun.Bindable; import com.github.tonivade.purefun.Matcher1; +import com.github.tonivade.purefun.Nothing; import com.github.tonivade.purefun.Producer; import com.github.tonivade.purefun.data.Sequence; @@ -70,36 +68,36 @@ static Option map2(Option optionA, Option optionB, Function2< @Override default Option map(Function1 mapper) { - if (this instanceof Some s) { - return some(mapper.apply(s.value)); - } - return none(); + return switch (this) { + case Some(var value) -> some(mapper.apply(value)); + case None n -> none(); + }; } @Override default Option flatMap(Function1> map) { - if (this instanceof Some s) { - return map.andThen(OptionOf::narrowK).apply(s.value); - } - return none(); + return switch (this) { + case Some(var value) -> map.andThen(OptionOf::narrowK).apply(value); + case None n -> none(); + }; } default Option ifPresent(Consumer1 consumer) { - if (this instanceof Some s) { - consumer.accept(s.value); + if (this instanceof Some(var value)) { + consumer.accept(value); } return this; } default Option ifEmpty(Runnable run) { - if (this instanceof None) { + if (this instanceof None) { run.run(); } return this; } default Option filter(Matcher1 matcher) { - if (this instanceof Some s && matcher.match(s.value)) { + if (this instanceof Some(var value) && matcher.match(value)) { return this; } return none(); @@ -115,7 +113,7 @@ default Option or(Producer> orElse) { } return this; } - + default Option orElse(Kind orElse) { return or(cons(orElse)); } @@ -133,24 +131,21 @@ default T getOrElse(Producer producer) { } default T getOrElseThrow() { - if (this instanceof Some s) { - return s.value; - } - throw new NoSuchElementException(); + return getOrElseThrow(NoSuchElementException::new); } default T getOrElseThrow(Producer producer) throws X { - if (this instanceof Some s) { - return s.value; + if (this instanceof Some(var value)) { + return value; } throw producer.get(); } default U fold(Producer orElse, Function1 mapper) { - if (this instanceof Some s) { - return mapper.apply(s.value); - } - return orElse.get(); + return switch (this) { + case Some(var value) -> mapper.apply(value); + case None n -> orElse.get(); + }; } default Stream stream() { @@ -173,17 +168,10 @@ default Try toTry() { return Try.fromEither(toEither()); } - final class Some implements Option, Serializable { - - @Serial - private static final long serialVersionUID = 7757183287962895363L; - - private static final Equal> EQUAL = Equal.>of().comparing(s -> s.value); - - private final T value; + record Some(T value) implements Option, Serializable { - private Some(T value) { - this.value = checkNonNull(value); + public Some { + checkNonNull(value); } @Override @@ -196,30 +184,14 @@ public boolean isPresent() { return true; } - @Override - public int hashCode() { - return Objects.hash(value); - } - - @Override - public boolean equals(Object obj) { - return EQUAL.applyTo(this, obj); - } - @Override public String toString() { return "Some(" + value + ")"; } } - final class None implements Option, Serializable { - - @Serial - private static final long serialVersionUID = 7202112931010040785L; - - private static final None INSTANCE = new None<>(); - - private None() { } + enum None implements Option { + INSTANCE; @Override public boolean isEmpty() { @@ -231,24 +203,9 @@ public boolean isPresent() { return false; } - @Override - public int hashCode() { - return 1; - } - - @Override - public boolean equals(Object obj) { - return this == obj; - } - @Override public String toString() { return "None"; } - - @Serial - private Object readResolve() { - return INSTANCE; - } } } diff --git a/core/src/main/java/com/github/tonivade/purefun/type/Try.java b/core/src/main/java/com/github/tonivade/purefun/type/Try.java index fa96a0967..e3039be65 100644 --- a/core/src/main/java/com/github/tonivade/purefun/type/Try.java +++ b/core/src/main/java/com/github/tonivade/purefun/type/Try.java @@ -8,8 +8,6 @@ import static com.github.tonivade.purefun.Function1.identity; import static com.github.tonivade.purefun.Precondition.checkNonNull; -import java.io.Serial; -import java.io.Serializable; import java.util.Arrays; import java.util.NoSuchElementException; import java.util.Objects; @@ -23,6 +21,7 @@ import com.github.tonivade.purefun.Kind; import com.github.tonivade.purefun.Bindable; import com.github.tonivade.purefun.Matcher1; +import com.github.tonivade.purefun.Nothing; import com.github.tonivade.purefun.Producer; import com.github.tonivade.purefun.Recoverable; import com.github.tonivade.purefun.data.ImmutableList; @@ -53,8 +52,9 @@ static Try failure() { return failure(new RuntimeException()); } + @SuppressWarnings("unchecked") static Try failure(Throwable error) { - return new Failure<>(error); + return (Try) new Failure(error); } static Try noSuchElementException() { @@ -120,48 +120,46 @@ default Try map(Function1 mapper) { } default Try mapError(Function1 mapper) { - if (this instanceof Failure f) { - return failure(mapper.apply(f.cause)); - } - return this; + return switch (this) { + case Failure(var cause) -> failure(mapper.apply(cause)); + case Success s -> this; + }; } @Override @SuppressWarnings("unchecked") default Try flatMap(Function1> mapper) { - if (this instanceof Success s) { - return mapper.andThen(TryOf::narrowK).apply(s.value); - } - return (Try) this; + return switch (this) { + case Success(var value) -> mapper.andThen(TryOf::narrowK).apply(value); + case Failure f -> (Try) this; + }; } default Try onFailure(Consumer1 consumer) { - if (this instanceof Failure f) { - consumer.accept(f.cause); + if (this instanceof Failure(var cause)) { + consumer.accept(cause); } return this; } default Try onSuccess(Consumer1 consumer) { - if (this instanceof Success s) { - consumer.accept(s.value); + if (this instanceof Success(var value)) { + consumer.accept(value); } return this; } default Try recover(Function1 mapper) { - if (this instanceof Failure f) { - return Try.of(() -> mapper.apply(f.cause)); + if (this instanceof Failure(var cause)) { + return Try.of(() -> mapper.apply(cause)); } return this; } @SuppressWarnings("unchecked") default Try recoverWith(Class type, Function1 mapper) { - if (this instanceof Failure f) { - if (type.isAssignableFrom(f.cause.getClass())) { - return Try.of(() -> mapper.apply((X) getCause())); - } + if (this instanceof Failure(var cause) && type.isAssignableFrom(cause.getClass())) { + return Try.of(() -> mapper.apply((X) cause)); } return this; } @@ -175,17 +173,20 @@ default Try filterNot(Matcher1 matcher) { } default Try filterOrElse(Matcher1 matcher, Producer> producer) { - if (this instanceof Failure || (this instanceof Success s && matcher.match(s.value))) { + if (this instanceof Failure) { + return this; + } + if (this instanceof Success(var value) && matcher.match(value)) { return this; } return producer.andThen(TryOf::narrowK).get(); } default U fold(Function1 failureMapper, Function1 successMapper) { - if (this instanceof Success s) { - return successMapper.apply(s.value); - } - return failureMapper.apply(getCause()); + return switch (this) { + case Success(var value) -> successMapper.apply(value); + case Failure(var cause) -> failureMapper.apply(cause); + }; } default Try or(Producer> orElse) { @@ -212,8 +213,8 @@ default T getOrElse(Producer producer) { } default T getOrElseThrow(Producer producer) throws X { - if (this instanceof Success s) { - return s.value; + if (this instanceof Success(var value)) { + return value; } throw producer.get(); } @@ -238,17 +239,10 @@ default Validation toValidation(Function1 implements Try, Serializable { - - @Serial - private static final long serialVersionUID = -3934628369477099278L; - - private static final Equal> EQUAL = Equal.>of().comparing(s -> s.value); - - private final T value; + record Success(T value) implements Try { - private Success(T value) { - this.value = checkNonNull(value); + public Success { + checkNonNull(value); } @Override @@ -271,34 +265,19 @@ public Throwable getCause() { throw new NoSuchElementException("success doesn't have any cause"); } - @Override - public int hashCode() { - return Objects.hash(value); - } - - @Override - public boolean equals(Object obj) { - return EQUAL.applyTo(this, obj); - } - @Override public String toString() { return "Success(" + value + ")"; } } - final class Failure implements Try, Serializable, Recoverable { + record Failure(Throwable cause) implements Try, Recoverable { - @Serial - private static final long serialVersionUID = -8155444386075553318L; + private static final Equal EQUAL = + Equal.of().comparing(Failure::getMessage).comparingArray(Failure::getStackTrace); - private static final Equal> EQUAL = - Equal.>of().comparing(Failure::getMessage).comparingArray(Failure::getStackTrace); - - private final Throwable cause; - - private Failure(Throwable cause) { - this.cause = checkNonNull(cause); + public Failure { + checkNonNull(cause); } @Override @@ -312,7 +291,7 @@ public boolean isSuccess() { } @Override - public T getOrElseThrow() { + public Nothing getOrElseThrow() { return sneakyThrow(cause); } diff --git a/core/src/main/java/com/github/tonivade/purefun/type/Validation.java b/core/src/main/java/com/github/tonivade/purefun/type/Validation.java index eb84a776d..e311b9016 100644 --- a/core/src/main/java/com/github/tonivade/purefun/type/Validation.java +++ b/core/src/main/java/com/github/tonivade/purefun/type/Validation.java @@ -83,20 +83,20 @@ static Validation, T> invalidOf(E error, E... errors) { @Override @SuppressWarnings("unchecked") default Validation map(Function1 mapper) { - if (this instanceof Valid v) { - return valid(mapper.apply(v.value)); + if (this instanceof Valid(var value)) { + return valid(mapper.apply(value)); } return (Validation) this; } @SuppressWarnings("unchecked") default Validation mapError(Function1 mapper) { - if (this instanceof Invalid v) { - return invalid(mapper.apply(v.error)); + if (this instanceof Invalid(var error)) { + return invalid(mapper.apply(error)); } return (Validation) this; } - + default Validation bimap(Function1 error, Function1 mapper) { Validation mapError = mapError(error); return mapError.map(mapper); @@ -105,14 +105,17 @@ default Validation bimap(Function1 error, @Override @SuppressWarnings("unchecked") default Validation flatMap(Function1, ? extends R>> mapper) { - if (this instanceof Valid v) { - return mapper.andThen(ValidationOf::narrowK).apply(v.value); + if (this instanceof Valid(var value)) { + return mapper.andThen(ValidationOf::narrowK).apply(value); } return (Validation) this; } default Option> filter(Matcher1 matcher) { - if (this instanceof Invalid || (this instanceof Valid v && matcher.match(v.value))) { + if (this instanceof Invalid) { + return Option.some(this); + } + if (this instanceof Valid(var value) && matcher.match(value)) { return Option.some(this); } return Option.none(); @@ -123,7 +126,10 @@ default Option> filterNot(Matcher1 matcher) { } default Validation filterOrElse(Matcher1 matcher, Producer, T>> orElse) { - if (this instanceof Invalid || (this instanceof Valid v && matcher.match(v.value))) { + if (this instanceof Invalid) { + return this; + } + if (this instanceof Valid(var value) && matcher.match(value)) { return this; } return orElse.andThen(ValidationOf::narrowK).get(); @@ -157,18 +163,18 @@ default T getOrElseThrow() { } default T getOrElseThrow(Function1 mapper) throws X { - if (this instanceof Valid v) { - return v.value; + if (this instanceof Valid(var value)) { + return value; } throw mapper.apply(getError()); } default U fold(Function1 invalidMap, Function1 validMap) { - if (this instanceof Valid v) { - return validMap.apply(v.value); + if (this instanceof Valid(var value)) { + return validMap.apply(value); } - if (this instanceof Invalid i) { - return invalidMap.apply(i.error); + if (this instanceof Invalid(var error)) { + return invalidMap.apply(error); } throw new UnsupportedOperationException(); } @@ -256,17 +262,10 @@ static Validation requireLowerThanOrEqual(Integer value, int x) return nonNullAnd(lowerThanOrEqual(x, () -> "require " + value + " <= " + x)).validate(value); } - final class Valid implements Validation, Serializable { + record Valid(T value) implements Validation { - @Serial - private static final long serialVersionUID = -4276395187736455243L; - - private static final Equal> EQUAL = Equal.>of().comparing(Valid::get); - - private final T value; - - private Valid(T value) { - this.value = checkNonNull(value); + public Valid { + checkNonNull(value); } @Override @@ -289,33 +288,16 @@ public E getError() { throw new NoSuchElementException("valid value"); } - @Override - public int hashCode() { - return Objects.hash(value); - } - - @Override - public boolean equals(Object obj) { - return EQUAL.applyTo(this, obj); - } - @Override public String toString() { return "Valid(" + value + ")"; } } - final class Invalid implements Validation, Serializable { + record Invalid(E error) implements Validation { - @Serial - private static final long serialVersionUID = -5116403366555721062L; - - private static final Equal> EQUAL = Equal.>of().comparing(Invalid::getError); - - private final E error; - - private Invalid(E error) { - this.error = Objects.requireNonNull(error); + public Invalid { + checkNonNull(error); } @Override @@ -338,16 +320,6 @@ public E getError() { return error; } - @Override - public int hashCode() { - return Objects.hash(error); - } - - @Override - public boolean equals(Object obj) { - return EQUAL.applyTo(this, obj); - } - @Override public String toString() { return "Invalid(" + error + ")"; diff --git a/core/src/main/java21/com/github/tonivade/purefun/concurrent/DefaultExecutor.java b/core/src/main/java21/com/github/tonivade/purefun/concurrent/DefaultExecutor.java deleted file mode 100644 index 0fd594893..000000000 --- a/core/src/main/java21/com/github/tonivade/purefun/concurrent/DefaultExecutor.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c) 2018-2023, Antonio Gabriel Muñoz Conejo - * Distributed under the terms of the MIT License - */ -package com.github.tonivade.purefun.concurrent; - -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -final class DefaultExecutor { - - static final Executor EXECUTOR = Executors.newVirtualThreadPerTaskExecutor(); -} diff --git a/core/src/test/java/com/github/tonivade/purefun/concurrent/FutureTest.java b/core/src/test/java/com/github/tonivade/purefun/concurrent/FutureTest.java index 149d36d94..3211da21f 100644 --- a/core/src/test/java/com/github/tonivade/purefun/concurrent/FutureTest.java +++ b/core/src/test/java/com/github/tonivade/purefun/concurrent/FutureTest.java @@ -294,6 +294,6 @@ public void noDeadlock() { } private Future currentThread(Executor executor, List result) { - return Future.exec(executor, () -> result.add(Thread.currentThread().getName())); + return Future.exec(executor, () -> result.add("thread-" + Thread.currentThread().threadId())); } } diff --git a/core/src/test/java/com/github/tonivade/purefun/concurrent/ParTest.java b/core/src/test/java/com/github/tonivade/purefun/concurrent/ParTest.java index d69eb21d0..99f80959d 100644 --- a/core/src/test/java/com/github/tonivade/purefun/concurrent/ParTest.java +++ b/core/src/test/java/com/github/tonivade/purefun/concurrent/ParTest.java @@ -15,6 +15,7 @@ import static org.mockito.Mockito.verify; import java.time.Duration; import java.util.List; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; @@ -42,7 +43,7 @@ public void onSuccess(@Mock Consumer1 consumerSuccess) { @Test public void onFailure(@Mock Consumer1 consumerFailure) { - UnsupportedOperationException error = new UnsupportedOperationException(); + var error = new UnsupportedOperationException(); Par par = Par.failure(error).onFailure(consumerFailure); Try result = par.apply(Future.DEFAULT_EXECUTOR).await(); @@ -144,13 +145,13 @@ public void sleep() { } private String currentThread() throws InterruptedException { - String name = Thread.currentThread().getName(); + var id = "thread-" + Thread.currentThread().threadId(); Thread.sleep(100); - return name; + return id; } private void currentThread(Consumer1 consumer) throws InterruptedException { - consumer.accept(Thread.currentThread().getName()); + consumer.accept("thread-" + Thread.currentThread().threadId()); Thread.sleep(100); } } \ No newline at end of file diff --git a/core/src/test/java/com/github/tonivade/purefun/data/RangeTest.java b/core/src/test/java/com/github/tonivade/purefun/data/RangeTest.java index 7b749c5a2..546a70c6a 100644 --- a/core/src/test/java/com/github/tonivade/purefun/data/RangeTest.java +++ b/core/src/test/java/com/github/tonivade/purefun/data/RangeTest.java @@ -4,14 +4,11 @@ */ package com.github.tonivade.purefun.data; +import static org.junit.jupiter.api.Assertions.*; + import org.junit.jupiter.api.Test; import static com.github.tonivade.purefun.data.Sequence.arrayOf; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; public class RangeTest { @@ -31,4 +28,9 @@ public void range() { () -> assertEquals(arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9), range.collect()) ); } + + @Test + public void validRange() { + assertThrows(IllegalArgumentException.class, () -> Range.of(10, 1)); + } } \ No newline at end of file diff --git a/core/src/test/java/com/github/tonivade/purefun/type/ConstTest.java b/core/src/test/java/com/github/tonivade/purefun/type/ConstTest.java index 944ce55f4..4fd7fcfa3 100644 --- a/core/src/test/java/com/github/tonivade/purefun/type/ConstTest.java +++ b/core/src/test/java/com/github/tonivade/purefun/type/ConstTest.java @@ -17,6 +17,6 @@ public void retag() { Const retag = val.retag(); assertEquals(retag, val); - assertEquals(retag.get(), val.get()); + assertEquals(retag.value(), val.value()); } } diff --git a/core/src/test/java/com/github/tonivade/purefun/type/IdTest.java b/core/src/test/java/com/github/tonivade/purefun/type/IdTest.java index 6fd438196..37c72e373 100644 --- a/core/src/test/java/com/github/tonivade/purefun/type/IdTest.java +++ b/core/src/test/java/com/github/tonivade/purefun/type/IdTest.java @@ -20,7 +20,7 @@ public void idTest() { Id id = Id.of("hola mundo!"); assertAll( - () -> assertEquals("hola mundo!", id.get()), + () -> assertEquals("hola mundo!", id.value()), () -> assertEquals(Id.of("HOLA MUNDO!"), id.map(toUpperCase)), () -> assertEquals(Id.of("HOLA MUNDO!"), id.flatMap(toUpperCase.andThen(Id::of)))); } diff --git a/effect/src/test/java/com/github/tonivade/purefun/effect/ZIOTest.java b/effect/src/test/java/com/github/tonivade/purefun/effect/ZIOTest.java index 0f0dcd33b..7c1f85b7c 100644 --- a/effect/src/test/java/com/github/tonivade/purefun/effect/ZIOTest.java +++ b/effect/src/test/java/com/github/tonivade/purefun/effect/ZIOTest.java @@ -40,27 +40,27 @@ @ExtendWith(MockitoExtension.class) public class ZIOTest { - + @Test public void recover() { PureIO ups = PureIO.fromEither(() -> { throw new RuntimeException("ups!"); }); - + assertEquals("ups!", PureIO.redeem(ups).provide(nothing()).getLeft().getMessage()); } - + @Test public void accessM() { PureIO access = PureIO.access(a -> a.toUpperCase()); - + assertEquals(Either.right("HELLO WORLD"), access.provide("hello world")); } - + @Test public void pure() { Either result = PureIO.pure("hello world").provide(nothing()); - + assertEquals(Either.right("hello world"), result); } @@ -81,38 +81,38 @@ public void swapLeft() { @Test public void swapRight() { Either result = PureIO.pure("value").swap().provide(nothing()); - + assertEquals(Either.left("value"), result); } - + @Test public void task() { Either result = PureIO.task(() -> "hello world").provide(nothing()); assertEquals(Either.right("hello world"), result); } - + @Test public void laterRight() { Either result = PureIO.fromEither(() -> Either.right("hello world")).provide(nothing()); assertEquals(Either.right("hello world"), result); } - + @Test public void laterLeft() { Either result = PureIO.fromEither(() -> Either.left("hello world")).provide(nothing()); assertEquals(Either.left("hello world"), result); } - + @Test public void deferRight() { Either result = PureIO.defer(() -> PureIO.pure("hello world")).provide(nothing()); assertEquals(Either.right("hello world"), result); } - + @Test public void deferLeft() { Either result = PureIO.defer(() -> PureIO.raiseError("hello world")).provide(nothing()); @@ -225,28 +225,28 @@ public void bracket(@Mock ResultSet resultSet) throws SQLException { assertEquals(Either.right("value"), bracket.provide(nothing())); verify(resultSet).close(); } - + @Test public void asyncSuccess() { PureIO async = PureIO.async((env, callback) -> { Thread.sleep(100); callback.accept(Try.success(Either.right("1"))); }); - + Either result = async.provide(nothing()); - + assertEquals("1", result.get()); } - + @Test public void asyncFailure() { PureIO async = PureIO.async((env, callback) -> { Thread.sleep(100); callback.accept(Try.success(Either.left(new UnsupportedOperationException()))); }); - + Either result = async.provide(nothing()); - + assertTrue(result.getLeft() instanceof UnsupportedOperationException); } @@ -254,7 +254,7 @@ public void asyncFailure() { public void safeRunAsync() { Ref> ref = Ref.of(ImmutableList.empty()); UIO> currentThread = - ref.updateAndGet(list -> list.append(Thread.currentThread().getName())); + ref.updateAndGet(list -> list.append("thread-" + Thread.currentThread().threadId())); UIO> program = currentThread .andThen(currentThread @@ -324,13 +324,13 @@ public void repeatFailure(@Mock Producer> co assertTrue(provide.isLeft()); verify(computation, times(4)).get(); } - + @Test public void timed() { PureIO> timed = PureIO.sleep(Duration.ofMillis(100)).timed(); - + Either> provide = timed.provide(nothing()); - + assertTrue(provide.getRight().get1().toMillis() >= 100); } @@ -354,48 +354,48 @@ public void stackSafety() { assertEquals(705082704, sum.unsafeRunSync()); assertEquals(Try.success(705082704), futureSum.await()); } - + @Test public void refineOrDie() { PureIO error = PureIO.raiseError(new IOException()); - + PureIO refine = error.refineOrDie(IOException.class); PureIO die = error.refineOrDie(UnsupportedOperationException.class); - + assertEquals(IOException.class, refine.provide(nothing()).getLeft().getClass()); assertThrows(ClassCastException.class, () -> die.provide(nothing())); } - + @Test public void toURIO() { PureIO unsupported = PureIO.raiseError(3); PureIO error = PureIO.raiseError(new IOException()); PureIO success = PureIO.pure("hola"); - + assertEquals("hola", success.toURIO().unsafeRunSync(nothing())); assertThrows(IOException.class, () -> error.toURIO().unsafeRunSync(nothing())); assertThrows(ClassCastException.class, () -> unsupported.toURIO().unsafeRunSync(nothing())); } - + @Test public void toRIO() { PureIO unsupported = PureIO.raiseError(3); IOException exception = new IOException(); PureIO error = PureIO.raiseError(exception); PureIO success = PureIO.pure("hola"); - + assertEquals(Try.success("hola"), success.toRIO().safeRunSync(nothing())); assertEquals(Try.failure(exception), error.toRIO().safeRunSync(nothing())); assertThrows(ClassCastException.class, () -> unsupported.toRIO().safeRunSync(nothing())); } - + @Test public void traverse() { PureIO left = PureIO.task(() -> "left"); PureIO right = PureIO.task(() -> "right"); - + PureIO> traverse = PureIO.traverse(listOf(left, right)); - + assertEquals(Either.right(listOf("left", "right")), traverse.provide(nothing())); } @@ -404,9 +404,9 @@ public void raceA() { PureIO> race = PureIO.race( PureIO.sleep(Duration.ofMillis(10)).map(x -> 10), PureIO.sleep(Duration.ofMillis(100)).map(x -> "b")); - + Either orElseThrow = race.provide(nothing()).get(); - + assertEquals(Either.left(10), orElseThrow); } @@ -415,12 +415,12 @@ public void raceB() { PureIO> race = PureIO.race( PureIO.sleep(Duration.ofMillis(100)).map(x -> 10), PureIO.sleep(Duration.ofMillis(10)).map(x -> "b")); - + Either orElseThrow = race.provide(nothing()).get(); - + assertEquals(Either.right("b"), orElseThrow); } - + @Test public void fork() { PureIO result = For.with(PureIOInstances.monad()) @@ -431,17 +431,17 @@ public void fork() { return sleep.andThen(task).fork(); }) .flatMap(Fiber::join).fix(toPureIO()); - + Either orElseThrow = result.runAsync(nothing()).getOrElseThrow(); assertEquals(Either.right("hola toni"), orElseThrow); } - + @Test public void timeoutFail() { assertThrows(TimeoutException.class, () -> PureIO.never().timeout(Duration.ofSeconds(1)).provide(nothing())); } - + @Test public void timeoutSuccess() { assertEquals(Either.right(1), PureIO.pure(1).timeout(Duration.ofSeconds(1)).provide(nothing())); diff --git a/free/src/main/java/com/github/tonivade/purefun/free/FreeAp.java b/free/src/main/java/com/github/tonivade/purefun/free/FreeAp.java index 4ea3d8e8b..609ab5d77 100644 --- a/free/src/main/java/com/github/tonivade/purefun/free/FreeAp.java +++ b/free/src/main/java/com/github/tonivade/purefun/free/FreeAp.java @@ -48,7 +48,7 @@ default FreeAp flatCompile( } default M analyze(FunctionK> functionK, Applicative> applicative) { - return foldMap(functionK, applicative).fix(toConst()).get(); + return foldMap(functionK, applicative).fix(toConst()).value(); } default Free monad() { diff --git a/free/src/test/java/com/github/tonivade/purefun/free/CofreeTest.java b/free/src/test/java/com/github/tonivade/purefun/free/CofreeTest.java index 0ed444a42..af91128ed 100644 --- a/free/src/test/java/com/github/tonivade/purefun/free/CofreeTest.java +++ b/free/src/test/java/com/github/tonivade/purefun/free/CofreeTest.java @@ -45,7 +45,7 @@ public void testMap() { .flatMap(Cofree::tailForced) .tuple().fix(toId()); - assertEquals(Tuple.of(2, 4, 6, 8), tuple4Id.get().map(Cofree::extract, Cofree::extract, Cofree::extract, Cofree::extract)); + assertEquals(Tuple.of(2, 4, 6, 8), tuple4Id.value().map(Cofree::extract, Cofree::extract, Cofree::extract, Cofree::extract)); } @Test diff --git a/free/src/test/java/com/github/tonivade/purefun/free/FreeApTest.java b/free/src/test/java/com/github/tonivade/purefun/free/FreeApTest.java index 7c3d7d354..03d26f732 100644 --- a/free/src/test/java/com/github/tonivade/purefun/free/FreeApTest.java +++ b/free/src/test/java/com/github/tonivade/purefun/free/FreeApTest.java @@ -94,7 +94,7 @@ public void compile() { FreeAp compile = readInt.compile(idTransform()); Id fold = compile.fold(IdInstances.applicative()).fix(toId()); - assertEquals(5, fold.get()); + assertEquals(5, fold.value()); } @Test diff --git a/gradle.properties b/gradle.properties index 74dff2a44..97c70d49d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,2 @@ -version=4.3-SNAPSHOT +version=5.0-SNAPSHOT +systemProp.sonar.gradle.skipCompile=true \ No newline at end of file diff --git a/instances/src/main/java/com/github/tonivade/purefun/instances/ConstInstances.java b/instances/src/main/java/com/github/tonivade/purefun/instances/ConstInstances.java index 0b9571f03..908ee579d 100644 --- a/instances/src/main/java/com/github/tonivade/purefun/instances/ConstInstances.java +++ b/instances/src/main/java/com/github/tonivade/purefun/instances/ConstInstances.java @@ -25,7 +25,7 @@ public interface ConstInstances { static Eq, A>> eq(Eq eq) { - return (a, b) -> eq.eqv(a.fix(ConstOf::narrowK).get(), a.fix(ConstOf::narrowK).get()); + return (a, b) -> eq.eqv(a.fix(ConstOf::narrowK).value(), a.fix(ConstOf::narrowK).value()); } static Functor> functor() { @@ -78,8 +78,8 @@ default Const ap( Kind, ? extends A> value, Kind, ? extends Function1> apply) { return Const.of(monoid().combine( - apply.fix(ConstOf::narrowK).retag().get(), - value.fix(ConstOf::narrowK).retag().get())); + apply.fix(ConstOf::narrowK).retag().value(), + value.fix(ConstOf::narrowK).retag().value())); } } diff --git a/instances/src/main/java/com/github/tonivade/purefun/instances/EitherInstances.java b/instances/src/main/java/com/github/tonivade/purefun/instances/EitherInstances.java index 602a1feb8..e09ca74ef 100644 --- a/instances/src/main/java/com/github/tonivade/purefun/instances/EitherInstances.java +++ b/instances/src/main/java/com/github/tonivade/purefun/instances/EitherInstances.java @@ -29,11 +29,11 @@ public interface EitherInstances { static Eq, R>> eq(Eq leftEq, Eq rightEq) { return (a, b) -> { - if (a instanceof Either.Left leftA && b instanceof Either.Left leftB) { - return leftEq.eqv(leftA.getLeft(), leftB.getLeft()); + if (a instanceof Either.Left(var leftA) && b instanceof Either.Left(var leftB)) { + return leftEq.eqv(leftA, leftB); } - if (a instanceof Either.Right rightA && b instanceof Either.Right rightB) { - return rightEq.eqv(rightA.getRight(), rightB.getRight()); + if (a instanceof Either.Right(var rightA) && b instanceof Either.Right(var rightB)) { + return rightEq.eqv(rightA, rightB); } return false; }; @@ -162,7 +162,7 @@ default B foldLeft(Kind, ? extends A> value, B initial, default Eval foldRight(Kind, ? extends A> value, Eval initial, Function2, ? extends Eval> mapper) { return EitherOf.narrowK(value).fold( - cons(initial).andThen(EvalOf::narrowK), + cons(initial).andThen(EvalOf::narrowK), a -> mapper.andThen(EvalOf::narrowK).apply(a, initial)); } } diff --git a/instances/src/main/java/com/github/tonivade/purefun/instances/IdInstances.java b/instances/src/main/java/com/github/tonivade/purefun/instances/IdInstances.java index af4901cb1..506923479 100644 --- a/instances/src/main/java/com/github/tonivade/purefun/instances/IdInstances.java +++ b/instances/src/main/java/com/github/tonivade/purefun/instances/IdInstances.java @@ -26,7 +26,7 @@ public interface IdInstances { static Eq> eq(Eq idEq) { - return (a, b) -> idEq.eqv(IdOf.narrowK(a).get(), IdOf.narrowK(b).get()); + return (a, b) -> idEq.eqv(IdOf.narrowK(a).value(), IdOf.narrowK(b).value()); } static Functor functor() { @@ -104,7 +104,7 @@ default Kind coflatMap(Kind value, Function1 A extract(Kind value) { - return IdOf.narrowK(value).get(); + return IdOf.narrowK(value).value(); } } @@ -114,12 +114,12 @@ interface IdFoldable extends Foldable { @Override default B foldLeft(Kind value, B initial, Function2 mapper) { - return mapper.apply(initial, value.fix(toId()).get()); + return mapper.apply(initial, value.fix(toId()).value()); } @Override default Eval foldRight(Kind value, Eval initial, Function2, ? extends Eval> mapper) { - return EvalOf.narrowK(mapper.apply(value.fix(toId()).get(), initial)); + return EvalOf.narrowK(mapper.apply(value.fix(toId()).value(), initial)); } } @@ -131,7 +131,7 @@ interface IdTraverse extends Traverse, IdFoldable { default Kind> traverse( Applicative applicative, Kind value, Function1> mapper) { - Kind apply = mapper.apply(value.fix(toId()).get()); + Kind apply = mapper.apply(value.fix(toId()).value()); return applicative.map(apply, Id::of); } } diff --git a/instances/src/main/java/com/github/tonivade/purefun/instances/OptionInstances.java b/instances/src/main/java/com/github/tonivade/purefun/instances/OptionInstances.java index f0ba780d9..1741107ca 100644 --- a/instances/src/main/java/com/github/tonivade/purefun/instances/OptionInstances.java +++ b/instances/src/main/java/com/github/tonivade/purefun/instances/OptionInstances.java @@ -36,10 +36,10 @@ public interface OptionInstances { static Eq> eq(Eq eqSome) { return (a, b) -> { - if (a instanceof Option.Some someA && b instanceof Option.Some someB) { - return eqSome.eqv(someA.getOrElseThrow(), someB.getOrElseThrow()); + if (a instanceof Option.Some(var valueA) && b instanceof Option.Some(var valueB)) { + return eqSome.eqv(valueA, valueB); } - return a instanceof Option.None && b instanceof Option.None; + return a instanceof Option.None && b instanceof Option.None; }; } @@ -99,7 +99,7 @@ interface OptionApplicative extends OptionPure { OptionApplicative INSTANCE = new OptionApplicative() {}; @Override - default Kind ap(Kind value, + default Kind ap(Kind value, Kind> apply) { return value.fix(toOption()).flatMap(t -> OptionOf.narrowK(apply).map(f -> f.apply(t))); } diff --git a/instances/src/main/java/com/github/tonivade/purefun/instances/TryInstances.java b/instances/src/main/java/com/github/tonivade/purefun/instances/TryInstances.java index 14410b18e..de6c615f3 100644 --- a/instances/src/main/java/com/github/tonivade/purefun/instances/TryInstances.java +++ b/instances/src/main/java/com/github/tonivade/purefun/instances/TryInstances.java @@ -29,11 +29,11 @@ public interface TryInstances { static Eq> eq(Eq eqSuccess) { final Eq eqFailure = Eq.throwable(); return (a, b) -> { - if (a instanceof Try.Failure failureA && b instanceof Try.Failure failureB) { - return eqFailure.eqv(failureA.getCause(), failureB.getCause()); + if (a instanceof Try.Failure(var causeA) && b instanceof Try.Failure(var causeB)) { + return eqFailure.eqv(causeA, causeB); } - if (a instanceof Try.Success successA && b instanceof Try.Success successB) { - return eqSuccess.eqv(successA.getOrElseThrow(), successB.getOrElseThrow()); + if (a instanceof Try.Success(var valueA) && b instanceof Try.Success(var valueB)) { + return eqSuccess.eqv(valueA, valueB); } return false; }; @@ -91,7 +91,7 @@ interface TryApplicative extends TryPure { TryApplicative INSTANCE = new TryApplicative() {}; @Override - default Kind ap(Kind value, + default Kind ap(Kind value, Kind> apply) { return TryOf.narrowK(value).flatMap(t -> TryOf.narrowK(apply).map(f -> f.apply(t))); } @@ -142,7 +142,7 @@ default B foldLeft(Kind value, B initial, Function2 Eval foldRight(Kind value, Eval initial, Function2, ? extends Eval> mapper) { return TryOf.narrowK(value).fold( - cons(initial).andThen(EvalOf::narrowK), + cons(initial).andThen(EvalOf::narrowK), a -> mapper.andThen(EvalOf::narrowK).apply(a, initial)); } } diff --git a/instances/src/main/java/com/github/tonivade/purefun/instances/ValidationInstances.java b/instances/src/main/java/com/github/tonivade/purefun/instances/ValidationInstances.java index a6a3004ef..ff6b2c9ba 100644 --- a/instances/src/main/java/com/github/tonivade/purefun/instances/ValidationInstances.java +++ b/instances/src/main/java/com/github/tonivade/purefun/instances/ValidationInstances.java @@ -27,11 +27,11 @@ public interface ValidationInstances { static Eq, T>> eq(Eq errorEq, Eq validEq) { return (a, b) -> { - if (a instanceof Validation.Invalid invalidA && b instanceof Validation.Invalid invalidB) { - return errorEq.eqv(invalidA.getError(), invalidB.getError()); + if (a instanceof Validation.Invalid(var invalidA) && b instanceof Validation.Invalid(var invalidB)) { + return errorEq.eqv(invalidA, invalidB); } - if (a instanceof Validation.Valid validA && b instanceof Validation.Valid validB) { - return validEq.eqv(validA.get(), validB.get()); + if (a instanceof Validation.Valid(var validA) && b instanceof Validation.Valid(var validB)) { + return validEq.eqv(validA, validB); } return false; }; @@ -72,7 +72,7 @@ interface ValidationFunctor extends Functor> { ValidationFunctor INSTANCE = new ValidationFunctor() {}; @Override - default Validation map(Kind, ? extends T> value, + default Validation map(Kind, ? extends T> value, Function1 map) { return ValidationOf.narrowK(value).map(map); } diff --git a/monad/src/test/java/com/github/tonivade/purefun/monad/IOTest.java b/monad/src/test/java/com/github/tonivade/purefun/monad/IOTest.java index 16f9d12c3..6d09b7386 100644 --- a/monad/src/test/java/com/github/tonivade/purefun/monad/IOTest.java +++ b/monad/src/test/java/com/github/tonivade/purefun/monad/IOTest.java @@ -64,29 +64,29 @@ public void pure() { pure.flatMap(string -> IO.task(() -> string.split(" "))).unsafeRunSync()), () -> assertEquals(Integer.valueOf(100), pure.andThen(IO.task(() -> 100)).unsafeRunSync())); } - + @Test public void asyncSuccess() { IO async = IO.async(callback -> { - System.out.println(Thread.currentThread().getName()); + System.out.println(Thread.currentThread().threadId()); Thread.sleep(100); callback.accept(Try.success("1")); }); - + Future foldMap = IO.forked().andThen(async).runAsync(); - + assertEquals("1", foldMap.getOrElseThrow()); } - + @Test public void asyncFailure() { IO async = IO.async(callback -> { Thread.sleep(100); callback.accept(Try.failure(new UnsupportedOperationException())); }); - + Future foldMap = IO.forked().andThen(async).runAsync(); - + assertThrows(UnsupportedOperationException.class, foldMap::getOrElseThrow); } @@ -257,24 +257,24 @@ public void timed() { assertEquals(705082704, result.get2()); assertTrue(result.get1().toMillis() > 0); } - + @Test public void timeoutFail() { assertThrows(TimeoutException.class, IO.never().timeout(Duration.ofSeconds(1))::unsafeRunSync); } - + @Test public void timeoutSuccess() { assertEquals(1, IO.pure(1).timeout(Duration.ofSeconds(1)).unsafeRunSync()); } - + @Test public void traverse() { IO left = IO.task(() -> "left"); IO right = IO.task(() -> "right"); - + IO> traverse = IO.traverse(listOf(left, right)); - + assertEquals(listOf("left", "right"), traverse.unsafeRunSync()); } @@ -283,9 +283,9 @@ public void raceA() { IO> race = IO.race( IO.delay(Duration.ofMillis(10), () -> 10), IO.delay(Duration.ofMillis(100), () -> "b")); - + Either orElseThrow = race.unsafeRunSync(); - + assertEquals(Either.left(10), orElseThrow); } @@ -294,40 +294,40 @@ public void raceB() { IO> race = IO.race( IO.delay(Duration.ofMillis(100), () -> 10), IO.delay(Duration.ofMillis(10), () -> "b")); - + Either orElseThrow = race.unsafeRunSync(); - + assertEquals(Either.right("b"), orElseThrow); } - + @Test public void fork() { IO result = Instances.monad().use() .then(IO.pure("hola")) .flatMap(hello -> IO.delay(Duration.ofSeconds(1), () -> hello + " toni").fork()) .flatMap(Fiber::join).fix(toIO()); - + String orElseThrow = result.runAsync().getOrElseThrow(); assertEquals("hola toni", orElseThrow); } - + @Test public void memoize(@Mock Function1 toUpperCase) { when(toUpperCase.apply(any())) .thenAnswer(args -> args.getArgument(0, String.class).toUpperCase()); - + IO>> memoized = IO.memoize((String str) -> IO.pure(toUpperCase.apply(str))); - + IO flatMap = memoized.flatMap(x -> x.apply("hola")); flatMap.unsafeRunSync(); flatMap.unsafeRunSync(); flatMap.unsafeRunSync(); flatMap.unsafeRunSync(); - + verify(toUpperCase).apply("hola"); } - + @Test public void fibSyncTest() { assertAll( @@ -343,7 +343,7 @@ public void fibSyncTest() { () -> assertEquals(6765, fibSync(20).unsafeRunSync()) ); } - + @Test public void fibAsyncTest() { assertAll( @@ -398,7 +398,7 @@ private IO sum(Integer n, Integer sum) { private IO> currentThreadIO() { Reference> ref = IOInstances.monadDefer().ref(ImmutableList.empty()); IO> currentThread = - ref.updateAndGet(list -> list.append(Thread.currentThread().getName())).fix(toIO()); + ref.updateAndGet(list -> list.append("thread-" + Thread.currentThread().threadId())).fix(toIO()); return currentThread .andThen(currentThread diff --git a/typeclasses/src/main/java/com/github/tonivade/purefun/typeclasses/Traverse.java b/typeclasses/src/main/java/com/github/tonivade/purefun/typeclasses/Traverse.java index feae7d380..3a0dbd7d9 100644 --- a/typeclasses/src/main/java/com/github/tonivade/purefun/typeclasses/Traverse.java +++ b/typeclasses/src/main/java/com/github/tonivade/purefun/typeclasses/Traverse.java @@ -26,7 +26,7 @@ default Kind> sequence(Applicative appli @Override default Kind map(Kind value, Function1 map) { Kind> traverse = traverse(Instances.applicative(), value, t -> Id.of(map.apply(t))); - return traverse.fix(toId()).get(); + return traverse.fix(toId()).value(); } static Traverse> compose(Traverse f, Traverse g) {