Skip to content

Commit

Permalink
change ResultTransformer/Consumer into inner interface of Result
Browse files Browse the repository at this point in the history
  • Loading branch information
ArtificialPB committed Jan 26, 2024
1 parent fb2e016 commit ec7b7df
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 40 deletions.
60 changes: 30 additions & 30 deletions ethers-core/src/main/kotlin/io/ethers/core/Result.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import kotlin.contracts.contract
sealed class Result<out T : Any?, out E : Result.Error> {
class Success<T : Any?>(val value: T) : Result<T, Nothing>() {
override fun <R> fold(
onSuccess: ResultTransformer<Success<T>, R>,
onFailure: ResultTransformer<Failure<Nothing>, R>,
onSuccess: Transformer<Success<T>, R>,
onFailure: Transformer<Failure<Nothing>, R>,
): R {
return onSuccess(this)
}
Expand All @@ -24,8 +24,8 @@ sealed class Result<out T : Any?, out E : Result.Error> {

class Failure<E : Error>(val error: E) : Result<Nothing, E>() {
override fun <R> fold(
onSuccess: ResultTransformer<Success<Nothing>, R>,
onFailure: ResultTransformer<Failure<E>, R>,
onSuccess: Transformer<Success<Nothing>, R>,
onFailure: Transformer<Failure<E>, R>,
): R {
return onFailure(this)
}
Expand All @@ -51,29 +51,29 @@ sealed class Result<out T : Any?, out E : Result.Error> {
* Maps a [Result]<[T], [E]> to [Result]<[R], [E]> by applying a function to a [Success] value, leaving a
* [Failure] value untouched.
* */
fun <R : Any?> map(mapper: ResultTransformer<in T, R>): Result<R, E> = fold({ Success(mapper(it.value)) }, { it })
fun <R : Any?> map(mapper: Transformer<in T, R>): Result<R, E> = fold({ Success(mapper(it.value)) }, { it })

/**
* Maps a [Result]<[T], [E]> to [Result]<[T], [R]> by applying a function to a [Failure], leaving a
* [Success] value untouched.
* */
fun <R : Error> mapError(mapper: ResultTransformer<in E, R>): Result<T, R> {
fun <R : Error> mapError(mapper: Transformer<in E, R>): Result<T, R> {
return fold({ it }, { Failure(mapper(it.error)) })
}

/**
* Call the function with value of [Success], expecting another result, and skipping if [Result] is [Failure].
* Useful when chaining multiple fallible operations on the result.
* */
fun <R : Any?> andThen(mapper: ResultTransformer<in T, Result<R, @UnsafeVariance E>>): Result<R, E> {
fun <R : Any?> andThen(mapper: Transformer<in T, Result<R, @UnsafeVariance E>>): Result<R, E> {
return fold({ mapper(it.value) }, { it })
}

/**
* Call the function with error of [Failure], expecting another result, and skipping if [Result] is [Success].
* Useful when chaining multiple fallible operations on the error (e.g. trying to recover from an error).
* */
fun <R : Error> orElse(mapper: ResultTransformer<in E, Result<@UnsafeVariance T, R>>): Result<T, R> {
fun <R : Error> orElse(mapper: Transformer<in E, Result<@UnsafeVariance T, R>>): Result<T, R> {
return fold({ it }, { mapper(it.error) })
}

Expand All @@ -95,7 +95,7 @@ sealed class Result<out T : Any?, out E : Result.Error> {
/**
* Unwrap the value if [Result] is [Success], or return the result of [default] function if [Result] is [Failure].
* */
fun unwrapOrElse(default: ResultTransformer<in E, @UnsafeVariance T>): T {
fun unwrapOrElse(default: Transformer<in E, @UnsafeVariance T>): T {
return fold({ it.value }, { default(it.error) })
}

Expand All @@ -117,27 +117,27 @@ sealed class Result<out T : Any?, out E : Result.Error> {
/**
* Unwrap the error if [Result] is [Failure], or return the result of [default] function if [Result] is [Success].
* */
fun unwrapErrorOrElse(default: ResultTransformer<in T, @UnsafeVariance E>): E {
fun unwrapErrorOrElse(default: Transformer<in T, @UnsafeVariance E>): E {
return fold({ default(it.value) }, { it.error })
}

/**
* Callback called if [Result] is [Success].
* */
fun onSuccess(block: ResultConsumer<in T>) = fold({ block(it.value) }, {})
fun onSuccess(block: Consumer<in T>) = fold({ block(it.value) }, {})

/**
* Callback called if [Result] is [Failure].
* */
fun onFailure(block: ResultConsumer<in E>) = fold({}, { block(it.error) })
fun onFailure(block: Consumer<in E>) = fold({}, { block(it.error) })

/**
* Call [onSuccess] if [Result] is [Success] or [onFailure] if [Result] is [Failure], returning the result of
* the called function.
* */
abstract fun <R> fold(
onSuccess: ResultTransformer<Success<@UnsafeVariance T>, R>,
onFailure: ResultTransformer<Failure<@UnsafeVariance E>, R>,
onSuccess: Transformer<Success<@UnsafeVariance T>, R>,
onFailure: Transformer<Failure<@UnsafeVariance E>, R>,
): R

/**
Expand All @@ -162,6 +162,22 @@ sealed class Result<out T : Any?, out E : Result.Error> {
}
}

/**
* Custom functional interface for better java interop with kotlin lambdas. Prevents the java caller having to
* explicitly return `Unit.INSTANCE`.
* */
fun interface Consumer<T> {
operator fun invoke(t: T)
}

/**
* Custom functional interface for better java interop with kotlin lambdas. Prevents the java caller having to
* explicitly return `Unit.INSTANCE`.
* */
fun interface Transformer<T, R> {
operator fun invoke(t: T): R
}

companion object {
/**
* Return a [Result.Success] with the given [value].
Expand Down Expand Up @@ -215,22 +231,6 @@ inline fun <reified T : Result.Error> Result.Error.asTypeOrNull(): T? {
return asTypeOrNull(T::class.java)
}

/**
* Custom functional interface for better java interop with kotlin lambdas. Prevents the java caller having to
* explicitly return `Unit.INSTANCE`.
* */
fun interface ResultConsumer<T> {
operator fun invoke(t: T)
}

/**
* Custom functional interface for better java interop with kotlin lambdas. Prevents the java caller having to
* explicitly return `Unit.INSTANCE`.
* */
fun interface ResultTransformer<T, R> {
operator fun invoke(t: T): R
}

/**
* Return a [Result.Success] with the given [value].
* */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package io.ethers.providers.types

import com.fasterxml.jackson.core.JsonParser
import io.ethers.core.Result
import io.ethers.core.ResultTransformer
import io.ethers.providers.JsonRpcClient
import io.ethers.providers.RpcError
import java.util.concurrent.CompletableFuture
Expand All @@ -29,7 +28,7 @@ abstract class RpcRequest<T, E : Result.Error> {
*
* The function will be executed asynchronously after the request is sent and response received.
*/
fun <R> map(mapper: ResultTransformer<T, R>): RpcRequest<R, E> {
fun <R> map(mapper: Result.Transformer<T, R>): RpcRequest<R, E> {
return MappingRpcRequest(this) { it.map(mapper) }
}

Expand All @@ -38,7 +37,7 @@ abstract class RpcRequest<T, E : Result.Error> {
*
* The function will be executed asynchronously after the request is sent and response received.
*/
fun <R : Result.Error> mapError(mapper: ResultTransformer<E, R>): RpcRequest<T, R> {
fun <R : Result.Error> mapError(mapper: Result.Transformer<E, R>): RpcRequest<T, R> {
return MappingRpcRequest(this) { it.mapError(mapper) }
}

Expand All @@ -48,7 +47,7 @@ abstract class RpcRequest<T, E : Result.Error> {
*
* The function will be executed asynchronously after the request is sent and response received.
*/
fun <R> andThen(mapper: ResultTransformer<T, Result<R, E>>): RpcRequest<R, E> {
fun <R> andThen(mapper: Result.Transformer<T, Result<R, E>>): RpcRequest<R, E> {
return MappingRpcRequest(this) { it.andThen(mapper) }
}

Expand All @@ -58,7 +57,7 @@ abstract class RpcRequest<T, E : Result.Error> {
*
* The function will be executed asynchronously after the request is sent and response received.
*/
fun <R : Result.Error> orElse(mapper: ResultTransformer<E, Result<T, R>>): RpcRequest<T, R> {
fun <R : Result.Error> orElse(mapper: Result.Transformer<E, Result<T, R>>): RpcRequest<T, R> {
return MappingRpcRequest(this) { it.orElse(mapper) }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package io.ethers.providers.types

import com.fasterxml.jackson.core.JsonParser
import io.ethers.core.Result
import io.ethers.core.ResultTransformer
import io.ethers.providers.JsonPubSubClient
import io.ethers.providers.RpcError
import io.ethers.providers.SubscriptionStream
Expand All @@ -25,7 +24,7 @@ interface RpcSubscribe<T, E : Result.Error> {
*
* The function will be executed asynchronously after the request is sent and response received.
*/
fun <R> map(mapper: ResultTransformer<SubscriptionStream<T>, SubscriptionStream<R>>): RpcSubscribe<R, E> {
fun <R> map(mapper: Result.Transformer<SubscriptionStream<T>, SubscriptionStream<R>>): RpcSubscribe<R, E> {
return MappingRpcSubscribe(this) { it.map(mapper) }
}

Expand All @@ -34,7 +33,7 @@ interface RpcSubscribe<T, E : Result.Error> {
*
* The function will be executed asynchronously after the request is sent and response received.
*/
fun <R : Result.Error> mapError(mapper: ResultTransformer<E, R>): RpcSubscribe<T, R> {
fun <R : Result.Error> mapError(mapper: Result.Transformer<E, R>): RpcSubscribe<T, R> {
return MappingRpcSubscribe(this) { it.mapError(mapper) }
}

Expand All @@ -44,7 +43,7 @@ interface RpcSubscribe<T, E : Result.Error> {
*
* The function will be executed asynchronously after the request is sent and response received.
*/
fun <R> andThen(mapper: ResultTransformer<SubscriptionStream<T>, Result<SubscriptionStream<R>, E>>): RpcSubscribe<R, E> {
fun <R> andThen(mapper: Result.Transformer<SubscriptionStream<T>, Result<SubscriptionStream<R>, E>>): RpcSubscribe<R, E> {
return MappingRpcSubscribe(this) { it.andThen(mapper) }
}

Expand All @@ -54,7 +53,7 @@ interface RpcSubscribe<T, E : Result.Error> {
*
* The function will be executed asynchronously after the request is sent and response received.
*/
fun <R : Result.Error> orElse(mapper: ResultTransformer<E, Result<SubscriptionStream<T>, R>>): RpcSubscribe<T, R> {
fun <R : Result.Error> orElse(mapper: Result.Transformer<E, Result<SubscriptionStream<T>, R>>): RpcSubscribe<T, R> {
return MappingRpcSubscribe(this) { it.orElse(mapper) }
}
}
Expand Down

0 comments on commit ec7b7df

Please sign in to comment.