-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
compat_before_go20.go
147 lines (137 loc) · 3.48 KB
/
compat_before_go20.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//go:build !go1.20
// +build !go1.20
package errors
import (
"fmt"
"reflect"
"strconv"
"unicode/utf8"
)
const (
rune1Max = 1<<7 - 1
rune2Max = 1<<11 - 1
rune3Max = 1<<16 - 1
surrogateMin = 0xD800
surrogateMax = 0xDFFF
maskx = 0b00111111
tx = 0b10000000
t2 = 0b11000000
t3 = 0b11100000
t4 = 0b11110000
)
// Copied from unicode/utf8/utf8.go available from Go 1.18 on.
func appendRune(p []byte, r rune) []byte {
// This function is inlineable for fast handling of ASCII.
if uint32(r) <= rune1Max {
return append(p, byte(r))
}
return appendRuneNonASCII(p, r)
}
func appendRuneNonASCII(p []byte, r rune) []byte {
// Negative values are erroneous. Making it unsigned addresses the problem.
switch i := uint32(r); {
case i <= rune2Max:
return append(p, t2|byte(r>>6), tx|byte(r)&maskx)
case i > utf8.MaxRune, surrogateMin <= i && i <= surrogateMax:
r = utf8.RuneError
fallthrough
case i <= rune3Max:
return append(p, t3|byte(r>>12), tx|byte(r>>6)&maskx, tx|byte(r)&maskx)
default:
return append(p, t4|byte(r>>18), tx|byte(r>>12)&maskx, tx|byte(r>>6)&maskx, tx|byte(r)&maskx)
}
}
// Copied from fmt/print.go available from Go 1.20 on.
func formatString(state fmt.State, verb rune) string {
var tmp [16]byte // Use a local buffer.
b := append(tmp[:0], '%')
for _, c := range " +-#0" { // All known flags
if state.Flag(int(c)) { // The argument is an int for historical reasons.
b = append(b, byte(c))
}
}
if w, ok := state.Width(); ok {
b = strconv.AppendInt(b, int64(w), 10)
}
if p, ok := state.Precision(); ok {
b = append(b, '.')
b = strconv.AppendInt(b, int64(p), 10)
}
b = appendRune(b, verb)
return string(b)
}
// Copied from errors/wrap.go available from Go 1.20 on with support for joined errors.
func stderrorsIs(err, target error) bool {
if target == nil {
return err == target
}
isComparable := reflect.TypeOf(target).Comparable()
for {
if isComparable && err == target {
return true
}
if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
return true
}
switch x := err.(type) {
case interface{ Unwrap() error }:
err = x.Unwrap()
if err == nil {
return false
}
case interface{ Unwrap() []error }:
for _, err := range x.Unwrap() {
if Is(err, target) {
return true
}
}
return false
default:
return false
}
}
}
var errorType = reflect.TypeOf((*error)(nil)).Elem()
// Copied from errors/wrap.go available from Go 1.20 on with support for joined errors.
func stderrorsAs(err error, target interface{}) bool {
if err == nil {
return false
}
if target == nil {
panic("errors: target cannot be nil")
}
val := reflect.ValueOf(target)
typ := val.Type()
if typ.Kind() != reflect.Ptr || val.IsNil() {
panic("errors: target must be a non-nil pointer")
}
targetType := typ.Elem()
if targetType.Kind() != reflect.Interface && !targetType.Implements(errorType) {
panic("errors: *target must be interface or implement error")
}
for {
if reflect.TypeOf(err).AssignableTo(targetType) {
val.Elem().Set(reflect.ValueOf(err))
return true
}
if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
return true
}
switch x := err.(type) {
case interface{ Unwrap() error }:
err = x.Unwrap()
if err == nil {
return false
}
case interface{ Unwrap() []error }:
for _, err := range x.Unwrap() {
if As(err, target) {
return true
}
}
return false
default:
return false
}
}
}