• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.internal.codegen.binding;
18 
19 import static com.google.common.base.CaseFormat.UPPER_CAMEL;
20 import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
21 
22 import androidx.room.compiler.processing.XProcessingEnv;
23 import com.squareup.javapoet.ClassName;
24 import com.squareup.javapoet.CodeBlock;
25 import com.squareup.javapoet.ParameterizedTypeName;
26 import com.squareup.javapoet.TypeName;
27 import dagger.internal.codegen.base.RequestKinds;
28 import dagger.internal.codegen.javapoet.Expression;
29 import dagger.internal.codegen.javapoet.TypeNames;
30 import dagger.internal.codegen.model.DependencyRequest;
31 import dagger.internal.codegen.model.RequestKind;
32 import java.util.Optional;
33 
34 /** One of the core types initialized as fields in a generated component. */
35 public enum FrameworkType {
36   /** A {@link javax.inject.Provider}. */
37   PROVIDER {
38     @Override
to( RequestKind requestKind, CodeBlock from)39     public CodeBlock to(
40         RequestKind requestKind,
41         CodeBlock from) {
42       switch (requestKind) {
43         case INSTANCE:
44           return CodeBlock.of("$L.get()", from);
45 
46         case LAZY:
47           return CodeBlock.of(
48               "$T.lazy($L)",
49               TypeNames.DOUBLE_CHECK,
50               from);
51 
52         case PROVIDER:
53           return from;
54 
55         case PROVIDER_OF_LAZY:
56           return CodeBlock.of("$T.create($L)", TypeNames.PROVIDER_OF_LAZY, from);
57 
58         case PRODUCER:
59           return CodeBlock.of("$T.producerFromProvider($L)", TypeNames.PRODUCERS, from);
60 
61         case FUTURE:
62           return CodeBlock.of(
63               "$T.immediateFuture($L)",
64               TypeNames.FUTURES,
65               to(
66                   RequestKind.INSTANCE,
67                   from));
68 
69         case PRODUCED:
70           return CodeBlock.of(
71               "$T.successful($L)",
72               TypeNames.PRODUCED,
73               to(
74                   RequestKind.INSTANCE, from));
75 
76         default:
77           throw new IllegalArgumentException(
78               String.format("Cannot request a %s from a %s", requestKind, this));
79       }
80     }
81 
82     @Override
to( RequestKind requestKind, Expression from, XProcessingEnv processingEnv)83     public Expression to(
84         RequestKind requestKind,
85         Expression from,
86         XProcessingEnv processingEnv) {
87       CodeBlock codeBlock = to(
88           requestKind,
89           from.codeBlock());
90       switch (requestKind) {
91         case INSTANCE:
92           return Expression.create(from.type().unwrapType(), codeBlock);
93 
94         case PROVIDER:
95           return from;
96 
97         case PROVIDER_OF_LAZY:
98           return Expression.create(
99               from.type().rewrapType(TypeNames.LAZY).wrapType(TypeNames.DAGGER_PROVIDER),
100               codeBlock);
101 
102         case FUTURE:
103           return Expression.create(from.type().rewrapType(TypeNames.LISTENABLE_FUTURE), codeBlock);
104 
105         default:
106           return Expression.create(
107               from.type().rewrapType(RequestKinds.frameworkClassName(requestKind)), codeBlock);
108       }
109     }
110   },
111 
112   /** A {@link dagger.producers.Producer}. */
113   PRODUCER_NODE {
114     @Override
to( RequestKind requestKind, CodeBlock from)115     public CodeBlock to(
116         RequestKind requestKind,
117         CodeBlock from) {
118       switch (requestKind) {
119         case FUTURE:
120           return CodeBlock.of("$L.get()", from);
121 
122         case PRODUCER:
123           return from;
124 
125         default:
126           throw new IllegalArgumentException(
127               String.format("Cannot request a %s from a %s", requestKind, this));
128       }
129     }
130 
131     @Override
to( RequestKind requestKind, Expression from, XProcessingEnv processingEnv)132     public Expression to(
133         RequestKind requestKind,
134         Expression from,
135         XProcessingEnv processingEnv) {
136       switch (requestKind) {
137         case FUTURE:
138           return Expression.create(
139               from.type().rewrapType(TypeNames.LISTENABLE_FUTURE),
140               to(
141                   requestKind,
142                   from.codeBlock()));
143 
144         case PRODUCER:
145           return Expression.create(from.type(), to(
146               requestKind,
147               from.codeBlock()));
148 
149         default:
150           throw new IllegalArgumentException(
151               String.format("Cannot request a %s from a %s", requestKind, this));
152       }
153     }
154   };
155 
156   /** Returns the framework type appropriate for fields for a given binding type. */
forBindingType(BindingType bindingType)157   public static FrameworkType forBindingType(BindingType bindingType) {
158     switch (bindingType) {
159       case PROVISION:
160         return PROVIDER;
161       case PRODUCTION:
162         return PRODUCER_NODE;
163       case MEMBERS_INJECTION:
164     }
165     throw new AssertionError(bindingType);
166   }
167 
168   /** Returns the framework type that exactly matches the given request kind, if one exists. */
forRequestKind(RequestKind requestKind)169   public static Optional<FrameworkType> forRequestKind(RequestKind requestKind) {
170     switch (requestKind) {
171       case PROVIDER:
172         return Optional.of(FrameworkType.PROVIDER);
173       default:
174         return Optional.empty();
175     }
176   }
177 
178   /** The class of fields of this type. */
frameworkClassName()179   public ClassName frameworkClassName() {
180     switch (this) {
181       case PROVIDER:
182         return TypeNames.DAGGER_PROVIDER;
183       case PRODUCER_NODE:
184         // TODO(cgdecker): Replace this with new class for representing internal producer nodes.
185         // Currently the new class is CancellableProducer, but it may be changed to ProducerNode and
186         // made to not implement Producer.
187         return TypeNames.PRODUCER;
188     }
189     throw new AssertionError("Unknown value: " + this.name());
190   }
191 
192   /** Returns the {@link #frameworkClassName()} parameterized with a type. */
frameworkClassOf(TypeName valueType)193   public ParameterizedTypeName frameworkClassOf(TypeName valueType) {
194     return ParameterizedTypeName.get(frameworkClassName(), valueType);
195   }
196 
197   /** The request kind that an instance of this framework type can satisfy directly, if any. */
requestKind()198   public RequestKind requestKind() {
199     switch (this) {
200       case PROVIDER:
201         return RequestKind.PROVIDER;
202       case PRODUCER_NODE:
203         return RequestKind.PRODUCER;
204     }
205     throw new AssertionError("Unknown value: " + this.name());
206   }
207 
208   /**
209    * Returns a {@link CodeBlock} that evaluates to a requested object given an expression that
210    * evaluates to an instance of this framework type.
211    *
212    * @param requestKind the kind of {@link DependencyRequest} that the returned expression can
213    *     satisfy
214    * @param from a {@link CodeBlock} that evaluates to an instance of this framework type
215    * @throws IllegalArgumentException if a valid expression cannot be generated for {@code
216    *     requestKind}
217    */
to( RequestKind requestKind, CodeBlock from)218   public abstract CodeBlock to(
219       RequestKind requestKind,
220       CodeBlock from);
221 
222   /**
223    * Returns an {@link Expression} that evaluates to a requested object given an expression that
224    * evaluates to an instance of this framework type.
225    *
226    * @param requestKind the kind of {@link DependencyRequest} that the returned expression can
227    *     satisfy
228    * @param from an expression that evaluates to an instance of this framework type
229    * @throws IllegalArgumentException if a valid expression cannot be generated for {@code
230    *     requestKind}
231    */
to( RequestKind requestKind, Expression from, XProcessingEnv processingEnv)232   public abstract Expression to(
233       RequestKind requestKind,
234       Expression from,
235       XProcessingEnv processingEnv);
236 
237   @Override
toString()238   public String toString() {
239     return UPPER_UNDERSCORE.to(UPPER_CAMEL, super.toString());
240   }
241 }
242