refactor/rename
This commit is contained in:
parent
c27b9c2daa
commit
8683d8ba40
35
field.go
35
field.go
@ -427,6 +427,18 @@ func fieldsReflect[T any]() []Field {
|
||||
return fields(t)
|
||||
}
|
||||
|
||||
func fieldsOf(t reflect.Type) []Field {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if hasCircularType(t) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fields(t)
|
||||
}
|
||||
|
||||
func fieldValuesReflect(structure any) []Field {
|
||||
v := reflect.ValueOf(structure)
|
||||
if hasCircularReference(v) {
|
||||
@ -499,22 +511,18 @@ func bindFieldsReflect(structure any, values []Field) []Field {
|
||||
return bindFields(receiver, values)
|
||||
}
|
||||
|
||||
func bindFieldsCreateReflect[T any](values []Field) (T, []Field) {
|
||||
t := reflect.TypeFor[T]()
|
||||
func bindFieldsCreate(t reflect.Type, values []Field) (reflect.Value, []Field) {
|
||||
if hasCircularType(t) {
|
||||
var r T
|
||||
return r, values
|
||||
return reflect.Zero(t), values
|
||||
}
|
||||
|
||||
if !acceptsFields(t) {
|
||||
var r T
|
||||
return r, values
|
||||
return reflect.Zero(t), values
|
||||
}
|
||||
|
||||
receiver, ok := allocate(t, 1)
|
||||
if !ok {
|
||||
var r T
|
||||
return r, values
|
||||
return reflect.Zero(t), values
|
||||
}
|
||||
|
||||
unmatched := bindFields(receiver, values)
|
||||
@ -522,5 +530,16 @@ func bindFieldsCreateReflect[T any](values []Field) (T, []Field) {
|
||||
receiver = reflect.Zero(t)
|
||||
}
|
||||
|
||||
return receiver, unmatched
|
||||
}
|
||||
|
||||
func bindFieldsCreateReflect[T any](values []Field) (T, []Field) {
|
||||
t := reflect.TypeFor[T]()
|
||||
receiver, unmatched := bindFieldsCreate(t, values)
|
||||
if len(unmatched) == len(values) {
|
||||
var t T
|
||||
return t, unmatched
|
||||
}
|
||||
|
||||
return receiver.Interface().(T), unmatched
|
||||
}
|
||||
|
||||
127
field_test.go
127
field_test.go
@ -3,12 +3,13 @@ package bind_test
|
||||
import (
|
||||
"code.squareroundforest.org/arpio/bind"
|
||||
"code.squareroundforest.org/arpio/notation"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func TestField(t *testing.T) {
|
||||
@ -173,6 +174,31 @@ func TestField(t *testing.T) {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("fields from reflection type", func(t *testing.T) {
|
||||
t.Run("ok", func(t *testing.T) {
|
||||
type s struct{ Foo int }
|
||||
f := bind.FieldsOf(reflect.TypeFor[s]())
|
||||
if len(f) != 1 || f[0].Name() != "foo" {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("nil type", func(t *testing.T) {
|
||||
f := bind.FieldsOf(nil)
|
||||
if len(f) != 0 {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("circular type", func(t *testing.T) {
|
||||
type p *p
|
||||
f := bind.FieldsOf(reflect.TypeFor[p]())
|
||||
if len(f) != 0 {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("field values", func(t *testing.T) {
|
||||
@ -428,7 +454,7 @@ func TestField(t *testing.T) {
|
||||
Bar int
|
||||
}
|
||||
var v s
|
||||
if len(bind.BindFields(&v, bind.NamedValue("bar", 42))) != 1 {
|
||||
if len(bind.Bind(&v, bind.NamedValue("bar", 42))) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
@ -437,7 +463,7 @@ func TestField(t *testing.T) {
|
||||
type s struct{ Foo int }
|
||||
type p *p
|
||||
var v p
|
||||
if len(bind.BindFields(&v, bind.NamedValue("foo", 42))) != 1 {
|
||||
if len(bind.Bind(&v, bind.NamedValue("foo", 42))) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
@ -445,7 +471,7 @@ func TestField(t *testing.T) {
|
||||
t.Run("set by name", func(t *testing.T) {
|
||||
type s struct{ FooBar int }
|
||||
var v s
|
||||
u := bind.BindFields(&v, bind.NamedValue("foo-bar", 42))
|
||||
u := bind.Bind(&v, bind.NamedValue("foo-bar", 42))
|
||||
if len(u) != 0 || v.FooBar != 42 {
|
||||
t.Fatal(notation.Sprint(u), notation.Sprint(v))
|
||||
}
|
||||
@ -454,7 +480,7 @@ func TestField(t *testing.T) {
|
||||
t.Run("set by path", func(t *testing.T) {
|
||||
type s struct{ FooBar int }
|
||||
var v s
|
||||
u := bind.BindFields(&v, bind.ValueByPath([]string{"FooBar"}, 42))
|
||||
u := bind.Bind(&v, bind.ValueByPath([]string{"FooBar"}, 42))
|
||||
if len(u) != 0 || v.FooBar != 42 {
|
||||
t.Fatal(notation.Sprint(u), notation.Sprint(v))
|
||||
}
|
||||
@ -466,7 +492,7 @@ func TestField(t *testing.T) {
|
||||
Bar int
|
||||
}
|
||||
var v s
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
&v,
|
||||
bind.NamedValue("foo", 21),
|
||||
bind.NamedValue("baz", 42),
|
||||
@ -480,7 +506,7 @@ func TestField(t *testing.T) {
|
||||
t.Run("bind list", func(t *testing.T) {
|
||||
type s struct{ Foo []int }
|
||||
var v s
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
&v,
|
||||
bind.NamedValue("foo", 21),
|
||||
bind.NamedValue("foo", 42),
|
||||
@ -495,7 +521,7 @@ func TestField(t *testing.T) {
|
||||
t.Run("bind list of structs", func(t *testing.T) {
|
||||
type s struct{ Foo []struct{ Bar int } }
|
||||
var v s
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
&v,
|
||||
bind.NamedValue("foo-bar", 21),
|
||||
bind.NamedValue("foo-bar", 42),
|
||||
@ -510,7 +536,7 @@ func TestField(t *testing.T) {
|
||||
t.Run("bind list in list", func(t *testing.T) {
|
||||
type s struct{ Foo []struct{ Bar []int } }
|
||||
var v s
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
&v,
|
||||
bind.NamedValue("foo-bar", 21),
|
||||
bind.NamedValue("foo-bar", 42),
|
||||
@ -527,7 +553,7 @@ func TestField(t *testing.T) {
|
||||
|
||||
t.Run("list receiver", func(t *testing.T) {
|
||||
var l []struct{ Foo int }
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
&l,
|
||||
bind.NamedValue("foo", 21),
|
||||
bind.NamedValue("foo", 42),
|
||||
@ -546,7 +572,7 @@ func TestField(t *testing.T) {
|
||||
)
|
||||
|
||||
v := s1{[]s0{{1}, {2}}}
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
v,
|
||||
bind.NamedValue("foo-bar", 21),
|
||||
bind.NamedValue("foo-bar", 42),
|
||||
@ -565,7 +591,7 @@ func TestField(t *testing.T) {
|
||||
)
|
||||
|
||||
v := s1{[]s0{{1}, {2}}}
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
&v,
|
||||
bind.NamedValue("foo-bar", 21),
|
||||
bind.NamedValue("foo-bar", 42),
|
||||
@ -584,7 +610,7 @@ func TestField(t *testing.T) {
|
||||
)
|
||||
|
||||
v := s1{[]s0{{nil}, {nil}}}
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
&v,
|
||||
bind.NamedValue("foo-bar", 21),
|
||||
bind.NamedValue("foo-bar", 42),
|
||||
@ -598,7 +624,7 @@ func TestField(t *testing.T) {
|
||||
|
||||
t.Run("bind scalar map", func(t *testing.T) {
|
||||
m := make(map[string]int)
|
||||
u := bind.BindFields(m, bind.NamedValue("foo-bar", 21), bind.NamedValue("baz-qux", 42))
|
||||
u := bind.Bind(m, bind.NamedValue("foo-bar", 21), bind.NamedValue("baz-qux", 42))
|
||||
if len(u) != 0 || len(m) != 2 || m["foo-bar"] != 21 || m["baz-qux"] != 42 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -607,7 +633,7 @@ func TestField(t *testing.T) {
|
||||
t.Run("scalar map key conversion", func(t *testing.T) {
|
||||
type key string
|
||||
m := make(map[key]int)
|
||||
u := bind.BindFields(m, bind.NamedValue("foo", 42))
|
||||
u := bind.Bind(m, bind.NamedValue("foo", 42))
|
||||
if len(u) != 0 || len(m) != 1 || m["foo"] != 42 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -615,7 +641,7 @@ func TestField(t *testing.T) {
|
||||
|
||||
t.Run("scalar map pointer key", func(t *testing.T) {
|
||||
m := make(map[*string]int)
|
||||
u := bind.BindFields(m, bind.NamedValue("foo", 42))
|
||||
u := bind.Bind(m, bind.NamedValue("foo", 42))
|
||||
if len(u) != 0 || len(m) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -629,7 +655,7 @@ func TestField(t *testing.T) {
|
||||
|
||||
t.Run("scalar map list value", func(t *testing.T) {
|
||||
m := make(map[string][]int)
|
||||
u := bind.BindFields(m, bind.NamedValue("foo", 21), bind.NamedValue("foo", 42), bind.NamedValue("foo", 84))
|
||||
u := bind.Bind(m, bind.NamedValue("foo", 21), bind.NamedValue("foo", 42), bind.NamedValue("foo", 84))
|
||||
if len(u) != 0 || len(m) != 1 || !slices.Equal(m["foo"], []int{21, 42, 84}) {
|
||||
t.Fatal(notation.Sprint(u), notation.Sprint(m))
|
||||
}
|
||||
@ -637,7 +663,7 @@ func TestField(t *testing.T) {
|
||||
|
||||
t.Run("scalar map pointer value", func(t *testing.T) {
|
||||
m := make(map[string]*int)
|
||||
u := bind.BindFields(m, bind.NamedValue("foo", 42))
|
||||
u := bind.Bind(m, bind.NamedValue("foo", 42))
|
||||
if len(u) != 0 || len(m) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -651,7 +677,7 @@ func TestField(t *testing.T) {
|
||||
|
||||
t.Run("scalar map list pointer value", func(t *testing.T) {
|
||||
m := make(map[string]*[]int)
|
||||
u := bind.BindFields(m, bind.NamedValue("foo", 21), bind.NamedValue("foo", 42), bind.NamedValue("foo", 84))
|
||||
u := bind.Bind(m, bind.NamedValue("foo", 21), bind.NamedValue("foo", 42), bind.NamedValue("foo", 84))
|
||||
if len(u) != 0 || len(m) != 1 || !slices.Equal(*m["foo"], []int{21, 42, 84}) {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -660,7 +686,7 @@ func TestField(t *testing.T) {
|
||||
t.Run("allocate scalar map", func(t *testing.T) {
|
||||
type s struct{ Foo map[string]int }
|
||||
var v s
|
||||
u := bind.BindFields(&v, bind.NamedValue("foo-bar", 42))
|
||||
u := bind.Bind(&v, bind.NamedValue("foo-bar", 42))
|
||||
if len(u) != 0 || len(v.Foo) != 1 || v.Foo["bar"] != 42 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -669,7 +695,7 @@ func TestField(t *testing.T) {
|
||||
t.Run("scalar map addressing via path", func(t *testing.T) {
|
||||
type s struct{ Foo map[string]int }
|
||||
var v s
|
||||
u := bind.BindFields(&v, bind.ValueByPath([]string{"Foo", "Bar"}, 42))
|
||||
u := bind.Bind(&v, bind.ValueByPath([]string{"Foo", "Bar"}, 42))
|
||||
if len(u) != 0 || len(v.Foo) != 1 || v.Foo["Bar"] != 42 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -677,7 +703,7 @@ func TestField(t *testing.T) {
|
||||
|
||||
t.Run("scalar map and too long field path", func(t *testing.T) {
|
||||
m := make(map[string]int)
|
||||
u := bind.BindFields(m, bind.ValueByPath([]string{"foo", "bar"}, 42))
|
||||
u := bind.Bind(m, bind.ValueByPath([]string{"foo", "bar"}, 42))
|
||||
if len(u) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -686,7 +712,7 @@ func TestField(t *testing.T) {
|
||||
t.Run("scalar map cannot be set", func(t *testing.T) {
|
||||
type s struct{ Foo map[string]int }
|
||||
var v s
|
||||
u := bind.BindFields(v, bind.NamedValue("foo-bar", 42))
|
||||
u := bind.Bind(v, bind.NamedValue("foo-bar", 42))
|
||||
if len(u) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -694,7 +720,7 @@ func TestField(t *testing.T) {
|
||||
|
||||
t.Run("scalar map with wrong value type", func(t *testing.T) {
|
||||
m := make(map[string]int)
|
||||
u := bind.BindFields(m, bind.NamedValue("foo", "bar"))
|
||||
u := bind.Bind(m, bind.NamedValue("foo", "bar"))
|
||||
if len(u) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -706,7 +732,7 @@ func TestField(t *testing.T) {
|
||||
Bar struct{ Baz string }
|
||||
}
|
||||
var v s
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
&v,
|
||||
bind.NamedValue("foo", 42),
|
||||
bind.NamedValue("bar-baz", "qux"),
|
||||
@ -723,7 +749,7 @@ func TestField(t *testing.T) {
|
||||
Bar struct{ Baz string }
|
||||
}
|
||||
var v s
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
&v,
|
||||
bind.NamedValue("foo", 42),
|
||||
bind.NamedValue("bar-qux", "qux"),
|
||||
@ -740,7 +766,7 @@ func TestField(t *testing.T) {
|
||||
Bar struct{ Baz string }
|
||||
}
|
||||
var v s
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
&v,
|
||||
bind.NamedValue("foo", 42),
|
||||
bind.NamedValue("bar-baz", "qux"),
|
||||
@ -760,7 +786,7 @@ func TestField(t *testing.T) {
|
||||
}
|
||||
|
||||
var v s
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
&v,
|
||||
bind.NamedValue("foo", 42),
|
||||
bind.NamedValue("bar-baz", "qux"),
|
||||
@ -775,7 +801,7 @@ func TestField(t *testing.T) {
|
||||
t.Run("pointer field with invalid value", func(t *testing.T) {
|
||||
type s struct{ Foo *struct{ Bar int } }
|
||||
var v s
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
&v,
|
||||
bind.NamedValue("foo-bar", "baz"),
|
||||
)
|
||||
@ -792,7 +818,7 @@ func TestField(t *testing.T) {
|
||||
}
|
||||
|
||||
var v s
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
&v,
|
||||
bind.NamedValue("foo", 42),
|
||||
bind.NamedValue("bar", "qux"),
|
||||
@ -811,7 +837,7 @@ func TestField(t *testing.T) {
|
||||
Bar struct{ Baz string }
|
||||
}
|
||||
var v s
|
||||
u := bind.BindFields(
|
||||
u := bind.Bind(
|
||||
&v,
|
||||
bind.ValueByPath([]string{"Foo"}, 42),
|
||||
bind.ValueByPath([]string{"Bar", "Baz"}, "qux"),
|
||||
@ -825,7 +851,7 @@ func TestField(t *testing.T) {
|
||||
t.Run("cannot set field", func(t *testing.T) {
|
||||
type s struct{ Foo int }
|
||||
var v s
|
||||
u := bind.BindFields(v, bind.NamedValue("foo", 42))
|
||||
u := bind.Bind(v, bind.NamedValue("foo", 42))
|
||||
if len(u) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -838,7 +864,7 @@ func TestField(t *testing.T) {
|
||||
)
|
||||
|
||||
var v s1
|
||||
u := bind.BindFields(&v, bind.NamedValue("foo", 42))
|
||||
u := bind.Bind(&v, bind.NamedValue("foo", 42))
|
||||
if len(u) != 0 || v.Foo != 42 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -847,7 +873,7 @@ func TestField(t *testing.T) {
|
||||
t.Run("receiver cannot be set", func(t *testing.T) {
|
||||
type s struct{ Foo *struct{ Bar int } }
|
||||
var v s
|
||||
u := bind.BindFields(v, bind.NamedValue("foo-bar", 42))
|
||||
u := bind.Bind(v, bind.NamedValue("foo-bar", 42))
|
||||
if len(u) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -855,7 +881,7 @@ func TestField(t *testing.T) {
|
||||
|
||||
t.Run("receiver not supported", func(t *testing.T) {
|
||||
v := make(chan int)
|
||||
u := bind.BindFields(&v, bind.NamedValue("foo-bar", 42))
|
||||
u := bind.Bind(&v, bind.NamedValue("foo-bar", 42))
|
||||
if len(u) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -863,7 +889,7 @@ func TestField(t *testing.T) {
|
||||
|
||||
t.Run("empty receiver", func(t *testing.T) {
|
||||
var v any
|
||||
u := bind.BindFields(&v, bind.NamedValue("foo", 42))
|
||||
u := bind.Bind(&v, bind.NamedValue("foo", 42))
|
||||
if len(u) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -872,14 +898,14 @@ func TestField(t *testing.T) {
|
||||
t.Run("nil value", func(t *testing.T) {
|
||||
type s struct{ Foo any }
|
||||
v := s{42}
|
||||
u := bind.BindFields(&v, bind.NamedValue("foo", nil))
|
||||
u := bind.Bind(&v, bind.NamedValue("foo", nil))
|
||||
if len(u) != 0 || v.Foo != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("nil receiver", func(t *testing.T) {
|
||||
u := bind.BindFields(nil, bind.NamedValue("foo", nil))
|
||||
u := bind.Bind(nil, bind.NamedValue("foo", nil))
|
||||
if len(u) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -892,7 +918,7 @@ func TestField(t *testing.T) {
|
||||
}
|
||||
|
||||
var v s
|
||||
u := bind.BindFields(&v, bind.NamedValue("foo-bar", 42))
|
||||
u := bind.Bind(&v, bind.NamedValue("foo-bar", 42))
|
||||
if len(u) != 0 || v.FooBar != 42 || v.Foo.Bar != 42 {
|
||||
t.Fatal(notation.Sprint(u), notation.Sprint(v))
|
||||
}
|
||||
@ -900,7 +926,7 @@ func TestField(t *testing.T) {
|
||||
|
||||
t.Run("scalar map with invalid field type", func(t *testing.T) {
|
||||
v := make(map[string]int)
|
||||
u := bind.BindFields(v, bind.NamedValue("foo", "bar"))
|
||||
u := bind.Bind(v, bind.NamedValue("foo", "bar"))
|
||||
if len(u) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -911,7 +937,7 @@ func TestField(t *testing.T) {
|
||||
var v s
|
||||
var str fmt.Stringer
|
||||
str = time.Second
|
||||
u := bind.BindFields(&v, bind.NamedValue("foo", &str))
|
||||
u := bind.Bind(&v, bind.NamedValue("foo", &str))
|
||||
if len(u) != 0 || v.Foo != time.Second {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -924,14 +950,14 @@ func TestField(t *testing.T) {
|
||||
Foo int
|
||||
Bar *s
|
||||
}
|
||||
_, u := bind.BindFieldsCreate[s](bind.NamedValue("foo", 42))
|
||||
_, u := bind.CreateAndBind[s](bind.NamedValue("foo", 42))
|
||||
if len(u) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("type does not accept fields", func(t *testing.T) {
|
||||
_, u := bind.BindFieldsCreate[[]int](bind.NamedValue("foo", 42))
|
||||
_, u := bind.CreateAndBind[[]int](bind.NamedValue("foo", 42))
|
||||
if len(u) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -939,7 +965,7 @@ func TestField(t *testing.T) {
|
||||
|
||||
t.Run("zero value when no fields were bound", func(t *testing.T) {
|
||||
type s struct{ Foo int }
|
||||
v, u := bind.BindFieldsCreate[*s](bind.NamedValue("bar", 42))
|
||||
v, u := bind.CreateAndBind[*s](bind.NamedValue("bar", 42))
|
||||
if len(u) != 1 || v != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
@ -947,17 +973,26 @@ func TestField(t *testing.T) {
|
||||
|
||||
t.Run("create receiver", func(t *testing.T) {
|
||||
type s struct{ Foo int }
|
||||
v, u := bind.BindFieldsCreate[*s](bind.NamedValue("foo", 42))
|
||||
v, u := bind.CreateAndBind[*s](bind.NamedValue("foo", 42))
|
||||
if len(u) != 0 || v == nil || v.Foo != 42 {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("any type", func(t *testing.T) {
|
||||
_, u := bind.BindFieldsCreate[any](bind.NamedValue("foo", 42))
|
||||
_, u := bind.CreateAndBind[any](bind.NamedValue("foo", 42))
|
||||
if len(u) != 1 {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("bind fields create with reflection type", func(t *testing.T) {
|
||||
type s struct{ Foo int }
|
||||
typ := reflect.TypeFor[s]()
|
||||
v, u := bind.CreateAndBindFor(typ, bind.NamedValue("foo", 42))
|
||||
if len(u) != 0 || v.Interface().(s).Foo != 42 {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
38
lib.go
38
lib.go
@ -49,13 +49,13 @@ func BindScalar(receiver any, value ...any) bool {
|
||||
}
|
||||
|
||||
// BindScalarCreate is like BindScalar, but it allocates the receiver from the type T.
|
||||
func BindScalarCreate[T any](value ...any) (T, bool) {
|
||||
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.
|
||||
func BindScalarCreateWith(t reflect.Type, value ...any) (reflect.Value, bool) {
|
||||
return reflect.Value{}, false
|
||||
func CreateAndBindScalarFor(t reflect.Type, value ...any) (reflect.Value, bool) {
|
||||
return bindScalarCreate(t, value)
|
||||
}
|
||||
|
||||
// ValueByPath defines a field for input to BindFields or BindFieldsCreate. It defines the field by its exact
|
||||
@ -119,7 +119,7 @@ func Fields[T any]() []Field {
|
||||
|
||||
// Fields of is like Fields but uses type t as the input.
|
||||
func FieldsOf(t reflect.Type) []Field {
|
||||
return nil
|
||||
return fieldsOf(t)
|
||||
}
|
||||
|
||||
// FieldValues returns the fields of a structure value recursively. It traverses through pointers, slices and
|
||||
@ -128,21 +128,21 @@ func FieldValues(structure any) []Field {
|
||||
return fieldValuesReflect(structure)
|
||||
}
|
||||
|
||||
// BindFields sets structure fields recursively. It traverses through poitners, slices and interfaces. It
|
||||
// returns the values for which it is not possible to find a compatible matching field. It supports maps that
|
||||
// have string keys and scalar values.
|
||||
func BindFields(structure any, values ...Field) []Field {
|
||||
return bindFieldsReflect(structure, values)
|
||||
// Bind sets structure fields recursively. It traverses through poitners, slices and interfaces. It returns the
|
||||
// values for which it is not possible to find a compatible matching field. It supports maps that have string
|
||||
// keys and scalar values.
|
||||
func Bind(structure any, value ...Field) []Field {
|
||||
return bindFieldsReflect(structure, value)
|
||||
}
|
||||
|
||||
// BindFieldsCreate is like BindFields, but it allocates the receiver from type T.
|
||||
func BindFieldsCreate[T any](values ...Field) (T, []Field) {
|
||||
return bindFieldsCreateReflect[T](values)
|
||||
// CreateAndBind is like Bind, but it allocates the receiver from type T.
|
||||
func CreateAndBind[T any](value ...Field) (T, []Field) {
|
||||
return bindFieldsCreateReflect[T](value)
|
||||
}
|
||||
|
||||
// BindFieldsCreate is like BindFields, but it allocates the receiver from type t.
|
||||
func BindFieldsCreateWith(t reflect.Type, values ...Field) (reflect.Value, []Field) {
|
||||
return reflect.Value{}, nil
|
||||
// CreateAndBindFor is like Bind, but it allocates the receiver from type t.
|
||||
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.
|
||||
@ -152,7 +152,7 @@ func AcceptsScalar[T any]() bool {
|
||||
|
||||
// TypeAcceptsScalar is like AcceptsScalar, but uses type t as input.
|
||||
func TypeAcceptsScalar(t reflect.Type) bool {
|
||||
return false
|
||||
return acceptsScalarChecked(t)
|
||||
}
|
||||
|
||||
// AcceptsFields checks if a type can be used with BindFieldsCreate or the values of the type with BindFields.
|
||||
@ -162,7 +162,7 @@ func AcceptsFields[T any]() bool {
|
||||
|
||||
// TypeAcceptsFields is like AcceptsFields, but uses type t as input.
|
||||
func TypeAcceptsFields(t reflect.Type) bool {
|
||||
return false
|
||||
return acceptsFieldsChecked(t)
|
||||
}
|
||||
|
||||
// AcceptsList checks if a type can be used to bind multiple values.
|
||||
@ -172,7 +172,7 @@ func AcceptsList[T any]() bool {
|
||||
|
||||
// TypeAcceptsList is like AcceptsList, but uses type t as input.
|
||||
func TypeAcceptsList(t reflect.Type) bool {
|
||||
return false
|
||||
return acceptsListChecked(t)
|
||||
}
|
||||
|
||||
// Bindable is the same as AcceptsScalar[T]() || AcceptsFields[T]().
|
||||
@ -182,5 +182,5 @@ func Bindable[T any]() bool {
|
||||
|
||||
// BindableType is like Bindable, but uses type t as input.
|
||||
func BindableType(t reflect.Type) bool {
|
||||
return false
|
||||
return bindableChecked(t)
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package bind_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"code.squareroundforest.org/arpio/bind"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLib(t *testing.T) {
|
||||
|
||||
22
scalar.go
22
scalar.go
@ -56,6 +56,16 @@ func bindScalarCreate(t reflect.Type, values []any) (reflect.Value, bool) {
|
||||
return reflect.Zero(t), false
|
||||
}
|
||||
|
||||
if hasCircularType(t) {
|
||||
return reflect.Zero(t), false
|
||||
}
|
||||
|
||||
for _, vi := range values {
|
||||
if hasCircularReference(reflect.ValueOf(vi)) {
|
||||
return reflect.Zero(t), false
|
||||
}
|
||||
}
|
||||
|
||||
if !acceptsScalar(t) {
|
||||
return reflect.Zero(t), false
|
||||
}
|
||||
@ -89,18 +99,6 @@ func bindScalarReflect(receiver any, values []any) bool {
|
||||
|
||||
func bindScalarCreateReflect[T any](values []any) (T, bool) {
|
||||
t := reflect.TypeFor[T]()
|
||||
if hasCircularType(t) {
|
||||
var tt T
|
||||
return tt, false
|
||||
}
|
||||
|
||||
for _, vi := range values {
|
||||
if hasCircularReference(reflect.ValueOf(vi)) {
|
||||
var tt T
|
||||
return tt, false
|
||||
}
|
||||
}
|
||||
|
||||
v, ok := bindScalarCreate(t, values)
|
||||
if !ok {
|
||||
var tt T
|
||||
|
||||
@ -2,6 +2,7 @@ package bind_test
|
||||
|
||||
import (
|
||||
"code.squareroundforest.org/arpio/bind"
|
||||
"reflect"
|
||||
"slices"
|
||||
"testing"
|
||||
)
|
||||
@ -181,62 +182,62 @@ func TestScalar(t *testing.T) {
|
||||
|
||||
t.Run("bind scalar with create", func(t *testing.T) {
|
||||
t.Run("no value", func(t *testing.T) {
|
||||
if _, ok := bind.BindScalarCreate[int](); ok {
|
||||
if _, ok := bind.CreateAndBindScalar[int](); ok {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("does not accept scalar", func(t *testing.T) {
|
||||
if _, ok := bind.BindScalarCreate[struct{ Foo int }]("42"); ok {
|
||||
if _, ok := bind.CreateAndBindScalar[struct{ Foo int }]("42"); ok {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("empty interface", func(t *testing.T) {
|
||||
if v, ok := bind.BindScalarCreate[any]("42"); !ok || v != "42" {
|
||||
if v, ok := bind.CreateAndBindScalar[any]("42"); !ok || v != "42" {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("scalar", func(t *testing.T) {
|
||||
if v, ok := bind.BindScalarCreate[int]("42"); !ok || v != 42 {
|
||||
if v, ok := bind.CreateAndBindScalar[int]("42"); !ok || v != 42 {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("slice", func(t *testing.T) {
|
||||
if v, ok := bind.BindScalarCreate[[]int]("21", "42", "84"); !ok || !slices.Equal(v, []int{21, 42, 84}) {
|
||||
if v, ok := bind.CreateAndBindScalar[[]int]("21", "42", "84"); !ok || !slices.Equal(v, []int{21, 42, 84}) {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("slice with non-scalar type", func(t *testing.T) {
|
||||
if _, ok := bind.BindScalarCreate[[]func(int)]("21", "42", "84"); ok {
|
||||
if _, ok := bind.CreateAndBindScalar[[]func(int)]("21", "42", "84"); ok {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("pointer to non-scalar", func(t *testing.T) {
|
||||
if _, ok := bind.BindScalarCreate[*func()]("42"); ok {
|
||||
if _, ok := bind.CreateAndBindScalar[*func()]("42"); ok {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("pointer", func(t *testing.T) {
|
||||
if v, ok := bind.BindScalarCreate[*int]("42"); !ok || *v != 42 {
|
||||
if v, ok := bind.CreateAndBindScalar[*int]("42"); !ok || *v != 42 {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("unscannable", func(t *testing.T) {
|
||||
if _, ok := bind.BindScalarCreate[int]("foo"); ok {
|
||||
if _, ok := bind.CreateAndBindScalar[int]("foo"); ok {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("receiver has circular type", func(t *testing.T) {
|
||||
type s []s
|
||||
if _, ok := bind.BindScalarCreate[s]("foo"); ok {
|
||||
if _, ok := bind.CreateAndBindScalar[s]("foo"); ok {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
@ -245,9 +246,16 @@ func TestScalar(t *testing.T) {
|
||||
var v any
|
||||
p := &v
|
||||
*p = p
|
||||
if _, ok := bind.BindScalarCreate[any](p); ok {
|
||||
if _, ok := bind.CreateAndBindScalar[any](p); ok {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("bind with reflection type", func(t *testing.T) {
|
||||
v, ok := bind.CreateAndBindScalarFor(reflect.TypeFor[int](), 42)
|
||||
if !ok || v.Interface() != 42 {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
25
type_test.go
25
type_test.go
@ -2,6 +2,7 @@ package bind_test
|
||||
|
||||
import (
|
||||
"code.squareroundforest.org/arpio/bind"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -274,6 +275,12 @@ func TestTypeChecks(t *testing.T) {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("with reflection type", func(t *testing.T) {
|
||||
if !bind.BindableType(reflect.TypeFor[int]()) {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("circular type", func(t *testing.T) {
|
||||
@ -378,6 +385,12 @@ func TestTypeChecks(t *testing.T) {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("with reflection type", func(t *testing.T) {
|
||||
if !bind.TypeAcceptsScalar(reflect.TypeFor[int]()) {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("fields", func(t *testing.T) {
|
||||
@ -400,6 +413,12 @@ func TestTypeChecks(t *testing.T) {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("with reflection type", func(t *testing.T) {
|
||||
if !bind.TypeAcceptsFields(reflect.TypeFor[struct{ Foo int }]()) {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("list", func(t *testing.T) {
|
||||
@ -421,6 +440,12 @@ func TestTypeChecks(t *testing.T) {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("with reflection type", func(t *testing.T) {
|
||||
if !bind.TypeAcceptsList(reflect.TypeFor[[]int]()) {
|
||||
t.Fatal()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user