63 lines
1.5 KiB
Go
63 lines
1.5 KiB
Go
|
// 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)
|
||
|
}
|