• 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 @file:Suppress("NOTHING_TO_INLINE")
18 
19 package com.android.systemui.kairos.util
20 
21 import com.android.systemui.kairos.util.Either.First
22 import com.android.systemui.kairos.util.Either.Second
23 
24 /**
25  * Contains a value of two possibilities: `First<A>` or `Second<B>`
26  *
27  * [Either] generalizes sealed classes the same way that [Pair] generalizes data classes; if a
28  * [Pair] is effectively an anonymous grouping of two instances, then an [Either] is an anonymous
29  * set of two options.
30  */
31 sealed interface Either<out A, out B> {
32     /** An [Either] that contains a [First] value. */
33     @JvmInline value class First<out A>(val value: A) : Either<A, Nothing>
34 
35     /** An [Either] that contains a [Second] value. */
36     @JvmInline value class Second<out B>(val value: B) : Either<Nothing, B>
37 
38     companion object {
39         /** Constructs an [Either] containing the first possibility. */
firstnull40         fun <A> first(value: A): Either<A, Nothing> = First(value)
41 
42         /** Constructs a [Either] containing the second possibility. */
43         fun <B> second(value: B): Either<Nothing, B> = Second(value)
44     }
45 }
46 
47 /**
48  * Returns an [Either] containing the result of applying [transform] to the [First] value, or the
49  * [Second] value unchanged.
50  */
51 inline fun <A, B, C> Either<A, C>.mapFirst(transform: (A) -> B): Either<B, C> =
52     when (this) {
53         is First -> First(transform(value))
54         is Second -> this
55     }
56 
57 /**
58  * Returns an [Either] containing the result of applying [transform] to the [Second] value, or the
59  * [First] value unchanged.
60  */
mapSecondnull61 inline fun <A, B, C> Either<A, B>.mapSecond(transform: (B) -> C): Either<A, C> =
62     when (this) {
63         is First -> this
64         is Second -> Second(transform(value))
65     }
66 
67 /** Returns a [Maybe] containing the [First] value held by this [Either], if present. */
firstMaybenull68 inline fun <A> Either<A, *>.firstMaybe(): Maybe<A> =
69     when (this) {
70         is First -> Maybe.present(value)
71         else -> Maybe.absent
72     }
73 
74 /** Returns the [First] value held by this [Either], or `null` if this is a [Second] value. */
firstOrNullnull75 inline fun <A> Either<A, *>.firstOrNull(): A? =
76     when (this) {
77         is First -> value
78         else -> null
79     }
80 
81 /** Returns a [Maybe] containing the [Second] value held by this [Either], if present. */
secondMaybenull82 inline fun <B> Either<*, B>.secondMaybe(): Maybe<B> =
83     when (this) {
84         is Second -> Maybe.present(value)
85         else -> Maybe.absent
86     }
87 
88 /** Returns the [Second] value held by this [Either], or `null` if this is a [First] value. */
secondOrNullnull89 inline fun <B> Either<*, B>.secondOrNull(): B? =
90     when (this) {
91         is Second -> value
92         else -> null
93     }
94 
95 /**
96  * Returns a [These] containing either the [First] value as [These.first], or the [Second] value as
97  * [These.second]. Will never return a [These.both].
98  */
asThesenull99 fun <A, B> Either<A, B>.asThese(): These<A, B> =
100     when (this) {
101         is Second -> These.second(value)
102         is First -> These.first(value)
103     }
104 
105 /**
106  * Partitions this sequence of [Either] into two lists; [Pair.first] contains all [First] values,
107  * and [Pair.second] contains all [Second] values.
108  */
partitionEithersnull109 fun <A, B> Sequence<Either<A, B>>.partitionEithers(): Pair<List<A>, List<B>> {
110     val firsts = mutableListOf<A>()
111     val seconds = mutableListOf<B>()
112     for (either in this) {
113         when (either) {
114             is First -> firsts.add(either.value)
115             is Second -> seconds.add(either.value)
116         }
117     }
118     return firsts to seconds
119 }
120 
121 /**
122  * Partitions this map of [Either] values into two maps; [Pair.first] contains all [First] values,
123  * and [Pair.second] contains all [Second] values.
124  */
partitionEithersnull125 fun <K, A, B> Map<K, Either<A, B>>.partitionEithers(): Pair<Map<K, A>, Map<K, B>> {
126     val firsts = mutableMapOf<K, A>()
127     val seconds = mutableMapOf<K, B>()
128     for ((k, e) in this) {
129         when (e) {
130             is First -> firsts[k] = e.value
131             is Second -> seconds[k] = e.value
132         }
133     }
134     return firsts to seconds
135 }
136