package usync import "sync" // Monitor guards access to a value. It must not be copied after first use. type Monitor[T any] struct { value T mutex sync.Mutex } // NewMonitor creates a new Monitor with the specified value. func NewMonitor[T any] (value T) Monitor[T] { return Monitor[T] { value: value, } } // Set sets the value of the Monitor. func (this *Monitor[T]) Set (value T) { this.mutex.Lock() defer this.mutex.Unlock() this.value = value } // Borrow borrows the value from the Monitor, and returns a function that must // immediately be deferred, like this: // // value, done := monitor.Borrow() // defer done() // // From the time Borrow is called to the time the done function is called, it is // safe to access the locked object from within the current goroutine. func (this *Monitor[T]) Borrow () (T, func ()) { this.mutex.Lock() return this.value, this.mutex.Unlock } // BorrowReturn is like borrow, but returns a "done" function that takes in an // updated value. The intended use of this function is like this: // // value, done := monitor.BorrowReturn() // defer done(value) func (this *Monitor[T]) BorrowReturn () (T, func (T)) { this.mutex.Lock() return this.value, func (value T) { defer this.mutex.Unlock() this.value = value } } // RWMonitor guards separate read/write access to a value. type RWMonitor[T any] struct { value T mutex sync.RWMutex } // NewRWMonitor creates a new Monitor with the specified value. It must not be // copied after first use. func NewRWMonitor[T any] (value T) RWMonitor[T] { return RWMonitor[T] { value: value, } } // Set sets the value of the Monitor. func (this *RWMonitor[T]) Set (value T) { this.mutex.Lock() defer this.mutex.Unlock() this.value = value } // Borrow borrows the value from the Monitor for write access, and returns a // function that must immediately be deferred, like this: // // value, done := monitor.Borrow() // defer done() // // From the time Borrow is called to the time the done function is called, it is // safe to access the locked object from within the current goroutine. func (this *RWMonitor[T]) Borrow () (T, func ()) { this.mutex.Lock() return this.value, this.mutex.Unlock } // BorrowReturn is like borrow, but returns a "done" function that takes in an // updated value. The intended use of this function is like this: // // value, done := monitor.BorrowReturn() // defer done(value) func (this *RWMonitor[T]) BorrowReturn () (T, func (T)) { this.mutex.Lock() return this.value, func (value T) { defer this.mutex.Unlock() this.value = value } } // RBorrow is like Borrow, but returns the item for read access only. Do not // under any circumstances modify anything returned by this method. func (this *RWMonitor[T]) RBorrow () (T, func ()) { this.mutex.Lock() return this.value, this.mutex.Unlock }