Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}