bidimapdemo.gno
2.73 Kb · 72 lines
1// Package bidimapdemo is a small gnoweb demo of the bidirectional map provided
2// by the [p/moul/x/daily/bidimap](/p/moul/x/daily/bidimap/v0) library: it shows
3// the reverse lookup and what happens when a binding is displaced.
4//
5// It contains no map logic of its own. Stateless, so Render is deterministic —
6// which is precisely what the library is for.
7package bidimapdemo
8
9import (
10 "strconv"
11 "strings"
12
13 "gno.land/p/moul/x/daily/bidimap/v0"
14)
15
16// Render renders the demo for gnoweb.
17func Render(path string) string {
18 var b strings.Builder
19 b.WriteString("# Bidirectional Map\n\n")
20 b.WriteString("Unique in both directions, demoing the ")
21 b.WriteString("[`p/moul/x/daily/bidimap`](/p/moul/x/daily/bidimap/v0) library.\n\n")
22
23 m := bidimap.New()
24 m.Put("alice", "admin")
25 m.Put("bob", "auditor")
26 m.Put("carol", "treasurer")
27
28 b.WriteString("## Roles\n\n")
29 b.WriteString(table(m))
30
31 b.WriteString("\n## Both directions are O(1)\n\n")
32 v, _ := m.Get("bob")
33 k, _ := m.GetKey("treasurer")
34 b.WriteString("- `Get(\"bob\")` → `" + v + "`\n")
35 b.WriteString("- `GetKey(\"treasurer\")` → `" + k + "` — the reverse index, not a scan\n\n")
36
37 b.WriteString("## Displacing a binding\n\n")
38 b.WriteString("Both sides are unique, so giving `alice` the `auditor` role cannot ")
39 b.WriteString("simply be written — `bob` already holds it, and `alice` already holds ")
40 b.WriteString("`admin`. `Put` **replaces**, and reports what it displaced:\n\n")
41 evicted, _ := m.Put("alice", "auditor")
42 b.WriteString("| displaced key | displaced value |\n|---|---|\n")
43 for _, p := range evicted {
44 b.WriteString("| `" + p[0] + "` | `" + p[1] + "` |\n")
45 }
46 b.WriteString("\n" + table(m))
47 b.WriteString("\n`bob` is now unassigned and the `admin` role is vacant — one call, ")
48 b.WriteString("both indexes still agreeing.\n\n")
49
50 b.WriteString("## Refusing instead\n\n")
51 b.WriteString("`PutUnique` makes the other choice: it declines rather than displace.\n\n")
52 ok := m.PutUnique("dave", "auditor")
53 b.WriteString("- `PutUnique(\"dave\", \"auditor\")` → `" + strconv.FormatBool(ok) + "` — the role is taken\n")
54 ok = m.PutUnique("dave", "secretary")
55 b.WriteString("- `PutUnique(\"dave\", \"secretary\")` → `" + strconv.FormatBool(ok) + "` — both sides free\n\n")
56 b.WriteString(table(m))
57
58 b.WriteString("\n> Keys come back **sorted**, never in map order: gno map iteration ")
59 b.WriteString("order is unspecified, and a page built from one can differ between ")
60 b.WriteString("nodes — a consensus bug, not a cosmetic one.\n")
61 return b.String()
62}
63
64func table(m *bidimap.BiMap) string {
65 var b strings.Builder
66 b.WriteString("| person | role |\n|---|---|\n")
67 m.Iterate(func(k, v string) bool {
68 b.WriteString("| `" + k + "` | `" + v + "` |\n")
69 return false
70 })
71 return b.String()
72}