diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2023-02-05 13:02:57 -0700 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2023-02-05 13:33:02 -0700 |
commit | 5a1a904b4264c6ee323c9bd433f9ee4da93c984d (patch) | |
tree | 035414c8e8f3b94e24b482e5096a3b4e3688e257 /typedsync | |
parent | 2d939c9c6e62395ed924fe7c5cd4c4b294e391a9 (diff) |
typedsync: Bring up to being a mostly-drop-in replacement for Go 1.20 sync
Diffstat (limited to 'typedsync')
-rw-r--r-- | typedsync/cond.go | 38 | ||||
-rw-r--r-- | typedsync/doc.go | 28 | ||||
-rw-r--r-- | typedsync/map.go | 21 | ||||
-rw-r--r-- | typedsync/map_go120.go | 51 | ||||
-rw-r--r-- | typedsync/pool.go | 5 | ||||
-rw-r--r-- | typedsync/value.go | 10 |
6 files changed, 146 insertions, 7 deletions
diff --git a/typedsync/cond.go b/typedsync/cond.go new file mode 100644 index 0000000..00d3164 --- /dev/null +++ b/typedsync/cond.go @@ -0,0 +1,38 @@ +// Copyright (C) 2023 Luke Shumaker <lukeshu@lukeshu.com> +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package typedsync + +import ( + "sync" +) + +// Cond is a type-safe equivalent of the standard library's sync.Cond. +// +// See the [sync.Cond documentation] for full details. +// +// [sync.Cond documentation]: https://pkg.go.dev/sync#Cond +type Cond[T Locker] struct { + L T + inner sync.Cond +} + +func NewCond[T Locker](l T) *Cond[T] { + return &Cond[T]{L: l} +} + +func (c *Cond[T]) Broadcast() { + c.inner.L = c.L + c.inner.Broadcast() +} + +func (c *Cond[T]) Signal() { + c.inner.L = c.L + c.inner.Signal() +} + +func (c *Cond[T]) Wait() { + c.inner.L = c.L + c.inner.Wait() +} diff --git a/typedsync/doc.go b/typedsync/doc.go new file mode 100644 index 0000000..e20d44c --- /dev/null +++ b/typedsync/doc.go @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Luke Shumaker <lukeshu@lukeshu.com> +// +// SPDX-License-Identifier: GPL-2.0-or-later + +// Package typedsync is an alternative to the standard library's sync +// that uses type-parameters for type safety. +// +// This package does not bother to duplicate documentation from the +// standard library's sync package; see [sync's documentation] for +// full documentation. +// +// Besides requiring type parameters and such, typedsync is a drop-in +// replacement for sync. +// +// [sync's documentation]: https://pkg.go.dev/sync +package typedsync + +import ( + "sync" +) + +type ( + Locker = sync.Locker + Mutex = sync.Mutex + Once = sync.Once + RWMutex = sync.RWMutex + WaitGroup = sync.WaitGroup +) diff --git a/typedsync/map.go b/typedsync/map.go index 6bb1170..2f94ae2 100644 --- a/typedsync/map.go +++ b/typedsync/map.go @@ -10,20 +10,33 @@ import ( // Map is a type-safe equivalent of the standard library's sync.Map. // -// With versions of Go prior to Go 1.20, Map is specified too loosely, -// as +// See the [sync.Map documentation] for full details. +// +// Go 1.20 added sync.Map.Swap method; this method is only available +// on typedsync.Map if built with Go 1.20 or later. +// +// Go 1.20 added sync.Map.CompareAndDelete and sync.Map.CompareAndSwap +// methods that are only usable if V is a comparable type; these +// methods are not available on typedsync.Map, but when typedsync is +// built with Go 1.20 or later they are available on a separate +// ComparableMap type. +// +// When typedsync is built versions of Go prior to Go 1.20, +// typedsync.Map is specified too loosely, as // // Map[K any, V any] // -// while with Go 1.20 and later, Map is specified as +// while with Go 1.20 and later, typedsync.Map is specified as // // Map[K comparable, V any] // // This is because with Go versions prior to 1.20, 'comparable' was // overly strict, disallowing many types that are valid map-keys (see // https://github.com/golang/go/issues/56548). The type used as K in -// a Map older versions of Go must be a valid map-key type, even +// a Map with older versions of Go must be a valid map-key type, even // though the type specification of Map does not enforce that. +// +// [sync.Map documentation]: https://pkg.go.dev/sync#Map type Map[K mapkey, V any] struct { inner sync.Map } diff --git a/typedsync/map_go120.go b/typedsync/map_go120.go index 0d4ff5b..6885e2a 100644 --- a/typedsync/map_go120.go +++ b/typedsync/map_go120.go @@ -7,3 +7,54 @@ package typedsync type mapkey = comparable + +func (m *Map[K, V]) Swap(key K, value V) (previous V, loaded bool) { + _previous, loaded := m.inner.Swap(key, value) + if loaded { + //nolint:forcetypeassert // Typed wrapper around untyped lib. + previous = _previous.(V) + } + return previous, loaded +} + +// ComparableMap is a variant of Map with a comparable type for V; +// affording additional CompareAndDelete and CompareAndSwap methods. +// +// See the [sync.Map documentation] for full details. +// +// [sync.Map documentation]: https://pkg.go.dev/sync#Map +type ComparableMap[K comparable, V comparable] struct { + inner Map[K, V] +} + +func (m *ComparableMap[K, V]) Delete(key K) { + m.inner.Delete(key) +} + +func (m *ComparableMap[K, V]) Load(key K) (value V, ok bool) { + return m.inner.Load(key) +} + +func (m *ComparableMap[K, V]) LoadAndDelete(key K) (value V, loaded bool) { + return m.inner.LoadAndDelete(key) +} + +func (m *ComparableMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) { + return m.inner.LoadOrStore(key, value) +} + +func (m *ComparableMap[K, V]) Range(f func(key K, value V) bool) { + m.inner.Range(f) +} + +func (m *ComparableMap[K, V]) Store(key K, value V) { + m.inner.Store(key, value) +} + +func (m *ComparableMap[K, V]) CompareAndDelete(key K, old V) (deleted bool) { + return m.inner.inner.CompareAndDelete(key, old) +} + +func (m *ComparableMap[K, V]) CompareAndSwap(key K, oldV, newV V) bool { + return m.inner.inner.CompareAndSwap(key, oldV, newV) +} diff --git a/typedsync/pool.go b/typedsync/pool.go index c196085..370d70a 100644 --- a/typedsync/pool.go +++ b/typedsync/pool.go @@ -8,6 +8,11 @@ import ( "sync" ) +// Pool is a type-safe equivalent of the standard library's sync.Pool. +// +// See the [sync.Pool documentation] for full details. +// +// [sync.Pool documentation]: https://pkg.go.dev/sync#Pool type Pool[T any] struct { New func() T diff --git a/typedsync/value.go b/typedsync/value.go index 99c8876..90c8b55 100644 --- a/typedsync/value.go +++ b/typedsync/value.go @@ -8,11 +8,15 @@ import ( "sync" ) -// Value is a typed equivalent of sync/atomic.Value. +// Value is a type-safe equivalent of the standard library's +// sync/atomic.Value. // -// It is not actually a wrapper around sync/atomic.Value for -// allocation-performance reasons. +// See the [sync/atomic.Value documentation] for full details. +// +// [sync/atomic.Value documentation]: https://pkg.go.dev/sync/atomic#Value type Value[T comparable] struct { + // It is not actually a wrapper around sync/atomic.Value for + // allocation-performance reasons. mu sync.Mutex ok bool val T |