codeberg.org/gruf/go-mutexes@v1.5.0/mutex.go (about)

     1  package mutexes
     2  
     3  import (
     4  	"sync"
     5  )
     6  
     7  // Mutex defines a wrappable mutex. By forcing unlocks
     8  // via returned function it makes wrapping much easier
     9  type Mutex interface {
    10  	// Lock performs a mutex lock, returning an unlock function
    11  	Lock() (unlock func())
    12  }
    13  
    14  // RWMutex defines a wrappable read-write mutex. By forcing
    15  // unlocks via returned functions it makes wrapping much easier
    16  type RWMutex interface {
    17  	Mutex
    18  
    19  	// RLock performs a mutex read lock, returning an unlock function
    20  	RLock() (runlock func())
    21  }
    22  
    23  // New returns a new base Mutex implementation
    24  func New() Mutex {
    25  	return &baseMutex{}
    26  }
    27  
    28  // NewRW returns a new base RWMutex implementation
    29  func NewRW() RWMutex {
    30  	return &baseRWMutex{}
    31  }
    32  
    33  // WithFunc wraps the supplied Mutex to call the provided hooks on lock / unlock
    34  func WithFunc(mu Mutex, onLock, onUnlock func()) Mutex {
    35  	return &fnMutex{mu: mu, lo: onLock, un: onUnlock}
    36  }
    37  
    38  // WithFuncRW wrapps the supplied RWMutex to call the provided hooks on lock / rlock / unlock/ runlock
    39  func WithFuncRW(mu RWMutex, onLock, onRLock, onUnlock, onRUnlock func()) RWMutex {
    40  	return &fnRWMutex{mu: mu, lo: onLock, rlo: onRLock, un: onUnlock, run: onRUnlock}
    41  }
    42  
    43  // baseMutex simply wraps a sync.Mutex to implement our Mutex interface
    44  type baseMutex sync.Mutex
    45  
    46  func (mu *baseMutex) Lock() func() {
    47  	(*sync.Mutex)(mu).Lock()
    48  	return (*sync.Mutex)(mu).Unlock
    49  }
    50  
    51  // baseRWMutex simply wraps a sync.RWMutex to implement our RWMutex interface
    52  type baseRWMutex sync.RWMutex
    53  
    54  func (mu *baseRWMutex) Lock() func() {
    55  	(*sync.RWMutex)(mu).Lock()
    56  	return (*sync.RWMutex)(mu).Unlock
    57  }
    58  
    59  func (mu *baseRWMutex) RLock() func() {
    60  	(*sync.RWMutex)(mu).RLock()
    61  	return (*sync.RWMutex)(mu).RUnlock
    62  }
    63  
    64  // fnMutex wraps a Mutex to add hooks for Lock and Unlock
    65  type fnMutex struct {
    66  	mu Mutex
    67  	lo func()
    68  	un func()
    69  }
    70  
    71  func (mu *fnMutex) Lock() func() {
    72  	unlock := mu.mu.Lock()
    73  	mu.lo()
    74  	return func() {
    75  		mu.un()
    76  		unlock()
    77  	}
    78  }
    79  
    80  // fnRWMutex wraps a RWMutex to add hooks for Lock, RLock, Unlock and RUnlock
    81  type fnRWMutex struct {
    82  	mu  RWMutex
    83  	lo  func()
    84  	rlo func()
    85  	un  func()
    86  	run func()
    87  }
    88  
    89  func (mu *fnRWMutex) Lock() func() {
    90  	unlock := mu.mu.Lock()
    91  	mu.lo()
    92  	return func() {
    93  		mu.un()
    94  		unlock()
    95  	}
    96  }
    97  
    98  func (mu *fnRWMutex) RLock() func() {
    99  	unlock := mu.mu.RLock()
   100  	mu.rlo()
   101  	return func() {
   102  		mu.run()
   103  		unlock()
   104  	}
   105  }