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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

jsonw.gno

2.87 Kb · 135 lines
  1// Package jsonw builds JSON text for realm query endpoints.
  2//
  3// Values are plain strings holding encoded JSON, composed with Obj and Arr:
  4//
  5//	jsonw.Obj(
  6//		"id", jsonw.Uint(b.ID),
  7//		"title", jsonw.String(b.Title),
  8//		"tags", jsonw.Strings(b.Tags),
  9//	)
 10//
 11// String escapes everything JSON requires and replaces invalid UTF-8, so
 12// user-supplied text can never break the document.
 13package jsonw
 14
 15import (
 16	"strconv"
 17	"strings"
 18	"time"
 19	"unicode/utf8"
 20)
 21
 22const Null = "null"
 23
 24// String encodes s as a JSON string.
 25func String(s string) string {
 26	var b strings.Builder
 27	b.WriteByte('"')
 28	for i := 0; i < len(s); {
 29		r, size := utf8.DecodeRuneInString(s[i:])
 30		if r == utf8.RuneError && size == 1 {
 31			b.WriteString(`\ufffd`)
 32			i++
 33			continue
 34		}
 35		switch {
 36		case r == '"':
 37			b.WriteString(`\"`)
 38		case r == '\\':
 39			b.WriteString(`\\`)
 40		case r == '\n':
 41			b.WriteString(`\n`)
 42		case r == '\r':
 43			b.WriteString(`\r`)
 44		case r == '\t':
 45			b.WriteString(`\t`)
 46		case r < 0x20 || r == 0x7f || r == 0x2028 || r == 0x2029:
 47			b.WriteString(`\u`)
 48			h := strconv.FormatInt(int64(r), 16)
 49			for j := len(h); j < 4; j++ {
 50				b.WriteByte('0')
 51			}
 52			b.WriteString(h)
 53		default:
 54			b.WriteString(s[i : i+size])
 55		}
 56		i += size
 57	}
 58	b.WriteByte('"')
 59	return b.String()
 60}
 61
 62// Int encodes n. Values beyond JavaScript's safe integer range are encoded
 63// as strings so clients never lose precision.
 64func Int(n int64) string {
 65	if n > 9007199254740991 || n < -9007199254740991 {
 66		return `"` + strconv.FormatInt(n, 10) + `"`
 67	}
 68	return strconv.FormatInt(n, 10)
 69}
 70
 71// Uint encodes n, as a string beyond JavaScript's safe integer range.
 72func Uint(n uint64) string {
 73	if n > 9007199254740991 {
 74		return `"` + strconv.FormatUint(n, 10) + `"`
 75	}
 76	return strconv.FormatUint(n, 10)
 77}
 78
 79// Bool encodes v.
 80func Bool(v bool) string {
 81	if v {
 82		return "true"
 83	}
 84	return "false"
 85}
 86
 87// Time encodes t as RFC 3339 in UTC, or null when zero.
 88func Time(t time.Time) string {
 89	if t.IsZero() {
 90		return Null
 91	}
 92	return String(t.UTC().Format(time.RFC3339))
 93}
 94
 95// Obj builds an object from alternating keys and encoded values.
 96func Obj(kv ...string) string {
 97	if len(kv)%2 != 0 {
 98		panic("jsonw: Obj needs key/value pairs")
 99	}
100	var b strings.Builder
101	b.WriteByte('{')
102	for i := 0; i < len(kv); i += 2 {
103		if i > 0 {
104			b.WriteByte(',')
105		}
106		b.WriteString(String(kv[i]))
107		b.WriteByte(':')
108		b.WriteString(kv[i+1])
109	}
110	b.WriteByte('}')
111	return b.String()
112}
113
114// Arr builds an array from encoded values.
115func Arr(items []string) string {
116	return "[" + strings.Join(items, ",") + "]"
117}
118
119// Strings encodes a list of strings.
120func Strings(ss []string) string {
121	out := make([]string, len(ss))
122	for i, s := range ss {
123		out[i] = String(s)
124	}
125	return Arr(out)
126}
127
128// Addresses encodes a list of addresses as strings.
129func Addresses(as []address) string {
130	out := make([]string, len(as))
131	for i, a := range as {
132		out[i] = String(a.String())
133	}
134	return Arr(out)
135}