1 /*
2  * Copyright (C) 2024 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 com.android.systemui.kairos.internal
18 
19 import com.android.systemui.kairos.FrpDeferredValue
20 import com.android.systemui.kairos.FrpTransactionScope
21 import com.android.systemui.kairos.TFlow
22 import com.android.systemui.kairos.TFlowInit
23 import com.android.systemui.kairos.TFlowLoop
24 import com.android.systemui.kairos.TState
25 import com.android.systemui.kairos.TStateInit
26 import com.android.systemui.kairos.Transactional
27 import com.android.systemui.kairos.emptyTFlow
28 import com.android.systemui.kairos.init
29 import com.android.systemui.kairos.mapCheap
30 import com.android.systemui.kairos.switch
31 import kotlin.coroutines.Continuation
32 import kotlin.coroutines.CoroutineContext
33 import kotlin.coroutines.EmptyCoroutineContext
34 import kotlin.coroutines.startCoroutine
35 import kotlinx.coroutines.CompletableDeferred
36 import kotlinx.coroutines.completeWith
37 import kotlinx.coroutines.job
38 
39 internal class EvalScopeImpl(networkScope: NetworkScope, deferScope: DeferScope) :
<lambda>null40     EvalScope, NetworkScope by networkScope, DeferScope by deferScope {
41 
42     private suspend fun <A> Transactional<A>.sample(): A =
43         impl.sample().sample(this@EvalScopeImpl).await()
44 
45     private suspend fun <A> TState<A>.sample(): A =
46         init.connect(evalScope = this@EvalScopeImpl).getCurrentWithEpoch(this@EvalScopeImpl).first
47 
48     private val <A> Transactional<A>.deferredValue: FrpDeferredValue<A>
49         get() = FrpDeferredValue(deferAsync { sample() })
50 
51     private val <A> TState<A>.deferredValue: FrpDeferredValue<A>
52         get() = FrpDeferredValue(deferAsync { sample() })
53 
54     private val nowInternal: TFlow<Unit> by lazy {
55         var result by TFlowLoop<Unit>()
56         result =
57             TStateInit(
58                     constInit(
59                         "now",
60                         mkState(
61                             "now",
62                             "now",
63                             this,
64                             { result.mapCheap { emptyTFlow }.init.connect(evalScope = this) },
65                             CompletableDeferred(
66                                 TFlowInit(
67                                     constInit(
68                                         "now",
69                                         TFlowCheap {
70                                             ActivationResult(
71                                                 connection = NodeConnection(AlwaysNode, AlwaysNode),
72                                                 needsEval = true,
73                                             )
74                                         },
75                                     )
76                                 )
77                             ),
78                         ),
79                     )
80                 )
81                 .switch()
82         result
83     }
84 
85     private fun <R> deferredInternal(
86         block: suspend FrpTransactionScope.() -> R
87     ): FrpDeferredValue<R> = FrpDeferredValue(deferAsync { runInTransactionScope(block) })
88 
89     override suspend fun <R> runInTransactionScope(block: suspend FrpTransactionScope.() -> R): R {
90         val complete = CompletableDeferred<R>(parent = coroutineContext.job)
91         block.startCoroutine(
92             frpScope,
93             object : Continuation<R> {
94                 override val context: CoroutineContext
95                     get() = EmptyCoroutineContext
96 
97                 override fun resumeWith(result: Result<R>) {
98                     complete.completeWith(result)
99                 }
100             },
101         )
102         return complete.await()
103     }
104 
105     override val frpScope: FrpTransactionScope = FrpTransactionScopeImpl()
106 
107     inner class FrpTransactionScopeImpl : FrpTransactionScope {
108         override fun <A> Transactional<A>.sampleDeferred(): FrpDeferredValue<A> = deferredValue
109 
110         override fun <A> TState<A>.sampleDeferred(): FrpDeferredValue<A> = deferredValue
111 
112         override fun <R> deferredTransactionScope(
113             block: suspend FrpTransactionScope.() -> R
114         ): FrpDeferredValue<R> = deferredInternal(block)
115 
116         override val now: TFlow<Unit>
117             get() = nowInternal
118     }
119 }
120