Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

vault.gno

2.87 Kb · 116 lines
  1package vault
  2
  3import (
  4	"chain"
  5	"chain/runtime/unsafe"
  6	"strconv"
  7	"strings"
  8
  9	"gno.land/p/nt/avl/v0"
 10)
 11
 12// vaults maps address string -> *avl.Tree (key string -> value string).
 13var vaults avl.Tree
 14
 15// vaultFor returns the caller's namespace tree, creating it if needed.
 16func vaultFor(owner address) *avl.Tree {
 17	k := owner.String()
 18	if v := vaults.Get(k); v != nil {
 19		return v.(*avl.Tree)
 20	}
 21	t := &avl.Tree{}
 22	vaults.Set(k, t)
 23	return t
 24}
 25
 26// Set stores value under key in the caller's own namespace.
 27func Set(cur realm, key string, value string) {
 28	if key == "" {
 29		panic("key must not be empty")
 30	}
 31	caller := unsafe.PreviousRealm().Address()
 32	t := vaultFor(caller)
 33	t.Set(key, value)
 34	chain.Emit("VaultSet", "owner", caller.String(), "key", key)
 35}
 36
 37// Delete removes key from the caller's own namespace.
 38func Delete(cur realm, key string) {
 39	caller := unsafe.PreviousRealm().Address()
 40	k := caller.String()
 41	v := vaults.Get(k)
 42	if v == nil {
 43		panic("no vault for caller")
 44	}
 45	t := v.(*avl.Tree)
 46	if _, removed := t.Remove(key); !removed {
 47		panic("key not found")
 48	}
 49	if t.Size() == 0 {
 50		vaults.Remove(k)
 51	}
 52	chain.Emit("VaultDelete", "owner", caller.String(), "key", key)
 53}
 54
 55// Render shows all vaults (root) or a single address's entries ("/<address>").
 56func Render(path string) string {
 57	p := strings.TrimPrefix(path, "/")
 58	if p == "" {
 59		return renderRoot()
 60	}
 61	return renderAddress(p)
 62}
 63
 64func renderRoot() string {
 65	var b strings.Builder
 66	b.WriteString("# Key-Value Vault\n\n")
 67	b.WriteString("A per-address key-value store. Each caller owns their own namespace; only the owner can mutate their entries.\n\n")
 68	if vaults.Size() == 0 {
 69		b.WriteString("_No vaults yet. Call `Set(cur, key, value)` to create one._\n")
 70		return b.String()
 71	}
 72	b.WriteString("## Vaults\n\n")
 73	b.WriteString("| Address | Entries |\n")
 74	b.WriteString("|---|---|\n")
 75	vaults.Iterate("", "", func(k string, v interface{}) bool {
 76		t := v.(*avl.Tree)
 77		b.WriteString("| [")
 78		b.WriteString(k)
 79		b.WriteString("](/r:")
 80		// link back into this realm's render for the address subpage
 81		b.WriteString(k)
 82		b.WriteString(") | ")
 83		b.WriteString(strconv.Itoa(t.Size()))
 84		b.WriteString(" |\n")
 85		return false
 86	})
 87	b.WriteString("\nView an address's entries at path `/<address>`.\n")
 88	return b.String()
 89}
 90
 91func renderAddress(addr string) string {
 92	var b strings.Builder
 93	b.WriteString("# Vault: ")
 94	b.WriteString(addr)
 95	b.WriteString("\n\n")
 96	v := vaults.Get(addr)
 97	if v == nil {
 98		b.WriteString("_No vault for this address._\n")
 99		return b.String()
100	}
101	t := v.(*avl.Tree)
102	b.WriteString("| Key | Value |\n")
103	b.WriteString("|---|---|\n")
104	t.Iterate("", "", func(k string, val interface{}) bool {
105		b.WriteString("| ")
106		b.WriteString(k)
107		b.WriteString(" | ")
108		b.WriteString(val.(string))
109		b.WriteString(" |\n")
110		return false
111	})
112	b.WriteString("\nTotal entries: ")
113	b.WriteString(strconv.Itoa(t.Size()))
114	b.WriteString("\n")
115	return b.String()
116}