• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
18 
19 import com.android.systemui.kairos.internal.CompletableLazy
20 import com.android.systemui.kairos.internal.InitScope
21 import com.android.systemui.kairos.internal.NoScope
22 import com.android.systemui.kairos.internal.TransactionalImpl
23 import com.android.systemui.kairos.internal.init
24 import com.android.systemui.kairos.internal.transactionalImpl
25 import com.android.systemui.kairos.internal.util.hashString
26 
27 /**
28  * A time-varying value. A [Transactional] encapsulates the idea of some continuous state; each time
29  * it is "sampled", a new result may be produced.
30  *
31  * Because Kairos operates over an "idealized" model of Time that can be passed around as a data
32  * type, [Transactionals][Transactional] are guaranteed to produce the same result if queried
33  * multiple times at the same (conceptual) time, in order to preserve _referential transparency_.
34  */
35 @ExperimentalKairosApi
36 class Transactional<out A> internal constructor(internal val impl: State<TransactionalImpl<A>>) {
toStringnull37     override fun toString(): String = "${this::class.simpleName}@$hashString"
38 }
39 
40 /** A constant [Transactional] that produces [value] whenever it is sampled. */
41 @ExperimentalKairosApi
42 fun <A> transactionalOf(value: A): Transactional<A> =
43     Transactional(stateOf(TransactionalImpl.Const(CompletableLazy(value))))
44 
45 /**
46  * Returns a [Transactional] that acts as a deferred-reference to the [Transactional] produced by
47  * this [DeferredValue].
48  *
49  * When the returned [Transactional] is accessed by the Kairos network, the [DeferredValue] will be
50  * queried and used.
51  *
52  * Useful for recursive definitions.
53  *
54  * ```
55  *   fun <A> DeferredValue<Transactional<A>>.defer() = deferredTransactional { get() }
56  * ```
57  */
58 @ExperimentalKairosApi
59 fun <A> DeferredValue<Transactional<A>>.defer(): Transactional<A> = deferInline { unwrapped.value }
60 
61 /**
62  * Returns a [Transactional] that acts as a deferred-reference to the [Transactional] produced by
63  * this [Lazy].
64  *
65  * When the returned [Transactional] is accessed by the Kairos network, the [Lazy]'s
66  * [value][Lazy.value] will be queried and used.
67  *
68  * Useful for recursive definitions.
69  *
70  * ```
71  *   fun <A> Lazy<Transactional<A>>.defer() = deferredTransactional { value }
72  * ```
73  */
74 @ExperimentalKairosApi
<lambda>null75 fun <A> Lazy<Transactional<A>>.defer(): Transactional<A> = deferInline { value }
76 
77 /**
78  * Returns a [Transactional] that acts as a deferred-reference to the [Transactional] produced by
79  * [block].
80  *
81  * When the returned [Transactional] is accessed by the Kairos network, [block] will be invoked and
82  * the returned [Transactional] will be used.
83  *
84  * Useful for recursive definitions.
85  */
86 @ExperimentalKairosApi
deferredTransactionalnull87 fun <A> deferredTransactional(block: KairosScope.() -> Transactional<A>): Transactional<A> =
88     deferInline {
89         NoScope.block()
90     }
91 
deferInlinenull92 private inline fun <A> deferInline(
93     crossinline block: InitScope.() -> Transactional<A>
94 ): Transactional<A> =
95     Transactional(StateInit(init(name = null) { block().impl.init.connect(evalScope = this) }))
96 
97 /**
98  * Returns a [Transactional]. The passed [block] will be evaluated on demand at most once per
99  * transaction; any subsequent sampling within the same transaction will receive a cached value.
100  *
101  * @sample com.android.systemui.kairos.KairosSamples.sampleTransactional
102  */
103 @ExperimentalKairosApi
transactionallynull104 fun <A> transactionally(block: TransactionScope.() -> A): Transactional<A> =
105     Transactional(stateOf(transactionalImpl { block() }))
106 
107 /** Returns a [Transactional] that, when queried, samples this [State]. */
asTransactionalnull108 fun <A> State<A>.asTransactional(): Transactional<A> =
109     Transactional(map { TransactionalImpl.Const(CompletableLazy(it)) })
110