Skip to content

Instantly share code, notes, and snippets.

@danieldietrich
Created May 14, 2015 22:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danieldietrich/29c9590714719921c30b to your computer and use it in GitHub Desktop.
Save danieldietrich/29c9590714719921c30b to your computer and use it in GitHub Desktop.
Match.of(value).when(function).get()
/* / \____ _ ______ _____ / \____ ____ _____
* / \__ \/ \ / \__ \ / __// \__ \ / \/ __ \ Javaslang
* _/ // _\ \ \/ / _\ \\_ \/ // _\ \ /\ \__/ / Copyright 2014-2015 Daniel Dietrich
* /___/ \_____/\____/\_____/____/\___\_____/_/ \_/____/ Licensed under the Apache License, Version 2.0
*/
package javaslang.control;
import javaslang.Function1;
import java.lang.invoke.MethodType;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
public interface Match2<T, R> extends Valences.Univalent<R> {
<U extends T> Match2<T, R> when(Function1<U, ? extends R> f);
static <T> Of<T> of(T value) {
return new Of<>(value);
}
final class Of<T> {
private final T value;
private Of(T value) {
this.value = value;
}
public <R> Typed<T, R> as(Class<R> type) {
Objects.requireNonNull(type, "type is null");
return new Typed<>(value);
}
@SuppressWarnings("unchecked")
public <U extends T, R> Match2<T, R> when(Function1<U, ? extends R> f) {
Objects.requireNonNull(f, "f is null");
final MethodType type = f.getType();
return matches(value, type) ? new Matched<>(f.apply((U) value)) : new Unmatched<>(value);
}
// method declared here because Java 8 does not support private interface methods
private static boolean matches(Object obj, MethodType type) {
// the compiler may add additional parameters to the lambda, our parameter is the last one
final Class<?> parameterType = type.parameterType(type.parameterCount() - 1);
return obj != null && parameterType.isAssignableFrom(obj.getClass());
}
}
final class Typed<T, R> {
private final T value;
private Typed(T value) {
this.value = value;
}
@SuppressWarnings("unchecked")
public <U extends T> Match2<T, R> when(Function1<U, ? extends R> f) {
Objects.requireNonNull(f, "f is null");
final MethodType type = f.getType();
return Of.matches(value, type) ? new Matched<>(f.apply((U) value)) : new Unmatched<>(value);
}
}
final class Matched<T, R> implements Match2<T, R> {
private final R result;
private Matched(R result) {
this.result = result;
}
@Override
public <U extends T> Matched<T, R> when(Function1<U, ? extends R> f) {
return this;
}
@Override
public R get() {
return result;
}
@Override
public R orElse(R other) {
return result;
}
@Override
public R orElseGet(Supplier<? extends R> other) {
return result;
}
@Override
public <X extends Throwable> R orElseThrow(Supplier<X> exceptionSupplier) throws X {
return result;
}
@Override
public Option<R> toOption() {
return new Some<>(result);
}
@Override
public Optional<R> toJavaOptional() {
return Optional.ofNullable(result); // caution: may be empty if result is null
}
}
final class Unmatched<T, R> implements Match2<T, R> {
private final T value;
private Unmatched(T value) {
this.value = value;
}
@SuppressWarnings("unchecked")
@Override
public <U extends T> Match2<T, R> when(Function1<U, ? extends R> f) {
final MethodType type = f.getType();
return Of.matches(value, type) ? new Matched<>(f.apply((U) value)) : this;
}
@Override
public R get() {
throw new MatchError(value);
}
@Override
public R orElse(R other) {
return other;
}
@Override
public R orElseGet(Supplier<? extends R> other) {
return other.get();
}
@Override
public <X extends Throwable> R orElseThrow(Supplier<X> exceptionSupplier) throws X {
throw exceptionSupplier.get();
}
@Override
public Option<R> toOption() {
return None.instance();
}
@Override
public Optional<R> toJavaOptional() {
return Optional.empty();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment