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  }