package sk.stuba.fiit.perconik.eclipse.jface.viewers;
import java.io.Serializable;
import com.google.common.base.Equivalence;
import com.google.common.reflect.TypeToken;
import org.eclipse.jface.viewers.IElementComparer;
import static com.google.common.base.Preconditions.checkNotNull;
public final class ElementComparers {
private ElementComparers() {}
private static final class EquivalenceElementComparer<T> implements IElementComparer, Serializable {
private static final long serialVersionUID = 0L;
final TypeToken<T> type;
final Equivalence<T> equivalence;
EquivalenceElementComparer(final TypeToken<T> type, final Equivalence<T> equivalence) {
this.type = checkNotNull(type);
this.equivalence = checkNotNull(equivalence);
}
// casts are unsafe but proper equivalence should fail on incorrectly typed objects
@SuppressWarnings("unchecked")
public boolean equals(final Object a, final Object b) {
return this.equivalence.equivalent((T) a, (T) b);
}
// see above note
@SuppressWarnings("unchecked")
public int hashCode(final Object o) {
return this.equivalence.hash((T) o);
}
}
private static final class ElementComparerEquivalence<T> extends Equivalence<T> implements Serializable {
private static final long serialVersionUID = 0L;
final TypeToken<T> type;
final IElementComparer comparer;
ElementComparerEquivalence(final TypeToken<T> type, final IElementComparer comparer) {
this.type = checkNotNull(type);
this.comparer = checkNotNull(comparer);
}
@Override
protected boolean doEquivalent(final Object a, final Object b) {
return this.comparer.equals(a, b);
}
@Override
protected int doHash(final Object o) {
return this.comparer.hashCode(o);
}
}
public static <T> IElementComparer fromEquivalence(final Class<T> type, final Equivalence<T> equivalence) {
return fromEquivalence(TypeToken.of(type), equivalence);
}
public static <T> IElementComparer fromEquivalence(final TypeToken<T> type, final Equivalence<T> equivalence) {
if (equivalence instanceof ElementComparerEquivalence) {
ElementComparerEquivalence<T> inner = (ElementComparerEquivalence<T>) equivalence;
if (inner.type.isAssignableFrom(type)) {
return inner.comparer;
}
}
return new EquivalenceElementComparer<>(type, equivalence);
}
public static <T> Equivalence<T> toEquivalence(final Class<T> type, final IElementComparer comparer) {
return toEquivalence(TypeToken.of(type), comparer);
}
public static <T> Equivalence<T> toEquivalence(final TypeToken<T> type, final IElementComparer comparer) {
if (comparer instanceof EquivalenceElementComparer) {
@SuppressWarnings("unchecked")
EquivalenceElementComparer<T> inner = (EquivalenceElementComparer<T>) comparer;
if (inner.type.isAssignableFrom(type)) {
return inner.equivalence;
}
}
return new ElementComparerEquivalence<>(type, comparer);
}
}