Files
pmomusic/upnp/devices/services/statevariables/utils_uint.go
2025-08-01 12:45:42 +02:00

101 lines
2.9 KiB
Go

package statevariables
import (
"errors"
"math"
"reflect"
"strconv"
)
// maxUint returns maximum unsigned integer value for specified bit size
func maxUint(bits int) uint64 {
switch bits {
case 8:
return math.MaxUint8
case 16:
return math.MaxUint16
case 32:
return math.MaxUint32
case 64:
return math.MaxUint64
default:
return math.MaxUint64 // fallback
}
}
// toUint converts various types of numeric values into a uint64 type. It
// supports conversions from signed and unsigned integers, floating-point
// numbers, and string representations of integers.
//
// Parameters:
// - v interface{}: input value that can be converted to uint64. The
// function will return an error if the input is not one of these types.
// - bits int: number of bits that should fit within the returned uint64.
// An error will be returned if the conversion would exceed this limit.
//
// Returns:
// - uint64: converted value from input 'v'. If the input 'v' is a string,
// it must represent an integer in base 10 and can fit into an uint64
// type with given number of bits.
// - error: if the conversion fails due to unsupported input type, overflow
// or underflow conditions, or invalid string representation, this will
// contain an appropriate error message. If 'v' is nil,
// it returns an "cannot convert nil to uint" error.
func toUint(v interface{}, bits int) (uint64, error) {
if v == nil {
return 0, errors.New("cannot convert nil to uint")
}
switch val := v.(type) {
case uint:
return checkUintBounds(uint64(val), bits)
case uint8:
return checkUintBounds(uint64(val), bits)
case uint16:
return checkUintBounds(uint64(val), bits)
case uint32:
return checkUintBounds(uint64(val), bits)
case uint64:
return checkUintBounds(val, bits)
case int, int8, int16, int32, int64:
i := reflect.ValueOf(val).Int()
if i < 0 {
return 0, errors.New("negative value cannot be converted to uint")
}
return checkUintBounds(uint64(i), bits)
case float32:
if val < 0 {
return 0, errors.New("negative float cannot be converted to uint")
}
return checkUintBounds(uint64(val), bits)
case float64:
if val < 0 {
return 0, errors.New("negative float cannot be converted to uint")
}
return checkUintBounds(uint64(val), bits)
case string:
u, err := strconv.ParseUint(val, 10, bits)
if err != nil {
return 0, err
}
return checkUintBounds(u, bits)
default:
return 0, errors.New("unsupported type for toUint")
}
}
// checkUintBounds checks whether the given unsigned integer 'v' is within the
// acceptable range defined by the number of bits 'bits'. If 'v' is out of
// bounds, it returns an error with a message "unsigned integer value out of
// bounds". Otherwise, it returns 'v' and nil.
func checkUintBounds(v uint64, bits int) (uint64, error) {
if v > maxUint(bits) {
return 0, errors.New("unsigned integer value out of bounds")
}
return v, nil
}