-
Notifications
You must be signed in to change notification settings - Fork 661
/
aliases.go
132 lines (111 loc) · 3.04 KB
/
aliases.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright (C) 2019-2022, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package ids
import (
"fmt"
"sync"
)
// AliaserReader allows one to lookup the aliases given to an ID.
type AliaserReader interface {
Lookup(alias string) (ID, error)
PrimaryAlias(id ID) (string, error)
Aliases(id ID) ([]string, error)
}
// Aliaser allows one to give an ID aliases. An ID can have arbitrarily many
// aliases; two IDs may not have the same alias.
type AliaserWriter interface {
Alias(id ID, alias string) error
RemoveAliases(id ID)
}
// Aliaser allows one to give an ID aliases and lookup the aliases given to an
// ID.
type Aliaser interface {
AliaserReader
AliaserWriter
PrimaryAliasOrDefault(id ID) string
}
type aliaser struct {
lock sync.RWMutex
dealias map[string]ID
aliases map[ID][]string
}
func NewAliaser() Aliaser {
return &aliaser{
dealias: make(map[string]ID),
aliases: make(map[ID][]string),
}
}
// Lookup returns the ID associated with alias
func (a *aliaser) Lookup(alias string) (ID, error) {
a.lock.RLock()
defer a.lock.RUnlock()
if id, ok := a.dealias[alias]; ok {
return id, nil
}
return ID{}, fmt.Errorf("there is no ID with alias %s", alias)
}
// PrimaryAlias returns the first alias of [id]
func (a *aliaser) PrimaryAlias(id ID) (string, error) {
a.lock.RLock()
defer a.lock.RUnlock()
aliases := a.aliases[id]
if len(aliases) == 0 {
return "", fmt.Errorf("there is no alias for ID %s", id)
}
return aliases[0], nil
}
// PrimaryAliasOrDefault returns the first alias of [id], or ID string as default
func (a *aliaser) PrimaryAliasOrDefault(id ID) string {
alias, err := a.PrimaryAlias(id)
if err != nil {
return id.String()
}
return alias
}
// Aliases returns the aliases of an ID
func (a *aliaser) Aliases(id ID) ([]string, error) {
a.lock.RLock()
defer a.lock.RUnlock()
return a.aliases[id], nil
}
// Alias gives [id] the alias [alias]
func (a *aliaser) Alias(id ID, alias string) error {
a.lock.Lock()
defer a.lock.Unlock()
if _, exists := a.dealias[alias]; exists {
return fmt.Errorf("%s is already used as an alias for an ID", alias)
}
a.dealias[alias] = id
a.aliases[id] = append(a.aliases[id], alias)
return nil
}
// RemoveAliases of the provided ID
func (a *aliaser) RemoveAliases(id ID) {
a.lock.Lock()
defer a.lock.Unlock()
aliases := a.aliases[id]
delete(a.aliases, id)
for _, alias := range aliases {
delete(a.dealias, alias)
}
}
// GetRelevantAliases returns the aliases with the redundant identity alias
// removed (each id is aliased to at least itself).
func GetRelevantAliases(aliaser Aliaser, ids []ID) (map[ID][]string, error) {
result := make(map[ID][]string, len(ids))
for _, id := range ids {
aliases, err := aliaser.Aliases(id)
if err != nil {
return nil, err
}
// remove the redundant alias where alias = id.
relevantAliases := make([]string, 0, len(aliases)-1)
for _, alias := range aliases {
if alias != id.String() {
relevantAliases = append(relevantAliases, alias)
}
}
result[id] = relevantAliases
}
return result, nil
}