Option.kt

package de.pflugradts.kotlinextensions

import de.pflugradts.kotlinextensions.MutableOption.Companion.optionOf
import java.util.Optional

interface Option<T> {
    val isPresent: Boolean
    val isEmpty: Boolean
    fun get(): T
    fun orNull(): T?
    fun orElse(other: T): T
    fun ifPresent(block: (T) -> Unit)
    fun ifPresentOrElse(block: (T) -> Unit, other: () -> Unit)
    fun <U> map(block: (T) -> U): Option<U>
    fun or(block: () -> Option<T>): Option<T>
}

class MutableOption<T> private constructor(private var value: T?) : Option<T> {
    override val isPresent get() = value != null
    override val isEmpty get() = !isPresent
    override fun get() = value!!
    override fun orNull() = value
    override fun orElse(other: T) = value ?: other
    override fun ifPresent(block: (T) -> Unit) {
        value?.let { block(it) }
    }
    override fun ifPresentOrElse(block: (T) -> Unit, other: () -> Unit) {
        ifPresent(block)
        value ?: other()
    }
    override fun <U> map(block: (T) -> U) = value?.let { optionOf(block(it)) } ?: emptyOption()
    fun <U> mapMutable(block: (T) -> U) = value?.let { mutableOptionOf(block(it)) } ?: mutableOptionOf()
    override fun or(block: () -> Option<T>) = if (isPresent) this else block()
    fun set(value: T?) {
        this.value = value
    }
    companion object {
        fun <T> emptyOption(): Option<T> = MutableOption(null)
        fun <T> optionOf(value: T? = null): Option<T> = MutableOption(value)
        fun <T> mutableOptionOf(value: T? = null): MutableOption<T> = MutableOption(value)
    }
}

fun <T> Optional<T>.toOption() = optionOf(this.orElse(null))