github.com/Mrs4s/go-cqhttp@v1.2.0/pkg/onebot/value.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package onebot 6 7 import ( 8 "fmt" 9 "math" 10 "strconv" 11 "time" 12 "unsafe" 13 ) 14 15 // A Value can represent any Go value, but unlike type any, 16 // it can represent most small values without an allocation. 17 // The zero Value corresponds to nil. 18 type Value struct { 19 _ [0]func() // disallow == 20 num uint64 // hold number value 21 any any // hold Kind or other value 22 } 23 24 type ( 25 stringptr *byte // used in Value.any when the Value is a string 26 groupptr *Attr // used in Value.any when the Value is a []Attr 27 ) 28 29 //go:generate stringer -type=Kind -trimprefix=Kind 30 31 // Kind is the kind of Value. 32 type Kind int 33 34 // Kind 35 const ( 36 KindAny Kind = iota 37 KindBool 38 KindDuration 39 KindFloat64 40 KindInt64 41 KindString 42 KindTime 43 KindUint64 44 KindGroup 45 ) 46 47 // Unexported version of Kind, just so we can store Kinds in Values. 48 // (No user-provided value has this type.) 49 type kind Kind 50 51 // Kind returns v's Kind. 52 func (v Value) Kind() Kind { 53 switch x := v.any.(type) { 54 case Kind: 55 return x 56 case stringptr: 57 return KindString 58 case timeLocation: 59 return KindTime 60 case groupptr: 61 return KindGroup 62 case kind: // a kind is just a wrapper for a Kind 63 return KindAny 64 default: 65 return KindAny 66 } 67 } 68 69 //////////////// Constructors 70 71 // StringValue returns a new Value for a string. 72 func StringValue(value string) Value { 73 return Value{num: uint64(len(value)), any: stringptr(unsafe.StringData(value))} 74 } 75 76 // IntValue returns a Value for an int. 77 func IntValue(v int) Value { 78 return Int64Value(int64(v)) 79 } 80 81 // Int64Value returns a Value for an int64. 82 func Int64Value(v int64) Value { 83 return Value{num: uint64(v), any: KindInt64} 84 } 85 86 // Uint64Value returns a Value for a uint64. 87 func Uint64Value(v uint64) Value { 88 return Value{num: v, any: KindUint64} 89 } 90 91 // Float64Value returns a Value for a floating-point number. 92 func Float64Value(v float64) Value { 93 return Value{num: math.Float64bits(v), any: KindFloat64} 94 } 95 96 // BoolValue returns a Value for a bool. 97 func BoolValue(v bool) Value { 98 u := uint64(0) 99 if v { 100 u = 1 101 } 102 return Value{num: u, any: KindBool} 103 } 104 105 // Unexported version of *time.Location, just so we can store *time.Locations in 106 // Values. (No user-provided value has this type.) 107 type timeLocation *time.Location 108 109 // TimeValue returns a Value for a time.Time. 110 // It discards the monotonic portion. 111 func TimeValue(v time.Time) Value { 112 if v.IsZero() { 113 // UnixNano on the zero time is undefined, so represent the zero time 114 // with a nil *time.Location instead. time.Time.Location method never 115 // returns nil, so a Value with any == timeLocation(nil) cannot be 116 // mistaken for any other Value, time.Time or otherwise. 117 return Value{any: timeLocation(nil)} 118 } 119 return Value{num: uint64(v.UnixNano()), any: timeLocation(v.Location())} 120 } 121 122 // DurationValue returns a Value for a time.Duration. 123 func DurationValue(v time.Duration) Value { 124 return Value{num: uint64(v.Nanoseconds()), any: KindDuration} 125 } 126 127 // GroupValue returns a new Value for a list of Attrs. 128 // The caller must not subsequently mutate the argument slice. 129 func GroupValue(as ...Attr) Value { 130 return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))} 131 } 132 133 // AnyValue returns a Value for the supplied value. 134 // 135 // If the supplied value is of type Value, it is returned 136 // unmodified. 137 // 138 // Given a value of one of Go's predeclared string, bool, or 139 // (non-complex) numeric types, AnyValue returns a Value of kind 140 // String, Bool, Uint64, Int64, or Float64. The width of the 141 // original numeric type is not preserved. 142 // 143 // Given a time.Time or time.Duration value, AnyValue returns a Value of kind 144 // KindTime or KindDuration. The monotonic time is not preserved. 145 // 146 // For nil, or values of all other types, including named types whose 147 // underlying type is numeric, AnyValue returns a value of kind KindAny. 148 func AnyValue(v any) Value { 149 switch v := v.(type) { 150 case string: 151 return StringValue(v) 152 case int: 153 return Int64Value(int64(v)) 154 case uint: 155 return Uint64Value(uint64(v)) 156 case int64: 157 return Int64Value(v) 158 case uint64: 159 return Uint64Value(v) 160 case bool: 161 return BoolValue(v) 162 case time.Duration: 163 return DurationValue(v) 164 case time.Time: 165 return TimeValue(v) 166 case uint8: 167 return Uint64Value(uint64(v)) 168 case uint16: 169 return Uint64Value(uint64(v)) 170 case uint32: 171 return Uint64Value(uint64(v)) 172 case uintptr: 173 return Uint64Value(uint64(v)) 174 case int8: 175 return Int64Value(int64(v)) 176 case int16: 177 return Int64Value(int64(v)) 178 case int32: 179 return Int64Value(int64(v)) 180 case float64: 181 return Float64Value(v) 182 case float32: 183 return Float64Value(float64(v)) 184 case []Attr: 185 return GroupValue(v...) 186 case Kind: 187 return Value{any: kind(v)} 188 case Value: 189 return v 190 default: 191 return Value{any: v} 192 } 193 } 194 195 //////////////// Accessors 196 197 // Any returns v's value as an any. 198 func (v Value) Any() any { 199 switch v.Kind() { 200 case KindAny: 201 if k, ok := v.any.(kind); ok { 202 return Kind(k) 203 } 204 return v.any 205 case KindGroup: 206 return v.group() 207 case KindInt64: 208 return int64(v.num) 209 case KindUint64: 210 return v.num 211 case KindFloat64: 212 return v.float() 213 case KindString: 214 return v.str() 215 case KindBool: 216 return v.bool() 217 case KindDuration: 218 return v.duration() 219 case KindTime: 220 return v.time() 221 default: 222 panic(fmt.Sprintf("bad kind: %s", v.Kind())) 223 } 224 } 225 226 // String returns Value's value as a string, formatted like fmt.Sprint. Unlike 227 // the methods Int64, Float64, and so on, which panic if v is of the 228 // wrong kind, String never panics. 229 func (v Value) String() string { 230 if sp, ok := v.any.(stringptr); ok { 231 return unsafe.String(sp, v.num) 232 } 233 var buf []byte 234 return string(v.append(buf)) 235 } 236 237 func (v Value) str() string { 238 return unsafe.String(v.any.(stringptr), v.num) 239 } 240 241 // Int64 returns v's value as an int64. It panics 242 // if v is not a signed integer. 243 func (v Value) Int64() int64 { 244 if g, w := v.Kind(), KindInt64; g != w { 245 panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) 246 } 247 return int64(v.num) 248 } 249 250 // Uint64 returns v's value as a uint64. It panics 251 // if v is not an unsigned integer. 252 func (v Value) Uint64() uint64 { 253 if g, w := v.Kind(), KindUint64; g != w { 254 panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) 255 } 256 return v.num 257 } 258 259 // Bool returns v's value as a bool. It panics 260 // if v is not a bool. 261 func (v Value) Bool() bool { 262 if g, w := v.Kind(), KindBool; g != w { 263 panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) 264 } 265 return v.bool() 266 } 267 268 func (v Value) bool() bool { 269 return v.num == 1 270 } 271 272 // Duration returns v's value as a time.Duration. It panics 273 // if v is not a time.Duration. 274 func (v Value) Duration() time.Duration { 275 if g, w := v.Kind(), KindDuration; g != w { 276 panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) 277 } 278 279 return v.duration() 280 } 281 282 func (v Value) duration() time.Duration { 283 return time.Duration(int64(v.num)) 284 } 285 286 // Float64 returns v's value as a float64. It panics 287 // if v is not a float64. 288 func (v Value) Float64() float64 { 289 if g, w := v.Kind(), KindFloat64; g != w { 290 panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) 291 } 292 293 return v.float() 294 } 295 296 func (v Value) float() float64 { 297 return math.Float64frombits(v.num) 298 } 299 300 // Time returns v's value as a time.Time. It panics 301 // if v is not a time.Time. 302 func (v Value) Time() time.Time { 303 if g, w := v.Kind(), KindTime; g != w { 304 panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) 305 } 306 return v.time() 307 } 308 309 func (v Value) time() time.Time { 310 loc := v.any.(timeLocation) 311 if loc == nil { 312 return time.Time{} 313 } 314 return time.Unix(0, int64(v.num)).In(loc) 315 } 316 317 // Group returns v's value as a []Attr. 318 // It panics if v's Kind is not KindGroup. 319 func (v Value) Group() []Attr { 320 if sp, ok := v.any.(groupptr); ok { 321 return unsafe.Slice(sp, v.num) 322 } 323 panic("Group: bad kind") 324 } 325 326 func (v Value) group() []Attr { 327 return unsafe.Slice((*Attr)(v.any.(groupptr)), v.num) 328 } 329 330 // append appends a text representation of v to dst. 331 // v is formatted as with fmt.Sprint. 332 func (v Value) append(dst []byte) []byte { 333 switch v.Kind() { 334 case KindString: 335 return append(dst, v.str()...) 336 case KindInt64: 337 return strconv.AppendInt(dst, int64(v.num), 10) 338 case KindUint64: 339 return strconv.AppendUint(dst, v.num, 10) 340 case KindFloat64: 341 return strconv.AppendFloat(dst, v.float(), 'g', -1, 64) 342 case KindBool: 343 return strconv.AppendBool(dst, v.bool()) 344 case KindDuration: 345 return append(dst, v.duration().String()...) 346 case KindTime: 347 return append(dst, v.time().String()...) 348 case KindGroup: 349 return fmt.Append(dst, v.group()) 350 case KindAny: 351 return fmt.Append(dst, v.any) 352 default: 353 panic(fmt.Sprintf("bad kind: %s", v.Kind())) 354 } 355 }