github.com/coyove/nj@v0.0.0-20221110084952-c7f8db1065c3/internal/utils.go (about)

     1  package internal
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"log"
     8  	"os"
     9  	"reflect"
    10  	"runtime/debug"
    11  	"strconv"
    12  	"strings"
    13  	"sync/atomic"
    14  	"unicode/utf8"
    15  	"unsafe"
    16  )
    17  
    18  var (
    19  	unnamedCounter int64
    20  	debugMode      = os.Getenv("njd") != ""
    21  )
    22  
    23  func UnnamedFunc() string {
    24  	return fmt.Sprintf("<native-%d>", atomic.AddInt64(&unnamedCounter, 1))
    25  }
    26  
    27  func UnnamedLoadString() string {
    28  	return fmt.Sprintf("<memory-%d>", atomic.AddInt64(&unnamedCounter, 1))
    29  }
    30  
    31  func Unnamed() string {
    32  	return "tmp." + strconv.FormatInt(atomic.AddInt64(&unnamedCounter, 1), 10)
    33  }
    34  
    35  func ShouldNotHappen(args ...interface{}) {
    36  	if len(args) > 0 {
    37  		panic(fmt.Errorf("fatal: should not happen, bad values: %v", args...))
    38  	}
    39  	panic(fmt.Errorf("fatal: should not happen"))
    40  }
    41  
    42  func Panic(msg string, args ...interface{}) {
    43  	panic(fmt.Errorf(msg, args...))
    44  }
    45  
    46  func PanicErr(err error) {
    47  	if err != nil {
    48  		panic(err)
    49  	}
    50  }
    51  
    52  func IsDebug() bool {
    53  	return debugMode
    54  }
    55  
    56  func CatchError(err *error) {
    57  	if r := recover(); r != nil {
    58  		if IsDebug() {
    59  			log.Println(string(debug.Stack()))
    60  		}
    61  
    62  		*err, _ = r.(error)
    63  		if *err == nil {
    64  			*err = fmt.Errorf("%v", r)
    65  		}
    66  	}
    67  }
    68  
    69  func CloseBuffer(p *bytes.Buffer, suffix string) {
    70  	for p.Len() > 0 {
    71  		b := p.Bytes()[p.Len()-1]
    72  		if b == ' ' || b == ',' {
    73  			p.Truncate(p.Len() - 1)
    74  		} else {
    75  			break
    76  		}
    77  	}
    78  	p.WriteString(suffix)
    79  }
    80  
    81  func IfStr(v bool, t, f string) string {
    82  	if v {
    83  		return t
    84  	}
    85  	return f
    86  }
    87  
    88  func IfInt(v bool, t, f int) int {
    89  	if v {
    90  		return t
    91  	}
    92  	return f
    93  }
    94  
    95  func WriteString(w io.Writer, s string) (int, error) {
    96  	a := struct {
    97  		b string
    98  		c int
    99  	}{s, len(s)}
   100  	var x []byte
   101  	*(*[3]int)(unsafe.Pointer(&x)) = *(*[3]int)(unsafe.Pointer(&a))
   102  	return w.Write(x)
   103  }
   104  
   105  func IfQuote(v bool, s string) string {
   106  	if v {
   107  		return strconv.Quote(s)
   108  	}
   109  	return s
   110  }
   111  
   112  func Or(a, b interface{}) interface{} {
   113  	if a != nil {
   114  		return a
   115  	}
   116  	return b
   117  }
   118  
   119  func ParseNumber(v string) (vf float64, vi int64, isInt bool, err error) {
   120  	i, err := strconv.ParseInt(v, 0, 64)
   121  	if err == nil {
   122  		return 0, i, true, nil
   123  	}
   124  	if err.(*strconv.NumError).Err == strconv.ErrRange {
   125  		i, err := strconv.ParseUint(v, 0, 64)
   126  		if err == nil {
   127  			return 0, (int64(i)), true, nil
   128  		}
   129  	}
   130  	f, err := strconv.ParseFloat(v, 64)
   131  	if err != nil {
   132  		return 0, 0, false, fmt.Errorf("invalid number format: %q", v)
   133  	}
   134  	return f, 0, false, nil
   135  }
   136  
   137  func LineOf(text string, line int) (string, bool) {
   138  	for line > 0 {
   139  		idx := strings.IndexByte(text, '\n')
   140  		line--
   141  		if line == 0 {
   142  			if idx >= 0 {
   143  				text = text[:idx]
   144  			}
   145  			if trunc := 256; len(text) > trunc {
   146  				for i := trunc - 1; i >= 0; i-- {
   147  					if r, _ := utf8.DecodeLastRuneInString(text[:i]); r != utf8.RuneError {
   148  						text = text[:i] + " ... truncated code"
   149  						break
   150  					}
   151  				}
   152  			}
   153  			return text, true
   154  		}
   155  		if idx == -1 {
   156  			break
   157  		}
   158  		text = text[idx+1:]
   159  	}
   160  	return "", false
   161  }
   162  
   163  func SanitizeName(s string) string {
   164  	tn := []byte(s)
   165  	for i := range tn {
   166  		switch tn[i] {
   167  		case '*':
   168  			tn[i] = 'p'
   169  		case '.', '[', ']':
   170  			tn[i] = '_'
   171  		}
   172  	}
   173  	return *(*string)(unsafe.Pointer(&tn))
   174  }
   175  
   176  func StringifyTo(w io.Writer, i interface{}) {
   177  	switch s := i.(type) {
   178  	case fmt.Stringer:
   179  		WriteString(w, s.String())
   180  	case error:
   181  		WriteString(w, s.Error())
   182  	default:
   183  		WriteString(w, "<")
   184  		WriteString(w, reflect.TypeOf(i).String())
   185  		WriteString(w, ">")
   186  	}
   187  }