github.com/haraldrudell/parl@v0.4.176/pio/context-closer.go (about) 1 /* 2 © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package pio 7 8 import ( 9 "io" 10 "sync/atomic" 11 12 "github.com/haraldrudell/parl" 13 ) 14 15 // ContextCloser is an idempotent io.Closer 16 // - implements [io.Closer] 17 type ContextCloser struct { 18 closer io.Closer 19 isClosed atomic.Bool 20 } 21 22 // NewContextCloser returns a an idempotent [io.Closer] 23 // - closer may be nil 24 // - panic-free idempotent observable 25 func NewContextCloser(closer io.Closer) (contextCloser *ContextCloser) { 26 return &ContextCloser{closer: closer} 27 } 28 29 // Close closes the io.Closer 30 // - if Close has already been invoked, noop, no error 31 // - if io.Closer is nil, noop, no error 32 // - panic-free idempotent 33 func (c *ContextCloser) Close() (err error) { 34 if c.isClosed.Load() { 35 return // Close already invoked 36 } else if !c.isClosed.CompareAndSwap(false, true) { 37 return // another thread already closed 38 } else if c.closer == nil { 39 return // closer is nil 40 } 41 parl.Close(c.closer, &err) 42 return 43 } 44 45 // IsCloseable indicates whether an [io.Closer] is present that can be closed 46 func (c *ContextCloser) IsCloseable() (isCloseable bool) { 47 return c.closer != nil 48 }