/**
* Copyright 2010 Wealthfront Inc. Licensed under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
* or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package com.kaching.platform.common;
import static java.lang.String.format;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.AbstractIterator;
/**
* Option<T> := None | Some<T>.
*/
public abstract class Option<T> implements Iterable<T> {
/** The singleton representing none.
*/
private final static Option<?> NONE = new Option<Object>() {
@Override
public Iterator<Object> iterator() {
return new AbstractIterator<Object>() {
@Override
protected Object computeNext() {
return endOfData();
}
};
}
@Override
public Object getOrNull() {
return null;
};
@Override
public Object getOrElse(Object defaultValue) {
return defaultValue;
}
@Override
public Object getOrElse(Thunk<Object> defaultValue) {
return defaultValue.get();
}
@Override
public Object getOrThrow() {
return getOrThrow(new IllegalArgumentException());
}
@Override
public Object getOrThrow(String message) {
return getOrThrow(new IllegalArgumentException(message));
}
@Override
public <E extends Throwable> Object getOrThrow(E e) throws E {
throw e;
}
@Override
public String toStringOr(String defaultValue) {
return defaultValue;
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public <U> U visit(OptionVisitor<Object, U> visitor) {
return visitor.caseNone();
}
@Override
public <U> Option<U> transform(Function<Object, U> function) {
return Option.none();
}
@Override
public Set<Object> asSet() {
return Collections.emptySet();
}
@Override
public int hashCode() {
return 0;
}
@Override
public boolean equals(Object that) {
return this == that;
}
@Override
public String toString() {
return "Option.None";
}
};
/** The object representing some result.
*/
private final static class Some<U> extends Option<U> {
private final U u;
private Some(U u) {
Preconditions.checkNotNull(u);
this.u = u;
}
@Override
public Iterator<U> iterator() {
return new AbstractIterator<U>() {
private boolean produce = true;
@Override
protected U computeNext() {
if (produce) {
produce = false;
return u;
} else {
return endOfData();
}
}
};
}
@Override
public U getOrNull() {
return u;
}
@Override
public U getOrElse(U defaultValue) {
return u;
}
@Override
public U getOrElse(Thunk<U> defaultValue) {
return u;
}
@Override
public U getOrThrow() {
return u;
}
@Override
public U getOrThrow(String message) {
return u;
}
@Override
public <E extends Throwable> U getOrThrow(E e) throws E {
return u;
}
@Override
public String toStringOr(String defaultValue) {
return u.toString();
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public <V> V visit(OptionVisitor<? super U, V> visitor) {
return visitor.caseSome(u);
}
@Override
public <V> Option<V> transform(Function<? super U, V> function) {
return Option.of(function.apply(u));
}
@Override
public Set<U> asSet() {
return Collections.singleton(u);
}
@Override
public int hashCode() {
return u.hashCode();
}
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (!(that instanceof Some<?>)) {
return false;
}
return this.u.equals(((Some<?>) that).u);
}
@Override
public String toString() {
return format("Option.Some(%s)", u);
}
}
/**
* If the option is nonempty returns its value, otherwise returns
* {@code null}.
*/
public abstract T getOrNull();
/**
* If the option is nonempty returns its value, otherwise returns
* {@code defaultValue}. Note that {@code defaultValue} is eagerly evaluated.
*/
public abstract T getOrElse(T defaultValue);
/**
* If the option is nonempty returns its value, otherwise returns
* {@code defaultValue}. The {@code defaultValue} is lazily evaluated.
*/
public abstract T getOrElse(Thunk<T> defaultValue);
/**
* Gets the value of this option. If this is a Some(T) the value is returned,
* otherwise an {@link IllegalArgumentException} is thrown.
*/
public abstract T getOrThrow();
/**
* Gets the value of this option. If this is a Some(T) the value is returned,
* otherwise an {@link IllegalArgumentException} is thrown with the specifed
* message.
*/
public abstract T getOrThrow(String message);
/**
* Returns its value if not empty, otherwise throws {@code e}.
*/
public abstract <E extends Throwable> T getOrThrow(E e) throws E;
public abstract String toStringOr(String defaultValue);
/**
* Returns {@code true} if the option is the {@code None} value.
*/
public abstract boolean isEmpty();
/**
* Returns {@code true} if the option is a {@code Some(...)}.
*/
public boolean isDefined() {
return !isEmpty();
}
/**
* Visits the {@code Option} using the {@code visitor}.
*/
public abstract <U> U visit(OptionVisitor<? super T, U> visitor);
public abstract <U> Option<U> transform(Function<? super T, U> function);
public abstract Set<T> asSet();
/**
* Gets the none object for the given type.
*
* Note: using a freely parameterized type {@code T} with an unchecked warning
* allows to simulate a bottom type in Java.
*/
@SuppressWarnings("unchecked")
public static <T> Option<T> none() {
return (Option<T>) NONE;
}
/**
* Gets the some object wrapping the given value.
*/
public static <T> Option<T> some(T t) {
return new Option.Some<T>(t);
}
/**
* Wraps anything.
*
* @param <T>
* @param t
* @return if null, none(), some(t) otherwise
*/
public static <T> Option<T> of(T t) {
return t == null ? Option.<T>none() : some(t);
}
}