about summary refs log tree commit diff stats
path: root/lib/uidstore/uidstore.go
diff options
context:
space:
mode:
Diffstat (limited to 'lib/uidstore/uidstore.go')
-rw-r--r--lib/uidstore/uidstore.go62
1 files changed, 62 insertions, 0 deletions
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)
+}