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.

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}