1*f585d8a3SJacky Wang /* 2*f585d8a3SJacky Wang * Copyright (C) 2015 The Dagger Authors. 3*f585d8a3SJacky Wang * 4*f585d8a3SJacky Wang * Licensed under the Apache License, Version 2.0 (the "License"); 5*f585d8a3SJacky Wang * you may not use this file except in compliance with the License. 6*f585d8a3SJacky Wang * You may obtain a copy of the License at 7*f585d8a3SJacky Wang * 8*f585d8a3SJacky Wang * http://www.apache.org/licenses/LICENSE-2.0 9*f585d8a3SJacky Wang * 10*f585d8a3SJacky Wang * Unless required by applicable law or agreed to in writing, software 11*f585d8a3SJacky Wang * distributed under the License is distributed on an "AS IS" BASIS, 12*f585d8a3SJacky Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*f585d8a3SJacky Wang * See the License for the specific language governing permissions and 14*f585d8a3SJacky Wang * limitations under the License. 15*f585d8a3SJacky Wang */ 16*f585d8a3SJacky Wang 17*f585d8a3SJacky Wang package dagger.producers.internal; 18*f585d8a3SJacky Wang 19*f585d8a3SJacky Wang import static com.google.common.base.Preconditions.checkNotNull; 20*f585d8a3SJacky Wang import static com.google.common.util.concurrent.Futures.transform; 21*f585d8a3SJacky Wang import static com.google.common.util.concurrent.MoreExecutors.directExecutor; 22*f585d8a3SJacky Wang import static dagger.internal.DaggerCollections.hasDuplicates; 23*f585d8a3SJacky Wang import static dagger.internal.DaggerCollections.presizedList; 24*f585d8a3SJacky Wang 25*f585d8a3SJacky Wang import com.google.common.base.Function; 26*f585d8a3SJacky Wang import com.google.common.collect.ImmutableSet; 27*f585d8a3SJacky Wang import com.google.common.util.concurrent.Futures; 28*f585d8a3SJacky Wang import com.google.common.util.concurrent.ListenableFuture; 29*f585d8a3SJacky Wang import dagger.producers.Producer; 30*f585d8a3SJacky Wang import java.util.ArrayList; 31*f585d8a3SJacky Wang import java.util.Collection; 32*f585d8a3SJacky Wang import java.util.List; 33*f585d8a3SJacky Wang import java.util.Set; 34*f585d8a3SJacky Wang 35*f585d8a3SJacky Wang /** 36*f585d8a3SJacky Wang * A {@link Producer} implementation used to implement {@link Set} bindings. This producer returns 37*f585d8a3SJacky Wang * a future {@link Set} whose elements are populated by subsequent calls to the delegate 38*f585d8a3SJacky Wang * {@link Producer#get} methods. 39*f585d8a3SJacky Wang */ 40*f585d8a3SJacky Wang public final class SetProducer<T> extends AbstractProducer<Set<T>> { 41*f585d8a3SJacky Wang private static final Producer<Set<Object>> EMPTY_PRODUCER = 42*f585d8a3SJacky Wang dagger.producers.Producers.<Set<Object>>immediateProducer(ImmutableSet.<Object>of()); 43*f585d8a3SJacky Wang 44*f585d8a3SJacky Wang @SuppressWarnings({"unchecked", "rawtypes"}) // safe covariant cast empty()45*f585d8a3SJacky Wang public static <T> Producer<Set<T>> empty() { 46*f585d8a3SJacky Wang return (Producer) EMPTY_PRODUCER; 47*f585d8a3SJacky Wang } 48*f585d8a3SJacky Wang 49*f585d8a3SJacky Wang /** 50*f585d8a3SJacky Wang * Constructs a new {@link Builder} for a {@link SetProducer} with {@code individualProducerSize} 51*f585d8a3SJacky Wang * individual {@code Producer<T>} and {@code collectionProducerSize} {@code 52*f585d8a3SJacky Wang * Producer<Collection<T>>} instances. 53*f585d8a3SJacky Wang */ builder(int individualProducerSize, int collectionProducerSize)54*f585d8a3SJacky Wang public static <T> Builder<T> builder(int individualProducerSize, int collectionProducerSize) { 55*f585d8a3SJacky Wang return new Builder<T>(individualProducerSize, collectionProducerSize); 56*f585d8a3SJacky Wang } 57*f585d8a3SJacky Wang 58*f585d8a3SJacky Wang /** 59*f585d8a3SJacky Wang * A builder to accumulate {@code Producer<T>} and {@code Producer<Collection<T>>} instances. 60*f585d8a3SJacky Wang * These are only intended to be single-use and from within generated code. Do <em>NOT</em> add 61*f585d8a3SJacky Wang * producers after calling {@link #build()}. 62*f585d8a3SJacky Wang */ 63*f585d8a3SJacky Wang public static final class Builder<T> { 64*f585d8a3SJacky Wang private final List<Producer<T>> individualProducers; 65*f585d8a3SJacky Wang private final List<Producer<Collection<T>>> collectionProducers; 66*f585d8a3SJacky Wang Builder(int individualProducerSize, int collectionProducerSize)67*f585d8a3SJacky Wang private Builder(int individualProducerSize, int collectionProducerSize) { 68*f585d8a3SJacky Wang individualProducers = presizedList(individualProducerSize); 69*f585d8a3SJacky Wang collectionProducers = presizedList(collectionProducerSize); 70*f585d8a3SJacky Wang } 71*f585d8a3SJacky Wang 72*f585d8a3SJacky Wang @SuppressWarnings("unchecked") addProducer(Producer<? extends T> individualProducer)73*f585d8a3SJacky Wang public Builder<T> addProducer(Producer<? extends T> individualProducer) { 74*f585d8a3SJacky Wang assert individualProducer != null : "Codegen error? Null producer"; 75*f585d8a3SJacky Wang individualProducers.add((Producer<T>) individualProducer); 76*f585d8a3SJacky Wang return this; 77*f585d8a3SJacky Wang } 78*f585d8a3SJacky Wang 79*f585d8a3SJacky Wang @SuppressWarnings("unchecked") addCollectionProducer( Producer<? extends Collection<? extends T>> multipleProducer)80*f585d8a3SJacky Wang public Builder<T> addCollectionProducer( 81*f585d8a3SJacky Wang Producer<? extends Collection<? extends T>> multipleProducer) { 82*f585d8a3SJacky Wang assert multipleProducer != null : "Codegen error? Null producer"; 83*f585d8a3SJacky Wang collectionProducers.add((Producer<Collection<T>>) multipleProducer); 84*f585d8a3SJacky Wang return this; 85*f585d8a3SJacky Wang } 86*f585d8a3SJacky Wang build()87*f585d8a3SJacky Wang public SetProducer<T> build() { 88*f585d8a3SJacky Wang assert !hasDuplicates(individualProducers) 89*f585d8a3SJacky Wang : "Codegen error? Duplicates in the producer list"; 90*f585d8a3SJacky Wang assert !hasDuplicates(collectionProducers) 91*f585d8a3SJacky Wang : "Codegen error? Duplicates in the producer list"; 92*f585d8a3SJacky Wang 93*f585d8a3SJacky Wang return new SetProducer<T>(individualProducers, collectionProducers); 94*f585d8a3SJacky Wang } 95*f585d8a3SJacky Wang } 96*f585d8a3SJacky Wang 97*f585d8a3SJacky Wang private final List<Producer<T>> individualProducers; 98*f585d8a3SJacky Wang private final List<Producer<Collection<T>>> collectionProducers; 99*f585d8a3SJacky Wang SetProducer( List<Producer<T>> individualProducers, List<Producer<Collection<T>>> collectionProducers)100*f585d8a3SJacky Wang private SetProducer( 101*f585d8a3SJacky Wang List<Producer<T>> individualProducers, List<Producer<Collection<T>>> collectionProducers) { 102*f585d8a3SJacky Wang this.individualProducers = individualProducers; 103*f585d8a3SJacky Wang this.collectionProducers = collectionProducers; 104*f585d8a3SJacky Wang } 105*f585d8a3SJacky Wang 106*f585d8a3SJacky Wang /** 107*f585d8a3SJacky Wang * Returns a future {@link Set} that contains the elements given by each of the producers. 108*f585d8a3SJacky Wang * 109*f585d8a3SJacky Wang * <p>If any of the delegate collections, or any elements therein, are null, then this future will 110*f585d8a3SJacky Wang * fail with a NullPointerException. 111*f585d8a3SJacky Wang * 112*f585d8a3SJacky Wang * <p>Canceling this future will attempt to cancel all of the component futures, and if any of the 113*f585d8a3SJacky Wang * delegate futures fails or is canceled, this one is, too. 114*f585d8a3SJacky Wang * 115*f585d8a3SJacky Wang * @throws NullPointerException if any of the delegate producers return null 116*f585d8a3SJacky Wang */ 117*f585d8a3SJacky Wang @Override compute()118*f585d8a3SJacky Wang public ListenableFuture<Set<T>> compute() { 119*f585d8a3SJacky Wang List<ListenableFuture<T>> individualFutures = 120*f585d8a3SJacky Wang new ArrayList<ListenableFuture<T>>(individualProducers.size()); 121*f585d8a3SJacky Wang for (Producer<T> producer : individualProducers) { 122*f585d8a3SJacky Wang individualFutures.add(checkNotNull(producer.get())); 123*f585d8a3SJacky Wang } 124*f585d8a3SJacky Wang 125*f585d8a3SJacky Wang // Presize the list of collections produced by the amount of collectionProducers, with one more 126*f585d8a3SJacky Wang // for the consolidate individualFutures from Futures.allAsList. 127*f585d8a3SJacky Wang List<ListenableFuture<? extends Collection<T>>> futureCollections = 128*f585d8a3SJacky Wang new ArrayList<ListenableFuture<? extends Collection<T>>>(collectionProducers.size() + 1); 129*f585d8a3SJacky Wang futureCollections.add(Futures.allAsList(individualFutures)); 130*f585d8a3SJacky Wang for (Producer<Collection<T>> producer : collectionProducers) { 131*f585d8a3SJacky Wang futureCollections.add(checkNotNull(producer.get())); 132*f585d8a3SJacky Wang } 133*f585d8a3SJacky Wang return transform( 134*f585d8a3SJacky Wang Futures.allAsList(futureCollections), 135*f585d8a3SJacky Wang new Function<List<Collection<T>>, Set<T>>() { 136*f585d8a3SJacky Wang @Override 137*f585d8a3SJacky Wang public Set<T> apply(List<Collection<T>> sets) { 138*f585d8a3SJacky Wang ImmutableSet.Builder<T> builder = ImmutableSet.builder(); 139*f585d8a3SJacky Wang for (Collection<T> set : sets) { 140*f585d8a3SJacky Wang builder.addAll(set); 141*f585d8a3SJacky Wang } 142*f585d8a3SJacky Wang return builder.build(); 143*f585d8a3SJacky Wang } 144*f585d8a3SJacky Wang }, 145*f585d8a3SJacky Wang directExecutor()); 146*f585d8a3SJacky Wang } 147*f585d8a3SJacky Wang } 148