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  }