From eb1f2cae1e1c0e8fa0dc8f30d26b7c5be491ea67 Mon Sep 17 00:00:00 2001 From: Aneeque Date: Thu, 19 Dec 2024 14:03:59 +0000 Subject: [PATCH] Add IsNil() (#2340) IsNil() checks if the underlying value of the interface is nil. --- adapters/p2p2core/felt.go | 6 ++---- utils/check.go | 34 ++++++++++++++++++++++++++++++++++ utils/check_test.go | 21 +++++++++++++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 utils/check.go create mode 100644 utils/check_test.go diff --git a/adapters/p2p2core/felt.go b/adapters/p2p2core/felt.go index cd4b3080b2..5be1c354fc 100644 --- a/adapters/p2p2core/felt.go +++ b/adapters/p2p2core/felt.go @@ -2,10 +2,10 @@ package p2p2core import ( "encoding/binary" - "reflect" "github.com/NethermindEth/juno/core/felt" "github.com/NethermindEth/juno/p2p/starknet/spec" + "github.com/NethermindEth/juno/utils" "github.com/ethereum/go-ethereum/common" ) @@ -26,9 +26,7 @@ func AdaptFelt(f *spec.Felt252) *felt.Felt { } func adapt(v interface{ GetElements() []byte }) *felt.Felt { - // when passing a nil pointer `v` is boxed to an interface and is not nil - // see: https://blog.devtrovert.com/p/go-secret-interface-nil-is-not-nil - if v == nil || reflect.ValueOf(v).IsNil() { + if utils.IsNil(v) { return nil } diff --git a/utils/check.go b/utils/check.go new file mode 100644 index 0000000000..2323315bec --- /dev/null +++ b/utils/check.go @@ -0,0 +1,34 @@ +package utils + +import "reflect" + +// IsNil checks if the underlying value of the interface is nil. +// +// In Golang, an interface is boxed by an underlying type and value; both of them need to be nil for the interface to be +// nil. See the following examples: +// +// var i interface{} +// fmt.Println(i == nil) // true +// +// var p *int +// var i interface{} = p +// fmt.Println(i == nil) // false! +// +// A solution for this is to use i == nil || reflect.ValueOf(i).IsNil()), however, this can cause a panic as not all +// reflect.Value has IsNil() defined. Therefore, default is to return false. For example, reflect.Array cannot be nil, +// hence calling IsNil() will cause a panic. +func IsNil(i interface{}) bool { + if i == nil { + return true + } + + v := reflect.ValueOf(i) + k := v.Kind() + + switch k { + case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Interface, reflect.Slice: + return v.IsNil() + default: + return false + } +} diff --git a/utils/check_test.go b/utils/check_test.go new file mode 100644 index 0000000000..9edec66694 --- /dev/null +++ b/utils/check_test.go @@ -0,0 +1,21 @@ +package utils + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIsNil(t *testing.T) { + t.Run("both interface's type and value are nil", func(t *testing.T) { + var i interface{} + // assert.Nil() is not used to avoid assert package from using reflection + assert.True(t, IsNil(i)) + }) + t.Run("only interface's value is nil", func(t *testing.T) { + var arr []int + var i interface{} = arr + // assert.Nil() is not used to avoid assert package from using reflection + assert.True(t, IsNil(i)) + }) +}