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

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

There is a newer version: 2.52
Show newest version
/*
 * Copyright (C) 2015 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.transform;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static dagger.internal.DaggerCollections.hasDuplicates;
import static dagger.internal.DaggerCollections.presizedList;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import dagger.producers.Producer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
 * A {@link Producer} implementation used to implement {@link Set} bindings. This producer returns
 * a future {@link Set} whose elements are populated by subsequent calls to the delegate
 * {@link Producer#get} methods.
 */
public final class SetProducer extends AbstractProducer> {
  private static final Producer> EMPTY_PRODUCER =
      new Producer>() {
        @Override
        public ListenableFuture> get() {
          return Futures.>immediateFuture(ImmutableSet.of());
        }
      };

  @SuppressWarnings({"unchecked", "rawtypes"}) // safe covariant cast
  public static  Producer> empty() {
    return (Producer) EMPTY_PRODUCER;
  }

  /**
   * Constructs a new {@link Builder} for a {@link SetProducer} with {@code individualProducerSize}
   * individual {@code Producer} and {@code collectionProducerSize} {@code
   * Producer>} instances.
   */
  public static  Builder builder(int individualProducerSize, int collectionProducerSize) {
    return new Builder(individualProducerSize, collectionProducerSize);
  }

  /**
   * A builder to accumulate {@code Producer} and {@code Producer>} instances.
   * These are only intended to be single-use and from within generated code. Do NOT add
   * producers after calling {@link #build()}.
   */
  public static final class Builder {
    private final List> individualProducers;
    private final List>> collectionProducers;

    private Builder(int individualProducerSize, int collectionProducerSize) {
      individualProducers = presizedList(individualProducerSize);
      collectionProducers = presizedList(collectionProducerSize);
    }

    @SuppressWarnings("unchecked")
    public Builder addProducer(Producer individualProducer) {
      assert individualProducer != null : "Codegen error? Null producer";
      individualProducers.add((Producer) individualProducer);
      return this;
    }

    @SuppressWarnings("unchecked")
    public Builder addCollectionProducer(
        Producer> multipleProducer) {
      assert multipleProducer != null : "Codegen error? Null producer";
      collectionProducers.add((Producer>) multipleProducer);
      return this;
    }

    public SetProducer build() {
      assert !hasDuplicates(individualProducers)
          : "Codegen error?  Duplicates in the producer list";
      assert !hasDuplicates(collectionProducers)
          : "Codegen error?  Duplicates in the producer list";

      return new SetProducer(individualProducers, collectionProducers);
    }
  }

  private final List> individualProducers;
  private final List>> collectionProducers;

  private SetProducer(
      List> individualProducers, List>> collectionProducers) {
    this.individualProducers = individualProducers;
    this.collectionProducers = collectionProducers;
  }

  /**
   * Returns a future {@link Set} whose iteration order is that of the elements given by each of the
   * producers, which are invoked in the order given at creation.
   *
   * 

If any of the delegate collections, or any elements therein, are null, then this future will * fail with a NullPointerException. * *

Canceling this future will attempt to cancel all of the component futures, and if any of the * delegate futures fails or is canceled, this one is, too. * * @throws NullPointerException if any of the delegate producers return null */ @Override public ListenableFuture> compute() { List> individualFutures = new ArrayList>(individualProducers.size()); for (Producer producer : individualProducers) { individualFutures.add(checkNotNull(producer.get())); } // Presize the list of collections produced by the amount of collectionProducers, with one more // for the consolidate individualFutures from Futures.allAsList. List>> futureCollections = new ArrayList>>(collectionProducers.size() + 1); futureCollections.add(Futures.allAsList(individualFutures)); for (Producer> producer : collectionProducers) { futureCollections.add(checkNotNull(producer.get())); } return transform( Futures.allAsList(futureCollections), new Function>, Set>() { @Override public Set apply(List> sets) { ImmutableSet.Builder builder = ImmutableSet.builder(); for (Collection set : sets) { builder.addAll(set); } return builder.build(); } }, directExecutor()); } }