github.com/git-amp/amp-sdk-go@v0.7.5/stdlib/generics/ref-closer.go (about)

     1  package generics
     2  
     3  import (
     4  	"io"
     5  	"sync/atomic"
     6  )
     7  
     8  // RefCloser is a reference counted io.Closer where the wrapped Closer is closed when its reference count reaches zero.
     9  type RefCloser interface {
    10  
    11  	// AddRef atomically increments the reference count.
    12  	AddRef()
    13  
    14  	// Release atomically decrements the reference count.
    15  	// If the ref count is remains greater than zero, nil is returned.
    16  	// If the ref count reaches zero, the underlying Closer was closed and it's error is returned.
    17  	Close() error
    18  }
    19  
    20  // Wraps the given io.Closer into a RefCloser, initializing its reference count to 1.
    21  func WrapInRefCloser(target io.Closer) RefCloser {
    22  	rc := &refCloser{
    23  		closer:   target,
    24  		refCount: 1,
    25  	}
    26  	return rc
    27  }
    28  
    29  type refCloser struct {
    30  	closer   io.Closer
    31  	refCount int32
    32  }
    33  
    34  func (rc *refCloser) AddRef() {
    35  	atomic.AddInt32(&rc.refCount, 1)
    36  }
    37  
    38  func (rc *refCloser) Close() error {
    39  	if atomic.AddInt32(&rc.refCount, -1) > 0 {
    40  		return nil
    41  	}
    42  	err := rc.closer.Close()
    43  	rc.closer = nil
    44  	return err
    45  }