summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-mutexes/mutex.go
blob: 3841c94231669cbc9252091cd75d22bf2e24eb8f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package mutexes

import (
	"sync"
)

// Mutex defines a wrappable mutex. By forcing unlocks
// via returned function it makes wrapping much easier
type Mutex interface {
	// Lock performs a mutex lock, returning an unlock function
	Lock() (unlock func())
}

// RWMutex defines a wrappable read-write mutex. By forcing
// unlocks via returned functions it makes wrapping much easier
type RWMutex interface {
	Mutex

	// RLock performs a mutex read lock, returning an unlock function
	RLock() (runlock func())
}

// New returns a new base Mutex implementation
func New() Mutex {
	return &baseMutex{}
}

// NewRW returns a new base RWMutex implementation
func NewRW() RWMutex {
	return &baseRWMutex{}
}

// WithFunc wraps the supplied Mutex to call the provided hooks on lock / unlock
func WithFunc(mu Mutex, onLock, onUnlock func()) Mutex {
	return &fnMutex{mu: mu, lo: onLock, un: onUnlock}
}

// WithFuncRW wrapps the supplied RWMutex to call the provided hooks on lock / rlock / unlock/ runlock
func WithFuncRW(mu RWMutex, onLock, onRLock, onUnlock, onRUnlock func()) RWMutex {
	return &fnRWMutex{mu: mu, lo: onLock, rlo: onRLock, un: onUnlock, run: onRUnlock}
}

// baseMutex simply wraps a sync.Mutex to implement our Mutex interface
type baseMutex sync.Mutex

func (mu *baseMutex) Lock() func() {
	(*sync.Mutex)(mu).Lock()
	return (*sync.Mutex)(mu).Unlock
}

// baseRWMutex simply wraps a sync.RWMutex to implement our RWMutex interface
type baseRWMutex sync.RWMutex

func (mu *baseRWMutex) Lock() func() {
	(*sync.RWMutex)(mu).Lock()
	return (*sync.RWMutex)(mu).Unlock
}

func (mu *baseRWMutex) RLock() func() {
	(*sync.RWMutex)(mu).RLock()
	return (*sync.RWMutex)(mu).RUnlock
}

// fnMutex wraps a Mutex to add hooks for Lock and Unlock
type fnMutex struct {
	mu Mutex
	lo func()
	un func()
}

func (mu *fnMutex) Lock() func() {
	unlock := mu.mu.Lock()
	mu.lo()
	return func() {
		mu.un()
		unlock()
	}
}

// fnRWMutex wraps a RWMutex to add hooks for Lock, RLock, Unlock and RUnlock
type fnRWMutex struct {
	mu  RWMutex
	lo  func()
	rlo func()
	un  func()
	run func()
}

func (mu *fnRWMutex) Lock() func() {
	unlock := mu.mu.Lock()
	mu.lo()
	return func() {
		mu.un()
		unlock()
	}
}

func (mu *fnRWMutex) RLock() func() {
	unlock := mu.mu.RLock()
	mu.rlo()
	return func() {
		mu.run()
		unlock()
	}
}