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