All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dagger.producers.internal.Producers Maven / Gradle / Ivy

There is a newer version: 2.52
Show newest version
/*
 * Copyright (C) 2014 The Dagger Authors.
 *
 * 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 dagger.producers.internal;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.util.concurrent.Futures.catchingAsync;
import static com.google.common.util.concurrent.Futures.transform;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static dagger.internal.Providers.asDaggerProvider;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import dagger.internal.Provider;
import dagger.producers.Produced;
import dagger.producers.Producer;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Utility methods for use in generated producer code.
 */
public final class Producers {
  /**
   * Returns a future of {@link Produced} that represents the completion (either success or failure)
   * of the given future. If the input future succeeds, then the resulting future also succeeds with
   * a successful {@code Produced}; if the input future fails, then the resulting future succeeds
   * with a failing {@code Produced}.
   *
   * 

Cancelling the resulting future will propagate the cancellation to the input future; but * cancelling the input future will trigger the resulting future to succeed with a failing * {@code Produced}. */ // TODO(beder): Document what happens with an InterruptedException after you figure out how to // trigger one in a test. public static ListenableFuture> createFutureProduced(ListenableFuture future) { return catchingAsync( transform(future, Producers.resultToProduced(), directExecutor()), Throwable.class, Producers.futureFallbackForProduced(), directExecutor()); } private static final Function> RESULT_TO_PRODUCED = new Function>() { @Override public Produced apply(Object result) { return Produced.successful(result); } }; @SuppressWarnings({"unchecked", "rawtypes"}) // bivariant implementation private static Function> resultToProduced() { return (Function) RESULT_TO_PRODUCED; } private static final AsyncFunction> FUTURE_FALLBACK_FOR_PRODUCED = new AsyncFunction>() { @Override public ListenableFuture> apply(Throwable t) throws Exception { Produced produced = Produced.failed(t); return Futures.immediateFuture(produced); } }; @SuppressWarnings({"unchecked", "rawtypes"}) // bivariant implementation private static AsyncFunction> futureFallbackForProduced() { return (AsyncFunction) FUTURE_FALLBACK_FOR_PRODUCED; } /** * Returns a future of a {@code Set} that contains a single element: the result of the input * future. */ public static ListenableFuture> createFutureSingletonSet(ListenableFuture future) { return transform( future, new Function>() { @Override public Set apply(T value) { return ImmutableSet.of(value); } }, directExecutor()); } /** * Creates a new {@code ListenableFuture} whose value is a set containing the values of all its * input futures, if all succeed. If any input fails, the returned future fails immediately. * *

This is the set equivalent of {@link Futures#allAsList}. */ public static ListenableFuture> allAsSet( Iterable> futures) { return transform( Futures.allAsList(futures), new Function, Set>() { @Override public Set apply(List values) { return ImmutableSet.copyOf(values); } }, directExecutor()); } /** * Returns a producer that immediately executes the binding logic for the given provider every * time it is called. */ public static Producer producerFromProvider(final Provider provider) { checkNotNull(provider); return new CompletedProducer() { @Override public ListenableFuture get() { return Futures.immediateFuture(provider.get()); } }; } /** * Legacy javax version of the method to support libraries compiled with an older version of * Dagger. Do not use directly. */ @Deprecated public static Producer producerFromProvider(final javax.inject.Provider provider) { return producerFromProvider(asDaggerProvider(provider)); } /** * Returns a producer that succeeds with the given value. * * @deprecated Prefer the non-internal version of this method: {@link * dagger.producers.Producers#immediateProducer(Object)}. */ @Deprecated public static Producer immediateProducer(T value) { return dagger.producers.Producers.immediateProducer(value); } /** * Returns a producer that fails with the given exception. * * @deprecated Prefer the non-internal version of this method: {@link * dagger.producers.Producers#immediateFailedProducer(Throwable)}. */ @Deprecated public static Producer immediateFailedProducer(Throwable throwable) { return dagger.producers.Producers.immediateFailedProducer(throwable); } /** * Returns a new view of the given {@code producer} if and only if it is a {@link * CancellableProducer}. Cancelling the returned producer's future will not cancel the underlying * task for the given producer. * * @throws IllegalArgumentException if {@code producer} is not a {@code CancellableProducer} */ public static Producer nonCancellationPropagatingViewOf(Producer producer) { // This is a hack until we change the types of Producer fields to be CancellableProducer or // some other type. if (producer instanceof CancellableProducer) { return ((CancellableProducer) producer).newDependencyView(); } throw new IllegalArgumentException( "nonCancellationPropagatingViewOf called with non-CancellableProducer: " + producer); } /** * Returns a new view of the given {@code producer} for use as an entry point in a production * component, if and only if it is a {@link CancellableProducer}. When the returned producer's * future is cancelled, the given {@code cancellable} will also be cancelled. * * @throws IllegalArgumentException if {@code producer} is not a {@code CancellableProducer} */ public static Producer entryPointViewOf( Producer producer, CancellationListener cancellationListener) { // This is a hack until we change the types of Producer fields to be CancellableProducer or // some other type. if (producer instanceof CancellableProducer) { return ((CancellableProducer) producer).newEntryPointView(cancellationListener); } throw new IllegalArgumentException( "entryPointViewOf called with non-CancellableProducer: " + producer); } /** * Calls {@code cancel} on the given {@code producer} if it is a {@link CancellableProducer}. * * @throws IllegalArgumentException if {@code producer} is not a {@code CancellableProducer} */ public static void cancel(Producer producer, boolean mayInterruptIfRunning) { // This is a hack until we change the types of Producer fields to be CancellableProducer or // some other type. if (producer instanceof CancellableProducer) { ((CancellableProducer) producer).cancel(mayInterruptIfRunning); } else { throw new IllegalArgumentException("cancel called with non-CancellableProducer: " + producer); } } private static final Producer> EMPTY_MAP_PRODUCER = dagger.producers.Producers.>immediateProducer(ImmutableMap.of()); @SuppressWarnings("unchecked") // safe contravariant cast public static Producer> emptyMapProducer() { return (Producer>) (Producer) EMPTY_MAP_PRODUCER; } /** * A {@link CancellableProducer} which can't be cancelled because it represents an * already-completed task. */ private abstract static class CompletedProducer implements CancellableProducer { @Override public void cancel(boolean mayInterruptIfRunning) {} @Override public Producer newDependencyView() { return this; } @Override public Producer newEntryPointView(CancellationListener cancellationListener) { return this; } } private Producers() {} }