aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRobin Jarry <robin@jarry.cc>2024-08-14 16:59:11 +0200
committerRobin Jarry <robin@jarry.cc>2024-08-28 12:06:01 +0200
commit73dc39c6ee0827fc68b93af8dc438b0e1c14e929 (patch)
treeaff067600ea6326ff179447ed968b6712013b889 /lib
parent2950d919a5c5a55bd0eb53d6c41f989d8b70bd55 (diff)
downloadaerc-73dc39c6ee0827fc68b93af8dc438b0e1c14e929.tar.gz
treewide: replace uint32 uids with opaque strings
Add a new models.UID type (an alias to string). Replace all occurrences of uint32 being used as message UID or thread UID with models.UID. Update all workers to only expose models.UID values and deal with the conversion internally. Only IMAP needs to convert these to uint32. All other backends already use plain strings as message identifiers, in which case no conversion is even needed. The directory tree implementation needed to be heavily refactored in order to accommodate thread UID not being usable as a list index. Signed-off-by: Robin Jarry <robin@jarry.cc> Tested-by: Inwit <inwit@sindominio.net> Tested-by: Tim Culverhouse <tim@timculverhouse.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/emlview.go4
-rw-r--r--lib/iterator/impl.go9
-rw-r--r--lib/iterator/iterator_test.go17
-rw-r--r--lib/marker/marker.go48
-rw-r--r--lib/marker/marker_test.go27
-rw-r--r--lib/messageview.go4
-rw-r--r--lib/msgstore.go99
-rw-r--r--lib/rfc822/message.go2
-rw-r--r--lib/rfc822/message_test.go2
-rw-r--r--lib/sort/sort.go5
-rw-r--r--lib/threadbuilder.go42
-rw-r--r--lib/uidstore/uidstore.go62
12 files changed, 132 insertions, 189 deletions
diff --git a/lib/emlview.go b/lib/emlview.go
index e27edcb0..3f9c3f39 100644
--- a/lib/emlview.go
+++ b/lib/emlview.go
@@ -19,8 +19,8 @@ func (fm *EmlMessage) NewReader() (io.ReadCloser, error) {
return io.NopCloser(bytes.NewReader(*fm)), nil
}
-func (fm *EmlMessage) UID() uint32 {
- return 0xFFFFFFF
+func (fm *EmlMessage) UID() models.UID {
+ return ""
}
func (fm *EmlMessage) Labels() ([]string, error) {
diff --git a/lib/iterator/impl.go b/lib/iterator/impl.go
index 5e685166..be8c382e 100644
--- a/lib/iterator/impl.go
+++ b/lib/iterator/impl.go
@@ -3,6 +3,7 @@ package iterator
import (
"errors"
+ "git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/worker/types"
)
@@ -11,7 +12,7 @@ type defaultFactory struct{}
func (df *defaultFactory) NewIterator(a interface{}) Iterator {
switch data := a.(type) {
- case []uint32:
+ case []models.UID:
return &defaultUid{data: data, index: len(data)}
case []*types.Thread:
return &defaultThread{data: data, index: len(data)}
@@ -21,7 +22,7 @@ func (df *defaultFactory) NewIterator(a interface{}) Iterator {
// defaultUid
type defaultUid struct {
- data []uint32
+ data []models.UID
index int
}
@@ -70,7 +71,7 @@ type reverseFactory struct{}
func (rf *reverseFactory) NewIterator(a interface{}) Iterator {
switch data := a.(type) {
- case []uint32:
+ case []models.UID:
return &reverseUid{data: data, index: -1}
case []*types.Thread:
return &reverseThread{data: data, index: -1}
@@ -80,7 +81,7 @@ func (rf *reverseFactory) NewIterator(a interface{}) Iterator {
// reverseUid
type reverseUid struct {
- data []uint32
+ data []models.UID
index int
}
diff --git a/lib/iterator/iterator_test.go b/lib/iterator/iterator_test.go
index 6a8d3f6e..01ab9ff9 100644
--- a/lib/iterator/iterator_test.go
+++ b/lib/iterator/iterator_test.go
@@ -4,10 +4,11 @@ import (
"testing"
"git.sr.ht/~rjarry/aerc/lib/iterator"
+ "git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/worker/types"
)
-func toThreads(uids []uint32) []*types.Thread {
+func toThreads(uids []models.UID) []*types.Thread {
threads := make([]*types.Thread, len(uids))
for i, u := range uids {
threads[i] = &types.Thread{Uid: u}
@@ -16,8 +17,8 @@ func toThreads(uids []uint32) []*types.Thread {
}
func TestIterator_DefaultFactory(t *testing.T) {
- input := []uint32{1, 2, 3, 4, 5, 6, 7, 8, 9}
- want := []uint32{9, 8, 7, 6, 5, 4, 3, 2, 1}
+ input := []models.UID{"1", "2", "3", "4", "5", "6", "7", "8", "9"}
+ want := []models.UID{"9", "8", "7", "6", "5", "4", "3", "2", "1"}
factory := iterator.NewFactory(false)
if factory == nil {
@@ -30,8 +31,8 @@ func TestIterator_DefaultFactory(t *testing.T) {
}
func TestIterator_ReverseFactory(t *testing.T) {
- input := []uint32{1, 2, 3, 4, 5, 6, 7, 8, 9}
- want := []uint32{1, 2, 3, 4, 5, 6, 7, 8, 9}
+ input := []models.UID{"1", "2", "3", "4", "5", "6", "7", "8", "9"}
+ want := []models.UID{"1", "2", "3", "4", "5", "6", "7", "8", "9"}
factory := iterator.NewFactory(true)
if factory == nil {
@@ -45,13 +46,13 @@ func TestIterator_ReverseFactory(t *testing.T) {
}
func checkUids(t *testing.T, factory iterator.Factory,
- input []uint32, want []uint32, start, end int,
+ input []models.UID, want []models.UID, start, end int,
) {
label := "uids"
- got := make([]uint32, 0)
+ got := make([]models.UID, 0)
iter := factory.NewIterator(input)
for iter.Next() {
- got = append(got, iter.Value().(uint32))
+ got = append(got, iter.Value().(models.UID))
}
if len(got) != len(want) {
t.Errorf(label + "number of elements not correct")
diff --git a/lib/marker/marker.go b/lib/marker/marker.go
index a0860be9..55f70f42 100644
--- a/lib/marker/marker.go
+++ b/lib/marker/marker.go
@@ -1,13 +1,15 @@
package marker
+import "git.sr.ht/~rjarry/aerc/models"
+
// Marker provides the interface for the marking behavior of messages
type Marker interface {
- Mark(uint32)
- Unmark(uint32)
- ToggleMark(uint32)
+ Mark(models.UID)
+ Unmark(models.UID)
+ ToggleMark(models.UID)
Remark()
- Marked() []uint32
- IsMarked(uint32) bool
+ Marked() []models.UID
+ IsMarked(models.UID) bool
IsVisualMark() bool
ToggleVisualMark(bool)
UpdateVisualMark()
@@ -16,30 +18,30 @@ type Marker interface {
// UIDProvider provides the underlying uids and the selected message index
type UIDProvider interface {
- Uids() []uint32
+ Uids() []models.UID
SelectedIndex() int
}
type controller struct {
uidProvider UIDProvider
- marked map[uint32]struct{}
- lastMarked map[uint32]struct{}
- visualStartUID uint32
+ marked map[models.UID]struct{}
+ lastMarked map[models.UID]struct{}
+ visualStartUID models.UID
visualMarkMode bool
- visualBase map[uint32]struct{}
+ visualBase map[models.UID]struct{}
}
// New returns a new Marker
func New(up UIDProvider) Marker {
return &controller{
uidProvider: up,
- marked: make(map[uint32]struct{}),
- lastMarked: make(map[uint32]struct{}),
+ marked: make(map[models.UID]struct{}),
+ lastMarked: make(map[models.UID]struct{}),
}
}
// Mark markes the uid as marked
-func (mc *controller) Mark(uid uint32) {
+func (mc *controller) Mark(uid models.UID) {
if mc.visualMarkMode {
// visual mode has override, bogus input from user
return
@@ -48,7 +50,7 @@ func (mc *controller) Mark(uid uint32) {
}
// Unmark unmarks the uid
-func (mc *controller) Unmark(uid uint32) {
+func (mc *controller) Unmark(uid models.UID) {
if mc.visualMarkMode {
// user probably wanted to clear the visual marking
mc.ClearVisualMark()
@@ -63,7 +65,7 @@ func (mc *controller) Remark() {
}
// ToggleMark toggles the marked state for the given uid
-func (mc *controller) ToggleMark(uid uint32) {
+func (mc *controller) ToggleMark(uid models.UID) {
if mc.visualMarkMode {
// visual mode has override, bogus input from user
return
@@ -78,7 +80,7 @@ func (mc *controller) ToggleMark(uid uint32) {
// resetMark removes the marking from all messages
func (mc *controller) resetMark() {
mc.lastMarked = mc.marked
- mc.marked = make(map[uint32]struct{})
+ mc.marked = make(map[models.UID]struct{})
}
// removeStaleUID removes uids that are no longer presents in the UIDProvider
@@ -98,15 +100,15 @@ func (mc *controller) removeStaleUID() {
}
// IsMarked checks whether the given uid has been marked
-func (mc *controller) IsMarked(uid uint32) bool {
+func (mc *controller) IsMarked(uid models.UID) bool {
_, marked := mc.marked[uid]
return marked
}
// Marked returns the uids of all marked messages
-func (mc *controller) Marked() []uint32 {
+func (mc *controller) Marked() []models.UID {
mc.removeStaleUID()
- marked := make([]uint32, len(mc.marked))
+ marked := make([]models.UID, len(mc.marked))
i := 0
for uid := range mc.marked {
marked[i] = uid
@@ -132,7 +134,7 @@ func (mc *controller) ToggleVisualMark(clear bool) {
if idx := mc.uidProvider.SelectedIndex(); idx >= 0 && idx < len(uids) {
mc.visualStartUID = uids[idx]
mc.marked[mc.visualStartUID] = struct{}{}
- mc.visualBase = make(map[uint32]struct{})
+ mc.visualBase = make(map[models.UID]struct{})
for key, value := range mc.marked {
mc.visualBase[key] = value
}
@@ -144,7 +146,7 @@ func (mc *controller) ToggleVisualMark(clear bool) {
func (mc *controller) ClearVisualMark() {
mc.resetMark()
mc.visualMarkMode = false
- mc.visualStartUID = 0
+ mc.visualStartUID = ""
}
// UpdateVisualMark updates the index with the currently selected message
@@ -167,13 +169,13 @@ func (mc *controller) UpdateVisualMark() {
uids := mc.uidProvider.Uids()
- var visUids []uint32
+ var visUids []models.UID
if selectedIdx > startIdx {
visUids = uids[startIdx : selectedIdx+1]
} else {
visUids = uids[selectedIdx : startIdx+1]
}
- mc.marked = make(map[uint32]struct{})
+ mc.marked = make(map[models.UID]struct{})
for uid := range mc.visualBase {
mc.marked[uid] = struct{}{}
}
diff --git a/lib/marker/marker_test.go b/lib/marker/marker_test.go
index df9eb2a3..04d3fedc 100644
--- a/lib/marker/marker_test.go
+++ b/lib/marker/marker_test.go
@@ -4,16 +4,17 @@ import (
"testing"
"git.sr.ht/~rjarry/aerc/lib/marker"
+ "git.sr.ht/~rjarry/aerc/models"
)
// mockUidProvider implements the UidProvider interface and mocks the message
// store for testing
type mockUidProvider struct {
- uids []uint32
+ uids []models.UID
idx int
}
-func (mock *mockUidProvider) Uids() []uint32 {
+func (mock *mockUidProvider) Uids() []models.UID {
return mock.uids
}
@@ -23,7 +24,7 @@ func (mock *mockUidProvider) SelectedIndex() int {
func createMarker() (marker.Marker, *mockUidProvider) {
uidProvider := &mockUidProvider{
- uids: []uint32{1, 2, 3, 4},
+ uids: []models.UID{"1", "2", "3", "4"},
idx: 1,
}
m := marker.New(uidProvider)
@@ -32,7 +33,7 @@ func createMarker() (marker.Marker, *mockUidProvider) {
func TestMarker_MarkUnmark(t *testing.T) {
m, _ := createMarker()
- uid := uint32(4)
+ uid := models.UID("4")
m.Mark(uid)
if !m.IsMarked(uid) {
@@ -47,7 +48,7 @@ func TestMarker_MarkUnmark(t *testing.T) {
func TestMarker_ToggleMark(t *testing.T) {
m, _ := createMarker()
- uid := uint32(4)
+ uid := models.UID("4")
if m.IsMarked(uid) {
t.Errorf("ToggleMark: uid should not be marked")
@@ -66,9 +67,9 @@ func TestMarker_ToggleMark(t *testing.T) {
func TestMarker_Marked(t *testing.T) {
m, _ := createMarker()
- expected := map[uint32]struct{}{
- uint32(1): {},
- uint32(4): {},
+ expected := map[models.UID]struct{}{
+ "1": {},
+ "4": {},
}
for uid := range expected {
m.Mark(uid)
@@ -81,7 +82,7 @@ func TestMarker_Marked(t *testing.T) {
for _, uid := range got {
if _, ok := expected[uid]; !ok {
- t.Errorf("Marked: received uid %d as marked but it should not be", uid)
+ t.Errorf("Marked: received uid %q as marked but it should not be", uid)
}
}
}
@@ -93,15 +94,15 @@ func TestMarker_VisualMode(t *testing.T) {
m.ToggleVisualMark(false)
// marking should now fail silently because we're in visual mode
- m.Mark(1)
- if m.IsMarked(1) {
+ m.Mark("1")
+ if m.IsMarked("1") {
t.Errorf("marking in visual mode should not work")
}
// move selection index to last item
up.idx = len(up.uids) - 1
m.UpdateVisualMark()
- expectedMarked := []uint32{2, 3, 4}
+ expectedMarked := []models.UID{"2", "3", "4"}
for _, uidMarked := range expectedMarked {
if !m.IsMarked(uidMarked) {
@@ -128,7 +129,7 @@ func TestMarker_VisualMode(t *testing.T) {
func TestMarker_MarkOutOfBound(t *testing.T) {
m, _ := createMarker()
- outOfBoundUid := uint32(100)
+ outOfBoundUid := models.UID("100")
m.Mark(outOfBoundUid)
for _, markedUid := range m.Marked() {
diff --git a/lib/messageview.go b/lib/messageview.go
index 34549023..b849148a 100644
--- a/lib/messageview.go
+++ b/lib/messageview.go
@@ -75,7 +75,7 @@ func NewMessageStoreView(messageInfo *models.MessageInfo, setSeen bool,
cb := func(msv MessageView, err error) {
if msv != nil && setSeen && err == nil &&
!messageInfo.Flags.Has(models.SeenFlag) {
- store.Flag([]uint32{messageInfo.Uid}, models.SeenFlag, true, nil)
+ store.Flag([]models.UID{messageInfo.Uid}, models.SeenFlag, true, nil)
}
innerCb(msv, err)
}
@@ -147,7 +147,7 @@ func (msv *MessageStoreView) MessageDetails() *models.MessageDetails {
func (msv *MessageStoreView) FetchFull(cb func(io.Reader)) {
if msv.message == nil && msv.messageStore != nil {
- msv.messageStore.FetchFull([]uint32{msv.messageInfo.Uid},
+ msv.messageStore.FetchFull([]models.UID{msv.messageInfo.Uid},
func(fm *types.FullMessage) {
cb(fm.Content.Reader)
})
diff --git a/lib/msgstore.go b/lib/msgstore.go
index 5c8b3ef1..1250a9c0 100644
--- a/lib/msgstore.go
+++ b/lib/msgstore.go
@@ -20,8 +20,8 @@ import (
type MessageStore struct {
sync.Mutex
Name string
- Deleted map[uint32]interface{}
- Messages map[uint32]*models.MessageInfo
+ Deleted map[models.UID]interface{}
+ Messages map[models.UID]*models.MessageInfo
Sorting bool
ui func() *config.UIConfig
@@ -30,21 +30,21 @@ type MessageStore struct {
ctx context.Context
// Ordered list of known UIDs
- uids []uint32
+ uids []models.UID
threads []*types.Thread
// Visible UIDs
scrollOffset int
scrollLen int
- selectedUid uint32
- bodyCallbacks map[uint32][]func(*types.FullMessage)
+ selectedUid models.UID
+ bodyCallbacks map[models.UID][]func(*types.FullMessage)
// marking
marker marker.Marker
// Search/filter results
- results []uint32
+ results []models.UID
resultIndex int
filter *types.SearchCriteria
@@ -60,11 +60,11 @@ type MessageStore struct {
onUpdate func(store *MessageStore) // TODO: multiple onUpdate handlers
onFilterChange func(store *MessageStore)
onUpdateDirs func()
- pendingBodies map[uint32]interface{}
- pendingHeaders map[uint32]interface{}
+ pendingBodies map[models.UID]interface{}
+ pendingHeaders map[models.UID]interface{}
worker *types.Worker
- needsFlags []uint32
+ needsFlags []models.UID
fetchFlagsDebounce *time.Timer
fetchFlagsDelay time.Duration
@@ -85,7 +85,7 @@ type MessageStore struct {
onSelect func(*models.MessageInfo)
}
-const MagicUid = 0xFFFFFFFF
+const MagicUid = models.UID("")
func NewMessageStore(worker *types.Worker, name string,
ui func() *config.UIConfig,
@@ -97,8 +97,8 @@ func NewMessageStore(worker *types.Worker, name string,
) *MessageStore {
return &MessageStore{
Name: name,
- Deleted: make(map[uint32]interface{}),
- Messages: make(map[uint32]*models.MessageInfo),
+ Deleted: make(map[models.UID]interface{}),
+ Messages: make(map[models.UID]*models.MessageInfo),
ui: ui,
@@ -108,13 +108,12 @@ func NewMessageStore(worker *types.Worker, name string,
// default window height until account is drawn once
scrollLen: 25,
- bodyCallbacks: make(map[uint32][]func(*types.FullMessage)),
-
- pendingBodies: make(map[uint32]interface{}),
- pendingHeaders: make(map[uint32]interface{}),
+ bodyCallbacks: make(map[models.UID][]func(*types.FullMessage)),
+ pendingBodies: make(map[models.UID]interface{}),
+ pendingHeaders: make(map[models.UID]interface{}),
worker: worker,
- needsFlags: []uint32{},
+ needsFlags: []models.UID{},
fetchFlagsDelay: 50 * time.Millisecond,
triggerNewEmail: triggerNewEmail,
@@ -158,12 +157,12 @@ func (store *MessageStore) UpdateScroll(offset, length int) {
store.scrollLen = length
}
-func (store *MessageStore) FetchHeaders(uids []uint32,
+func (store *MessageStore) FetchHeaders(uids []models.UID,
cb func(types.WorkerMessage),
) {
// TODO: this could be optimized by pre-allocating toFetch and trimming it
// at the end. In practice we expect to get most messages back in one frame.
- var toFetch []uint32
+ var toFetch []models.UID
for _, uid := range uids {
if _, ok := store.pendingHeaders[uid]; !ok {
toFetch = append(toFetch, uid)
@@ -189,10 +188,10 @@ func (store *MessageStore) FetchHeaders(uids []uint32,
}
}
-func (store *MessageStore) FetchFull(uids []uint32, cb func(*types.FullMessage)) {
+func (store *MessageStore) FetchFull(uids []models.UID, cb func(*types.FullMessage)) {
// TODO: this could be optimized by pre-allocating toFetch and trimming it
// at the end. In practice we expect to get most messages back in one frame.
- var toFetch []uint32
+ var toFetch []models.UID
for _, uid := range uids {
if _, ok := store.pendingBodies[uid]; !ok {
toFetch = append(toFetch, uid)
@@ -220,7 +219,7 @@ func (store *MessageStore) FetchFull(uids []uint32, cb func(*types.FullMessage))
}
}
-func (store *MessageStore) FetchBodyPart(uid uint32, part []int, cb func(io.Reader)) {
+func (store *MessageStore) FetchBodyPart(uid models.UID, part []int, cb func(io.Reader)) {
store.worker.PostAction(&types.FetchMessageBodyPart{
Uid: uid,
Part: part,
@@ -253,7 +252,7 @@ func merge(to *models.MessageInfo, from *models.MessageInfo) {
}
func (store *MessageStore) Update(msg types.WorkerMessage) {
- var newUids []uint32
+ var newUids []models.UID
update := false
updateThreads := false
directoryChange := false
@@ -265,7 +264,7 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
store.Sort(store.sortCriteria, nil)
update = true
case *types.DirectoryContents:
- newMap := make(map[uint32]*models.MessageInfo, len(msg.Uids))
+ newMap := make(map[models.UID]*models.MessageInfo, len(msg.Uids))
for i, uid := range msg.Uids {
if msg, ok := store.Messages[uid]; ok {
newMap[uid] = msg
@@ -291,7 +290,7 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
store.uids = store.builder.Uids()
store.threads = msg.Threads
- newMap := make(map[uint32]*models.MessageInfo, len(store.uids))
+ newMap := make(map[models.UID]*models.MessageInfo, len(store.uids))
for i, uid := range store.uids {
if msg, ok := store.Messages[uid]; ok {
newMap[uid] = msg
@@ -351,13 +350,13 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
break
}
- toDelete := make(map[uint32]interface{})
+ toDelete := make(map[models.UID]interface{})
for _, uid := range msg.Uids {
toDelete[uid] = nil
delete(store.Messages, uid)
delete(store.Deleted, uid)
}
- uids := make([]uint32, 0, len(store.uids)-len(msg.Uids))
+ uids := make([]models.UID, 0, len(store.uids)-len(msg.Uids))
for _, uid := range store.uids {
if _, deleted := toDelete[uid]; deleted {
continue
@@ -369,7 +368,7 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
store.Select(MagicUid)
}
- var newResults []uint32
+ var newResults []models.UID
for _, res := range store.results {
if _, deleted := toDelete[res]; !deleted {
newResults = append(newResults, res)
@@ -528,7 +527,7 @@ func (store *MessageStore) runThreadBuilderNow() {
}
// Thread returns the thread for the given UId
-func (store *MessageStore) Thread(uid uint32) (*types.Thread, error) {
+func (store *MessageStore) Thread(uid models.UID) (*types.Thread, error) {
if store.builder == nil {
return nil, errors.New("no threads found")
}
@@ -540,15 +539,15 @@ func (store *MessageStore) SelectedThread() (*types.Thread, error) {
return store.Thread(store.SelectedUid())
}
-func (store *MessageStore) Fold(uid uint32, toggle bool) error {
+func (store *MessageStore) Fold(uid models.UID, toggle bool) error {
return store.doThreadFolding(uid, true, toggle)
}
-func (store *MessageStore) Unfold(uid uint32, toggle bool) error {
+func (store *MessageStore) Unfold(uid models.UID, toggle bool) error {
return store.doThreadFolding(uid, false, toggle)
}
-func (store *MessageStore) doThreadFolding(uid uint32, hide bool, toggle bool) error {
+func (store *MessageStore) doThreadFolding(uid models.UID, hide bool, toggle bool) error {
thread, err := store.Thread(uid)
if err != nil {
return err
@@ -596,7 +595,7 @@ func (store *MessageStore) doThreadFolding(uid uint32, hide bool, toggle bool) e
return nil
}
-func (store *MessageStore) Delete(uids []uint32, mfs *types.MultiFileStrategy,
+func (store *MessageStore) Delete(uids []models.UID, mfs *types.MultiFileStrategy,
cb func(msg types.WorkerMessage),
) {
for _, uid := range uids {
@@ -618,13 +617,13 @@ func (store *MessageStore) Delete(uids []uint32, mfs *types.MultiFileStrategy,
})
}
-func (store *MessageStore) revertDeleted(uids []uint32) {
+func (store *MessageStore) revertDeleted(uids []models.UID) {
for _, uid := range uids {
delete(store.Deleted, uid)
}
}
-func (store *MessageStore) Copy(uids []uint32, dest string, createDest bool,
+func (store *MessageStore) Copy(uids []models.UID, dest string, createDest bool,
mfs *types.MultiFileStrategy, cb func(msg types.WorkerMessage),
) {
if createDest {
@@ -646,7 +645,7 @@ func (store *MessageStore) Copy(uids []uint32, dest string, createDest bool,
})
}
-func (store *MessageStore) Move(uids []uint32, dest string, createDest bool,
+func (store *MessageStore) Move(uids []models.UID, dest string, createDest bool,
mfs *types.MultiFileStrategy, cb func(msg types.WorkerMessage),
) {
for _, uid := range uids {
@@ -699,7 +698,7 @@ func (store *MessageStore) Append(dest string, flags models.Flags, date time.Tim
})
}
-func (store *MessageStore) Flag(uids []uint32, flags models.Flags,
+func (store *MessageStore) Flag(uids []models.UID, flags models.Flags,
enable bool, cb func(msg types.WorkerMessage),
) {
store.worker.PostAction(&types.FlagMessages{
@@ -729,7 +728,7 @@ func (store *MessageStore) Flag(uids []uint32, flags models.Flags,
})
}
-func (store *MessageStore) Answered(uids []uint32, answered bool,
+func (store *MessageStore) Answered(uids []models.UID, answered bool,
cb func(msg types.WorkerMessage),
) {
store.worker.PostAction(&types.AnsweredMessages{
@@ -738,7 +737,7 @@ func (store *MessageStore) Answered(uids []uint32, answered bool,
}, cb)
}
-func (store *MessageStore) Forwarded(uids []uint32, forwarded bool,
+func (store *MessageStore) Forwarded(uids []models.UID, forwarded bool,
cb func(msg types.WorkerMessage),
) {
store.worker.PostAction(&types.ForwardedMessages{
@@ -747,7 +746,7 @@ func (store *MessageStore) Forwarded(uids []uint32, forwarded bool,
}, cb)
}
-func (store *MessageStore) Uids() []uint32 {
+func (store *MessageStore) Uids() []models.UID {
if store.ThreadedView() && store.builder != nil {
if uids := store.builder.Uids(); len(uids) > 0 {
return uids
@@ -764,7 +763,7 @@ func (store *MessageStore) Selected() *models.MessageInfo {
return store.Messages[store.selectedUid]
}
-func (store *MessageStore) SelectedUid() uint32 {
+func (store *MessageStore) SelectedUid() models.UID {
if store.selectedUid == MagicUid && len(store.Uids()) > 0 {
iter := store.UidsIterator()
idx := iter.StartIndex()
@@ -776,14 +775,14 @@ func (store *MessageStore) SelectedUid() uint32 {
return store.selectedUid
}
-func (store *MessageStore) Select(uid uint32) {
+func (store *MessageStore) Select(uid models.UID) {
store.selectPriv(uid, false)
if store.onSelect != nil {
store.onSelect(store.Selected())
}
}
-func (store *MessageStore) selectPriv(uid uint32, lockHeld bool) {
+func (store *MessageStore) selectPriv(uid models.UID, lockHeld bool) {
if !lockHeld {
store.threadsMutex.Lock()
}
@@ -844,14 +843,14 @@ func (store *MessageStore) Prev() {
store.NextPrev(-1)
}
-func (store *MessageStore) Search(terms *types.SearchCriteria, cb func([]uint32)) {
+func (store *MessageStore) Search(terms *types.SearchCriteria, cb func([]models.UID)) {
store.worker.PostAction(&types.SearchDirectory{
Context: store.ctx,
Criteria: terms,
}, func(msg types.WorkerMessage) {
if msg, ok := msg.(*types.SearchResults); ok {
allowedUids := store.Uids()
- uids := make([]uint32, 0, len(msg.Uids))
+ uids := make([]models.UID, 0, len(msg.Uids))
for _, uid := range msg.Uids {
for _, uidCheck := range allowedUids {
if uid == uidCheck {
@@ -866,14 +865,14 @@ func (store *MessageStore) Search(terms *types.SearchCriteria, cb func([]uint32)
})
}
-func (store *MessageStore) ApplySearch(results []uint32) {
+func (store *MessageStore) ApplySearch(results []models.UID) {
store.results = results
store.resultIndex = -1
store.NextResult()
}
// IsResult returns true if uid is a search result
-func (store *MessageStore) IsResult(uid uint32) bool {
+func (store *MessageStore) IsResult(uid models.UID) bool {
for _, hit := range store.results {
if hit == uid {
return true
@@ -935,7 +934,7 @@ func (store *MessageStore) PrevResult() {
store.nextPrevResult(-1)
}
-func (store *MessageStore) ModifyLabels(uids []uint32, add, remove []string,
+func (store *MessageStore) ModifyLabels(uids []models.UID, add, remove []string,
cb func(msg types.WorkerMessage),
) {
store.worker.PostAction(&types.ModifyLabels{
@@ -999,7 +998,7 @@ func (store *MessageStore) Marker() marker.Marker {
}
// FindIndexByUid returns the index in store.Uids() or -1 if not found
-func (store *MessageStore) FindIndexByUid(uid uint32) int {
+func (store *MessageStore) FindIndexByUid(uid models.UID) int {
for idx, u := range store.Uids() {
if u == uid {
return idx
@@ -1029,7 +1028,7 @@ func (store *MessageStore) fetchFlags() {
Context: store.ctx,
Uids: store.needsFlags,
}, nil)
- store.needsFlags = []uint32{}
+ store.needsFlags = []models.UID{}
store.Unlock()
})
}
diff --git a/lib/rfc822/message.go b/lib/rfc822/message.go
index 3f0c447e..653cb2fe 100644
--- a/lib/rfc822/message.go
+++ b/lib/rfc822/message.go
@@ -291,7 +291,7 @@ type RawMessage interface {
NewReader() (io.ReadCloser, error)
ModelFlags() (models.Flags, error)
Labels() ([]string, error)
- UID() uint32
+ UID() models.UID
}
// MessageInfo populates a models.MessageInfo struct for the message.
diff --git a/lib/rfc822/message_test.go b/lib/rfc822/message_test.go
index f5f222e4..ca5ae014 100644
--- a/lib/rfc822/message_test.go
+++ b/lib/rfc822/message_test.go
@@ -185,7 +185,7 @@ func (m *mockRawMessage) NewReader() (io.ReadCloser, error) {
}
func (m *mockRawMessage) ModelFlags() (models.Flags, error) { return 0, nil }
func (m *mockRawMessage) Labels() ([]string, error) { return nil, nil }
-func (m *mockRawMessage) UID() uint32 { return 0 }
+func (m *mockRawMessage) UID() models.UID { return "" }
func die(err error) {
if err != nil {
diff --git a/lib/sort/sort.go b/lib/sort/sort.go
index 082ba48b..b62b8d04 100644
--- a/lib/sort/sort.go
+++ b/lib/sort/sort.go
@@ -6,6 +6,7 @@ import (
"sort"
"strings"
+ "git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/worker/types"
)
@@ -61,9 +62,9 @@ func parseSortField(arg string) (types.SortField, error) {
// Sorts toSort by sortBy so that toSort becomes a permutation following the
// order of sortBy.
// toSort should be a subset of sortBy
-func SortBy(toSort []uint32, sortBy []uint32) {
+func SortBy(toSort []models.UID, sortBy []models.UID) {
// build a map from sortBy
- uidMap := make(map[uint32]int)
+ uidMap := make(map[models.UID]int)
for i, uid := range sortBy {
uidMap[uid] = i
}
diff --git a/lib/threadbuilder.go b/lib/threadbuilder.go
index abfbadb7..d7373b10 100644
--- a/lib/threadbuilder.go
+++ b/lib/threadbuilder.go
@@ -15,41 +15,41 @@ import (
type ThreadBuilder struct {
sync.Mutex
- threadBlocks map[uint32]jwz.Threadable
- threadedUids []uint32
- threadMap map[uint32]*types.Thread
+ threadBlocks map[models.UID]jwz.Threadable
+ threadedUids []models.UID
+ threadMap map[models.UID]*types.Thread
iterFactory iterator.Factory
bySubject bool
}
func NewThreadBuilder(i iterator.Factory, bySubject bool) *ThreadBuilder {
tb := &ThreadBuilder{
- threadBlocks: make(map[uint32]jwz.Threadable),
+ threadBlocks: make(map[models.UID]jwz.Threadable),
iterFactory: i,
- threadMap: make(map[uint32]*types.Thread),
+ threadMap: make(map[models.UID]*types.Thread),
bySubject: bySubject,
}
return tb
}
-func (builder *ThreadBuilder) ThreadForUid(uid uint32) (*types.Thread, error) {
+func (builder *ThreadBuilder) ThreadForUid(uid models.UID) (*types.Thread, error) {
builder.Lock()
defer builder.Unlock()
t, ok := builder.threadMap[uid]
var err error
if !ok {
- err = fmt.Errorf("no thread found for uid '%d'", uid)
+ err = fmt.Errorf("no thread found for uid '%s'", uid)
}
return t, err
}
// Uids returns the uids in threading order
-func (builder *ThreadBuilder) Uids() []uint32 {
+func (builder *ThreadBuilder) Uids() []models.UID {
builder.Lock()
defer builder.Unlock()
if builder.threadedUids == nil {
- return []uint32{}
+ return []models.UID{}
}
return builder.threadedUids
}
@@ -68,7 +68,7 @@ func (builder *ThreadBuilder) Update(msg *models.MessageInfo) {
}
// Threads returns a slice of threads for the given list of uids
-func (builder *ThreadBuilder) Threads(uids []uint32, inverse bool, sort bool,
+func (builder *ThreadBuilder) Threads(uids []models.UID, inverse bool, sort bool,
) []*types.Thread {
builder.Lock()
defer builder.Unlock()
@@ -91,7 +91,7 @@ func (builder *ThreadBuilder) Threads(uids []uint32, inverse bool, sort bool,
return threads
}
-func (builder *ThreadBuilder) generateStructure(uids []uint32) jwz.Threadable {
+func (builder *ThreadBuilder) generateStructure(uids []models.UID) jwz.Threadable {
jwzThreads := make([]jwz.Threadable, 0, len(builder.threadBlocks))
for _, uid := range uids {
if thr, ok := builder.threadBlocks[uid]; ok {
@@ -108,7 +108,7 @@ func (builder *ThreadBuilder) generateStructure(uids []uint32) jwz.Threadable {
}
func (builder *ThreadBuilder) buildAercThreads(structure jwz.Threadable,
- uids []uint32, sort bool,
+ uids []models.UID, sort bool,
) []*types.Thread {
threads := make([]*types.Thread, 0, len(builder.threadBlocks))
@@ -121,7 +121,7 @@ func (builder *ThreadBuilder) buildAercThreads(structure jwz.Threadable,
// prepare bigger function
var bigger func(l, r *types.Thread) bool
if sort {
- sortMap := make(map[uint32]int)
+ sortMap := make(map[models.UID]int)
for i, uid := range uids {
sortMap[uid] = i
}
@@ -148,7 +148,7 @@ func (builder *ThreadBuilder) buildAercThreads(structure jwz.Threadable,
}
// build thread tree
- root := &types.Thread{Uid: 0}
+ root := &types.Thread{}
builder.buildTree(structure, root, bigger, true)
// copy top-level threads to thread slice
@@ -197,16 +197,16 @@ func (builder *ThreadBuilder) newThread(c jwz.Threadable, parent *types.Thread,
return nil
}
-func (builder *ThreadBuilder) sortThreads(threads []*types.Thread, orderedUids []uint32) {
+func (builder *ThreadBuilder) sortThreads(threads []*types.Thread, orderedUids []models.UID) {
types.SortThreadsBy(threads, orderedUids)
}
// RebuildUids rebuilds the uids from the given slice of threads
func (builder *ThreadBuilder) RebuildUids(threads []*types.Thread, inverse bool) {
- uids := make([]uint32, 0, len(threads))
+ uids := make([]models.UID, 0, len(threads))
iterT := builder.iterFactory.NewIterator(threads)
for iterT.Next() {
- var threaduids []uint32
+ var threaduids []models.UID
_ = iterT.Value().(*types.Thread).Walk(
func(t *types.Thread, level int, currentErr error) error {
stored, ok := builder.threadMap[t.Uid]
@@ -231,10 +231,10 @@ func (builder *ThreadBuilder) RebuildUids(threads []*types.Thread, inverse bool)
}
}
- result := make([]uint32, 0, len(uids))
+ result := make([]models.UID, 0, len(uids))
iterU := builder.iterFactory.NewIterator(uids)
for iterU.Next() {
- result = append(result, iterU.Value().(uint32))
+ result = append(result, iterU.Value().(models.UID))
}
builder.threadedUids = result
}
@@ -310,9 +310,9 @@ func cleanRefs(m, irp string, refs []string) []string {
return cleanRefs
}
-func (t *threadable) UID() uint32 {
+func (t *threadable) UID() models.UID {
if t.MsgInfo == nil {
- return 0
+ return ""
}
return t.MsgInfo.Uid
}
diff --git a/lib/uidstore/uidstore.go b/lib/uidstore/uidstore.go
deleted file mode 100644
index 11c5e47c..00000000
--- a/lib/uidstore/uidstore.go
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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)
-}