Skip to content

Commit

Permalink
Merge pull request #1219 from nyaruka/less_isnil
Browse files Browse the repository at this point in the history
Limit use of reflect nil checking
  • Loading branch information
rowanseymour authored Feb 23, 2024
2 parents 0af2f80 + c842159 commit 3d11612
Show file tree
Hide file tree
Showing 22 changed files with 55 additions and 75 deletions.
4 changes: 2 additions & 2 deletions excellent/functions/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -1809,7 +1809,7 @@ func JSON(env envs.Environment, value types.XValue) types.XValue {
//
// @function format(value)
func Format(env envs.Environment, value types.XValue) types.XValue {
if !utils.IsNil(value) {
if !types.IsNil(value) {
return types.NewXText(value.Format(env))
}
return types.XTextEmpty
Expand Down Expand Up @@ -2090,7 +2090,7 @@ func IsError(env envs.Environment, value types.XValue) types.XValue {
// @function count(value)
func Count(env envs.Environment, value types.XValue) types.XValue {
// a nil has count of zero
if utils.IsNil(value) {
if types.IsNil(value) {
return types.XNumberZero
}

Expand Down
3 changes: 1 addition & 2 deletions excellent/tools/context_walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package tools

import (
"github.com/nyaruka/goflow/excellent/types"
"github.com/nyaruka/goflow/utils"
)

// ContextWalk traverses the given context invoking the callback for each non-nil value
Expand All @@ -21,7 +20,7 @@ func ContextWalkObjects(context *types.XObject, callback func(*types.XObject)) {
}

func contextWalk(v types.XValue, callback func(types.XValue)) {
if utils.IsNil(v) {
if types.IsNil(v) {
return
}

Expand Down
5 changes: 2 additions & 3 deletions excellent/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/nyaruka/goflow/excellent/functions"
"github.com/nyaruka/goflow/excellent/operators"
"github.com/nyaruka/goflow/excellent/types"
"github.com/nyaruka/goflow/utils"
)

type Warnings struct {
Expand Down Expand Up @@ -43,7 +42,7 @@ func (x *ContextReference) Evaluate(env envs.Environment, scope *Scope, warnings
return types.NewXErrorf("context has no property '%s'", x.name)
}

if !utils.IsNil(value) && value.Deprecated() != "" {
if !types.IsNil(value) && value.Deprecated() != "" {
warnings.deprecatedContext(value)
}

Expand Down Expand Up @@ -422,7 +421,7 @@ func resolveLookup(env envs.Environment, container types.XValue, lookup types.XV
return types.NewXErrorf("%s doesn't support lookups", types.Describe(container))
}

if !utils.IsNil(resolved) && resolved.Deprecated() != "" {
if !types.IsNil(resolved) && resolved.Deprecated() != "" {
warnings.deprecatedContext(resolved)
}

Expand Down
2 changes: 1 addition & 1 deletion excellent/types/array.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ var XArrayEmpty = NewXArray()

// ToXArray converts the given value to an array
func ToXArray(env envs.Environment, x XValue) (*XArray, *XError) {
if utils.IsNil(x) {
if IsNil(x) {
return XArrayEmpty, nil
}
if IsXError(x) {
Expand Down
27 changes: 16 additions & 11 deletions excellent/types/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"reflect"

"github.com/nyaruka/goflow/envs"
"github.com/nyaruka/goflow/utils"
)

// XValue is the base interface of all excellent types
Expand Down Expand Up @@ -54,9 +53,9 @@ type XComparable interface {
// specifically means text(x) == text(y)
func Equals(x1 XValue, x2 XValue) bool {
// nil == nil
if utils.IsNil(x1) && utils.IsNil(x2) {
if IsNil(x1) && IsNil(x2) {
return true
} else if utils.IsNil(x1) || utils.IsNil(x2) {
} else if IsNil(x1) || IsNil(x2) {
return false
}

Expand All @@ -71,11 +70,11 @@ func Equals(x1 XValue, x2 XValue) bool {
// Compare compares two given values
func Compare(x1 XValue, x2 XValue) int {
// nil == nil
if utils.IsNil(x1) && utils.IsNil(x2) {
if IsNil(x1) && IsNil(x2) {
return 0
} else if utils.IsNil(x1) {
} else if IsNil(x1) {
return -1
} else if utils.IsNil(x2) {
} else if IsNil(x2) {
return 1
}

Expand All @@ -99,44 +98,50 @@ func SameType(x1 XValue, x2 XValue) bool {

// Describe returns a representation of the given value for use in error messages
func Describe(x XValue) string {
if utils.IsNil(x) {
if IsNil(x) {
return "null"
}
return x.Describe()
}

// Truthy determines truthiness for the given value
func Truthy(x XValue) bool {
if utils.IsNil(x) {
if IsNil(x) {
return false
}
return x.Truthy()
}

// Render returns the canonical text representation
func Render(x XValue) string {
if utils.IsNil(x) {
if IsNil(x) {
return ""
}
return x.Render()
}

// Format returns the pretty text representation
func Format(env envs.Environment, x XValue) string {
if utils.IsNil(x) {
if IsNil(x) {
return ""
}
return x.Format(env)
}

// String returns a representation of the given value for use in debugging
func String(x XValue) string {
if utils.IsNil(x) {
if IsNil(x) {
return "nil"
}
return x.String()
}

// IsNil returns whether the given value is nil... because of golang's love of autoboxing nil pointers into non-nil
// interfaces, we need to check if interface itself is nil or the underlying pointer is nil.
func IsNil(x XValue) bool {
return x == nil || reflect.ValueOf(x).IsNil()
}

// baseValue is shared by all X types
type baseValue struct {
deprecated string
Expand Down
3 changes: 1 addition & 2 deletions excellent/types/boolean.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (

"github.com/nyaruka/gocommon/jsonx"
"github.com/nyaruka/goflow/envs"
"github.com/nyaruka/goflow/utils"
)

// XBoolean is a boolean `true` or `false`.
Expand Down Expand Up @@ -90,7 +89,7 @@ var _ XValue = XBooleanFalse

// ToXBoolean converts the given value to a boolean
func ToXBoolean(x XValue) (*XBoolean, *XError) {
if utils.IsNil(x) {
if IsNil(x) {
return XBooleanFalse, nil
}
if IsXError(x) {
Expand Down
3 changes: 1 addition & 2 deletions excellent/types/date.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"github.com/nyaruka/gocommon/dates"
"github.com/nyaruka/gocommon/jsonx"
"github.com/nyaruka/goflow/envs"
"github.com/nyaruka/goflow/utils"
)

// XDate is a Gregorian calendar date value.
Expand Down Expand Up @@ -82,7 +81,7 @@ var _ XValue = XDateZero

// ToXDate converts the given value to a time or returns an error if that isn't possible
func ToXDate(env envs.Environment, x XValue) (*XDate, *XError) {
if !utils.IsNil(x) {
if !IsNil(x) {
switch typed := x.(type) {
case *XError:
return XDateZero, typed
Expand Down
3 changes: 1 addition & 2 deletions excellent/types/datetime.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/nyaruka/gocommon/dates"
"github.com/nyaruka/gocommon/jsonx"
"github.com/nyaruka/goflow/envs"
"github.com/nyaruka/goflow/utils"
)

// XDateTime is a datetime value.
Expand Down Expand Up @@ -135,7 +134,7 @@ func ToXDateTimeWithTimeFill(env envs.Environment, x XValue) (*XDateTime, *XErro

// converts the given value to a time or returns an error if that isn't possible
func toXDateTime(env envs.Environment, x XValue, fillTime bool) (*XDateTime, *XError) {
if !utils.IsNil(x) {
if !IsNil(x) {
switch typed := x.(type) {
case *XError:
return XDateTimeZero, typed
Expand Down
3 changes: 1 addition & 2 deletions excellent/types/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (

"github.com/buger/jsonparser"
"github.com/nyaruka/gocommon/jsonx"
"github.com/nyaruka/goflow/utils"
"github.com/pkg/errors"
"github.com/shopspring/decimal"
)
Expand Down Expand Up @@ -82,7 +81,7 @@ func jsonToArray(data []byte) *XArray {

// ToXJSON converts the given value to a JSON string
func ToXJSON(x XValue) (*XText, *XError) {
if utils.IsNil(x) {
if IsNil(x) {
return NewXText(`null`), nil
}
if IsXError(x) {
Expand Down
3 changes: 1 addition & 2 deletions excellent/types/number.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/nyaruka/gocommon/jsonx"
"github.com/nyaruka/goflow/envs"
"github.com/nyaruka/goflow/utils"
"github.com/pkg/errors"
"github.com/shopspring/decimal"
)
Expand Down Expand Up @@ -152,7 +151,7 @@ func newXNumberFromString(s string) (*XNumber, error) {

// ToXNumber converts the given value to a number or returns an error if that isn't possible
func ToXNumber(env envs.Environment, x XValue) (*XNumber, *XError) {
if !utils.IsNil(x) {
if !IsNil(x) {
switch typed := x.(type) {
case *XError:
return XNumberZero, typed
Expand Down
2 changes: 1 addition & 1 deletion excellent/types/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ var _ json.Marshaler = (*XObject)(nil)

// ToXObject converts the given value to an object
func ToXObject(env envs.Environment, x XValue) (*XObject, *XError) {
if utils.IsNil(x) {
if IsNil(x) {
return XObjectEmpty, nil
}
if IsXError(x) {
Expand Down
3 changes: 1 addition & 2 deletions excellent/types/text.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/nyaruka/gocommon/jsonx"
"github.com/nyaruka/goflow/envs"
"github.com/nyaruka/goflow/utils"
)

// XText is a string of characters.
Expand Down Expand Up @@ -89,7 +88,7 @@ var _ XValue = XTextEmpty

// ToXText converts the given value to a string
func ToXText(env envs.Environment, x XValue) (*XText, *XError) {
if utils.IsNil(x) {
if IsNil(x) {
return XTextEmpty, nil
}
if IsXError(x) {
Expand Down
3 changes: 1 addition & 2 deletions excellent/types/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"github.com/nyaruka/gocommon/dates"
"github.com/nyaruka/gocommon/jsonx"
"github.com/nyaruka/goflow/envs"
"github.com/nyaruka/goflow/utils"
)

// XTime is a time of day.
Expand Down Expand Up @@ -88,7 +87,7 @@ var _ XValue = XTimeZero

// ToXTime converts the given value to a time or returns an error if that isn't possible
func ToXTime(env envs.Environment, x XValue) (*XTime, *XError) {
if !utils.IsNil(x) {
if !IsNil(x) {
switch typed := x.(type) {
case *XError:
return XTimeZero, typed
Expand Down
3 changes: 1 addition & 2 deletions flows/definition/legacy/expressions/migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/nyaruka/goflow/excellent/types"
"github.com/nyaruka/goflow/flows/definition/legacy/expressions"
"github.com/nyaruka/goflow/test"
"github.com/nyaruka/goflow/utils"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -277,7 +276,7 @@ func (v legacyVariables) Context(env envs.Environment) *types.XObject {
}

func toXType(env envs.Environment, val any) types.XValue {
if utils.IsNil(val) {
if val == nil {
return nil
}

Expand Down
15 changes: 9 additions & 6 deletions flows/expressions.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package flows

import (
"reflect"
"strconv"

"github.com/nyaruka/goflow/envs"
"github.com/nyaruka/goflow/excellent/types"
"github.com/nyaruka/goflow/utils"
)

// Contextable is an object that can accessed in expressions as a object with properties
Expand All @@ -15,12 +15,15 @@ type Contextable interface {

// Context generates a lazy object for use in expressions
func Context(env envs.Environment, contextable Contextable) types.XValue {
if !utils.IsNil(contextable) {
return types.NewXLazyObject(func() map[string]types.XValue {
return contextable.Context(env)
})
// we allow passing nil pointers which will become non-nil Contextables
if contextable == nil || reflect.ValueOf(contextable).IsNil() {
return nil
}
return nil

return types.NewXLazyObject(func() map[string]types.XValue {
return contextable.Context(env)
})

}

// ContextFunc generates a lazy object for use in expressions
Expand Down
3 changes: 1 addition & 2 deletions flows/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/nyaruka/goflow/assets"
"github.com/nyaruka/goflow/envs"
"github.com/nyaruka/goflow/excellent/types"
"github.com/nyaruka/goflow/utils"
)

// Field represents a contact field
Expand Down Expand Up @@ -284,7 +283,7 @@ func (f FieldValues) Context(env envs.Environment) map[string]types.XValue {
val := v.ToXValue(env)
entries[string(k)] = val

if !utils.IsNil(val) {
if val != nil {
lines = append(lines, fmt.Sprintf("%s: %s", v.field.Name(), types.Render(val)))
}
}
Expand Down
2 changes: 1 addition & 1 deletion flows/routers/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (r *baseRouter) Categories() []flows.Category { return r.categories }

// AllowTimeout returns whether this router can be resumed at with a timeout
func (r *baseRouter) AllowTimeout() bool {
return r.wait != nil && !utils.IsNil(r.wait.Timeout())
return r.wait != nil && r.wait.Timeout() != nil
}

// ResultName returns the name which the result of this router should be saved as (if any)
Expand Down
7 changes: 6 additions & 1 deletion flows/routers/waits/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ func newBaseWait(typeName string, timeout *Timeout) baseWait {
func (w *baseWait) Type() string { return w.type_ }

// Timeout returns the timeout of this wait or nil if no timeout is set
func (w *baseWait) Timeout() flows.Timeout { return w.timeout }
func (w *baseWait) Timeout() flows.Timeout {
if w.timeout == nil {
return nil
}
return w.timeout
}

func (w *baseWait) expiresOn(run flows.Run) *time.Time {
expiresAfterMins := run.Flow().ExpireAfterMinutes()
Expand Down
9 changes: 7 additions & 2 deletions flows/runs/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,13 @@ func (r *run) RootContext(env envs.Environment) map[string]types.XValue {
}
}

var child = newRelatedRunContext(r.Session().GetCurrentChild(r))
var parent = newRelatedRunContext(r.Parent())
var child, parent *relatedRunContext
if r.Session().GetCurrentChild(r) != nil {
child = newRelatedRunContext(r.Session().GetCurrentChild(r))
}
if r.Parent() != nil {
parent = newRelatedRunContext(r.Parent())
}

_, n, _ := r.PathLocation()
if n != nil {
Expand Down
Loading

0 comments on commit 3d11612

Please sign in to comment.