Skip to content

Commit

Permalink
Support conversion of primitive values to pointer types. (#42)
Browse files Browse the repository at this point in the history
Closes #35: Conversion from primitive to pointer of primitive fixed.
  • Loading branch information
TristonianJones authored Jun 8, 2018
1 parent 2226ee7 commit b5faa5c
Show file tree
Hide file tree
Showing 19 changed files with 254 additions and 107 deletions.
2 changes: 1 addition & 1 deletion checker/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ package checker
import (
"github.com/google/cel-go/checker/decls"
"github.com/google/cel-go/common"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/packages"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/parser"
"github.com/google/cel-spec/proto/checked/v1/checked"
Expand Down
27 changes: 17 additions & 10 deletions common/types/bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,23 @@ func (b Bool) Compare(other ref.Value) ref.Value {
}

func (b Bool) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
if typeDesc == jsonValueType {
return &structpb.Value{
Kind: &structpb.Value_BoolValue{
BoolValue: b.Value().(bool)}}, nil
}
if typeDesc.Kind() == reflect.Bool {
return b.Value(), nil
}
if reflect.TypeOf(b).AssignableTo(typeDesc) {
return b, nil
switch typeDesc.Kind() {
case reflect.Bool:
return bool(b), nil
case reflect.Ptr:
if typeDesc == jsonValueType {
return &structpb.Value{
Kind: &structpb.Value_BoolValue{
BoolValue: b.Value().(bool)}}, nil
}
if typeDesc.Elem().Kind() == reflect.Bool {
p := bool(b)
return &p, nil
}
case reflect.Interface:
if reflect.TypeOf(b).Implements(typeDesc) {
return b, nil
}
}
return nil, fmt.Errorf("type conversion error from bool to '%v'", typeDesc)
}
Expand Down
27 changes: 20 additions & 7 deletions common/types/bool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,39 @@ func TestBool_Compare(t *testing.T) {
func TestBool_ConvertToNative_Bool(t *testing.T) {
refType := reflect.TypeOf(true)
val, err := True.ConvertToNative(refType)
if err != nil || IsError(val) || !val.(bool) {
t.Error("Error during conversion to bool", err, val)
if err != nil {
t.Error(err)
} else if !val.(bool) {
t.Error("Error during conversion to bool", val)
}
}

func TestBool_ConvertToNative_Error(t *testing.T) {
refType := reflect.TypeOf("")
val, err := True.ConvertToNative(refType)
if err == nil {
t.Error("Got '%v', expected error", val)
t.Errorf("Got '%v', expected error", val)
}
}

func TestBool_ConvertToNative_Json(t *testing.T) {
val, err := True.ConvertToNative(jsonValueType)
pbVal := &structpb.Value{Kind: &structpb.Value_BoolValue{true}}
if err != nil ||
IsError(val) ||
!proto.Equal(val.(proto.Message), pbVal) {
t.Error("Error during conversion to json Value type", err, val)
if err != nil {
t.Error(err)
} else if !proto.Equal(val.(proto.Message), pbVal) {
t.Error("Error during conversion to json Value type", val)
}
}

func TestBool_ConvertToNative_Ptr(t *testing.T) {
ptrType := true
refType := reflect.TypeOf(&ptrType)
val, err := True.ConvertToNative(refType)
if err != nil {
t.Error(err)
} else if !*val.(*bool) {
t.Error("Error during conversion to *bool", val)
}
}

Expand Down
7 changes: 4 additions & 3 deletions common/types/bytes.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ func (b Bytes) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
if typeDesc.Elem().Kind() == reflect.Uint8 {
return b.Value(), nil
}
}
if reflect.TypeOf(b).AssignableTo(typeDesc) {
return b, nil
case reflect.Interface:
if reflect.TypeOf(b).Implements(typeDesc) {
return b, nil
}
}
return nil, fmt.Errorf("type conversion error from Bytes to '%v'", typeDesc)
}
Expand Down
4 changes: 2 additions & 2 deletions common/types/bytes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ func TestBytes_Compare(t *testing.T) {

func TestBytes_ConvertToNative_ByteSlice(t *testing.T) {
val, err := Bytes("123").ConvertToNative(reflect.TypeOf([]byte{}))
if err != nil || IsError(val) || !bytes.Equal(val.([]byte), []byte{49, 50, 51}) {
t.Errorf("Got '%v', wanted []byte{49, 50, 51}", val)
if err != nil || !bytes.Equal(val.([]byte), []byte{49, 50, 51}) {
t.Error("Got unexpected value, wanted []byte{49, 50, 51}", err, val)
}
}

Expand Down
23 changes: 15 additions & 8 deletions common/types/double.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,22 +58,29 @@ func (d Double) Compare(other ref.Value) ref.Value {
}

func (d Double) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
value := d.Value()
refKind := typeDesc.Kind()
switch refKind {
switch typeDesc.Kind() {
case reflect.Float32:
return float32(value.(float64)), nil
return float32(d), nil
case reflect.Float64:
return value, nil
return float64(d), nil
case reflect.Ptr:
if typeDesc == jsonValueType {
return &structpb.Value{
Kind: &structpb.Value_NumberValue{
NumberValue: float64(d)}}, nil
}
}
if reflect.TypeOf(d).AssignableTo(typeDesc) {
return d, nil
switch typeDesc.Elem().Kind() {
case reflect.Float32:
p := float32(d)
return &p, nil
case reflect.Float64:
p := float64(d)
return &p, nil
}
case reflect.Interface:
if reflect.TypeOf(d).Implements(typeDesc) {
return d, nil
}
}
return nil, fmt.Errorf("type conversion error from Double to '%v'", typeDesc)
}
Expand Down
36 changes: 30 additions & 6 deletions common/types/double_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,25 +56,49 @@ func TestDouble_ConvertToNative_Error(t *testing.T) {

func TestDouble_ConvertToNative_Float32(t *testing.T) {
val, err := Double(3.1415).ConvertToNative(reflect.TypeOf(float32(0)))
if err != nil || val.(float32) != 3.1415 {
if err != nil {
t.Error(err)
} else if val.(float32) != 3.1415 {
t.Errorf("Got '%v', wanted 3.1415", val)
}
}

func TestDouble_ConvertToNative_Float64(t *testing.T) {
val, err := Double(30000000.1).ConvertToNative(reflect.TypeOf(float64(0)))
if err != nil || val.(float64) != 30000000.1 {
if err != nil {
t.Error(err)
} else if val.(float64) != 30000000.1 {
t.Errorf("Got '%v', wanted 330000000.1", val)
}
}

func TestDouble_ConvertToNative_Json(t *testing.T) {
val, err := Double(-1.4).ConvertToNative(jsonValueType)
pbVal := &structpb.Value{Kind: &structpb.Value_NumberValue{-1.4}}
if err != nil ||
IsError(val) ||
!proto.Equal(val.(proto.Message), pbVal) {
t.Error("Error during conversion to json Value type", err, val)
if err != nil {
t.Error(err)
} else if !proto.Equal(val.(proto.Message), pbVal) {
t.Errorf("Got '%v', expected -1.4", val)
}
}

func TestDouble_ConvertToNative_Ptr_Float32(t *testing.T) {
ptrType := float32(0)
val, err := Double(3.1415).ConvertToNative(reflect.TypeOf(&ptrType))
if err != nil {
t.Error(err)
} else if *val.(*float32) != 3.1415 {
t.Errorf("Got '%v', wanted 3.1415", val)
}
}

func TestDouble_ConvertToNative_Ptr_Float64(t *testing.T) {
ptrType := float64(0)
val, err := Double(30000000.1).ConvertToNative(reflect.TypeOf(&ptrType))
if err != nil {
t.Error(err)
} else if *val.(*float64) != 30000000.1 {
t.Errorf("Got '%v', wanted 330000000.1", val)
}
}

Expand Down
4 changes: 3 additions & 1 deletion common/types/duration.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (d Duration) Compare(other ref.Value) ref.Value {
}

func (d Duration) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
if typeDesc == reflect.TypeOf(&dpb.Duration{}) {
if typeDesc == durationValueType {
return d.Value(), nil
}
// If the duration is already assignable to the desired type return it.
Expand Down Expand Up @@ -167,6 +167,8 @@ func (d Duration) Value() interface{} {
}

var (
durationValueType = reflect.TypeOf(&dpb.Duration{})

durationZeroArgOverloads = map[string]func(time.Duration) ref.Value{
overloads.TimeGetHours: func(dur time.Duration) ref.Value {
return Int(dur.Hours())
Expand Down
18 changes: 13 additions & 5 deletions common/types/int.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ func (i Int) Compare(other ref.Value) ref.Value {
}

func (i Int) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
refKind := typeDesc.Kind()
switch refKind {
switch typeDesc.Kind() {
case reflect.Int32:
return int32(i), nil
case reflect.Int64:
Expand All @@ -77,9 +76,18 @@ func (i Int) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
Kind: &structpb.Value_NumberValue{
NumberValue: float64(i)}}, nil
}
}
if reflect.TypeOf(i).AssignableTo(typeDesc) {
return i, nil
switch typeDesc.Elem().Kind() {
case reflect.Int32:
p := int32(i)
return &p, nil
case reflect.Int64:
p := int64(i)
return &p, nil
}
case reflect.Interface:
if reflect.TypeOf(i).Implements(typeDesc) {
return i, nil
}
}
return nil, fmt.Errorf("unsupported type conversion from 'int' to %v", typeDesc)
}
Expand Down
39 changes: 33 additions & 6 deletions common/types/int_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,24 +56,51 @@ func TestInt_ConvertToNative_Error(t *testing.T) {

func TestInt_ConvertToNative_Int32(t *testing.T) {
val, err := Int(20050).ConvertToNative(reflect.TypeOf(int32(0)))
if err != nil || val.(int32) != 20050 {
t.Errorf("Got '%v', expected 20050", err)
if err != nil {
t.Error(err)
} else if val.(int32) != 20050 {
t.Errorf("Got '%v', expected 20050", val)
}
}

func TestInt_ConvertToNative_Int64(t *testing.T) {
// Value greater than max int32.
val, err := Int(4147483648).ConvertToNative(reflect.TypeOf(int64(0)))
if err != nil || val.(int64) != 4147483648 {
t.Errorf("Got '%v', expected 4147483648", err)
if err != nil {
t.Error(err)
} else if val.(int64) != 4147483648 {
t.Errorf("Got '%v', expected 4147483648", val)
}
}

func TestInt_ConvertToNative_Json(t *testing.T) {
val, err := Int(4147483648).ConvertToNative(jsonValueType)
if err != nil || !proto.Equal(val.(proto.Message),
if err != nil {
t.Error(err)
} else if !proto.Equal(val.(proto.Message),
&structpb.Value{Kind: &structpb.Value_NumberValue{NumberValue: 4147483648}}) {
t.Errorf("Got '%v', expected a json number")
t.Errorf("Got '%v', expected a json number", val)
}
}

func TestInt_ConvertToNative_Ptr_Int32(t *testing.T) {
ptrType := int32(0)
val, err := Int(20050).ConvertToNative(reflect.TypeOf(&ptrType))
if err != nil {
t.Error(err)
} else if *val.(*int32) != 20050 {
t.Errorf("Got '%v', expected 20050", val)
}
}

func TestInt_ConvertToNative_Ptr_Int64(t *testing.T) {
// Value greater than max int32.
ptrType := int64(0)
val, err := Int(4147483648).ConvertToNative(reflect.TypeOf(&ptrType))
if err != nil {
t.Error(err)
} else if *val.(*int64) != 4147483648 {
t.Errorf("Got '%v', expected 4147483648", val)
}
}

Expand Down
20 changes: 11 additions & 9 deletions common/types/json_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,24 @@ func (l *jsonListValue) ConvertToNative(typeDesc reflect.Type) (interface{}, err
nativeList.Index(i).Set(reflect.ValueOf(nativeElemVal))
}
return nativeList.Interface(), nil

case reflect.Ptr:
if typeDesc == jsonValueType {
switch typeDesc {
case jsonValueType:
return &structpb.Value{
Kind: &structpb.Value_ListValue{
ListValue: l.ListValue}}, nil
}
if typeDesc == jsonListValueType {
case jsonListValueType:
return l.ListValue, nil
}
if typeDesc == anyValueType {
case anyValueType:
return ptypes.MarshalAny(l.Value().(proto.Message))
}
}
// If the list is already assignable to the desired type return it.
if reflect.TypeOf(l).AssignableTo(typeDesc) {
return l, nil

case reflect.Interface:
// If the list is already assignable to the desired type return it.
if reflect.TypeOf(l).Implements(typeDesc) {
return l, nil
}
}
return nil, fmt.Errorf("no conversion found from list type to native type."+
" list elem: google.protobuf.Value, native type: %v", typeDesc)
Expand Down
20 changes: 11 additions & 9 deletions common/types/json_struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,24 @@ func (m *jsonStruct) ConvertToNative(typeDesc reflect.Type) (interface{}, error)
}
return nativeMap.Interface(), nil
}

case reflect.Ptr:
if typeDesc == jsonValueType {
switch typeDesc {
case jsonValueType:
return &structpb.Value{
Kind: &structpb.Value_StructValue{
StructValue: m.Struct}}, nil
}
if typeDesc == jsonStructType {
case jsonStructType:
return m.Struct, nil
}
if typeDesc == anyValueType {
case anyValueType:
return ptypes.MarshalAny(m.Value().(proto.Message))
}
}
// If the struct is already assignable to the desired type return it.
if reflect.TypeOf(m).AssignableTo(typeDesc) {
return m, nil

case reflect.Interface:
// If the struct is already assignable to the desired type return it.
if reflect.TypeOf(m).Implements(typeDesc) {
return m, nil
}
}
return nil, fmt.Errorf(
"no conversion found from map type to native type."+
Expand Down
Loading

0 comments on commit b5faa5c

Please sign in to comment.