xref: /aosp_15_r20/frameworks/base/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/util/Either.kt (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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 /**
22  * Contains a value of two possibilities: `Left<A>` or `Right<B>`
23  *
24  * [Either] generalizes sealed classes the same way that [Pair] generalizes data classes; if a
25  * [Pair] is effectively an anonymous grouping of two instances, then an [Either] is an anonymous
26  * set of two options.
27  */
28 sealed class Either<out A, out B>
29 
30 /** An [Either] that contains a [Left] value. */
31 data class Left<out A>(val value: A) : Either<A, Nothing>()
32 
33 /** An [Either] that contains a [Right] value. */
34 data class Right<out B>(val value: B) : Either<Nothing, B>()
35 
36 /**
37  * Returns an [Either] containing the result of applying [transform] to the [Left] value, or the
38  * [Right] value unchanged.
39  */
mapLeftnull40 inline fun <A, B, C> Either<A, C>.mapLeft(transform: (A) -> B): Either<B, C> =
41     when (this) {
42         is Left -> Left(transform(value))
43         is Right -> this
44     }
45 
46 /**
47  * Returns an [Either] containing the result of applying [transform] to the [Right] value, or the
48  * [Left] value unchanged.
49  */
mapRightnull50 inline fun <A, B, C> Either<A, B>.mapRight(transform: (B) -> C): Either<A, C> =
51     when (this) {
52         is Left -> this
53         is Right -> Right(transform(value))
54     }
55 
56 /** Returns a [Maybe] containing the [Left] value held by this [Either], if present. */
leftMaybenull57 inline fun <A> Either<A, *>.leftMaybe(): Maybe<A> =
58     when (this) {
59         is Left -> just(value)
60         else -> None
61     }
62 
63 /** Returns the [Left] value held by this [Either], or `null` if this is a [Right] value. */
leftOrNullnull64 inline fun <A> Either<A, *>.leftOrNull(): A? =
65     when (this) {
66         is Left -> value
67         else -> null
68     }
69 
70 /** Returns a [Maybe] containing the [Right] value held by this [Either], if present. */
rightMaybenull71 inline fun <B> Either<*, B>.rightMaybe(): Maybe<B> =
72     when (this) {
73         is Right -> just(value)
74         else -> None
75     }
76 
77 /** Returns the [Right] value held by this [Either], or `null` if this is a [Left] value. */
rightOrNullnull78 inline fun <B> Either<*, B>.rightOrNull(): B? =
79     when (this) {
80         is Right -> value
81         else -> null
82     }
83 
84 /**
85  * Partitions this sequence of [Either] into two lists; [Pair.first] contains all [Left] values, and
86  * [Pair.second] contains all [Right] values.
87  */
partitionEithersnull88 fun <A, B> Sequence<Either<A, B>>.partitionEithers(): Pair<List<A>, List<B>> {
89     val lefts = mutableListOf<A>()
90     val rights = mutableListOf<B>()
91     for (either in this) {
92         when (either) {
93             is Left -> lefts.add(either.value)
94             is Right -> rights.add(either.value)
95         }
96     }
97     return lefts to rights
98 }
99 
100 /**
101  * Partitions this map of [Either] values into two maps; [Pair.first] contains all [Left] values,
102  * and [Pair.second] contains all [Right] values.
103  */
partitionEithersnull104 fun <K, A, B> Map<K, Either<A, B>>.partitionEithers(): Pair<Map<K, A>, Map<K, B>> {
105     val lefts = mutableMapOf<K, A>()
106     val rights = mutableMapOf<K, B>()
107     for ((k, e) in this) {
108         when (e) {
109             is Left -> lefts[k] = e.value
110             is Right -> rights[k] = e.value
111         }
112     }
113     return lefts to rights
114 }
115