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

feature: Options to support byte string map keys as struct field names #471

Closed
benluddy opened this issue Jan 17, 2024 · 4 comments
Closed

Comments

@benluddy
Copy link
Contributor

Is your feature request related to a problem? Please describe.

I found a gap in the byte string options I contributed recently and I'm not sure whether it should be considered a bug in ByteStringToString or a separate feature request.

I need to support the case where a client encodes map[string]interface{}{"f":1} with the "String" option set to StringToByteString, transmits the CBOR payload to a server which decodes into a struct value with an int64 field and tag f with "ByteStringToString" set to ByteStringToStringAllowed.

Here's a test to illustrate:

func TestUnmarshalFieldNameByteString(t *testing.T) {
	em, err := EncOptions{
		String: StringToByteString,
	}.EncMode()
	if err != nil {
		t.Fatal(err)
	}

	b, err := em.Marshal(map[string]interface{}{
		"f": 1,
	})
	if err != nil {
		t.Fatal(err)
	}

	diagm, err := DiagOptions{
		ByteStringText: true,
	}.DiagMode()
	if err != nil {
		t.Fatal(err)
	}
	diag, err := diagm.Diagnose(b)
	if err != nil {
		t.Fatal(err)
	}
	t.Logf("encoded as: %s\n", diag)

	dm, err := DecOptions{
		ByteStringToString: ByteStringToStringAllowed,
	}.DecMode()
	if err != nil {
		t.Fatal(err)
	}

	var s struct {
		F int64 `json:"f"`
	}
	err = dm.Unmarshal(b, &s)
	if err != nil {
		t.Fatal(err)
	}
}
--- FAIL: TestUnmarshalFieldNameByteString (0.00s)
    decode_test.go:8334: encoded as: {'f': 1}
    decode_test.go:8351: cbor: cannot unmarshal byte string into Go value of type string (map key is of type byte string and cannot be used to match struct field name)

Describe the solution you'd like

A decode option, FieldNameByteString (or similar), that controls whether byte string map keys are forbidden when decoding into a struct (the backwards-compatible default) or allowed. This is consistent with the existing MapKeyByteString and ByteStringToString options which make byte string decode behavior configurable per-destination-type.

Describe alternatives you've considered

  • MapKeyByteString is specified as controlling only decodes of CBOR maps with byte string keys into Go interface values.
  • Initially felt that it would have been intuitive for ByteStringToString to also control decoding byte strings into struct field names, but on reflection I now feel that an option specific to struct destination types would be consistent with existing options.

Additional context

@fxamacker
Copy link
Owner

I found a gap in the byte string options I contributed recently and I'm not sure whether it should be considered a bug in ByteStringToString or a separate feature request.

@benluddy Thanks for spotting this! 👍

I also initially preferred modifying ByteStringToString but you make a great point about more consistency with existing options.

Maybe new decoding option could be named StructFieldNameByteString (or similar). Please feel free to open PR to add new decoding option (or if you prefer, I can add this during one of the remaining weekends this month).

Thanks again!

@benluddy
Copy link
Contributor Author

Great, I'll open a PR today.

On a related note, I realized after filing this issue that the behavior of the StringMode encode option similarly doesn't affect the CBOR type for struct fields. It would be impossible for a struct field name to be an invalid UTF-8 sequence, due to the syntax of Go identifiers, and it would be very strange for a field tag to be an invalid UTF-8 sequence (you'd have to go out of your way to do this with escape sequences in a tag), so I'm not concerned about producing invalid CBOR text strings. It does mean that validating decoders must validate all field names, and avoiding that overhead is one of the reasons a user would choose this option.

Does a parallel encode option to set the struct field string type sound reasonable to you? It's not my use case, but I can imagine being unwilling/unable to validate/sanitize string values on the encoder side and still encoding struct field names (which we're practically sure are valid) as CBOR text strings.

@benluddy benluddy changed the title feature: Option to allow decoding CBOR map with byte string keys as struct field names feature: Options to support byte string map keys as struct field names Jan 18, 2024
@benluddy
Copy link
Contributor Author

I included options for both encode and decode directions in #472.

@fxamacker
Copy link
Owner

Closed by #472

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

2 participants