807 lines
24 KiB
Plaintext
807 lines
24 KiB
Plaintext
------- /pmoupnp/devices/services/statevariables/statevartype_arithm.go ------
|
|
package statevariables
|
|
|
|
// Add performs addition operation on two interfaces if both are of numeric
|
|
// type, otherwise it returns an error. If the types are not numeric, it checks
|
|
// and converts them into float64 before performing the addition. The function
|
|
// then casts the result back to its original type using Cast method from
|
|
// StateVarType t and returns this value or any encountered error.
|
|
//
|
|
// Parameters:
|
|
//
|
|
// a (interface{}): First operand for addition operation. Can be of any type.
|
|
// b (interface{}): Second operand for addition operation. Can be of any type.
|
|
//
|
|
// Returns:
|
|
//
|
|
// interface{}: Result of the addition, casted back to its original type using StateVarType t if no error encountered.
|
|
// error: Encountered error in case any conversion or casting fails. This includes non-numeric types for this operation.
|
|
func (t StateVarType) Add(a, b interface{}) (interface{}, error) {
|
|
af, bf, err := valuesToNumericOperands(t, a, b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return t.Cast(af + bf)
|
|
}
|
|
|
|
// Sub subtracts 'b' from 'a'. It converts both values to numeric types
|
|
// and then performs a subtraction operation, casting the result back to its
|
|
// original type. If either conversion fails or an unsupported type is used,
|
|
// it returns an error.
|
|
func (t StateVarType) Sub(a, b interface{}) (interface{}, error) {
|
|
af, bf, err := valuesToNumericOperands(t, a, b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return t.Cast(af - bf)
|
|
}
|
|
|
|
// Mul takes in two interface types 'a' and 'b', multiplies them together
|
|
// and returns the result along with any error encountered during this
|
|
// process. If either of the inputs is not compatible with numeric values, an
|
|
// error will be returned. The multiplication operation is performed between two
|
|
// numbers represented as 'float64' types (since Go does not support generic
|
|
// types on its own). The resulting value will be cast to the type represented
|
|
// by the receiver of this method 't'. If a casting error occurs, it will also
|
|
// be returned along with nil for the result.
|
|
func (t StateVarType) Mul(a, b interface{}) (interface{}, error) {
|
|
af, bf, err := valuesToNumericOperands(t, a, b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return t.Cast(af * bf)
|
|
}
|
|
|
|
// Div performs division between the provided arguments 'a' and 'b'. The function casts both operands to their numeric equivalents using valuesToNumericOperands() before performing the division.
|
|
//
|
|
// Parameters:
|
|
// - a: first operand of type interface{}, can be of any type, will be converted if necessary
|
|
// - b: second operand of type interface{}, can be of any type, will be converted if necessary
|
|
//
|
|
// Returns:
|
|
// - result: the division result in numeric form after casting it with function t.Cast()
|
|
// - err: error that might occur during the conversion or division operation
|
|
func (t StateVarType) Div(a, b interface{}) (interface{}, error) {
|
|
af, bf, err := valuesToNumericOperands(t, a, b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return t.Cast(af / bf)
|
|
}
|
|
-----------------
|
|
------- /pmoupnp/devices/services/statevariables/statevartype_cast.go ------
|
|
package statevariables
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// Cast converts a value to the Go type corresponding to the UPnP type.
|
|
// Supports conversion from various primitive types and strings.
|
|
// Returns an error for unsupported conversions or invalid values.
|
|
//
|
|
// Examples:
|
|
// - StateType_UI2.Cast(42) // uint16(42), nil
|
|
// - StateType_Boolean.Cast("true") // true, nil
|
|
// - StateType_UI1.Cast(300) // nil, error (overflow)
|
|
func (t StateVarType) Cast(val interface{}) (interface{}, error) {
|
|
switch t {
|
|
case StateType_UI1:
|
|
v, err := toUint(val, 8)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot cast %v (%T) to UI1", val, val)
|
|
}
|
|
return uint8(v), nil
|
|
|
|
case StateType_UI2:
|
|
v, err := toUint(val, 16)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot cast %v (%T) to UI2", val, val)
|
|
}
|
|
return uint16(v), nil
|
|
|
|
case StateType_UI4:
|
|
v, err := toUint(val, 32)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot cast %v (%T) to UI4", val, val)
|
|
}
|
|
return uint32(v), nil
|
|
|
|
case StateType_I1:
|
|
v, err := toInt(val, 8)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot cast %v (%T) to I1", val, val)
|
|
}
|
|
return int8(v), nil
|
|
|
|
case StateType_I2:
|
|
v, err := toInt(val, 16)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot cast %v (%T) to I2", val, val)
|
|
}
|
|
return int16(v), nil
|
|
|
|
case StateType_I4, StateType_Int:
|
|
v, err := toInt(val, 32)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot cast %v (%T) to I4", val, val)
|
|
}
|
|
return int32(v), nil
|
|
|
|
case StateType_R4:
|
|
v, err := toFloat(val, 32)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot cast %v (%T) to R4", val, val)
|
|
}
|
|
return float32(v), nil
|
|
|
|
case StateType_R8, StateType_Number, StateType_Fixed14_4:
|
|
v, err := toFloat(val, 64)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot cast %v (%T) to R8", val, val)
|
|
}
|
|
return v, nil
|
|
|
|
case StateType_Boolean:
|
|
b, err := toBool(val)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot cast %v (%T) to Boolean", val, val)
|
|
}
|
|
return b, nil
|
|
|
|
case StateType_Char:
|
|
switch s := val.(type) {
|
|
case string:
|
|
if len(s) != 1 {
|
|
return nil, fmt.Errorf("invalid Char: string too long %q", s)
|
|
}
|
|
return rune(s[0]), nil
|
|
case rune:
|
|
return s, nil
|
|
default:
|
|
return nil, fmt.Errorf("cannot cast %v (%T) to Char", val, val)
|
|
}
|
|
|
|
case StateType_String:
|
|
return fmt.Sprint(val), nil
|
|
|
|
case StateType_UUID:
|
|
switch val := val.(type) {
|
|
case uuid.UUID:
|
|
return val, nil
|
|
case string:
|
|
u, err := uuid.Parse(strings.TrimSpace(val))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid UUID %v: %v", val, err)
|
|
}
|
|
return u, nil
|
|
default:
|
|
return nil, fmt.Errorf("cannot cast %v (%T) to UUID", val, val)
|
|
}
|
|
|
|
case StateType_URI:
|
|
switch val := val.(type) {
|
|
case *url.URL:
|
|
return val, nil
|
|
case string:
|
|
u, err := url.Parse(strings.TrimSpace(val))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid URI %v: %v", val, err)
|
|
}
|
|
return u, nil
|
|
default:
|
|
return nil, fmt.Errorf("cannot cast %v (%T) to URI", val, val)
|
|
}
|
|
|
|
case StateType_BinBase64, StateType_BinHex:
|
|
switch v := val.(type) {
|
|
case []byte:
|
|
return v, nil
|
|
case string:
|
|
return decodeBinary(t, v)
|
|
default:
|
|
return nil, fmt.Errorf("cannot cast %v (%T) to binary", val, val)
|
|
}
|
|
|
|
case StateType_Date, StateType_DateTime, StateType_DateTimeTZ,
|
|
StateType_Time, StateType_TimeTZ:
|
|
switch v := val.(type) {
|
|
case time.Time:
|
|
return v, nil
|
|
case string:
|
|
return parseUPnPTime(t, v)
|
|
default:
|
|
return nil, fmt.Errorf("cannot cast %v (%T) to time", val, val)
|
|
}
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unsupported type: %v", t)
|
|
}
|
|
}
|
|
-----------------
|
|
------- /pmoupnp/devices/services/statevariables/statevartype_cmp.go ------
|
|
package statevariables
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
)
|
|
|
|
// Cmp compares two values of a given type 'StateVarType'. The comparison is
|
|
// made based on the specific type of 'a' and 'b'. It returns an integer
|
|
// indicating whether 'a' is less than, equal to, or greater than 'b'. If 'a' is
|
|
// less than 'b', it returns -1. If they are equal, it returns 0. If 'a' is
|
|
// greater than 'b', it returns 1. It also returns an error if any of the values
|
|
// can't be cast to the required type or if comparison isn't supported for the
|
|
// given type 'StateVarType'.
|
|
//
|
|
// - t: StateVarType representing the specific type to use for comparison.
|
|
// - a, b: The values to compare. They should be of type interface{} as they could be
|
|
// any valid Go type.
|
|
//
|
|
// Returns: An integer indicating the result of the comparison (-1 if 'a' is
|
|
// less than 'b', 0 if they are equal, and 1 if 'a' is greater than 'b'). It
|
|
// also returns an error if any values can't be cast or if comparison isn't
|
|
// supported for the given type.
|
|
//
|
|
// Example:
|
|
//
|
|
// result, err := t.Cmp(int32(5), int32(7)) // Returns -1 and nil error as 5 is less than 7.
|
|
func (t StateVarType) Cmp(a, b interface{}) (int, error) {
|
|
a, err1 := t.Cast(a)
|
|
b, err2 := t.Cast(b)
|
|
|
|
if err1 != nil || err2 != nil {
|
|
log.Fatalf("Failed to cast for comparison: %v vs %v (errors: %v, %v)", a, b, err1, err2)
|
|
}
|
|
|
|
switch {
|
|
case t.IsInteger():
|
|
ai, err := toInt(a, t.BitSize())
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid int value for a: %w", err)
|
|
}
|
|
bi, err := toInt(b, t.BitSize())
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid int value for b: %w", err)
|
|
}
|
|
return cmpInt(ai, bi), nil
|
|
|
|
case t.IsUnsignedInt():
|
|
ai, err := toUint(a, t.BitSize())
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid uint value for a: %w", err)
|
|
}
|
|
bi, err := toUint(b, t.BitSize())
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid uint value for b: %w", err)
|
|
}
|
|
return cmpUint(ai, bi), nil
|
|
|
|
case t.IsFloat():
|
|
af, err := toFloat(a, t.BitSize())
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid float value for a: %w", err)
|
|
}
|
|
bf, err := toFloat(b, t.BitSize())
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid float value for b: %w", err)
|
|
}
|
|
return cmpFloat64(af, bf), nil
|
|
|
|
case t == StateType_Boolean:
|
|
ab, err := toBool(a)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid bool value for a: %w", err)
|
|
}
|
|
bb, err := toBool(b)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid bool value for b: %w", err)
|
|
}
|
|
return cmpBool(ab, bb), nil
|
|
|
|
case t == StateType_String || t == StateType_Char:
|
|
as, err := toString(a)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid string value for a")
|
|
}
|
|
bs, err := toString(b)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid string value for b")
|
|
}
|
|
return strings.Compare(as, bs), nil
|
|
|
|
case t.IsTime():
|
|
at, err := toTime(a)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid time value for a")
|
|
}
|
|
bt, err := toTime(b)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid time value for b")
|
|
}
|
|
return cmpTime(at, bt), nil
|
|
|
|
default:
|
|
return 0, fmt.Errorf("comparison not supported for type %v", t)
|
|
}
|
|
}
|
|
|
|
func (t StateVarType) Equal(a, b interface{}) (bool, error) {
|
|
switch {
|
|
case t.IsInteger():
|
|
ai, err1 := toInt(a, 64)
|
|
bi, err2 := toInt(b, 64)
|
|
if err1 != nil || err2 != nil {
|
|
return false, fmt.Errorf("invalid integer value for type %s", t.String())
|
|
}
|
|
return ai == bi, nil
|
|
|
|
case t.IsFloat():
|
|
af, err := toFloat(a, 64)
|
|
if err != nil {
|
|
return false, fmt.Errorf("invalid float value for type %s: %v", t.String(), err)
|
|
}
|
|
bf, err := toFloat(b, 64)
|
|
if err != nil {
|
|
return false, fmt.Errorf("invalid float value for type %s: %v", t.String(), err)
|
|
}
|
|
return af == bf, nil
|
|
|
|
case t.IsString():
|
|
as, ok1 := a.(string)
|
|
bs, ok2 := b.(string)
|
|
if !ok1 || !ok2 {
|
|
return false, fmt.Errorf("invalid string value for type %s", t.String())
|
|
}
|
|
return as == bs, nil
|
|
|
|
case t.IsBool():
|
|
ab, err1 := toBool(a)
|
|
bb, err2 := toBool(b)
|
|
if err1 != nil || err2 != nil {
|
|
return false, fmt.Errorf("invalid boolean value for type %s", t.String())
|
|
}
|
|
return ab == bb, nil
|
|
|
|
case t.IsTime():
|
|
at, err1 := toTime(a)
|
|
bt, err2 := toTime(b)
|
|
if err1 != nil || err2 != nil {
|
|
return false, fmt.Errorf("invalid time.Time value for type %s", t.String())
|
|
}
|
|
return at.Equal(bt), nil
|
|
|
|
case t.IsUUID():
|
|
au, err1 := toUUID(a)
|
|
bu, err2 := toUUID(b)
|
|
if err1 != nil || err2 != nil {
|
|
return false, fmt.Errorf("invalid uuid.UUID value for type %s", t.String())
|
|
}
|
|
return au == bu, nil
|
|
|
|
case t.IsURI():
|
|
au, err1 := toURI(a)
|
|
bu, err2 := toURI(b)
|
|
if err1 != nil || err2 != nil {
|
|
return false, fmt.Errorf("invalid *url.URL value for type %s", t.String())
|
|
}
|
|
return au.String() == bu.String(), nil
|
|
|
|
case t.IsBinary():
|
|
ab, err1 := toBinary(a)
|
|
bb, err2 := toBinary(b)
|
|
if err1 != nil || err2 != nil {
|
|
return false, fmt.Errorf("invalid []byte value for type %s", t.String())
|
|
}
|
|
return bytes.Equal(ab, bb), nil
|
|
|
|
default:
|
|
return false, fmt.Errorf("equality not supported for type %s", t.String())
|
|
}
|
|
}
|
|
|
|
// InRange checks if a value falls within an inclusive range [min, max].
|
|
// Uses the type's comparison logic. Returns true if val is between min and max (inclusive).
|
|
//
|
|
// Example:
|
|
//
|
|
// range := ValueRange{min: uint16(10), max: uint16(100)}
|
|
// StateType_UI2.InRange(uint16(50), range) // true
|
|
func (t StateVarType) InRange(val interface{}, interval *ValueRange) (bool, error) {
|
|
if interval == nil {
|
|
return true, nil
|
|
}
|
|
cmp1, err1 := t.Cmp(val, interval.min)
|
|
cmp2, err2 := t.Cmp(val, interval.max)
|
|
if err1 != nil || err2 != nil {
|
|
err := err1
|
|
if err == nil {
|
|
err = err2
|
|
}
|
|
return false, err
|
|
}
|
|
return cmp1 >= 0 && cmp2 <= 0, nil
|
|
}
|
|
-----------------
|
|
------- /pmoupnp/devices/services/statevariables/statevartype_typechecking.go ------
|
|
package statevariables
|
|
|
|
// IsNumeric checks whether a given StateVarType represents a numeric type or
|
|
// not. Numeric types are defined as those that can be used to store number-like
|
|
// values. The following types are considered numeric: UI1, UI2, UI4, I1, I2,
|
|
// I4, Int, R4, R8, Number and Fixed14_4.
|
|
//
|
|
// t: StateVarType to check if it's a numeric type or not.
|
|
//
|
|
// Returns true if the given StateVarType represents a numeric type; false
|
|
// otherwise.
|
|
func (t StateVarType) IsNumeric() bool {
|
|
switch t {
|
|
case StateType_UI1, StateType_UI2, StateType_UI4,
|
|
StateType_I1, StateType_I2, StateType_I4,
|
|
StateType_Int,
|
|
StateType_R4, StateType_R8,
|
|
StateType_Number,
|
|
StateType_Fixed14_4:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// IsInteger checks if the state variable type is integer or not.
|
|
//
|
|
// It returns a boolean value indicating whether the provided StateVarType (t)
|
|
// is an integer type or not. The function takes one parameter, t of type
|
|
// StateVarType, which represents the state variable type to be checked.
|
|
//
|
|
// Parameters: - t (StateVarType): The StateVarType to check for comparability.
|
|
//
|
|
// Returns: bool: If the state variable type is any of the defined integer types
|
|
// (StateType_UI1, StateType_UI2, StateType_UI4, StateType_I1, StateType_I2,
|
|
// StateType_I4, StateType_Int), it returns true. Otherwise, it returns false.
|
|
func (t StateVarType) IsInteger() bool {
|
|
switch t {
|
|
case StateType_UI1, StateType_UI2, StateType_UI4,
|
|
StateType_I1, StateType_I2, StateType_I4,
|
|
StateType_Int:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// IsSignedInt checks if the state variable type is a signed integer type.
|
|
// The function returns true for StateType_I1, StateType_I2, StateType_I4, and
|
|
// StateType_Int, otherwise it will return false. This method is part of the
|
|
// StateVarType enumeration in statevaluetype package. It takes no parameters
|
|
// but operates on the receiver 't' of type StateVarType.
|
|
//
|
|
// The returned value is a boolean.
|
|
func (t StateVarType) IsSignedInt() bool {
|
|
switch t {
|
|
case StateType_I1, StateType_I2, StateType_I4, StateType_Int:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// IsUnsignedInt checks if the state variable type is an unsigned integer. It
|
|
// returns a boolean indicating whether or not the current StateVarType
|
|
// represents an unsigned integer type, namely: StateType_UI1, StateType_UI2,
|
|
// and StateType_UI4.
|
|
func (t StateVarType) IsUnsignedInt() bool {
|
|
switch t {
|
|
case StateType_UI1, StateType_UI2, StateType_UI4:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// IsFloat returns a boolean indicating whether the given state variable type
|
|
// represents a float number. If the state variable type is one of R4, R8, Number or
|
|
// Fixed14_4 it returns true; otherwise, it returns false.
|
|
func (t StateVarType) IsFloat() bool {
|
|
switch t {
|
|
case StateType_R4, StateType_R8, StateType_Number, StateType_Fixed14_4:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// IsBool checks if a StateVarType is of type Boolean. It returns true if the
|
|
// StateVarType equals to StateType_Boolean, false otherwise.
|
|
func (t StateVarType) IsBool() bool {
|
|
return t == StateType_Boolean
|
|
}
|
|
|
|
// IsString reports whether or not the state variable type represents a string
|
|
// value.
|
|
//
|
|
// This method returns true if the StateVarType is either StateType_String or
|
|
// StateType_Char, otherwise it returns false.
|
|
func (t StateVarType) IsString() bool {
|
|
switch t {
|
|
case StateType_String, StateType_Char:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// IsTime checks whether a given StateVarType is of time type or not. It accepts
|
|
// a StateVarType parameter 't' and returns a boolean value based on the check.
|
|
//
|
|
// The possible values for 't' are: StateType_Date, StateType_DateTime,
|
|
// StateType_DateTimeTZ, StateType_Time, StateType_TimeTZ. If 't' is any of
|
|
// these types, the function returns true; otherwise, it returns false.
|
|
func (t StateVarType) IsTime() bool {
|
|
switch t {
|
|
case StateType_Date, StateType_DateTime, StateType_DateTimeTZ,
|
|
StateType_Time, StateType_TimeTZ:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// IsUUID reports whether the receiver represents a UUID (Universally Unique
|
|
// Identifier). The StateVarType should be of type StateType_UUID to return
|
|
// true. Otherwise, it returns false.
|
|
func (t StateVarType) IsUUID() bool {
|
|
return t == StateType_UUID
|
|
}
|
|
|
|
// IsURI checks if the given state variable type is a URI.
|
|
//
|
|
// This function returns true if and only if the receiver (StateVarType t)
|
|
// equals StateType_URI, which represents URIs in UPnP protocol. Otherwise, it
|
|
// returns false.
|
|
func (t StateVarType) IsURI() bool {
|
|
return t == StateType_URI
|
|
}
|
|
|
|
// IsBinary checks if the given StateVarType is binary type or not. It returns
|
|
// true for types StateType_BinBase64 and StateType_BinHex, otherwise it returns
|
|
// false.
|
|
func (t StateVarType) IsBinary() bool {
|
|
switch t {
|
|
case StateType_BinBase64, StateType_BinHex:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// IsComparable function checks if a StateVarType is comparable or not.
|
|
//
|
|
// It returns false for binary types (StateType_BinBase64 and StateType_BinHex)
|
|
// as they are non-comparable. For all other types, it returns true indicating
|
|
// that these types can be compared.
|
|
//
|
|
// Parameters: - t (StateVarType): The StateVarType to check for comparability.
|
|
//
|
|
// Returns: bool: A boolean value indicating whether the given StateVarType is
|
|
// comparable or not. True means it's comparable, False means it isn't.
|
|
func (t StateVarType) IsComparable() bool {
|
|
// Tous les types sauf les binaires sont comparables
|
|
switch t {
|
|
case StateType_BinBase64, StateType_BinHex:
|
|
return false
|
|
default:
|
|
return true
|
|
}
|
|
}
|
|
-----------------
|
|
------- /pmoupnp/devices/services/statevariables/statevartype.go ------
|
|
// package stateVariables provides comprehensive handling of UPnP state variable types.
|
|
// It includes type identification, value casting, comparison, and range validation
|
|
// for all standard UPnP state variable types.
|
|
package statevariables
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// StateVarType represents UPnP state variable types with corresponding Go type mappings.
|
|
type StateVarType int
|
|
|
|
// Constants defining all supported UPnP state variable types
|
|
const (
|
|
StateType_Unknown StateVarType = iota
|
|
StateType_UI1 // Unsigned 8-bit integer (Go: uint8)
|
|
StateType_UI2 // Unsigned 16-bit integer (Go: uint16)
|
|
StateType_UI4 // Unsigned 32-bit integer (Go: uint32)
|
|
StateType_I1 // Signed 8-bit integer (Go: int8)
|
|
StateType_I2 // Signed 16-bit integer (Go: int16)
|
|
StateType_I4 // Signed 32-bit integer (Go: int32)
|
|
StateType_Int // Synonymous with i4 (Go: int32)
|
|
StateType_R4 // 32-bit floating point (Go: float32)
|
|
StateType_R8 // 64-bit floating point (Go: float64)
|
|
StateType_Number // Synonymous with r8 (Go: float64)
|
|
StateType_Fixed14_4 // Fixed-point decimal (Go: float64)
|
|
StateType_Char // Single Unicode character (Go: rune)
|
|
StateType_String // Character string (Go: string)
|
|
StateType_Boolean // Boolean value (Go: bool)
|
|
StateType_BinBase64 // Base64-encoded binary (Go: []byte)
|
|
StateType_BinHex // Hex-encoded binary (Go: []byte)
|
|
StateType_Date // Date (YYYY-MM-DD) (Go: time.Time)
|
|
StateType_DateTime // DateTime without timezone (Go: time.Time)
|
|
StateType_DateTimeTZ // DateTime with timezone (Go: time.Time)
|
|
StateType_Time // Time without timezone (Go: time.Time)
|
|
StateType_TimeTZ // Time with timezone (Go: time.Time)
|
|
StateType_UUID // Universally unique identifier (Go: uuid.UUID)
|
|
StateType_URI // Uniform Resource Identifier (Go: *url.URL)
|
|
)
|
|
|
|
// typeNames maps UPnP XML type names to StateVarType constants
|
|
var typeNames = map[string]StateVarType{
|
|
"ui1": StateType_UI1,
|
|
"ui2": StateType_UI2,
|
|
"ui4": StateType_UI4,
|
|
"i1": StateType_I1,
|
|
"i2": StateType_I2,
|
|
"i4": StateType_I4,
|
|
"int": StateType_Int,
|
|
"r4": StateType_R4,
|
|
"r8": StateType_R8,
|
|
"number": StateType_Number,
|
|
"fixed.14.4": StateType_Fixed14_4,
|
|
"char": StateType_Char,
|
|
"string": StateType_String,
|
|
"boolean": StateType_Boolean,
|
|
"bin.base64": StateType_BinBase64,
|
|
"bin.hex": StateType_BinHex,
|
|
"date": StateType_Date,
|
|
"dateTime": StateType_DateTime,
|
|
"dateTime.tz": StateType_DateTimeTZ,
|
|
"time": StateType_Time,
|
|
"time.tz": StateType_TimeTZ,
|
|
"uuid": StateType_UUID,
|
|
"uri": StateType_URI,
|
|
}
|
|
|
|
// typeStrings provides string representations for StateVarType constants
|
|
var typeStrings = [...]string{
|
|
"unknown",
|
|
"ui1",
|
|
"ui2",
|
|
"ui4",
|
|
"i1",
|
|
"i2",
|
|
"i4",
|
|
"int",
|
|
"r4",
|
|
"r8",
|
|
"number",
|
|
"fixed.14.4",
|
|
"char",
|
|
"string",
|
|
"boolean",
|
|
"bin.base64",
|
|
"bin.hex",
|
|
"date",
|
|
"dateTime",
|
|
"dateTime.tz",
|
|
"time",
|
|
"time.tz",
|
|
"uuid",
|
|
"uri",
|
|
}
|
|
|
|
// StateVarTypeFactory takes a string and attempts to build from it a valid
|
|
// StateVarType. The input string is cleaned before processing -
|
|
// leading/trailing spaces are trimmed, the case is lowered for comparison with
|
|
// known types, and if no match is found 'StateType_Unknown' is returned.
|
|
func StateVarTypeFactory(s string) StateVarType {
|
|
s = strings.ToLower(strings.TrimSpace(s))
|
|
if val, ok := typeNames[s]; ok {
|
|
return val
|
|
}
|
|
return StateType_Unknown
|
|
}
|
|
|
|
// String returns a string representation of the StateVarType. It defaults to
|
|
// "unknown" if the type is not recognized.
|
|
func (t StateVarType) String() string {
|
|
if int(t) >= 0 && int(t) < len(typeStrings) {
|
|
return typeStrings[t]
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
// BitSize returns the bit size of the StateVarType value, or -1 if not numeric.
|
|
// The possible return values are 8 for StateTypes I1, UI1, and 64 for others.
|
|
func (t StateVarType) BitSize() int {
|
|
// If t isn't numeric, return -1
|
|
if !t.IsNumeric() {
|
|
return -1
|
|
}
|
|
|
|
// Check the value of t and return the appropriate bit size
|
|
switch t {
|
|
case StateType_I1, StateType_UI1:
|
|
return 8
|
|
case StateType_I2, StateType_UI2:
|
|
return 16
|
|
case StateType_I4, StateType_UI4, StateType_Int, StateType_R4:
|
|
return 32
|
|
case StateType_R8, StateType_Number, StateType_Fixed14_4:
|
|
return 64
|
|
default:
|
|
return 64
|
|
}
|
|
}
|
|
|
|
// NewStateValue creates and returns a new StateValue struct instance with the given name
|
|
// and the receiver's state variable type. The created StateValue is initialized with an
|
|
// empty map for event conditions. If name is an empty string, it will cause panic in later
|
|
// usage. Name is typically used to identify or represent a specific value or condition
|
|
// associated with the variable type 't'.
|
|
func (t StateVarType) NewStateValue(name string) *StateVariable {
|
|
return &StateVariable{
|
|
name: name,
|
|
valueType: t,
|
|
eventConditions: make(map[string]StateConditionFunc),
|
|
}
|
|
}
|
|
|
|
func (t StateVarType) DefaultValue() interface{} {
|
|
switch t {
|
|
case StateType_Unknown:
|
|
|
|
case StateType_UI1, StateType_UI2, StateType_UI4:
|
|
return uint64(0)
|
|
|
|
case StateType_I1, StateType_I2, StateType_I4, StateType_Int:
|
|
return int64(0)
|
|
|
|
case StateType_R4, StateType_R8, StateType_Number, StateType_Fixed14_4:
|
|
return float64(0)
|
|
|
|
case StateType_Char, StateType_String:
|
|
return ""
|
|
case StateType_Boolean:
|
|
return false
|
|
|
|
case StateType_BinBase64:
|
|
return ""
|
|
case StateType_BinHex:
|
|
return ""
|
|
case StateType_Date:
|
|
return time.Unix(int64(1718985600), 0).UTC()
|
|
case StateType_DateTime:
|
|
return time.Unix(int64(1718985600), 0).UTC()
|
|
case StateType_DateTimeTZ:
|
|
return time.Unix(int64(1718985600), 0).UTC()
|
|
case StateType_Time:
|
|
return time.Unix(int64(1718985600), 0).UTC()
|
|
case StateType_TimeTZ:
|
|
return time.Unix(int64(1718985600), 0).UTC()
|
|
case StateType_UUID:
|
|
return ""
|
|
case StateType_URI:
|
|
return ""
|
|
|
|
}
|
|
|
|
return nil
|
|
}
|
|
-----------------
|