xref: /aosp_15_r20/external/dagger2/java/dagger/producers/internal/SetProducer.java (revision f585d8a307d0621d6060bd7e80091fdcbf94fe27)
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