From d7cd35e72b81644774e5f1ab44ff8645e31aa510 Mon Sep 17 00:00:00 2001 From: Ben Burwell Date: Thu, 11 Jul 2019 09:44:50 -0400 Subject: [PATCH] Create UIDStore package This package can be used to provide a source for mapping mock UIDs back to relevant keys for alternate backends. For example, for the Maildir backend, we need to map between UID and message file names. --- lib/uidstore/uidstore.go | 62 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 lib/uidstore/uidstore.go diff --git a/lib/uidstore/uidstore.go b/lib/uidstore/uidstore.go new file mode 100644 index 0000000..11c5e47 --- /dev/null +++ b/lib/uidstore/uidstore.go @@ -0,0 +1,62 @@ +// Package uidstore provides a concurrency-safe two-way mapping between UIDs +// used by the UI and arbitrary string keys as used by different mail backends. +// +// Multiple Store instances can safely be created and the UIDs that they +// generate will be globally unique. +package uidstore + +import ( + "sync" + "sync/atomic" +) + +var nextUID uint32 = 1 + +// Store holds a mapping between application keys and globally-unique UIDs. +type Store struct { + keyByUID map[uint32]string + uidByKey map[string]uint32 + m sync.Mutex +} + +// NewStore creates a new, empty Store. +func NewStore() *Store { + return &Store{ + keyByUID: make(map[uint32]string), + uidByKey: make(map[string]uint32), + } +} + +// GetOrInsert returns the UID for the provided key. If the key was already +// present in the store, the same UID value is returned. Otherwise, the key is +// inserted and the newly generated UID is returned. +func (s *Store) GetOrInsert(key string) uint32 { + s.m.Lock() + defer s.m.Unlock() + if uid, ok := s.uidByKey[key]; ok { + return uid + } + uid := atomic.AddUint32(&nextUID, 1) + s.keyByUID[uid] = key + s.uidByKey[key] = uid + return uid +} + +// GetKey returns the key for the provided UID, if available. +func (s *Store) GetKey(uid uint32) (string, bool) { + s.m.Lock() + defer s.m.Unlock() + key, ok := s.keyByUID[uid] + return key, ok +} + +// RemoveUID removes the specified UID from the store. +func (s *Store) RemoveUID(uid uint32) { + s.m.Lock() + defer s.m.Unlock() + key, ok := s.keyByUID[uid] + if ok { + delete(s.uidByKey, key) + } + delete(s.keyByUID, uid) +}