package dev.inmo.tgbotapi.utils.extensions import kotlinx.coroutines.* import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.ReceiveChannel private sealed class DebounceAction { abstract val value: T } private data class AddValue(override val value: T) : DebounceAction() private data class RemoveJob(override val value: T, val job: Job) : DebounceAction() @Deprecated("Unused and will be removed in next major release") fun ReceiveChannel.debounceByValue( delayMillis: Long, scope: CoroutineScope = CoroutineScope(Dispatchers.Default), resultBroadcastChannelCapacity: Int = 32 ): ReceiveChannel { val outChannel = Channel(resultBroadcastChannelCapacity) val values = HashMap() val channel = Channel>(Channel.UNLIMITED) scope.launch { for (action in channel) { when (action) { is AddValue -> { val msg = action.value values[msg] ?.cancel() lateinit var job: Job job = launch { delay(delayMillis) outChannel.send(msg) channel.send(RemoveJob(msg, job)) } values[msg] = job } is RemoveJob -> if (values[action.value] == action.job) { values.remove(action.value) } } } } scope.launch { for (msg in this@debounceByValue) { channel.send(AddValue(msg)) } } return outChannel } typealias AccumulatedValues = Pair> fun ReceiveChannel>.accumulateByKey( delayMillis: Long, scope: CoroutineScope = CoroutineScope(Dispatchers.Default), resultBroadcastChannelCapacity: Int = 32 ): ReceiveChannel> { val outChannel = Channel>(resultBroadcastChannelCapacity) val values = HashMap>() val jobs = HashMap() val channel = Channel>>(Channel.UNLIMITED) scope.launch { for (action in channel) { val (key, value) = action.value when (action) { is AddValue -> { jobs[key] ?.cancel() (values[key] ?: mutableListOf().also { values[key] = it }).add(value) lateinit var job: Job job = launch { delay(delayMillis) values[key] ?.let { outChannel.send(key to it) channel.send(RemoveJob(key to value, job)) } } jobs[key] = job } is RemoveJob -> if (values[key] == action.job) { values.remove(key) jobs.remove(key) } } } } scope.launch { for (msg in this@accumulateByKey) { channel.send(AddValue(msg)) } } return outChannel }