diff --git a/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/Optional.kt b/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/Optional.kt new file mode 100644 index 00000000000..82919cfc60c --- /dev/null +++ b/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/Optional.kt @@ -0,0 +1,52 @@ +package dev.inmo.micro_utils.common + +import kotlinx.serialization.Serializable + +/** + * This type represents [T] as not only potentially nullable data, but also as a data which can not be presented. This + * type will be useful in cases when [T] is nullable and null as valuable data too in time of data absence should be + * presented by some third type. + * + * Let's imagine, you have nullable name in some database. In case when name is not nullable everything is clear - null + * will represent absence of row in the database. In case when name is nullable null will be a little bit dual-meaning, + * cause this null will say nothing about availability of the row (of course, it is exaggerated example) + * + * @see Optional.presented + * @see Optional.absent + * @see Optional.optional + * @see Optional.onPresented + * @see Optional.onAbsent + */ +@Serializable +data class Optional internal constructor( + internal val data: T?, + internal val dataPresented: Boolean +) { + companion object { + /** + * Will create [Optional] with presented data + */ + fun presented(data: T) = Optional(data, true) + /** + * Will create [Optional] without data + */ + fun absent() = Optional(null, false) + } +} + +inline val T.optional + get() = Optional.presented(this) + +/** + * Will call [block] when data presented ([Optional.dataPresented] == true) + */ +fun Optional.onPresented(block: (T) -> Unit): Optional = apply { + if (dataPresented) { block(data as T) } +} + +/** + * Will call [block] when data absent ([Optional.dataPresented] == false) + */ +fun Optional.onAbsent(block: () -> Unit): Optional = apply { + if (!dataPresented) { block() } +}