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 }