go-bare: allow unions to roundtrip without errors v1 PROPOSED

~mvdan: 1
 allow unions to roundtrip without errors

 2 files changed, 28 insertions(+), 1 deletions(-)
#334273 .build.yml success
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~sircmpwn/public-inbox/patches/14700/mbox | git am -3
Learn more about email & git
View this thread in the archives

[PATCH go-bare] allow unions to roundtrip without errors Export this patch

From: Daniel Martí <mvdan@mvdan.cc>

If a union contains a type T, when decoding into a struct field of said
union type, we would end up with a value of type *T.

This is fine for Unmarshal itself. However, Marshal errors when it
encounters *T instead of T for that union, because the ut.tags map does
not contain *T.

Teach it to reach past the pointer if it encounters *T instead of T, so
that it can encode the type T. Add a simple test round-tripping what's
explained above, which fails without the fix:

		Error Trace: marshal_test.go:274
		Error:       Expected nil, but got: &errors.errorString{s:"Invalid union value: <*bare.Age Value>"}
		Test:        TestRoundtrip
 marshal.go      |  8 +++++++-
 marshal_test.go | 21 +++++++++++++++++++++
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/marshal.go b/marshal.go
index 737bf6b..55acce7 100644
--- a/marshal.go
+++ b/marshal.go
@@ -212,7 +212,13 @@ func encodeUnion(t reflect.Type) encodeFunc {

	return func(w *Writer, v reflect.Value) error {
		tag, ok := ut.tags[v.Elem().Type()]
		t := v.Elem().Type()
		if t.Kind() == reflect.Ptr {
			// If T is a valid union value type, *T is valid too.
			t = t.Elem()
			v = v.Elem()
		tag, ok := ut.tags[t]
		if !ok {
			return fmt.Errorf("Invalid union value: %s", v.Elem().String())
diff --git a/marshal_test.go b/marshal_test.go
index 91f028f..093100a 100644
--- a/marshal_test.go
+++ b/marshal_test.go
@@ -255,6 +255,27 @@ func TestMarshalUnion(t *testing.T) {
	assert.Equal(t, reference, data)

func TestRoundtrip(t *testing.T) {
	type T struct {
		// Ensure that unions roundtrip correctly.
		NameAge NameAge
	val := T{
		NameAge: Age(25),
	data, err := Marshal(&val)
	assert.Nil(t, err)

	var val2 T
	err = Unmarshal(data, &val2)
	assert.Nil(t, err)

	data2, err := Marshal(&val2)
	assert.Nil(t, err)

	assert.Equal(t, data, data2)

func TestMarshalCustom(t *testing.T) {
	var val = Custom(0x42)
	data, err := Marshal(&val)
go-bare/patches/.build.yml: SUCCESS in 29s

[allow unions to roundtrip without errors][0] from [~mvdan][1]

[0]: https://lists.sr.ht/~sircmpwn/public-inbox/patches/14700
[1]: mailto:mvdan@mvdan.cc

✓ #334273 SUCCESS go-bare/patches/.build.yml https://builds.sr.ht/~sircmpwn/job/334273

To git@git.sr.ht:~sircmpwn/go-bare
   29260d4..  master -> master