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