1
0

add bind scalar from field type

This commit is contained in:
Arpad Ryszka 2025-09-04 01:48:21 +02:00
parent 8683d8ba40
commit f3e17035cd
3 changed files with 173 additions and 6 deletions

13
lib.go
View File

@ -18,12 +18,10 @@ const (
Uint16 FieldType = reflect.Uint16
Uint32 FieldType = reflect.Uint32
Uint64 FieldType = reflect.Uint64
Uintptr FieldType = reflect.Uintptr
Float32 FieldType = reflect.Float32
Float64 FieldType = reflect.Float64
String FieldType = reflect.String
Any FieldType = reflect.Interface
Struct FieldType = reflect.Struct
Duration FieldType = 0xfffe
Time FieldType = 0xffff
)
@ -48,16 +46,21 @@ func BindScalar(receiver any, value ...any) bool {
return bindScalarReflect(receiver, value)
}
// BindScalarCreate is like BindScalar, but it allocates the receiver from the type T.
// CreateAndBindScalar is like BindScalar, but it allocates the receiver from the type T.
func CreateAndBindScalar[T any](value ...any) (T, bool) {
return bindScalarCreateReflect[T](value)
}
// BindScalarCreate is like BindScalar, but it allocates the receiver from the type t.
// CreateAndBindScalarFor is like BindScalar, but it allocates the receiver from the type t.
func CreateAndBindScalarFor(t reflect.Type, value ...any) (reflect.Value, bool) {
return bindScalarCreate(t, value)
}
// CreateAndBindScalarFieldType is like BindScalar, but it allocates the receiver from the field type t.
func CreateAndBindScalarFieldType(t FieldType, value ...any) (reflect.Value, bool) {
return bindScalarCreateFieldType(t, value)
}
// ValueByPath defines a field for input to BindFields or BindFieldsCreate. It defines the field by its exact
// field path in the receiver structure.
func ValueByPath(path []string, value any) Field {
@ -145,7 +148,7 @@ func CreateAndBindFor(t reflect.Type, value ...Field) (reflect.Value, []Field) {
return bindFieldsCreate(t, value)
}
// AcceptsScalar checks if a type can be used with BindScalarCreate or the values of the type with BindScalar.
// AcceptsScalar checks if a type can be used with CreateScalarAndBind or the values of the type with BindScalar.
func AcceptsScalar[T any]() bool {
return acceptsScalarReflect[T]()
}

View File

@ -1,6 +1,9 @@
package bind
import "reflect"
import (
"reflect"
"time"
)
func bindScalar(receiver reflect.Value, values []any) bool {
if !receiver.IsValid() || len(values) == 0 {
@ -107,3 +110,47 @@ func bindScalarCreateReflect[T any](values []any) (T, bool) {
return v.Interface().(T), true
}
func bindScalarCreateFieldType(t FieldType, values []any) (reflect.Value, bool) {
var r reflect.Type
switch t {
case Bool:
r = reflect.TypeFor[bool]()
case Int:
r = reflect.TypeFor[int]()
case Int8:
r = reflect.TypeFor[int8]()
case Int16:
r = reflect.TypeFor[int16]()
case Int32:
r = reflect.TypeFor[int32]()
case Int64:
r = reflect.TypeFor[int64]()
case Uint:
r = reflect.TypeFor[uint]()
case Uint8:
r = reflect.TypeFor[uint8]()
case Uint16:
r = reflect.TypeFor[uint16]()
case Uint32:
r = reflect.TypeFor[uint32]()
case Uint64:
r = reflect.TypeFor[uint64]()
case Float32:
r = reflect.TypeFor[float32]()
case Float64:
r = reflect.TypeFor[float64]()
case String:
r = reflect.TypeFor[string]()
case Any:
r = reflect.TypeFor[any]()
case Duration:
r = reflect.TypeFor[time.Duration]()
case Time:
r = reflect.TypeFor[time.Time]()
default:
return reflect.Value{}, false
}
return bindScalarCreate(r, values)
}

View File

@ -5,6 +5,7 @@ import (
"reflect"
"slices"
"testing"
"time"
)
type valuer interface {
@ -258,4 +259,120 @@ func TestScalar(t *testing.T) {
t.Fatal()
}
})
t.Run("bind from field type", func(t *testing.T) {
t.Run("bool", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Bool, true); !ok || !v.Interface().(bool) {
t.Fatal()
}
})
t.Run("int", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Int, 42); !ok || v.Interface().(int) != 42 {
t.Fatal()
}
})
t.Run("int8", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Int8, 42); !ok || v.Interface().(int8) != 42 {
t.Fatal()
}
})
t.Run("int16", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Int16, 42); !ok || v.Interface().(int16) != 42 {
t.Fatal()
}
})
t.Run("int32", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Int32, 42); !ok || v.Interface().(int32) != 42 {
t.Fatal()
}
})
t.Run("int64", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Int64, 42); !ok || v.Interface().(int64) != 42 {
t.Fatal()
}
})
t.Run("uint", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Uint, 42); !ok || v.Interface().(uint) != 42 {
t.Fatal()
}
})
t.Run("uint8", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Uint8, 42); !ok || v.Interface().(uint8) != 42 {
t.Fatal()
}
})
t.Run("uint16", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Uint16, 42); !ok || v.Interface().(uint16) != 42 {
t.Fatal()
}
})
t.Run("uint32", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Uint32, 42); !ok || v.Interface().(uint32) != 42 {
t.Fatal()
}
})
t.Run("uint64", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Uint64, 42); !ok || v.Interface().(uint64) != 42 {
t.Fatal()
}
})
t.Run("float32", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Float32, 42); !ok || v.Interface().(float32) != 42 {
t.Fatal()
}
})
t.Run("float64", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Float64, 42); !ok || v.Interface().(float64) != 42 {
t.Fatal()
}
})
t.Run("string", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.String, "foo"); !ok || v.Interface().(string) != "foo" {
t.Fatal()
}
})
t.Run("any", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Any, 42); !ok || v.Interface() != 42 {
t.Fatal()
}
})
t.Run("duration", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Duration, time.Second); !ok || v.Interface().(time.Duration) != time.Second {
t.Fatal()
}
})
t.Run("time", func(t *testing.T) {
if v, ok := bind.CreateAndBindScalarFieldType(bind.Time, "14:22:45"); !ok || v.Interface().(time.Time).Hour() != 14 {
t.Fatal()
}
})
t.Run("fail", func(t *testing.T) {
if _, ok := bind.CreateAndBindScalarFieldType(bind.Int, "foo"); ok {
t.Fatal()
}
})
t.Run("unsupported type", func(t *testing.T) {
if _, ok := bind.CreateAndBindScalarFieldType(bind.Duration*bind.Time, "foo"); ok {
t.Fatal()
}
})
})
}