github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/ufmt/ufmt.gno (about) 1 // Package ufmt provides utility functions for formatting strings, similarly 2 // to the Go package "fmt", of which only a subset is currently supported 3 // (hence the name µfmt - micro fmt). 4 package ufmt 5 6 import ( 7 "strconv" 8 "strings" 9 ) 10 11 // Println formats using the default formats for its operands and writes to standard output. 12 // Println writes the given arguments to standard output with spaces between arguments 13 // and a newline at the end. 14 func Println(args ...interface{}) { 15 var strs []string 16 for _, arg := range args { 17 switch v := arg.(type) { 18 case string: 19 strs = append(strs, v) 20 case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: 21 strs = append(strs, Sprintf("%d", v)) 22 case bool: 23 if v { 24 strs = append(strs, "true") 25 26 continue 27 } 28 29 strs = append(strs, "false") 30 default: 31 strs = append(strs, "(unhandled)") 32 } 33 } 34 35 // TODO: remove println after gno supports os.Stdout 36 println(strings.Join(strs, " ")) 37 } 38 39 // Sprintf offers similar functionality to Go's fmt.Sprintf, or the sprintf 40 // equivalent available in many languages, including C/C++. 41 // The number of args passed must exactly match the arguments consumed by the format. 42 // A limited number of formatting verbs and features are currently supported, 43 // hence the name ufmt (µfmt, micro-fmt). 44 // 45 // The currently formatted verbs are the following: 46 // 47 // %s: places a string value directly. 48 // If the value implements the interface interface{ String() string }, 49 // the String() method is called to retrieve the value. 50 // %d: formats an integer value using package "strconv". 51 // Currently supports only uint, uint64, int, int64. 52 // %t: formats a boolean value to "true" or "false". 53 // %%: outputs a literal %. Does not consume an argument. 54 func Sprintf(format string, args ...interface{}) string { 55 // we use runes to handle multi-byte characters 56 sTor := []rune(format) 57 end := len(sTor) 58 argNum := 0 59 argLen := len(args) 60 buf := "" 61 62 for i := 0; i < end; { 63 isLast := i == end-1 64 c := string(sTor[i]) 65 66 if isLast || c != "%" { 67 // we don't check for invalid format like a one ending with "%" 68 buf += string(c) 69 i++ 70 continue 71 } 72 73 verb := string(sTor[i+1]) 74 if verb == "%" { 75 buf += "%" 76 i += 2 77 continue 78 } 79 80 if argNum > argLen { 81 panic("invalid number of arguments to ufmt.Sprintf") 82 } 83 arg := args[argNum] 84 argNum++ 85 86 switch verb { 87 case "s": 88 switch v := arg.(type) { 89 case interface{ String() string }: 90 buf += v.String() 91 case string: 92 buf += v 93 default: 94 buf += "(unhandled)" 95 } 96 case "d": 97 switch v := arg.(type) { 98 case int: 99 buf += strconv.Itoa(v) 100 case int8: 101 buf += strconv.Itoa(int(v)) 102 case int16: 103 buf += strconv.Itoa(int(v)) 104 case int32: 105 buf += strconv.Itoa(int(v)) 106 case int64: 107 buf += strconv.Itoa(int(v)) 108 case uint: 109 buf += strconv.FormatUint(uint64(v), 10) 110 case uint8: 111 buf += strconv.FormatUint(uint64(v), 10) 112 case uint16: 113 buf += strconv.FormatUint(uint64(v), 10) 114 case uint32: 115 buf += strconv.FormatUint(uint64(v), 10) 116 case uint64: 117 buf += strconv.FormatUint(v, 10) 118 default: 119 buf += "(unhandled)" 120 } 121 case "t": 122 switch v := arg.(type) { 123 case bool: 124 if v { 125 buf += "true" 126 } else { 127 buf += "false" 128 } 129 default: 130 buf += "(unhandled)" 131 } 132 // % handled before, as it does not consume an argument 133 default: 134 buf += "(unhandled)" 135 } 136 137 i += 2 138 } 139 if argNum < argLen { 140 panic("too many arguments to ufmt.Sprintf") 141 } 142 return buf 143 } 144 145 // errMsg implements the error interface. 146 type errMsg struct { 147 msg string 148 } 149 150 // Error defines the requirements of the error interface. 151 // It functions similarly to Go's errors.New() 152 func (e *errMsg) Error() string { 153 return e.msg 154 } 155 156 // Errorf is a function that mirrors the functionality of fmt.Errorf. 157 // 158 // It takes a format string and arguments to create a formatted string, 159 // then sets this string as the 'msg' field of an errMsg struct and returns a pointer to this struct. 160 // 161 // This function operates in a similar manner to Go's fmt.Errorf, 162 // providing a way to create formatted error messages. 163 // 164 // The currently formatted verbs are the following: 165 // 166 // %s: places a string value directly. 167 // If the value implements the interface interface{ String() string }, 168 // the String() method is called to retrieve the value. 169 // %d: formats an integer value using package "strconv". 170 // Currently supports only uint, uint64, int, int64. 171 // %t: formats a boolean value to "true" or "false". 172 // %%: outputs a literal %. Does not consume an argument. 173 func Errorf(format string, args ...interface{}) error { 174 return &errMsg{Sprintf(format, args...)} 175 }