Path: blob/main/pkg/river/internal/value/number_value.go
4096 views
package value12import (3"math"4"reflect"5"strconv"6)78var (9nativeIntBits = reflect.TypeOf(int(0)).Bits()10nativeUintBits = reflect.TypeOf(uint(0)).Bits()11)1213// NumberKind categorizes a type of Go number.14type NumberKind uint81516const (17// NumberKindInt represents an int-like type (e.g., int, int8, etc.).18NumberKindInt NumberKind = iota19// NumberKindUint represents a uint-like type (e.g., uint, uint8, etc.).20NumberKindUint21// NumberKindFloat represents both float32 and float64.22NumberKindFloat23)2425// makeNumberKind converts a Go kind to a River kind.26func makeNumberKind(k reflect.Kind) NumberKind {27switch k {28case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:29return NumberKindInt30case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:31return NumberKindUint32case reflect.Float32, reflect.Float64:33return NumberKindFloat34default:35panic("river/value: makeNumberKind called with unsupported Kind value")36}37}3839// Number is a generic representation of Go numbers. It is intended to be40// created on the fly for numerical operations when the real number type is not41// known.42type Number struct {43// Value holds the raw data for the number. Note that for numberKindFloat,44// value is the raw bits of the float64 and must be converted back to a45// float64 before it can be used.46value uint644748bits uint8 // 8, 16, 32, 64, used for overflow checking49k NumberKind // int, uint, float50}5152func newNumberValue(v reflect.Value) Number {53var (54val uint6455bits int56nk NumberKind57)5859switch v.Kind() {60case reflect.Int:61val, bits, nk = uint64(v.Int()), nativeIntBits, NumberKindInt62case reflect.Int8:63val, bits, nk = uint64(v.Int()), 8, NumberKindInt64case reflect.Int16:65val, bits, nk = uint64(v.Int()), 16, NumberKindInt66case reflect.Int32:67val, bits, nk = uint64(v.Int()), 32, NumberKindInt68case reflect.Int64:69val, bits, nk = uint64(v.Int()), 64, NumberKindInt70case reflect.Uint:71val, bits, nk = v.Uint(), nativeUintBits, NumberKindUint72case reflect.Uint8:73val, bits, nk = v.Uint(), 8, NumberKindUint74case reflect.Uint16:75val, bits, nk = v.Uint(), 16, NumberKindUint76case reflect.Uint32:77val, bits, nk = v.Uint(), 32, NumberKindUint78case reflect.Uint64:79val, bits, nk = v.Uint(), 64, NumberKindUint80case reflect.Float32:81val, bits, nk = math.Float64bits(v.Float()), 32, NumberKindFloat82case reflect.Float64:83val, bits, nk = math.Float64bits(v.Float()), 64, NumberKindFloat84default:85panic("river/value: unrecognized Go number type " + v.Kind().String())86}8788return Number{val, uint8(bits), nk}89}9091// Kind returns the Number's NumberKind.92func (nv Number) Kind() NumberKind { return nv.k }9394// Int converts the Number into an int64.95func (nv Number) Int() int64 {96if nv.k == NumberKindFloat {97return int64(math.Float64frombits(nv.value))98}99return int64(nv.value)100}101102// Uint converts the Number into a uint64.103func (nv Number) Uint() uint64 {104if nv.k == NumberKindFloat {105return uint64(math.Float64frombits(nv.value))106}107return nv.value108}109110// Float converts the Number into a float64.111func (nv Number) Float() float64 {112switch nv.k {113case NumberKindInt:114// Convert nv.value to an int64 before converting to a float64 so the sign115// flag gets handled correctly.116return float64(int64(nv.value))117case NumberKindFloat:118return math.Float64frombits(nv.value)119}120return float64(nv.value)121}122123// ToString converts the Number to a string.124func (nv Number) ToString() string {125switch nv.k {126case NumberKindUint:127return strconv.FormatUint(nv.value, 10)128case NumberKindInt:129return strconv.FormatInt(int64(nv.value), 10)130case NumberKindFloat:131return strconv.FormatFloat(math.Float64frombits(nv.value), 'f', -1, 64)132}133panic("river/value: unreachable")134}135136137