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.util
18
19 import com.android.systemui.kairos.util.Maybe.Present
20
21 /** Contains at least one of two potential values. */
22 sealed class These<out A, out B> {
23 /** A [These] that contains a [First] value. */
24 class First<A, B> internal constructor(val value: A) : These<A, B>()
25
26 /** A [These] that contains a [Second] value. */
27 class Second<A, B> internal constructor(val value: B) : These<A, B>()
28
29 /** A [These] that contains [Both] a [first] and [second] value. */
30 class Both<A, B> internal constructor(val first: A, val second: B) : These<A, B>()
31
32 companion object {
33 /** Constructs a [These] containing the first possibility. */
firstnull34 fun <A> first(value: A): These<A, Nothing> = First(value)
35
36 /** Constructs a [These] containing the second possibility. */
37 fun <B> second(value: B): These<Nothing, B> = Second(value)
38
39 /** Constructs a [These] containing both possibilities. */
40 fun <A, B> both(first: A, second: B): These<A, B> = Both(first, second)
41 }
42 }
43
44 /**
45 * Returns a single value from this [These]; either the single value held within, or the result of
46 * applying [f] to both values.
47 */
48 inline fun <A> These<A, A>.merge(f: (A, A) -> A): A =
49 when (this) {
50 is These.First -> value
51 is These.Second -> value
52 is These.Both -> f(first, second)
53 }
54
55 /** Returns the [These.First] [value][These.First.value] present in this [These] as a [Maybe]. */
maybeFirstnull56 fun <A> These<A, *>.maybeFirst(): Maybe<A> =
57 when (this) {
58 is These.Both -> Maybe.present(first)
59 is These.Second -> Maybe.absent
60 is These.First -> Maybe.present(value)
61 }
62
63 /**
64 * Returns the [These.First] [value][These.First.value] present in this [These], or `null` if not
65 * present.
66 */
firstOrNullnull67 fun <A : Any> These<A, *>.firstOrNull(): A? =
68 when (this) {
69 is These.Both -> first
70 is These.Second -> null
71 is These.First -> value
72 }
73
74 /** Returns the [These.Second] [value][These.Second.value] present in this [These] as a [Maybe]. */
maybeSecondnull75 fun <A> These<*, A>.maybeSecond(): Maybe<A> =
76 when (this) {
77 is These.Both -> Maybe.present(second)
78 is These.Second -> Maybe.present(value)
79 is These.First -> Maybe.absent
80 }
81
82 /**
83 * Returns the [These.Second] [value][These.Second.value] present in this [These], or `null` if not
84 * present.
85 */
secondOrNullnull86 fun <A : Any> These<*, A>.secondOrNull(): A? =
87 when (this) {
88 is These.Both -> second
89 is These.Second -> value
90 is These.First -> null
91 }
92
93 /** Returns [These.Both] values present in this [These] as a [Maybe]. */
maybeBothnull94 fun <A, B> These<A, B>.maybeBoth(): Maybe<Pair<A, B>> =
95 when (this) {
96 is These.Both -> Maybe.present(first to second)
97 else -> Maybe.absent
98 }
99
100 /** Returns a [These] containing [first] and/or [second] if they are present. */
thesenull101 fun <A, B> these(first: Maybe<A>, second: Maybe<B>): Maybe<These<A, B>> =
102 when (first) {
103 is Present ->
104 Maybe.present(
105 when (second) {
106 is Present -> These.both(first.value, second.value)
107 else -> These.first(first.value)
108 }
109 )
110
111 else ->
112 when (second) {
113 is Present -> Maybe.present(These.second(second.value))
114 else -> Maybe.absent
115 }
116 }
117
118 /**
119 * Returns a [These] containing [first] and/or [second] if they are non-null, or `null` if both are
120 * `null`.
121 */
theseNotNullnull122 fun <A : Any, B : Any> theseNotNull(first: A?, second: B?): These<A, B>? =
123 first?.let { second?.let { These.both(first, second) } ?: These.first(first) }
<lambda>null124 ?: second?.let { These.second(second) }
125
126 /**
127 * Returns two maps, with [Pair.first] containing all [These.First] values and [Pair.second]
128 * containing all [These.Second] values.
129 *
130 * If the value is [These.Both], then the associated key with appear in both output maps, bound to
131 * [These.Both.first] and [These.Both.second] in each respective output.
132 */
partitionThesenull133 fun <K, A, B> Map<K, These<A, B>>.partitionThese(): Pair<Map<K, A>, Map<K, B>> {
134 val a = mutableMapOf<K, A>()
135 val b = mutableMapOf<K, B>()
136 for ((k, t) in this) {
137 when (t) {
138 is These.Both -> {
139 a[k] = t.first
140 b[k] = t.second
141 }
142 is These.Second -> {
143 b[k] = t.value
144 }
145 is These.First -> {
146 a[k] = t.value
147 }
148 }
149 }
150 return a to b
151 }
152