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

ufmt.gno

4.83 Kb · 189 lines
  1package ufmt
  2
  3import (
  4	"io"
  5	"strings"
  6)
  7
  8// State is what a Formatter's Format method is handed: the flags, width and
  9// precision of the verb being printed, and somewhere to write.
 10type State interface {
 11	// Write emits formatted output.
 12	Write(b []byte) (n int, err error)
 13	// Width returns the width and whether one was set.
 14	Width() (wid int, ok bool)
 15	// Precision returns the precision and whether one was set.
 16	Precision() (prec int, ok bool)
 17	// Flag reports whether the flag c, a character, was set.
 18	Flag(c int) bool
 19}
 20
 21// Formatter is implemented by a value that formats itself. Format is called
 22// for every verb, and its output replaces what ufmt would have printed.
 23type Formatter interface {
 24	Format(f State, verb rune)
 25}
 26
 27// Stringer is implemented by a value that has a natural string form. It is
 28// used for %v, %s, %q, %x and %X, and by Print.
 29type Stringer interface {
 30	String() string
 31}
 32
 33// GoStringer is implemented by a value that has a Go-syntax form, used for %#v.
 34type GoStringer interface {
 35	GoString() string
 36}
 37
 38// Sprintf formats according to a format specifier and returns the string.
 39func Sprintf(format string, a ...any) string {
 40	p := newPrinter()
 41	p.doPrintf(format, a)
 42	return string(p.buf)
 43}
 44
 45// Appendf formats according to a format specifier and appends the result to b.
 46func Appendf(b []byte, format string, a ...any) []byte {
 47	p := newPrinter()
 48	p.doPrintf(format, a)
 49	return append(b, p.buf...)
 50}
 51
 52// Fprintf formats according to a format specifier and writes to w.
 53func Fprintf(w io.Writer, format string, a ...any) (n int, err error) {
 54	p := newPrinter()
 55	p.doPrintf(format, a)
 56	return w.Write(p.buf)
 57}
 58
 59// Printf formats according to a format specifier and prints the result with
 60// the print builtin, which is what a test or a filetest captures.
 61func Printf(format string, a ...any) (n int, err error) {
 62	return printOut(Sprintf(format, a...))
 63}
 64
 65// Sprint formats its operands with %v and returns the string. A space is added
 66// between two operands when neither is a string.
 67func Sprint(a ...any) string {
 68	p := newPrinter()
 69	p.doPrint(a)
 70	return string(p.buf)
 71}
 72
 73// Append formats its operands as Sprint does and appends the result to b.
 74func Append(b []byte, a ...any) []byte {
 75	p := newPrinter()
 76	p.doPrint(a)
 77	return append(b, p.buf...)
 78}
 79
 80// Fprint formats its operands as Sprint does and writes to w.
 81func Fprint(w io.Writer, a ...any) (n int, err error) {
 82	p := newPrinter()
 83	p.doPrint(a)
 84	return w.Write(p.buf)
 85}
 86
 87// Print formats its operands as Sprint does and prints the result.
 88func Print(a ...any) (n int, err error) {
 89	return printOut(Sprint(a...))
 90}
 91
 92// Sprintln formats its operands with %v, always separated by a space, and
 93// appends a newline.
 94func Sprintln(a ...any) string {
 95	p := newPrinter()
 96	p.doPrintln(a)
 97	return string(p.buf)
 98}
 99
100// Appendln formats its operands as Sprintln does and appends the result to b.
101func Appendln(b []byte, a ...any) []byte {
102	p := newPrinter()
103	p.doPrintln(a)
104	return append(b, p.buf...)
105}
106
107// Fprintln formats its operands as Sprintln does and writes to w.
108func Fprintln(w io.Writer, a ...any) (n int, err error) {
109	p := newPrinter()
110	p.doPrintln(a)
111	return w.Write(p.buf)
112}
113
114// Println formats its operands as Sprintln does and prints the result.
115func Println(a ...any) (n int, err error) {
116	return printOut(Sprintln(a...))
117}
118
119func printOut(s string) (int, error) {
120	var sb strings.Builder
121	n, err := sb.WriteString(s)
122	print(sb.String())
123	return n, err
124}
125
126// Errorf formats according to a format specifier and returns the string as an
127// error. Each %w operand must be an error; it is printed as %v and returned by
128// the error's Unwrap method, so errors.Is and errors.Unwrap can find it. One %w
129// gives an Unwrap() error, several give an Unwrap() []error, as in Go.
130func Errorf(format string, a ...any) error {
131	p := newPrinter()
132	p.wrapErrs = true
133	p.doPrintf(format, a)
134	s := string(p.buf)
135
136	switch len(p.wrapped) {
137	case 0:
138		return &errorString{s}
139	case 1:
140		w := &wrapError{msg: s}
141		w.err, _ = a[p.wrapped[0]].(error)
142		return w
143	default:
144		if p.reordered {
145			sortInts(p.wrapped)
146		}
147		var errs []error
148		for i, argNum := range p.wrapped {
149			if i > 0 && p.wrapped[i-1] == argNum {
150				continue
151			}
152			if e, ok := a[argNum].(error); ok {
153				errs = append(errs, e)
154			}
155		}
156		return &wrapErrors{s, errs}
157	}
158}
159
160type errorString struct {
161	s string
162}
163
164func (e *errorString) Error() string { return e.s }
165
166type wrapError struct {
167	msg string
168	err error
169}
170
171func (e *wrapError) Error() string { return e.msg }
172func (e *wrapError) Unwrap() error { return e.err }
173
174type wrapErrors struct {
175	msg  string
176	errs []error
177}
178
179func (e *wrapErrors) Error() string   { return e.msg }
180func (e *wrapErrors) Unwrap() []error { return e.errs }
181
182// sortInts is an insertion sort: the slice holds one entry per %w.
183func sortInts(a []int) {
184	for i := 1; i < len(a); i++ {
185		for j := i; j > 0 && a[j] < a[j-1]; j-- {
186			a[j], a[j-1] = a[j-1], a[j]
187		}
188	}
189}