-
Notifications
You must be signed in to change notification settings - Fork 67
feature: Support JSON Tag 262? #657
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
Comments
@theory yes the alternative approach you considered works if you use https://go.dev/play/p/bjXlFdYTg_P // Example program for:
// https://github.com/fxamacker/cbor/issues/657
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/fxamacker/cbor/v2"
)
type JSON struct {
any
}
func NewJSON(val any) JSON { return JSON{val} }
func (jt JSON) MarshalCBOR() ([]byte, error) {
data, err := jt.MarshalJSON()
if err != nil {
return nil, err
}
// IMPORTANT: Need to use cbor.Tag (instead of cbor.RawTag) here.
// Only use cbor.RawTag if tag.Content is already encoded in CBOR.
tag := cbor.Tag{Number: 262, Content: data}
return cbor.Marshal(tag)
}
func (jt *JSON) UnmarshalCBOR(b []byte) error {
var tag cbor.Tag
if err := cbor.Unmarshal(b, &tag); err != nil {
return err
}
// Check if tag number is 262.
if tag.Number != 262 {
return fmt.Errorf("failed to unmarshal to JSON: got tag number %d, expect tag number %d", tag.Number, 262)
}
// Check if tag content is []byte.
switch content := tag.Content.(type) {
case []byte:
return jt.UnmarshalJSON(content)
default:
return fmt.Errorf("failed to unmarshal to JSON: got tag content type %T, expect tag content []byte", tag.Content)
}
}
func (jt JSON) MarshalJSON() ([]byte, error) {
return json.Marshal(jt.any)
}
func (jt *JSON) UnmarshalJSON(b []byte) error {
enc := json.NewDecoder(bytes.NewReader(b))
enc.UseNumber()
return enc.Decode(&jt.any)
}
func main() {
user := NewJSON(map[string]any{
"name": "theory",
"id": json.Number("1024"),
})
data, err := cbor.Marshal(user)
if err != nil {
panic(err)
}
edn, _ := cbor.Diagnose(data)
fmt.Printf("encoded CBOR is %d bytes because this example includes JSON encoding embedded inside CBOR.\n", len(data))
fmt.Printf(" Hex: %x\n", data)
fmt.Printf(" EDN: %s\n", edn)
var v JSON
err = cbor.Unmarshal(data, &v)
if err != nil {
panic(err)
}
fmt.Printf("decoded v.any: %+v\n", v.any)
for k, v := range v.any.(map[string]interface{}) {
fmt.Printf(" key: %s, value: %v (%T)\n", k, v, v)
}
} Program outputs:
In general, I prefer not adding extra CBOR tags (defined outside RFC 8949) if this library has API that allows users to add support for those tags (as in your example code with one minor tweak). Please let me know if this works for you. |
Ah, thank you, very nice. Might I suggest adding this or something similar as an example? |
Sounds good! I'll add this or something similar as an example next weekend (April 26-27). |
Is your feature request related to a problem? Please describe.
I inquired with the CBOR mail list about adding a tag for JSON numbers as string, toward having an official tag number to use for the pattern I posted in #441. They suggested that tag 262, an embedded JSON value, might also apply. However, since encoding/json values into
any
except forjson.Number
resolve to core Go types, and will vary, I can't see a clear way to register 262 withTagSet.Add
.Describe the solution you'd like
Either formal support for tag 262 or else some sort of way to register a tag that resolves to more than one type.
Describe alternatives you've considered
I tried to create a JSON type that wraps JSON values:
However, an attempt to marshal a value of this type fails; I probably don't fully understand the RawTag bit:
Output:
Am I on the right track?
The text was updated successfully, but these errors were encountered: