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

text.gno

3.26 Kb · 136 lines
  1// Package text holds the small string helpers shared by the GnoRadio realms.
  2package text
  3
  4import (
  5	"strconv"
  6	"strings"
  7	"unicode"
  8)
  9
 10// Str quotes a value as a JSON string without escaping. Use it only for values
 11// whose validator already refuses `"`, `\` and control characters (Valid text,
 12// validated URLs, hashes, addresses, constants): escaping costs about 1M gas
 13// per field in the VM.
 14func Str(s string) string { return `"` + s + `"` }
 15
 16// Valid accepts min..max runes of letters (any script), digits, spaces and
 17// . , ' - ! ? : / &. Markdown, HTML and JSON specials are refused, so the text
 18// is safe in markdown and JSON as is (SVG still escapes '&'). Fullwidth and
 19// mathematical letters (which dodge word filters) and the blank Hangul fillers
 20// are refused too.
 21func Valid(s string, min, max int) bool {
 22	n := 0
 23	for _, r := range s {
 24		n++
 25		if r >= 0xFF01 && r <= 0xFF5E || r >= 0x1D400 && r <= 0x1D7FF || r == 0x115F || r == 0x1160 || r == 0x3164 || r == 0xFFA0 {
 26			return false
 27		}
 28		if unicode.IsLetter(r) || unicode.IsDigit(r) {
 29			continue
 30		}
 31		switch r {
 32		case ' ', '.', ',', '\'', '-', '!', '?', ':', '/', '&':
 33			continue
 34		}
 35		return false
 36	}
 37	return n >= min && n <= max
 38}
 39
 40// Digits reports whether s is a non-empty run of ASCII digits.
 41func Digits(s string) bool {
 42	if s == "" {
 43		return false
 44	}
 45	for _, c := range s {
 46		if c < '0' || c > '9' {
 47			return false
 48		}
 49	}
 50	return true
 51}
 52
 53// GNOT formats ugnot as GNOT with up to 6 decimals.
 54func GNOT(u int64) string {
 55	const ugnot = 1_000_000
 56	whole := strconv.FormatInt(u/ugnot, 10)
 57	frac := u % ugnot
 58	if frac == 0 {
 59		return whole + " GNOT"
 60	}
 61	f := strconv.FormatInt(frac, 10)
 62	f = strings.TrimRight(strings.Repeat("0", 6-len(f))+f, "0")
 63	return whole + "." + f + " GNOT"
 64}
 65
 66// Itoa and Itoa64 skip strconv for the frequent zero: every conversion
 67// costs gas.
 68func Itoa(n int) string {
 69	if n == 0 {
 70		return "0"
 71	}
 72	return strconv.Itoa(n)
 73}
 74
 75func Itoa64(n int64) string {
 76	if n == 0 {
 77		return "0"
 78	}
 79	return strconv.FormatInt(n, 10)
 80}
 81
 82// Atoi and Atoi64 read a stored decimal; anything else is 0.
 83func Atoi(s string) int {
 84	n, _ := strconv.Atoi(s)
 85	return n
 86}
 87
 88func Atoi64(s string) int64 {
 89	n, _ := strconv.ParseInt(s, 10, 64)
 90	return n
 91}
 92
 93// MustAtoi and MustAtoi64 read a stored number on a money or authority path:
 94// a corrupt record panics (the transaction reverts) instead of reading as 0.
 95func MustAtoi(s string) int {
 96	n, err := strconv.Atoi(s)
 97	if err != nil {
 98		panic("text: not a number: " + s)
 99	}
100	return n
101}
102
103func MustAtoi64(s string) int64 {
104	n, err := strconv.ParseInt(s, 10, 64)
105	if err != nil {
106		panic("text: not a number: " + s)
107	}
108	return n
109}
110
111// Flag is a stored boolean: "1" or "".
112func Flag(b bool) string {
113	if b {
114		return "1"
115	}
116	return ""
117}
118
119// URLChars accepts only URL-safe characters (A-Z a-z 0-9 - . _ ~ : / ? # =
120// & % + @): safe in markdown link destinations and JSON as is.
121func URLChars(s string) bool {
122	for _, c := range s {
123		switch {
124		case c >= 'a' && c <= 'z', c >= 'A' && c <= 'Z', c >= '0' && c <= '9':
125		case strings.ContainsRune("-._~:/?#=&%+@", c):
126		default:
127			return false
128		}
129	}
130	return true
131}
132
133// HTTPS accepts an https link of URL-safe characters, 11 to max bytes.
134func HTTPS(s string, max int) bool {
135	return strings.HasPrefix(s, "https://") && len(s) > 10 && len(s) <= max && URLChars(s)
136}