Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v3: Feature Request: Decoder/Encoder Options #639

Open
abursavich opened this issue Jul 31, 2020 · 3 comments
Open

v3: Feature Request: Decoder/Encoder Options #639

abursavich opened this issue Jul 31, 2020 · 3 comments

Comments

@abursavich
Copy link

abursavich commented Jul 31, 2020

I was trying to upgrade a project from v2 to v3 and found liberal uses of yaml.UmarshalStrict which is no longer available in v3. I assume the removal of that function was a conscious decision and UnmarshalStrict is being avoided along with MarshalIndent.

Instead of having to wrap the bytes with a bytes.Reader, create a Decoder, call dec.KnownFields(true), then Decode, I think it would be more ergonomic to have options for Marshal/Unmarshal and/or NewDecoder/NewEncoder.

type DecoderOption func(*Decoder)

func KnownFields(enable bool) DecoderOption {
    return func(d *Decoder) { d.KnownFields(enable) }
}

func NewDecoder(r io.Reader, options ...DecoderOption) *Decoder { /* ... */ }

func Unmarshal(in []byte, out interface{}, options ...DecoderOption) error { /* ... */ }

type EncoderOption func(*Encoder)

func SetIndent(spaces int) EncoderOption {
    return func(e *Encoder) { e.SetIndent(spaces) }
}

func NewEncoder(w io.Writer, options ...EncoderOption) *Encoder { /* ... */ }

func Marshal(in interface{}, options ...EncoderOption) ([]byte, error) { /* ... */ }

This would allow:

if err := yaml.Unmarshal(b, &out, yaml.KnownFields(true)); err != nil { /* ... */ }
// or
if err := yaml.NewDecoder(r, yaml.KnownFields(true)).Decode(&out); err != nil { /* ... */ }

Similar for Marshal and SetIndent.

Or just add UnmarshalStrict and MarshalIndent functions :)

@abursavich
Copy link
Author

Continuing to convert the code from v2 to v3, I found a subtle bug that might hit other people. Unmarshal and Decode handle empty buffers differently.

yaml.Unmarshal([]byte{}, &out) == nil
yaml.NewDecoder(bytes.NewReader([]byte{})).Decode(&out) == io.EOF

Naively replacing:

if err := yaml.UnmarshalStrict(b, &out); err != nil { /* ... */ }

with:

dec := yaml.NewDecoder(bytes.NewReader(b))
dec.KnownFields(true)
if err := dec.Decode(&out); err != nil { /* ... */ }

won't work.

To maintain the existing behavior, you also need to check for io.EOF:

dec := yaml.NewDecoder(bytes.NewReader(b))
dec.KnownFields(true)
if err := dec.Decode(&out); err != nil && err != io.EOF { /* ... */ }

@abursavich abursavich changed the title Feature Request: Decoder/Encoder Options v3: Feature Request: Decoder/Encoder Options or UnmarshalStrict/MarshalIndent functions Aug 1, 2020
@abursavich abursavich changed the title v3: Feature Request: Decoder/Encoder Options or UnmarshalStrict/MarshalIndent functions v3: Feature Request: Decoder/Encoder Options Aug 1, 2020
@anthonyraymond
Copy link

Great idea, i'd like to have it

@lzh-lab
Copy link

lzh-lab commented Nov 12, 2021

Maybe restoring yaml.UmarshalStrict is a much more desirable one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants