/*****************************************************************************
* ------------------------------------------------------------------------- *
* 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.google.mu.util;
import static java.util.Objects.requireNonNull;
import java.util.AbstractList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletionStage;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
/** Some relatively trivial re-invented wheels as cost of 0-dependency. */
final class Utils {
/** Only need it because we don't have Guava Lists.transform(). */
static <F, T> List<T> mapList(List<F> list, Function<? super F, ? extends T> mapper) {
requireNonNull(list);
requireNonNull(mapper);
return new AbstractList<T>() {
@Override public int size() {
return list.size();
}
@Override public T get(int index) {
return mapper.apply(list.get(index));
}
};
}
static <T> Predicate<Object> typed(Class<T> type, Predicate<? super T> condition) {
requireNonNull(type);
requireNonNull(condition);
return x -> type.isInstance(x) && condition.test(type.cast(x));
}
/**
* Casts {@code object} to {@code type} if it's a non-null instance of {@code T}, or else
* returns {@code Optional.empty()}.
*/
static <T> Optional<T> cast(Object object, Class<T> type) {
return type.isInstance(object) ? Optional.of(type.cast(object)) : Optional.empty();
}
/** Propagates {@code exception} if it's unchecked, or else return it as is. */
static <E extends Throwable> E propagateIfUnchecked(E exception) {
requireNonNull(exception);
if (exception instanceof RuntimeException) {
throw (RuntimeException) exception;
} else if (exception instanceof Error) {
throw (Error) exception;
} else {
return exception;
}
}
static CompletionStage<?> ifCancelled(
CompletionStage<?> stage, Consumer<? super CancellationException> action) {
requireNonNull(action);
return stage.exceptionally(e -> {
cast(e, CancellationException.class).ifPresent(action);
return null;
});
}
/** Propagates cancellation from {@code outer} to {@code inner}. */
static <T> CompletionStage<T> propagateCancellation(
CompletionStage<T> outer, CompletionStage<?> inner) {
requireNonNull(inner);
ifCancelled(outer, e -> {
// Even if this isn't supported, the worst is that we don't propagate cancellation.
// But that's fine because without a Future we cannot propagate anyway.
inner.toCompletableFuture().completeExceptionally(e);
});
return outer;
}
}