@@ -9,131 +9,163 @@ import (
99	resultext "github.com/go-playground/pkg/v5/values/result" 
1010)
1111
12+ // MutexGuard protects the inner contents of a Mutex2 for safety and unlocking. 
13+ type  MutexGuard [T  any , M  interface { Unlock () }] struct  {
14+ 	m  M 
15+ 	// T is the inner generic type of the Mutex 
16+ 	T  T 
17+ }
18+ 
19+ // Unlock unlocks the Mutex2 value. 
20+ func  (g  MutexGuard [T , M ]) Unlock () {
21+ 	g .m .Unlock ()
22+ }
23+ 
1224// NewMutex2 creates a new Mutex for use. 
13- func  NewMutex2 [T  any ](value  T ) * Mutex2 [T ] {
14- 	return  & Mutex2 [T ]{
25+ func  NewMutex2 [T  any , M  * sync.Mutex ](value  T ) Mutex2 [T , M ] {
26+ 	return  Mutex2 [T , M ]{
27+ 		m :     new (sync.Mutex ),
1528		value : value ,
1629	}
1730}
1831
1932// Mutex2 creates a type safe mutex wrapper ensuring one cannot access the values of a locked values 
2033// without first gaining a lock. 
21- type  Mutex2 [T  any ] struct  {
22- 	m      sync.Mutex 
34+ type  Mutex2 [T  any ,  M   * sync. Mutex ] struct  {
35+ 	m      * sync.Mutex 
2336	value  T 
2437}
2538
2639// Lock locks the Mutex and returns value for use, safe for mutation if 
2740// 
2841// If the lock is already in use, the calling goroutine blocks until the mutex is available. 
29- func  (m  * Mutex2 [T ]) Lock () T  {
42+ func  (m  Mutex2 [T ,  M ]) Lock () MutexGuard [ T ,  * sync. Mutex ]  {
3043	m .m .Lock ()
31- 	return  m .value 
44+ 	return  MutexGuard [T , * sync.Mutex ]{
45+ 		m : m .m ,
46+ 		T : m .value ,
47+ 	}
3248}
3349
34- // Unlock unlocks the Mutex accepting a value to set as the new or mutated value. 
35- // It is optional to pass a new value to be set but NOT required for there reasons: 
36- // 1. If the internal value is already mutable then no need to set as changes apply as they happen. 
37- // 2. If there's a failure working with the locked value you may NOT want to set it, but still unlock. 
38- // 3. Supports locked values that are not mutable. 
39- // 
40- // It is a run-time error if the Mutex is not locked on entry to Unlock. 
41- func  (m  * Mutex2 [T ]) Unlock () {
42- 	m .m .Unlock ()
43- }
50+ ////  Unlock unlocks the Mutex accepting a value to set as the new or mutated value. 
51+ ////  It is optional to pass a new value to be set but NOT required for there reasons: 
52+ ////  1. If the internal value is already mutable then no need to set as changes apply as they happen. 
53+ ////  2. If there's a failure working with the locked value you may NOT want to set it, but still unlock. 
54+ ////  3. Supports locked values that are not mutable. 
55+ ////  
56+ ////  It is a run-time error if the Mutex is not locked on entry to Unlock. 
57+ // func (m Mutex2[T]) Unlock() {
58+ // 	m.m.Unlock()
59+ // }
4460
4561// PerformMut safely locks and unlocks the Mutex values and performs the provided function returning its error if one 
4662// otherwise setting the returned value as the new mutex value. 
47- func  (m  * Mutex2 [T ]) PerformMut (f  func (T )) {
48- 	f (m .Lock ())
49- 	m .Unlock ()
63+ func  (m  Mutex2 [T , M ]) PerformMut (f  func (T )) {
64+ 	guard  :=  m .Lock ()
65+ 	f (guard .T )
66+ 	guard .Unlock ()
5067}
5168
5269// TryLock tries to lock Mutex and reports whether it succeeded. 
5370// If it does the value is returned for use in the Ok result otherwise Err with empty value. 
54- func  (m  * Mutex2 [T ]) TryLock () resultext.Result [T , struct {}] {
71+ func  (m  Mutex2 [T ,  M ]) TryLock () resultext.Result [MutexGuard [ T ,  * sync. Mutex ] , struct {}] {
5572	if  m .m .TryLock () {
56- 		return  resultext.Ok [T , struct {}](m .value )
73+ 		return  resultext.Ok [MutexGuard [T , * sync.Mutex ], struct {}](MutexGuard [T , * sync.Mutex ]{
74+ 			m : m .m ,
75+ 			T : m .value ,
76+ 		})
5777	} else  {
58- 		return  resultext.Err [T , struct {}](struct {}{})
78+ 		return  resultext.Err [MutexGuard [ T ,  * sync. Mutex ] , struct {}](struct {}{})
5979	}
6080}
6181
82+ // RMutexGuard protects the inner contents of a RWMutex2 for safety and unlocking. 
83+ type  RMutexGuard [T  any ] struct  {
84+ 	rw  * sync.RWMutex 
85+ 	// T is the inner generic type of the Mutex 
86+ 	T  T 
87+ }
88+ 
89+ // RUnlock unlocks the RWMutex2 value. 
90+ func  (g  RMutexGuard [T ]) RUnlock () {
91+ 	g .rw .RUnlock ()
92+ }
93+ 
6294// NewRWMutex2 creates a new RWMutex for use. 
63- func  NewRWMutex2 [T  any ](value  T ) * RWMutex2 [T ] {
64- 	return  & RWMutex2 [T ]{
95+ func  NewRWMutex2 [T  any ](value  T ) RWMutex2 [T ] {
96+ 	return  RWMutex2 [T ]{
97+ 		rw :    new (sync.RWMutex ),
6598		value : value ,
6699	}
67100}
68101
69102// RWMutex2 creates a type safe RWMutex wrapper ensuring one cannot access the values of a locked values 
70103// without first gaining a lock. 
71104type  RWMutex2 [T  any ] struct  {
72- 	rw     sync.RWMutex 
105+ 	rw     * sync.RWMutex 
73106	value  T 
74107}
75108
76109// Lock locks the Mutex and returns value for use, safe for mutation if 
77110// 
78111// If the lock is already in use, the calling goroutine blocks until the mutex is available. 
79- func  (m  * RWMutex2 [T ]) Lock () T  {
112+ func  (m  RWMutex2 [T ]) Lock () MutexGuard [ T ,  * sync. RWMutex ]  {
80113	m .rw .Lock ()
81- 	return  m .value 
82- }
83- 
84- // Unlock unlocks the Mutex accepting a value to set as the new or mutated value. 
85- // It is optional to pass a new value to be set but NOT required for there reasons: 
86- // 1. If the internal value is already mutable then no need to set as changes apply as they happen. 
87- // 2. If there's a failure working with the locked value you may NOT want to set it, but still unlock. 
88- // 3. Supports locked values that are not mutable. 
89- // 
90- // It is a run-time error if the Mutex is not locked on entry to Unlock. 
91- func  (m  * RWMutex2 [T ]) Unlock () {
92- 	m .rw .Unlock ()
114+ 	return  MutexGuard [T , * sync.RWMutex ]{
115+ 		m : m .rw ,
116+ 		T : m .value ,
117+ 	}
93118}
94119
95120// PerformMut safely locks and unlocks the RWMutex mutable values and performs the provided function. 
96- func  (m  * RWMutex2 [T ]) PerformMut (f  func (T )) {
97- 	f (m .Lock ())
98- 	m .Unlock ()
121+ func  (m  RWMutex2 [T ]) PerformMut (f  func (T )) {
122+ 	guard  :=  m .Lock ()
123+ 	f (guard .T )
124+ 	guard .Unlock ()
99125}
100126
101127// TryLock tries to lock RWMutex and returns the value in the Ok result if successful. 
102128// If it does the value is returned for use in the Ok result otherwise Err with empty value. 
103- func  (m  * RWMutex2 [T ]) TryLock () resultext.Result [T , struct {}] {
129+ func  (m  RWMutex2 [T ]) TryLock () resultext.Result [MutexGuard [ T ,  * sync. RWMutex ] , struct {}] {
104130	if  m .rw .TryLock () {
105- 		return  resultext.Ok [T , struct {}](m .value )
131+ 		return  resultext.Ok [MutexGuard [T , * sync.RWMutex ], struct {}](
132+ 			MutexGuard [T , * sync.RWMutex ]{
133+ 				m : m .rw ,
134+ 				T : m .value ,
135+ 			})
106136	} else  {
107- 		return  resultext.Err [T , struct {}](struct {}{})
137+ 		return  resultext.Err [MutexGuard [ T ,  * sync. RWMutex ] , struct {}](struct {}{})
108138	}
109139}
110140
111141// Perform safely locks and unlocks the RWMutex read-only values and performs the provided function. 
112- func  (m  * RWMutex2 [T ]) Perform (f  func (T )) {
113- 	result  :=  m .RLock ()
114- 	f (result )
115- 	m .RUnlock ()
142+ func  (m  RWMutex2 [T ]) Perform (f  func (T )) {
143+ 	guard  :=  m .RLock ()
144+ 	f (guard . T )
145+ 	guard .RUnlock ()
116146}
117147
118148// RLock locks the RWMutex for reading and returns the value for read-only use. 
119149// It should not be used for recursive read locking; a blocked Lock call excludes new readers from acquiring the lock 
120- func  (m  * RWMutex2 [T ]) RLock () T  {
150+ func  (m  RWMutex2 [T ]) RLock () RMutexGuard [ T ]  {
121151	m .rw .RLock ()
122- 	return  m .value 
123- }
124- 
125- // RUnlock undoes a single RLock call; it does not affect other simultaneous readers. 
126- // It is a run-time error if rw is not locked for reading on entry to RUnlock. 
127- func  (m  * RWMutex2 [T ]) RUnlock () {
128- 	m .rw .RUnlock ()
152+ 	return  RMutexGuard [T ]{
153+ 		rw : m .rw ,
154+ 		T :  m .value ,
155+ 	}
129156}
130157
131158// TryRLock tries to lock RWMutex for reading and returns the value in the Ok result if successful. 
132159// If it does the value is returned for use in the Ok result otherwise Err with empty value. 
133- func  (m  * RWMutex2 [T ]) TryRLock () resultext.Result [T , struct {}] {
160+ func  (m  RWMutex2 [T ]) TryRLock () resultext.Result [RMutexGuard [ T ] , struct {}] {
134161	if  m .rw .TryRLock () {
135- 		return  resultext.Ok [T , struct {}](m .value )
162+ 		return  resultext.Ok [RMutexGuard [T ], struct {}](
163+ 			RMutexGuard [T ]{
164+ 				rw : m .rw ,
165+ 				T :  m .value ,
166+ 			},
167+ 		)
136168	} else  {
137- 		return  resultext.Err [T , struct {}](struct {}{})
169+ 		return  resultext.Err [RMutexGuard [ T ] , struct {}](struct {}{})
138170	}
139171}
0 commit comments