github.com/go-playground/pkg/v5@v5.29.1/sync/mutex2.go (about)

     1  //go:build go1.18
     2  // +build go1.18
     3  
     4  package syncext
     5  
     6  import (
     7  	"sync"
     8  
     9  	resultext "github.com/go-playground/pkg/v5/values/result"
    10  )
    11  
    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  
    24  // NewMutex2 creates a new Mutex for use.
    25  func NewMutex2[T any](value T) Mutex2[T] {
    26  	return Mutex2[T]{
    27  		m:     new(sync.Mutex),
    28  		value: value,
    29  	}
    30  }
    31  
    32  // Mutex2 creates a type safe mutex wrapper ensuring one cannot access the values of a locked values
    33  // without first gaining a lock.
    34  type Mutex2[T any] struct {
    35  	m     *sync.Mutex
    36  	value T
    37  }
    38  
    39  // Lock locks the Mutex and returns value for use, safe for mutation if
    40  //
    41  // If the lock is already in use, the calling goroutine blocks until the mutex is available.
    42  func (m Mutex2[T]) Lock() MutexGuard[T, *sync.Mutex] {
    43  	m.m.Lock()
    44  	return MutexGuard[T, *sync.Mutex]{
    45  		m: m.m,
    46  		T: m.value,
    47  	}
    48  }
    49  
    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  //}
    60  
    61  // PerformMut safely locks and unlocks the Mutex values and performs the provided function returning its error if one
    62  // otherwise setting the returned value as the new mutex value.
    63  func (m Mutex2[T]) PerformMut(f func(T)) {
    64  	guard := m.Lock()
    65  	f(guard.T)
    66  	guard.Unlock()
    67  }
    68  
    69  // TryLock tries to lock Mutex and reports whether it succeeded.
    70  // If it does the value is returned for use in the Ok result otherwise Err with empty value.
    71  func (m Mutex2[T]) TryLock() resultext.Result[MutexGuard[T, *sync.Mutex], struct{}] {
    72  	if m.m.TryLock() {
    73  		return resultext.Ok[MutexGuard[T, *sync.Mutex], struct{}](MutexGuard[T, *sync.Mutex]{
    74  			m: m.m,
    75  			T: m.value,
    76  		})
    77  	} else {
    78  		return resultext.Err[MutexGuard[T, *sync.Mutex], struct{}](struct{}{})
    79  	}
    80  }
    81  
    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  
    94  // NewRWMutex2 creates a new RWMutex for use.
    95  func NewRWMutex2[T any](value T) RWMutex2[T] {
    96  	return RWMutex2[T]{
    97  		rw:    new(sync.RWMutex),
    98  		value: value,
    99  	}
   100  }
   101  
   102  // RWMutex2 creates a type safe RWMutex wrapper ensuring one cannot access the values of a locked values
   103  // without first gaining a lock.
   104  type RWMutex2[T any] struct {
   105  	rw    *sync.RWMutex
   106  	value T
   107  }
   108  
   109  // Lock locks the Mutex and returns value for use, safe for mutation if
   110  //
   111  // If the lock is already in use, the calling goroutine blocks until the mutex is available.
   112  func (m RWMutex2[T]) Lock() MutexGuard[T, *sync.RWMutex] {
   113  	m.rw.Lock()
   114  	return MutexGuard[T, *sync.RWMutex]{
   115  		m: m.rw,
   116  		T: m.value,
   117  	}
   118  }
   119  
   120  // PerformMut safely locks and unlocks the RWMutex mutable values and performs the provided function.
   121  func (m RWMutex2[T]) PerformMut(f func(T)) {
   122  	guard := m.Lock()
   123  	f(guard.T)
   124  	guard.Unlock()
   125  }
   126  
   127  // TryLock tries to lock RWMutex and returns the value in the Ok result if successful.
   128  // If it does the value is returned for use in the Ok result otherwise Err with empty value.
   129  func (m RWMutex2[T]) TryLock() resultext.Result[MutexGuard[T, *sync.RWMutex], struct{}] {
   130  	if m.rw.TryLock() {
   131  		return resultext.Ok[MutexGuard[T, *sync.RWMutex], struct{}](
   132  			MutexGuard[T, *sync.RWMutex]{
   133  				m: m.rw,
   134  				T: m.value,
   135  			})
   136  	} else {
   137  		return resultext.Err[MutexGuard[T, *sync.RWMutex], struct{}](struct{}{})
   138  	}
   139  }
   140  
   141  // Perform safely locks and unlocks the RWMutex read-only values and performs the provided function.
   142  func (m RWMutex2[T]) Perform(f func(T)) {
   143  	guard := m.RLock()
   144  	f(guard.T)
   145  	guard.RUnlock()
   146  }
   147  
   148  // RLock locks the RWMutex for reading and returns the value for read-only use.
   149  // It should not be used for recursive read locking; a blocked Lock call excludes new readers from acquiring the lock
   150  func (m RWMutex2[T]) RLock() RMutexGuard[T] {
   151  	m.rw.RLock()
   152  	return RMutexGuard[T]{
   153  		rw: m.rw,
   154  		T:  m.value,
   155  	}
   156  }
   157  
   158  // TryRLock tries to lock RWMutex for reading and returns the value in the Ok result if successful.
   159  // If it does the value is returned for use in the Ok result otherwise Err with empty value.
   160  func (m RWMutex2[T]) TryRLock() resultext.Result[RMutexGuard[T], struct{}] {
   161  	if m.rw.TryRLock() {
   162  		return resultext.Ok[RMutexGuard[T], struct{}](
   163  			RMutexGuard[T]{
   164  				rw: m.rw,
   165  				T:  m.value,
   166  			},
   167  		)
   168  	} else {
   169  		return resultext.Err[RMutexGuard[T], struct{}](struct{}{})
   170  	}
   171  }