import { ResultCallback , Suspender } from "./Types" ; /**
 * Channels are used to send and receive messages between coroutines. Channels can be buffered so
 * that senders do not suspend if there isn't a receiver waiting to receive the next message.
 * If there are multiple coroutines receiving on the same channel, they receive new values in first
 * come first served order.
 */ export class Channel < T > { private _receiverSuspenders : Array < ResultCallback < T > > = [ ] ; private _buffer : Array < [ T , ResultCallback < void > | void ] > = [ ] ; private readonly _bufferSize : number ; constructor ( options ? ) { this . _bufferSize = options ?. bufferSize ?? 0 ; } param resultCallback receive : Suspender < T > = ( resultCallback ) => { const valueCallback = this . _buffer . shift ( ) ; if ( valueCallback !== undefined ) { const senderSuccessCallback = valueCallback [ 1 ] ; if ( senderSuccessCallback !== undefined ) { senderSuccessCallback ( { value : undefined } ) ; } resultCallback ( { value : valueCallback [ 0 ] } ) ; let resumeCount = 0 ; for ( let index = 0 ; index < this . _buffer . length ; index ++ ) { if ( resumeCount >= this . _bufferSize ) { break ; } const pair = this . _buffer [ index ] ! ; const senderSuccessCallback = pair [ 1 ] ; if ( senderSuccessCallback !== undefined ) { senderSuccessCallback ( { value : undefined } ) ; pair [ 1 ] = undefined ; } resumeCount ++ ; } return ; } else { this . _receiverSuspenders . push ( resultCallback ) ; return ( ) => { const index = this . _receiverSuspenders . findIndex ( ( x ) => x === resultCallback ) ; if ( index !== - 1 ) { this . _receiverSuspenders . splice ( index , 1 ) ; } } ; } } ; param value send ( value ) { return ( resultCallback ) => { const receiver = this . _receiverSuspenders . shift ( ) ; if ( receiver !== undefined ) { receiver ( { value } ) ; resultCallback ( { value : undefined } ) ; return ; } else if ( this . _buffer . length < this . _bufferSize ) { const valueCallback = [ value , undefined ] ; this . _buffer . push ( valueCallback ) ; resultCallback ( { value : undefined } ) ; return ; } else { const valueCallback = [ value , resultCallback ] ; this . _buffer . push ( valueCallback ) ; return ( ) => { const index = this . _buffer . findIndex ( ( x ) => x === valueCallback ) ; if ( index !== - 1 ) { this . _buffer . splice ( index , 1 ) ; } } ; } } ; } param value trySend ( value ) { const receiver = this . _receiverSuspenders . shift ( ) ; if ( receiver !== undefined ) { receiver ( { value } ) ; return true ; } else if ( this . _buffer . length < this . _bufferSize ) { const valueCallback = [ value , undefined ] ; this . _buffer . push ( valueCallback ) ; return true ; } else { return false ; } } }