commonMain.entity.optional.OptionalSnowflake.kt Maven / Gradle / Ivy
package dev.kord.common.entity.optional
import dev.kord.common.entity.Snowflake
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlin.jvm.JvmName
/**
* Represents a value that encapsulate a [Snowflake]'s
* [optional and value state in the Discord API](https://discord.com/developers/docs/reference#nullable-and-optional-resource-fields).
*
* Specifically:
*
* * [Missing] - a [Snowflake] field that was not present in the serialized entity.
* * [Value] - a [Snowflake] field that was assigned a non-null value in the serialized entity.
*
* > Note that there is no nullable variant present. Use `Snowflake?` or `OptionalSnowflake?` for this case instead.
*
* The base class is (de)serializable with kotlinx.serialization.
*
* Note that kotlinx.serialization does **not** call serializers for values that are not
* present in the serialized format. `Optional` fields should have a default value of `OptionalSnowflake.Missing`:
*
* ```kotlin
* @Serializable
* class DiscordUser(
* val id: Long,
* val username: String,
* val bot: OptionalSnowflake = OptionalSnowflake.Missing
* )
* ```
*/
@Serializable(with = OptionalSnowflake.Serializer::class)
public sealed class OptionalSnowflake {
public open val value: Snowflake?
get() = when (this) {
Missing -> null
is Value -> value
}
public val asOptional: Optional
get() = when (this) {
Missing -> Optional.Missing()
is Value -> Optional.Value(value)
}
/**
* returns [default] if the optional is [Missing], or [Value.value] if is [Value].
*/
public fun orElse(default: Snowflake): Snowflake = when (this) {
Missing -> default
is Value -> value
}
/**
* Represents a [Snowflake] field that was not present in the serialized entity.
*/
public object Missing : OptionalSnowflake() {
override fun toString(): String = "OptionalSnowflake.Missing"
}
/**
* Represents a [Snowflake] field that was assigned a non-null value in the serialized entity.
* Equality and hashcode is implemented through its [value].
*
* @param uLongValue the raw value this optional wraps.
* See [Snowflake.value] and [Snowflake.validValues] for more details.
*/
public class Value(private val uLongValue: ULong) : OptionalSnowflake() {
public constructor(value: Snowflake) : this(value.value)
override val value: Snowflake get() = Snowflake(uLongValue)
/**
* Destructures this optional to its [value].
*/
public operator fun component1(): Snowflake = value
override fun toString(): String = "OptionalSnowflake.Value(snowflake=$value)"
override fun equals(other: Any?): Boolean {
val value = other as? Value ?: return false
return value.value == this.value
}
override fun hashCode(): Int = value.hashCode()
}
internal object Serializer : KSerializer {
override val descriptor: SerialDescriptor = ULong.serializer().descriptor
override fun deserialize(decoder: Decoder): OptionalSnowflake =
Value(decoder.decodeInline(descriptor).decodeLong().toULong())
override fun serialize(encoder: Encoder, value: OptionalSnowflake) = when (value) {
Missing -> Unit // ignore value
is Value -> encoder.encodeInline(descriptor).encodeLong(value.value.value.toLong())
}
}
}
/**
* returns `null` if this is `null` or [OptionalSnowflake.Missing], calls [OptionalSnowflake.Value.value] otherwise.
*/
public val OptionalSnowflake?.value: Snowflake?
get() = when (this) {
is OptionalSnowflake.Value -> value
OptionalSnowflake.Missing, null -> null
}
public fun Snowflake.optionalSnowflake(): OptionalSnowflake.Value = OptionalSnowflake.Value(this.value)
@JvmName("optionalNullable")
public fun Snowflake?.optionalSnowflake(): OptionalSnowflake.Value? = this?.optionalSnowflake()
public inline fun OptionalSnowflake.map(mapper: (Snowflake) -> T): Optional = when (this) {
OptionalSnowflake.Missing -> Optional.Missing()
is OptionalSnowflake.Value -> Optional.Value(mapper(value))
}