Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}