-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmutex.go
More file actions
68 lines (55 loc) · 2.32 KB
/
Copy pathmutex.go
File metadata and controls
68 lines (55 loc) · 2.32 KB
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
package g
import "sync"
// Mutex is a mutual exclusion lock that protects a value of type T.
// Unlike sync.Mutex, it binds the protected data to the lock itself,
// making it impossible to access the data without holding the lock.
//
// A Mutex must not be copied after first use: it embeds a sync.Mutex and a
// copy would protect a different value than the original (go vet's copylocks
// analyzer flags such copies). Always pass a *Mutex, never a Mutex by value.
type Mutex[T any] struct {
mu sync.Mutex
val T
}
// MutexGuard provides access to the value protected by a Mutex.
// The guard must be explicitly unlocked when done.
//
// A guard holds pointers into its owning Mutex; copying the guard and calling
// Unlock on more than one copy unlocks the same underlying lock twice, which
// panics. Use each guard exactly once and do not copy it.
type MutexGuard[T any] struct {
mu *sync.Mutex
val *T
}
// NewMutex creates a new Mutex containing the given value.
func NewMutex[T any](value T) *Mutex[T] { return &Mutex[T]{val: value} }
// Lock acquires the mutex and returns a guard that provides access to the protected value.
// The caller must call Unlock on the guard when done (typically via defer).
func (m *Mutex[T]) Lock() MutexGuard[T] {
m.mu.Lock()
return MutexGuard[T]{mu: &m.mu, val: &m.val}
}
// With acquires the mutex, calls fn with a pointer to the protected value,
// and releases the mutex when fn returns.
// This is a convenience method that eliminates the need for manual Lock/Unlock management.
func (m *Mutex[T]) With(fn func(*T)) {
m.mu.Lock()
defer m.mu.Unlock()
fn(&m.val)
}
// TryLock attempts to acquire the mutex without blocking.
// Returns Some(guard) if successful, None if the mutex is already locked.
func (m *Mutex[T]) TryLock() Option[MutexGuard[T]] {
if m.mu.TryLock() {
return Some(MutexGuard[T]{mu: &m.mu, val: &m.val})
}
return None[MutexGuard[T]]()
}
// Get returns a copy of the protected value.
func (g MutexGuard[T]) Get() T { return *g.val }
// Set replaces the protected value with a new one.
func (g MutexGuard[T]) Set(value T) { *g.val = value }
// Deref returns a pointer to the protected value for direct manipulation.
func (g MutexGuard[T]) Deref() *T { return g.val }
// Unlock releases the mutex. Must be called when done with the guard.
func (g MutexGuard[T]) Unlock() { g.mu.Unlock() }