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