1 /*
<lambda>null2 * 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.internal.util.logDuration
20
21 internal val neverImpl: EventsImpl<Nothing> = EventsImplCheap { null }
22
23 internal class MapNode<A, B>(val upstream: PullNode<A>, val transform: EvalScope.(A, Int) -> B) :
24 PullNode<B> {
getPushEventnull25 override fun getPushEvent(logIndent: Int, evalScope: EvalScope): B =
26 logDuration(logIndent, "MapNode.getPushEvent") {
27 val upstream =
28 logDuration("upstream event") { upstream.getPushEvent(currentLogIndent, evalScope) }
29 logDuration("transform") { evalScope.transform(upstream, currentLogIndent) }
30 }
31 }
32
mapImplnull33 internal inline fun <A, B> mapImpl(
34 crossinline upstream: EvalScope.() -> EventsImpl<A>,
35 noinline transform: EvalScope.(A, Int) -> B,
36 ): EventsImpl<B> = EventsImplCheap { downstream ->
37 upstream().activate(evalScope = this, downstream)?.let { (connection, needsEval) ->
38 ActivationResult(
39 connection =
40 NodeConnection(
41 directUpstream = MapNode(connection.directUpstream, transform),
42 schedulerUpstream = connection.schedulerUpstream,
43 ),
44 needsEval = needsEval,
45 )
46 }
47 }
48
49 internal class CachedNode<A>(
50 private val transactionCache: TransactionCache<Lazy<A>>,
51 val upstream: PullNode<A>,
52 ) : PullNode<A> {
getPushEventnull53 override fun getPushEvent(logIndent: Int, evalScope: EvalScope): A =
54 logDuration(logIndent, "CachedNode.getPushEvent") {
55 val deferred =
56 logDuration("CachedNode.getOrPut", false) {
57 transactionCache.getOrPut(evalScope) {
58 evalScope.deferAsync {
59 logDuration("CachedNode.getUpstreamEvent") {
60 upstream.getPushEvent(currentLogIndent, evalScope)
61 }
62 }
63 }
64 }
65 logDuration("await") { deferred.value }
66 }
67 }
68
cachednull69 internal fun <A> EventsImpl<A>.cached(): EventsImpl<A> {
70 val key = TransactionCache<Lazy<A>>()
71 return EventsImplCheap { it ->
72 activate(this, it)?.let { (connection, needsEval) ->
73 ActivationResult(
74 connection =
75 NodeConnection(
76 directUpstream = CachedNode(key, connection.directUpstream),
77 schedulerUpstream = connection.schedulerUpstream,
78 ),
79 needsEval = needsEval,
80 )
81 }
82 }
83 }
84