grants.gno
3.17 Kb · 122 lines
1package rbac
2
3import (
4 "gno.land/p/akkadia/v0/ds/btree"
5 "gno.land/p/akkadia/v0/ds/btreeset"
6)
7
8type grants struct {
9 degree int
10 grantIndex *btree.Uint32BTree
11}
12
13func newGrants(degree int) *grants {
14 return &grants{
15 degree: degree,
16 grantIndex: btree.NewUint32BTree(degree),
17 }
18}
19
20func (gs *grants) Add(granterRoleID uint32, granteeRoleID uint32) {
21 grantees := gs.getOrCreateGranteeSet(granterRoleID)
22 if grantees.Has(granteeRoleID) {
23 panic("grant already exists: granterRoleID=" + formatRoleID(granterRoleID) + ", granteeRoleID=" + formatRoleID(granteeRoleID))
24 }
25 grantees.Set(granteeRoleID)
26}
27
28func (gs *grants) Delete(granterRoleID uint32, granteeRoleID uint32) {
29 grantees, found := gs.findGranteeSet(granterRoleID)
30 if !found || !grantees.Has(granteeRoleID) {
31 panic("grant not found: granterRoleID=" + formatRoleID(granterRoleID) + ", granteeRoleID=" + formatRoleID(granteeRoleID))
32 }
33 grantees.Remove(granteeRoleID)
34 if grantees.Size() == 0 {
35 gs.grantIndex.Remove(granterRoleID)
36 }
37}
38
39func (gs *grants) Has(granterRoleID uint32, granteeRoleID uint32) bool {
40 grantees, found := gs.findGranteeSet(granterRoleID)
41 if !found {
42 return false
43 }
44 return grantees.Has(granteeRoleID)
45}
46
47func (gs *grants) DeleteRole(roleID uint32) {
48 gs.grantIndex.Remove(roleID)
49
50 emptyGranters := []uint32{}
51 gs.grantIndex.Iterate(nil, nil, func(granterRoleID uint32, granteesValue any) bool {
52 grantees := castGranteeSet(granterRoleID, granteesValue)
53 grantees.Remove(roleID)
54 if grantees.Size() == 0 {
55 emptyGranters = append(emptyGranters, granterRoleID)
56 }
57 return false
58 })
59 for _, granterRoleID := range emptyGranters {
60 gs.grantIndex.Remove(granterRoleID)
61 }
62}
63
64func (gs *grants) ListGrantees(granterRoleID uint32, page int, count int) []uint32 {
65 offset := pageOffset(page, count)
66
67 grantees, found := gs.findGranteeSet(granterRoleID)
68 if !found {
69 return []uint32{}
70 }
71
72 result := make([]uint32, 0, count)
73 grantees.IterateByOffset(offset, count, func(granteeRoleID uint32) bool {
74 result = append(result, granteeRoleID)
75 return false
76 })
77 return result
78}
79
80func (gs *grants) Size() int {
81 size := 0
82 gs.grantIndex.Iterate(nil, nil, func(granterRoleID uint32, granteesValue any) bool {
83 size += castGranteeSet(granterRoleID, granteesValue).Size()
84 return false
85 })
86 return size
87}
88
89func (gs *grants) GranteeSize(granterRoleID uint32) int {
90 grantees, found := gs.findGranteeSet(granterRoleID)
91 if !found {
92 return 0
93 }
94 return grantees.Size()
95}
96
97func (gs *grants) findGranteeSet(granterRoleID uint32) (*btreeset.Uint32BTreeSet, bool) {
98 granteesValue, found := gs.grantIndex.Get(granterRoleID)
99 if !found {
100 return nil, false
101 }
102 return castGranteeSet(granterRoleID, granteesValue), true
103}
104
105func (gs *grants) getOrCreateGranteeSet(granterRoleID uint32) *btreeset.Uint32BTreeSet {
106 grantees, found := gs.findGranteeSet(granterRoleID)
107 if found {
108 return grantees
109 }
110
111 grantees = btreeset.NewUint32BTreeSet(gs.degree)
112 gs.grantIndex.Set(granterRoleID, grantees)
113 return grantees
114}
115
116func castGranteeSet(granterRoleID uint32, granteesValue any) *btreeset.Uint32BTreeSet {
117 grantees, ok := granteesValue.(*btreeset.Uint32BTreeSet)
118 if !ok {
119 panic("invalid grant index: " + formatRoleID(granterRoleID))
120 }
121 return grantees
122}