fishy
10/07/2026, 9:20 PMtransform that gives you functions for both receiving and for emitting, instead of being automatically called once per published item with the value being passed into the lambda? Sort of like how a channel has a suspending receive functionephemient
10/07/2026, 10:20 PMfun <T, R> Flow<T>.transform(block: (from: ReceiveChannel<T>, to: SendChannel<R>) -> Unit): Flow<R> = channelFlow {
coroutineScope {
block(this@transform.produceIn(this@coroutineScope), this@channelFlow)
}
}fishy
10/07/2026, 10:41 PMfishy
10/07/2026, 10:48 PMinline fun <T, R> Flow<T>.channelTransform(crossinline block: suspend ChannelTransformScope<T, R>.() -> Unit): Flow<R> = channelFlow {
coroutineScope {
val recv = this@channelTransform.produceIn(this@coroutineScope)
val send = this@channelFlow
ChannelTransformScopeImpl(recv, send).block()
}
}
interface ChannelTransformScope<out T, in R> : ReceiveChannel<T>, SendChannel<R>
@PublishedApi
internal class ChannelTransformScopeImpl<out T, in R>(val rec: ReceiveChannel<T>, val send: SendChannel<R>) :
ReceiveChannel<T> by rec, SendChannel<R> by send, ChannelTransformScope<T, R>ephemient
10/07/2026, 10:53 PMfishy
10/07/2026, 10:54 PMchannelTransform implicitly in a scope where the context parameters are provided, but they still need to be named in the lambda in the actual usage?ephemient
10/07/2026, 10:55 PMwith awayephemient
10/07/2026, 10:55 PMfishy
10/07/2026, 10:55 PMfishy
10/07/2026, 10:55 PMephemient
10/07/2026, 10:58 PMfishy
10/07/2026, 10:58 PM