From 08f15a7e3d1165a1bd14bb696fbe3c907dab1942 Mon Sep 17 00:00:00 2001 From: Zsolt Tasnadi Date: Sun, 30 Aug 2026 09:50:28 +0200 Subject: [PATCH] Manager.Set and Manager.All Set is the deliberate overwrite: it replaces a registered entry in place, keeping its position in the insertion order, and falls back to Register when the name is new. Register keeps panicking on duplicates. All returns every entry in insertion order; orderedWidgets is now just that call, and reversedWidgets builds on it. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 7 +++++++ core.manager.go | 21 +++++++++++++++++++++ ui.manager.go | 17 +++++------------ 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 138b1c9..82a9c4b 100644 --- a/README.md +++ b/README.md @@ -189,11 +189,13 @@ type ThemeManager = Manager[Theme] | Method | Behaviour | |------------------------|------------------------------------------------------------| | `Register(v T)` | Adds `v` to the registry. Panics on empty or duplicate `Name`. | +| `Set(v T)` | Replaces an entry in place, keeping its position; registers it when the name is new. | | `Get(name) (T, bool)` | Looks up by name. The boolean is `false` if absent. | | `MustGet(name) T` | Same as `Get`, but panics on missing names. | | `Has(name) bool` | True if the name is registered. | | `Len() int` | Number of registered entries. | | `Names() []string` | Returns names in **insertion order** (used for widget Z-order). | +| `All() []T` | Returns every entry in **insertion order**. | | `SortedNames() []string` | Returns names alphabetically. | | `Each(fn func(T))` | Iterates in insertion order. | | `Remove(name string)` | Drops a registration; silent no-op if unknown. | @@ -216,6 +218,11 @@ on startup. Crashing loudly during `Build()` surfaces the problem in development; quietly accepting the second registration would silently mask shadowed entities at runtime. +When a registration genuinely has to be rewritten — a derived field filled in +after the fact, a hot-reloaded entity — `Set` is the deliberate overwrite. It +keeps the entry's place in the insertion order, so widget Z-order and any other +order-sensitive iteration survive the rewrite. + --- ## 4. The Game aggregate diff --git a/core.manager.go b/core.manager.go index 895b3e4..c1e164d 100644 --- a/core.manager.go +++ b/core.manager.go @@ -33,6 +33,18 @@ func (m *Manager[T]) Register(v T) { m.order = append(m.order, name) } +// Set replaces a registered entry in place, keeping its position in the +// registration order, and registers the entry when the name is new. Register +// panics on a duplicate; Set is the deliberate overwrite. +func (m *Manager[T]) Set(v T) { + name := v.GetName() + if _, ok := m.items[name]; !ok { + m.Register(v) + return + } + m.items[name] = v +} + func (m *Manager[T]) Get(name string) (T, bool) { v, ok := m.items[name] return v, ok @@ -59,6 +71,15 @@ func (m *Manager[T]) Names() []string { return append([]string(nil), m.order...) } +// All returns every registered entry in insertion order. +func (m *Manager[T]) All() []T { + out := make([]T, len(m.order)) + for i, n := range m.order { + out[i] = m.items[n] + } + return out +} + func (m *Manager[T]) SortedNames() []string { names := append([]string(nil), m.order...) sort.Strings(names) diff --git a/ui.manager.go b/ui.manager.go index cda87e7..65f9889 100644 --- a/ui.manager.go +++ b/ui.manager.go @@ -7,20 +7,13 @@ type UIManager = Manager[Widget] // order — used by the engine for top-down input dispatch (the widget // drawn on top gets the click first). func reversedWidgets(m *UIManager) []Widget { - names := m.Names() - out := make([]Widget, len(names)) - for i, n := range names { - out[len(names)-1-i] = m.MustGet(n) + all := m.All() + out := make([]Widget, len(all)) + for i, w := range all { + out[len(all)-1-i] = w } return out } // orderedWidgets iterates in registration order — bottom-up draw. -func orderedWidgets(m *UIManager) []Widget { - names := m.Names() - out := make([]Widget, len(names)) - for i, n := range names { - out[i] = m.MustGet(n) - } - return out -} +func orderedWidgets(m *UIManager) []Widget { return m.All() }