goccy / go-yaml

YAML support for the Go language

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

req: better docs around InterfaceMarshaler/InterfaceUnmarshaler

nergdron opened this issue · comments

Is your feature request related to a problem? Please describe.
I'm trying to wrap Masterminds/semver's Version type with a custom (un)marshaler. However, when I write an UnmarshalYAML for it, I get an error I don't understand trying to unmarshal the simple string field in my YAML file.

Describe the solution you'd like
It'd be great to have examples of unmarshaling custom types from basic, complex, and nested YAML fields in the docs, to make it clear how this is supposed to function. the Canonical YAML lib has already moved away from this interface, and instead provides direct *Node access when parsing, so it's been hard finding any examples of what I'm trying to do (parse a string field to a more nuanced type).

Describe alternatives you've considered
I could probably implement this by implementing the BytesUnmarshaler interface instead, but the docs indicate that InterfaceUnmarshaler is more efficient, and my use case involves rapidly generating a lot of YAML from a constantly changing dataset, so I'd really like to figure out how to implement this correctly.

Additional context
Here's my current implementation:

type Data struct {
  Version
}

type Version semver.Version

// UnmarshalYAML is a custom unmarshaler for go-yaml.
func (V *Version) UnmarshalYAML(unmarshal func(interface{}) error) (err error) {
	var raw string
	if err = unmarshal(&raw); err != nil {
		return err
	}

	v, err := semver.NewVersion(raw)
	if err != nil {
		return err
	}
	*V = (Version)(*v)

	return nil
}

// MarshalYAML is a custom marshaler for go-yaml.
func (V *Version) MarshalYAML() (i interface{}, err error) {
	s := (*semver.Version)(V).String()
	return s, nil
}

here's my test YAML file:

version: 0.0.1

when trying to unmarshal the above YAML into a Data struct, I get the following error:

=== RUN   TestValidation
    schema_v0_test.go:35: [1:8] cannot unmarshal map[string]interface {} into Go value of type string
            >  1 | version: "0.0.1"
                          ^
    schema_v0_test.go:27: 0.0.0
        
--- FAIL: TestValidation (0.00s)
FAIL
exit status 1

I really don't understand why it thinks this field is a map, when it's just a simple string field. and when I tested unmarshaling it to a map[string]string, the library seems to unmarshal the whole document into a map, rather than the specific field I'm trying to parse. so I clearly don't understand how this is supposed to work. 😅