package types
import (
"fmt"
"math"
"reflect"
"github.com/google/cel-go/common/types/ref"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
type Double float64
var (
doubleWrapperType = reflect.TypeOf(&wrapperspb.DoubleValue{})
floatWrapperType = reflect.TypeOf(&wrapperspb.FloatValue{})
)
func (d Double) Add(other ref.Val) ref.Val {
otherDouble, ok := other.(Double)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
return d + otherDouble
}
func (d Double) Compare(other ref.Val) ref.Val {
if math.IsNaN(float64(d)) {
return NewErr("NaN values cannot be ordered")
}
switch ov := other.(type) {
case Double:
if math.IsNaN(float64(ov)) {
return NewErr("NaN values cannot be ordered")
}
return compareDouble(d, ov)
case Int:
return compareDoubleInt(d, ov)
case Uint:
return compareDoubleUint(d, ov)
default:
return MaybeNoSuchOverloadErr(other)
}
}
func (d Double) ConvertToNative(typeDesc reflect.Type) (any, error) {
switch typeDesc.Kind() {
case reflect.Float32:
v := float32(d)
return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil
case reflect.Float64:
v := float64(d)
return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil
case reflect.Ptr:
switch typeDesc {
case anyValueType:
return anypb.New(wrapperspb.Double(float64(d)))
case doubleWrapperType:
return wrapperspb.Double(float64(d)), nil
case floatWrapperType:
return wrapperspb.Float(float32(d)), nil
case jsonValueType:
return structpb.NewNumberValue(float64(d)), nil
}
switch typeDesc.Elem().Kind() {
case reflect.Float32:
v := float32(d)
p := reflect.New(typeDesc.Elem())
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
return p.Interface(), nil
case reflect.Float64:
v := float64(d)
p := reflect.New(typeDesc.Elem())
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
return p.Interface(), nil
}
case reflect.Interface:
dv := d.Value()
if reflect.TypeOf(dv).Implements(typeDesc) {
return dv, nil
}
if reflect.TypeOf(d).Implements(typeDesc) {
return d, nil
}
}
return nil, fmt.Errorf("type conversion error from Double to '%v'", typeDesc)
}
func (d Double) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case IntType:
i, err := doubleToInt64Checked(float64(d))
if err != nil {
return WrapErr(err)
}
return Int(i)
case UintType:
i, err := doubleToUint64Checked(float64(d))
if err != nil {
return WrapErr(err)
}
return Uint(i)
case DoubleType:
return d
case StringType:
return String(fmt.Sprintf("%g", float64(d)))
case TypeType:
return DoubleType
}
return NewErr("type conversion error from '%s' to '%s'", DoubleType, typeVal)
}
func (d Double) Divide(other ref.Val) ref.Val {
otherDouble, ok := other.(Double)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
return d / otherDouble
}
func (d Double) Equal(other ref.Val) ref.Val {
if math.IsNaN(float64(d)) {
return False
}
switch ov := other.(type) {
case Double:
if math.IsNaN(float64(ov)) {
return False
}
return Bool(d == ov)
case Int:
return Bool(compareDoubleInt(d, ov) == 0)
case Uint:
return Bool(compareDoubleUint(d, ov) == 0)
default:
return False
}
}
func (d Double) IsZeroValue() bool {
return float64(d) == 0.0
}
func (d Double) Multiply(other ref.Val) ref.Val {
otherDouble, ok := other.(Double)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
return d * otherDouble
}
func (d Double) Negate() ref.Val {
return -d
}
func (d Double) Subtract(subtrahend ref.Val) ref.Val {
subtraDouble, ok := subtrahend.(Double)
if !ok {
return MaybeNoSuchOverloadErr(subtrahend)
}
return d - subtraDouble
}
func (d Double) Type() ref.Type {
return DoubleType
}
func (d Double) Value() any {
return float64(d)
}