/*******************************************************************************
* Copyright (c) 2015 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.dash.livexp;
import org.springsource.ide.eclipse.commons.livexp.core.AsyncLiveExpression.AsyncMode;
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
import org.springsource.ide.eclipse.commons.livexp.core.ObservableSet;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;
/**
* @author Kris De Volder
*/
public class LiveSets {
@SuppressWarnings("rawtypes")
private static final ObservableSet EMPTY_SET = (ObservableSet) ObservableSet.constant(ImmutableSet.of());
@SuppressWarnings("unchecked")
public static <T> ObservableSet<T> emptySet(Class<T> t) {
return EMPTY_SET;
}
@SuppressWarnings("unchecked")
public static <R, A extends R, B extends R> ObservableSet<R> union(ObservableSet<A> e1, ObservableSet<B> e2) {
if (e1==EMPTY_SET) {
return (ObservableSet<R>) e2;
} else if (e2==EMPTY_SET) {
return (ObservableSet<R>) e1;
} else {
return new LiveUnion<>(e1, e2);
}
}
//////////////////////////////////////////////////////////////////////
private static class LiveUnion<T, A extends T, B extends T> extends ObservableSet<T> {
private ObservableSet<A> e1;
private ObservableSet<B> e2;
public LiveUnion(ObservableSet<A> e1, ObservableSet<B> e2) {
this.e1 = e1;
this.e2 = e2;
this.dependsOn(e1);
this.dependsOn(e2);
}
@Override
protected ImmutableSet<T> compute() {
return ImmutableSet.copyOf(Sets.union(e1.getValue(), e2.getValue()));
}
}
public static <S,T> ObservableSet<T> filter(final ObservableSet<S> source, final Class<T> retainType) {
ObservableSet<T> filtered = new ObservableSet<T>() {
@SuppressWarnings("unchecked")
@Override
protected ImmutableSet<T> compute() {
return (ImmutableSet<T>) ImmutableSet.copyOf(
Sets.filter(source.getValue(), new Predicate<S>() {
@Override
public boolean apply(S input) {
return retainType.isAssignableFrom(input.getClass());
}
})
);
}
};
filtered.dependsOn(source);
return filtered;
}
public static <T> ObservableSet<T> singletonOrEmpty(final LiveExpression<T> exp) {
return new ObservableSet<T>() {
{
dependsOn(exp);
}
protected ImmutableSet<T> compute() {
T val = exp.getValue();
if (val==null) {
return ImmutableSet.of();
} else {
return ImmutableSet.of(val);
}
}
};
}
@SuppressWarnings("unchecked")
public static <A,R> ObservableSet<R> map(ObservableSet<A> input, AsyncMode asyncRefresh, AsyncMode asyncEvents, Function<A, R> function) {
if (input==EMPTY_SET) {
return EMPTY_SET;
}
return new MapSet<>(input, asyncRefresh, asyncEvents, function);
}
/**
* Creates a {@link ObservableSet} by applying a mapping function to another ObservableSet.
* <p>
* The resulting set is synchronously updated when the input set changes.
*/
public static <A,R> ObservableSet<R> mapSync(ObservableSet<A> input, Function<A, R> function) {
return map(input, AsyncMode.SYNC, AsyncMode.SYNC, function);
}
/**
* Creates an observable, sorted set by applying a mapping function to each value of an ObservableSet of LiveExps.
*/
@SuppressWarnings("unchecked")
public static <T, R extends Comparable<?>> ObservableSet<R> sortedMappedValues(ObservableSet<LiveExpression<T>> input, final Function<T,R> mappingFunction) {
if (input==EMPTY_SET) {
return EMPTY_SET;
}
return new MappedValuesSet<T, R>(input) {
@Override
protected R applyFun(T arg) {
return mappingFunction.apply(arg);
}
@Override
protected ImmutableSortedSet.Builder<R> immutableSetBuilder() {
return ImmutableSortedSet.naturalOrder();
}
};
}
}