package app import "sync" // Topic is a generic pub/sub for broadcasting updates. type Topic[T any] struct { c []chan *T mu sync.Mutex } // Watch subscribes a channel to receive updates. func (t *Topic[T]) Watch(c chan *T) { t.mu.Lock() defer t.mu.Unlock() t.c = append(t.c, c) } // Send broadcasts to all subscribers. If a subscriber's channel is full, // the message is dropped for that subscriber only; the subscriber is not // removed, so the connection stays alive and later updates are still delivered. func (t *Topic[T]) Send(b *T) { t.mu.Lock() defer t.mu.Unlock() for i := 0; i < len(t.c); i++ { select { case t.c[i] <- b: default: // Channel full: drop this message for this subscriber, keep them subscribed } } } // Close closes all subscriber channels. func (t *Topic[T]) Close() { t.mu.Lock() defer t.mu.Unlock() for _, c := range t.c { close(c) } t.c = t.c[:0] } // Merge represents a map merge event (two maps becoming one). type Merge struct { From, To int Shift Coord }