1 /*
2  * Copyright 2018 The Android Open Source Project
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 androidx.room.solver.shortcut.binderprovider
18 
19 import androidx.room.compiler.processing.XRawType
20 import androidx.room.compiler.processing.XType
21 import androidx.room.ext.KotlinTypeNames
22 import androidx.room.processor.Context
23 import androidx.room.solver.RxType
24 import androidx.room.solver.shortcut.binder.DeleteOrUpdateFunctionBinder
25 import androidx.room.solver.shortcut.binder.LambdaDeleteOrUpdateFunctionBinder
26 
27 /** Provider for Rx Callable binders. */
28 open class RxCallableDeleteOrUpdateFunctionBinderProvider
29 internal constructor(val context: Context, private val rxType: RxType) :
30     DeleteOrUpdateFunctionBinderProvider {
31 
32     /**
33      * [Single] and [Maybe] are generics but [Completable] is not so each implementation of this
34      * class needs to define how to extract the type argument.
35      */
extractTypeArgnull36     open fun extractTypeArg(declared: XType): XType = declared.typeArguments.first()
37 
38     override fun matches(declared: XType): Boolean =
39         declared.typeArguments.size == 1 && matchesRxType(declared)
40 
41     private fun matchesRxType(declared: XType): Boolean {
42         return declared.rawType.asTypeName() == rxType.className
43     }
44 
providenull45     override fun provide(declared: XType): DeleteOrUpdateFunctionBinder {
46         val typeArg = extractTypeArg(declared)
47         val adapter = context.typeAdapterStore.findDeleteOrUpdateAdapter(typeArg)
48         return LambdaDeleteOrUpdateFunctionBinder(
49             typeArg = typeArg,
50             functionName = rxType.factoryMethodName,
51             adapter = adapter
52         )
53     }
54 
55     companion object {
getAllnull56         fun getAll(context: Context) =
57             listOf(
58                 RxSingleOrMaybeDeleteOrUpdateFunctionBinderProvider(context, RxType.RX2_SINGLE),
59                 RxSingleOrMaybeDeleteOrUpdateFunctionBinderProvider(context, RxType.RX2_MAYBE),
60                 RxCompletableDeleteOrUpdateFunctionBinderProvider(context, RxType.RX2_COMPLETABLE),
61                 RxSingleOrMaybeDeleteOrUpdateFunctionBinderProvider(context, RxType.RX3_SINGLE),
62                 RxSingleOrMaybeDeleteOrUpdateFunctionBinderProvider(context, RxType.RX3_MAYBE),
63                 RxCompletableDeleteOrUpdateFunctionBinderProvider(context, RxType.RX3_COMPLETABLE)
64             )
65     }
66 }
67 
68 private class RxCompletableDeleteOrUpdateFunctionBinderProvider(context: Context, rxType: RxType) :
69     RxCallableDeleteOrUpdateFunctionBinderProvider(context, rxType) {
70 
71     private val completableType: XRawType? by lazy {
72         context.processingEnv.findType(rxType.className.canonicalName)?.rawType
73     }
74 
75     /**
76      * Since Completable has no type argument, the supported return type is Unit (non-nullable)
77      * since the 'createCompletable" factory method take a Kotlin lambda.
78      */
79     override fun extractTypeArg(declared: XType): XType =
80         context.processingEnv.requireType(KotlinTypeNames.UNIT)
81 
82     override fun matches(declared: XType): Boolean = isCompletable(declared)
83 
84     private fun isCompletable(declared: XType): Boolean {
85         val completableType = this.completableType ?: return false
86         return declared.rawType.isAssignableFrom(completableType)
87     }
88 }
89 
90 private class RxSingleOrMaybeDeleteOrUpdateFunctionBinderProvider(
91     context: Context,
92     rxType: RxType
93 ) : RxCallableDeleteOrUpdateFunctionBinderProvider(context, rxType) {
94 
95     /** Since Maybe can have null values, the lambda returned must allow for null values. */
extractTypeArgnull96     override fun extractTypeArg(declared: XType): XType =
97         declared.typeArguments.first().makeNullable()
98 }
99