base32demo.gno
2.59 Kb · 88 lines
1// Package base32demo is a small gnoweb demo of the base32 codec provided by the
2// [p/moul/x/daily/base32](/p/moul/x/daily/base32/v0) library: it shows the RFC
3// 4648 vectors alongside Crockford, and the forgiving decodes Crockford allows.
4//
5// It contains no codec logic of its own. Stateless, so Render is deterministic.
6package base32demo
7
8import (
9 "strings"
10
11 "gno.land/p/moul/x/daily/base32/v0"
12)
13
14// The RFC 4648 §10 vectors — every partial-group length.
15var vectors = []string{"", "f", "fo", "foo", "foob", "fooba", "foobar"}
16
17// Render renders the demo for gnoweb.
18//
19// Render("") / Render("/") -> the vectors + Crockford forgiveness
20// Render("/<text>") -> encode that text both ways
21func Render(path string) string {
22 var b strings.Builder
23 b.WriteString("# Base32\n\n")
24 b.WriteString("RFC 4648 and Crockford, demoing the ")
25 b.WriteString("[`p/moul/x/daily/base32`](/p/moul/x/daily/base32/v0) library.\n\n")
26
27 if in := parseArg(path); in != "" {
28 std, _ := base32.Encode(in)
29 ck, _ := base32.EncodeCrockford(in)
30 b.WriteString("## `")
31 b.WriteString(in)
32 b.WriteString("`\n\n- RFC 4648: `")
33 b.WriteString(std)
34 b.WriteString("`\n- Crockford: `")
35 b.WriteString(ck)
36 b.WriteString("`\n")
37 return b.String()
38 }
39
40 b.WriteString("| input | RFC 4648 | Crockford |\n|---|---|---|\n")
41 for _, v := range vectors {
42 std, _ := base32.Encode(v)
43 ck, _ := base32.EncodeCrockford(v)
44 b.WriteString("| ")
45 if v == "" {
46 b.WriteString("_(empty)_")
47 } else {
48 b.WriteString("`" + v + "`")
49 }
50 b.WriteString(" | `")
51 b.WriteString(std)
52 b.WriteString("` | `")
53 b.WriteString(ck)
54 b.WriteString("` |\n")
55 }
56
57 b.WriteString("\n## Crockford forgives\n\n")
58 enc, _ := base32.EncodeCrockford("hello")
59 b.WriteString("`hello` encodes to `")
60 b.WriteString(enc)
61 b.WriteString("`, and all of these decode back to it:\n\n")
62 variants := []string{enc, strings.ToLower(enc), enc[:2] + "-" + enc[2:]}
63 for _, v := range variants {
64 dec, err := base32.DecodeCrockford(v)
65 b.WriteString("- `")
66 b.WriteString(v)
67 b.WriteString("` → ")
68 if err == nil && dec == "hello" {
69 b.WriteString("`hello` ✅")
70 } else {
71 b.WriteString("❌")
72 }
73 b.WriteString("\n")
74 }
75 b.WriteString("\n> Crockford folds case, reads `I`/`L` as `1` and `O` as `0`, and ")
76 b.WriteString("ignores hyphens — so an identifier survives being read aloud and typed back. ")
77 b.WriteString("`U` is left out of the alphabet on purpose.\n")
78 return b.String()
79}
80
81func parseArg(path string) string {
82 s := strings.TrimSpace(path)
83 s = strings.TrimPrefix(s, "/")
84 if i := strings.IndexByte(s, '/'); i >= 0 {
85 s = s[:i]
86 }
87 return s
88}