WIP constructing pointers

This commit is contained in:
Thomas Pelletier
2021-02-18 21:24:26 -05:00
parent 1f41c556e8
commit 46573551f1
4 changed files with 89 additions and 23 deletions
+41 -6
View File
@@ -44,7 +44,6 @@ func (b *Builder) getOrGenerateFieldGettersRecursive(m structFieldGetters, idx [
// only consider exported fields
continue
}
// TODO: handle embedded structs
if f.Anonymous {
b.getOrGenerateFieldGettersRecursive(m, copyAndAppend(idx, i), f.Type)
} else {
@@ -223,6 +222,10 @@ func (b *Builder) IsSlice() bool {
return b.top().Kind() == reflect.Slice
}
func (b *Builder) IsSliceOrPtr() bool {
return b.top().Kind() == reflect.Slice || (b.top().Kind() == reflect.Ptr && b.top().Type().Elem().Kind() == reflect.Slice)
}
// Last moves the cursor to the last value of the current value.
// For a slice or an array, it is the last element they contain, if any.
// For anything else, it's a no-op.
@@ -269,12 +272,40 @@ func (b *Builder) SliceNewElem() error {
return nil
}
func assertPtr(v reflect.Value) {
if v.Kind() != reflect.Ptr {
panic(fmt.Sprintf("value '%s' should be a ptr, not '%s'", v, v.Kind()))
}
}
func (b *Builder) SliceAppend(v reflect.Value) error {
assertPtr(v)
t := b.top()
// pointer to a slice
if t.Kind() == reflect.Ptr {
// if the pointer is nil we need to allocate the slice
if t.IsNil() {
x := reflect.New(t.Type().Elem())
t.Set(x)
}
// target the slice itself
t = t.Elem()
}
err := checkKind(t.Type(), reflect.Slice)
if err != nil {
return err
}
if t.Type().Elem().Kind() == reflect.Ptr {
// if it is a slice of pointers, we can just append
} else {
// otherwise we need to reference the value
v = v.Elem()
}
newSlice := reflect.Append(t, v)
t.Set(newSlice)
b.replace(t.Index(t.Len() - 1))
@@ -286,12 +317,16 @@ func (b *Builder) SliceAppend(v reflect.Value) error {
func (b *Builder) SetString(s string) error {
t := b.top()
err := checkKind(t.Type(), reflect.String)
if err != nil {
return err
}
if t.Kind() == reflect.Ptr {
t.Set(reflect.ValueOf(&s))
} else {
err := checkKind(t.Type(), reflect.String)
if err != nil {
return err
}
t.SetString(s)
t.SetString(s)
}
return nil
}
@@ -165,3 +165,41 @@ func TestCursor(t *testing.T) {
require.NoError(t, b.DigField("Field"))
assert.Equal(t, b.Cursor().Kind(), reflect.String)
}
func TestStringPtr(t *testing.T) {
x := struct {
Field *string
}{}
b, err := reflectbuild.NewBuilder("", &x)
require.NoError(t, err)
assert.Equal(t, b.Cursor().Kind(), reflect.Struct)
require.NoError(t, b.DigField("Field"))
assert.NoError(t, b.SetString("A"))
assert.Equal(t, "A", *x.Field)
}
func TestAppendSlicePtr(t *testing.T) {
x := struct {
Field *[]string
}{}
b, err := reflectbuild.NewBuilder("", &x)
require.NoError(t, err)
assert.Equal(t, b.Cursor().Kind(), reflect.Struct)
require.NoError(t, b.DigField("Field"))
v := "A"
assert.NoError(t, b.SliceAppend(reflect.ValueOf(&v)))
assert.Equal(t, []string{"A"}, *x.Field)
}
func TestAppendPtrSlicePtr(t *testing.T) {
x := struct {
Field *[]*string
}{}
b, err := reflectbuild.NewBuilder("", &x)
require.NoError(t, err)
assert.Equal(t, b.Cursor().Kind(), reflect.Struct)
require.NoError(t, b.DigField("Field"))
v := "A"
assert.NoError(t, b.SliceAppend(reflect.ValueOf(&v)))
assert.Equal(t, "A", *(*x.Field)[0])
}