summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorBen Burwell <ben@benburwell.com>2019-07-11 09:44:50 -0400
committerDrew DeVault <sir@cmpwn.com>2019-07-12 11:09:47 -0400
commitd7cd35e72b81644774e5f1ab44ff8645e31aa510 (patch)
treec768fd6d1547d873d86210a85045e29f6c36c9cb /lib
parent3b09c07e7a75feed8a9086b0a9003c2cf3ffea59 (diff)
downloadaerc-d7cd35e72b81644774e5f1ab44ff8645e31aa510.tar.gz
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.
Diffstat (limited to 'lib')
-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)
+}