Documentation
¶
Overview ¶
Package snapshot provides Value[T any], a copy-on-write container for read-mostly shared state. Load is lock-free and allocation-free (a single atomic.Pointer load); writers (Store / Swap / Update) serialise on a mutex so a read-modify-write publish never loses a concurrent update. Stdlib-only and domain-neutral: any frozen-after-init or rarely-mutated table — a codec registry, a routing table, a feature-flag map, a hot-reloaded config — can reuse it.
The codec registry (internal/core/codec) is built ON this primitive: three atomic.Pointer[map] fields with hand-rolled CAS-loop writers collapse to three Value[map] fields. The mechanism lives here; the domain clone logic stays with the consumer (ADR 0011).
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Value ¶
type Value[T any] struct { // contains filtered or unexported fields }
Value is a copy-on-write container for a *T. Readers call Load with no lock; writers replace the whole pointer under a mutex so concurrent read-modify-write publishes cannot lose updates. The zero value is ready to use — Load returns nil until the first Store. Always used behind a pointer: the embedded mutex and atomic.Pointer must not be copied.
func NewValue ¶
NewValue returns a Value holding initial. A nil initial is valid and leaves the container empty (Load returns nil), the same state as the zero value — offered as call-site sugar when an initial value is already known.
func (*Value[T]) Load ¶
func (v *Value[T]) Load() *T
Load returns the current value pointer without taking the lock — a single atomic load, zero allocation. This is the hot path. The returned *T is shared with every other reader and MUST be treated as immutable: mutate a clone and publish it via Store or Update instead.
func (*Value[T]) Store ¶
func (v *Value[T]) Store(next *T)
Store atomically replaces the current value with next. It takes the writer lock so a Store cannot interleave with an in-flight Update's read-modify-write and clobber it.
func (*Value[T]) Swap ¶
func (v *Value[T]) Swap(next *T) *T
Swap atomically replaces the current value with next and returns the previous value pointer (nil when the container was empty). Takes the writer lock for the same reason as Store.
func (*Value[T]) Update ¶
func (v *Value[T]) Update(fn func(current *T) (next *T))
Update runs fn under the writer lock and publishes its result. fn receives the current value (nil when empty) and returns the replacement; it MUST NOT mutate the value it is handed — other goroutines may be reading it — and should build and return a fresh *T. fn MUST NOT call Store / Swap / Update on the same Value, which would deadlock. Returning the unchanged current pointer is a no-op publish, which lets fn abort a conditional update.