github.com/haraldrudell/parl@v0.4.176/channel-send.go (about)

     1  /*
     2  © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package parl
     7  
     8  import (
     9  	"github.com/haraldrudell/parl/perrors"
    10  	"github.com/haraldrudell/parl/pruntime"
    11  )
    12  
    13  // with nonBlocking set to SendNonBlocking, ChannelSend will never block
    14  const SendNonBlocking = true
    15  
    16  // ChannelSend is channel send without panics and possibly non-blocking
    17  //   - if nonBlocking is SendNonBlocking or true, channel send will be attempted but not block
    18  //   - didSend is true if value was successfully sent on ch
    19  //   - err is non-nil if a panic occurred or ch is nil
    20  //   - isNilChannel is true if the channel is nil, ie. send would block indefinitely
    21  //   - isClosedChannel is true if the panic was caused by ch being closed
    22  //   - there should be no panics other than from ch being closed
    23  func ChannelSend[T any](ch chan<- T, value T, nonBlocking ...bool) (didSend, isNilChannel, isClosedChannel bool, err error) {
    24  
    25  	// check for nil channel
    26  	if isNilChannel = ch == nil; isNilChannel {
    27  		err = perrors.NewPF("ch channel nil")
    28  		return
    29  	}
    30  
    31  	// get non-blocking flag
    32  	var sendNb bool
    33  	if len(nonBlocking) > 0 {
    34  		sendNb = nonBlocking[0]
    35  	}
    36  
    37  	// send, recovering panics
    38  	didSend, err = channelSend(ch, value, sendNb)
    39  
    40  	// set isClosed flag
    41  	if err != nil && pruntime.IsSendOnClosedChannel(err) {
    42  		isClosedChannel = true
    43  	}
    44  
    45  	return
    46  }
    47  
    48  // channelSend sends possibly non-blocking
    49  //   - the only way to determine closed channel is to send, which panics
    50  //   - a separate function to recover the panic
    51  func channelSend[T any](ch chan<- T, value T, sendNb bool) (didSend bool, err error) {
    52  	defer PanicToErr(&err)
    53  
    54  	// send non-blocking
    55  	if sendNb {
    56  		select {
    57  		case ch <- value:
    58  			didSend = true
    59  		default:
    60  		}
    61  		return
    62  	}
    63  
    64  	// send blocking: blocks here
    65  	ch <- value
    66  	didSend = true
    67  
    68  	return
    69  }