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

codec.gno

4.13 Kb · 124 lines
  1package golf
  2
  3import (
  4	"strconv"
  5	"strings"
  6)
  7
  8// How golf's rows are kept in store: strings, never golf's own types (a value
  9// of a realm's type kept in another realm would carry this realm's methods into
 10// it, and would not outlive these rules). Each is its format's version, then
 11// its fields, each as its length, ":" and itself (store's own rows are so): a
 12// row reads back by its lengths, not by a scan of every byte (a scan, as
 13// strings.Split, costs several times more gas), whatever its fields hold. A
 14// later version of the rules reads every format ever written, row by row.
 15const format = "1"
 16
 17func join(fs ...string) string {
 18	var sb strings.Builder
 19	sb.WriteString("1:" + format)
 20	for _, f := range fs {
 21		sb.WriteString(strconv.Itoa(len(f)) + ":" + f)
 22	}
 23	return sb.String()
 24}
 25
 26// fields is a row's fields, its format checked: n of them, or it panics.
 27func fields(s, what string, n int) []string {
 28	f := make([]string, 0, n+1)
 29	for rest := s; len(rest) > 0; {
 30		i, l := 0, 0
 31		for i < len(rest) && i < 6 && rest[i] >= '0' && rest[i] <= '9' {
 32			l = l*10 + int(rest[i]-'0')
 33			i++
 34		}
 35		if i == 0 || i == len(rest) || rest[i] != ':' || len(rest)-i-1 < l || len(f) > n {
 36			panic("golf: a " + what + " not as golf keeps it: " + strconv.Quote(s))
 37		}
 38		f = append(f, rest[i+1:i+1+l])
 39		rest = rest[i+1+l:]
 40	}
 41	if len(f) != n+1 || f[0] != format {
 42		panic("golf: a " + what + " not as golf keeps it: " + strconv.Quote(s))
 43	}
 44	return f[1:]
 45}
 46
 47func itoa(n int) string      { return strconv.Itoa(n) }
 48func i64(n int64) string     { return strconv.FormatInt(n, 10) }
 49func ftoa(x float64) string  { return strconv.FormatFloat(x, 'g', -1, 64) } // (exact: it reads back to the same float)
 50func btoa(b bool) string {
 51	if b {
 52		return "1"
 53	}
 54	return "0"
 55}
 56
 57func atoi(s string) int {
 58	n, err := strconv.Atoi(s)
 59	if err != nil {
 60		panic("golf: a number not as golf keeps it: " + strconv.Quote(s))
 61	}
 62	return n
 63}
 64
 65func atoi64(s string) int64 {
 66	n, err := strconv.ParseInt(s, 10, 64)
 67	if err != nil {
 68		panic("golf: a number not as golf keeps it: " + strconv.Quote(s))
 69	}
 70	return n
 71}
 72
 73func atof(s string) float64 {
 74	x, err := strconv.ParseFloat(s, 64)
 75	if err != nil {
 76		panic("golf: a number not as golf keeps it: " + strconv.Quote(s))
 77	}
 78	return x
 79}
 80
 81// --- a version of a hole -------------------------------------------------------
 82
 83func encodeEntry(e *entry) string {
 84	out := []string{"", "", "", "", ""} // never archived: no drain
 85	if e.out != nil {
 86		out = []string{"1", e.out.from[assisted], e.out.from[pro], btoa(e.out.done[assisted]), btoa(e.out.done[pro])}
 87	}
 88	return join(append([]string{e.id, e.name, itoa(e.par), e.world, ftoa(e.order), btoa(e.official),
 89		e.slot, itoa(e.version), e.by.String(), i64(e.height), e.sha, e.note,
 90		itoa(e.plays), itoa(e.best), itoa(e.proBest), e.bestBy.String(), e.proBestBy.String(), e.next}, out...)...)
 91}
 92
 93func decodeEntry(s string) *entry {
 94	f := fields(s, "hole", 23)
 95	e := &entry{id: f[0], name: f[1], par: atoi(f[2]), world: f[3], order: atof(f[4]), official: f[5] == "1",
 96		slot: f[6], version: atoi(f[7]), by: address(f[8]), height: atoi64(f[9]), sha: f[10], note: f[11],
 97		plays: atoi(f[12]), best: atoi(f[13]), proBest: atoi(f[14]), bestBy: address(f[15]), proBestBy: address(f[16]), next: f[17]}
 98	if f[18] == "1" {
 99		e.out = &draining{from: [modes]string{f[19], f[20]}, done: [modes]bool{f[21] == "1", f[22] == "1"}}
100	}
101	return e
102}
103
104// --- a round under way ---------------------------------------------------------
105
106func encodeRound(r *round) string {
107	return join(ftoa(r.bx), ftoa(r.by), ftoa(r.fx), ftoa(r.fy), itoa(r.strokes), i64(r.period), r.shots, itoa(r.mode))
108}
109
110func decodeRound(s string) *round {
111	f := fields(s, "round", 8)
112	return &round{bx: atof(f[0]), by: atof(f[1]), fx: atof(f[2]), fy: atof(f[3]), strokes: atoi(f[4]), period: atoi64(f[5]), shots: f[6], mode: atoi(f[7])}
113}
114
115// --- a course standing ---------------------------------------------------------
116
117func encodeRow(r *row) string {
118	return join(r.player, itoa(r.holes), itoa(r.strokes), itoa(r.par), i64(r.height))
119}
120
121func decodeRow(s string) *row {
122	f := fields(s, "standing", 5)
123	return &row{player: f[0], holes: atoi(f[1]), strokes: atoi(f[2]), par: atoi(f[3]), height: atoi64(f[4])}
124}