permissions.gno
2.83 Kb · 131 lines
1package rbac
2
3import "gno.land/p/akkadia/v0/ds/btree"
4
5const maxPermissionID uint32 = 4294967295
6
7type permission struct {
8 ID uint32
9 Name string
10 Description string
11}
12
13type permissions struct {
14 idCounter uint32
15 permissionMap *btree.Uint32BTree
16 nameIndex *btree.StringBTree
17}
18
19func newPermissions(degree int) *permissions {
20 return &permissions{
21 permissionMap: btree.NewUint32BTree(degree),
22 nameIndex: btree.NewStringBTree(degree),
23 }
24}
25
26func (ps *permissions) Size() int {
27 return ps.permissionMap.Size()
28}
29
30func (ps *permissions) Add(name string, description string) {
31 ps.validateName(name)
32 if ps.nameIndex.Has(name) {
33 panic("permission already exists: " + name)
34 }
35
36 id := ps.nextID()
37 stored := &permission{
38 ID: id,
39 Name: name,
40 Description: description,
41 }
42 ps.permissionMap.Set(id, stored)
43 ps.nameIndex.Set(stored.Name, id)
44}
45
46func (ps *permissions) Update(name string, newName string, description string) {
47 ps.validateName(name)
48 ps.validateName(newName)
49
50 stored := ps.permission(name)
51 if name != newName && ps.nameIndex.Has(newName) {
52 panic("permission already exists: " + newName)
53 }
54
55 if stored.Name != newName {
56 ps.nameIndex.Remove(stored.Name)
57 ps.nameIndex.Set(newName, stored.ID)
58 stored.Name = newName
59 }
60 stored.Description = description
61}
62
63func (ps *permissions) Delete(name string) {
64 stored := ps.permission(name)
65 ps.permissionMap.Remove(stored.ID)
66 ps.nameIndex.Remove(stored.Name)
67}
68
69func (ps *permissions) Has(name string) bool {
70 ps.validateName(name)
71 return ps.nameIndex.Has(name)
72}
73
74func (ps *permissions) Get(name string) *permission {
75 return ps.permission(name)
76}
77
78func (ps *permissions) List(page int, count int) []*permission {
79 offset := pageOffset(page, count)
80 result := make([]*permission, 0, count)
81 ps.nameIndex.IterateByOffset(offset, count, func(_ string, idValue any) bool {
82 id, ok := idValue.(uint32)
83 if !ok {
84 panic("invalid permission index")
85 }
86 result = append(result, ps.permissionByID(id))
87 return false
88 })
89 return result
90}
91
92func (ps *permissions) permission(name string) *permission {
93 ps.validateName(name)
94
95 idValue, found := ps.nameIndex.Get(name)
96 if !found {
97 panic("permission not found: " + name)
98 }
99 id, ok := idValue.(uint32)
100 if !ok {
101 panic("invalid permission index")
102 }
103 return ps.permissionByID(id)
104}
105
106func (ps *permissions) permissionByID(id uint32) *permission {
107 permissionValue, found := ps.permissionMap.Get(id)
108 if !found {
109 panic("permission not found")
110 }
111 stored, ok := permissionValue.(*permission)
112 if !ok {
113 panic("invalid permission")
114 }
115 return stored
116}
117
118func (ps *permissions) nextID() uint32 {
119 if ps.idCounter == maxPermissionID {
120 panic("permission id exhausted")
121 }
122 id := ps.idCounter
123 ps.idCounter += 1
124 return id
125}
126
127func (ps *permissions) validateName(name string) {
128 if name == "" {
129 panic("permission name required")
130 }
131}