Struct field with "omitempty" option is omitted during encoding if:
- field is false
- field is 0
- field is empty string, array, slice, or map
- field is null pointer or interface
- field is nil or empty slice for cbor.RawMessage
- (new) field is nil or empty slice for types implementing cbor.BinaryMarshaler
- (new) field is empty struct
Currently "omitempty" option is a no-op for the following types:
- time.Time
- big.Int
- cbor.Tag
- cbor.RawTag
- types implementing cbor.Marshaler
Removed Go's copyright notice in encode.go.
Updated README and LICENSE to remove Go's copyright and license.
Closes#232
Two files contain a small amount of code from the Go standard library.
Add Go's copyright notice to 2 files:
- encode.go
- structfields.go
Updates issue #233, #234
CBOR tag support includes:
- API to use TagSet to register user-defined Go type with CBOR tag number.
- API to encode Go value with CBOR tag number without registering.
- API to extract CBOR tag number with Tag or RawTag structs.
- API to use immutable TagSet or mutable shared TagSet (shared tag registry).
- EncOptions/DecOptions settings to tag or not tag time.Time values.
Improved decoding speed and memory for "keyasint" struct (COSE, CWT, etc.):
- speed is faster by 24% - 28%.
- mem allocs is reduced by 44% - 61%.
- mem bytes is reduced by 13% - 26%.
Encoding is a bit slower around 2% - 4% because of added features. Optimization
of encoding can be tackled in future releases because it is still very fast.
TagSet is a Go interface to register tag support for user-defined Go types.
EncMode and DecMode are reusable interfaces that are safe for concurrency.
They export codec functions with identical signatures to encoding/json.
EncMode can be created by these functions:
EncOptions{...}.EncMode()
EncOptions{...}.EncModeWithTags(TagSet)
EncOptions{...}.EncModeWithSharedTags(TagSet)
DecMode can be created by these functions:
DecOptions{...}.DecMode()
DecOptions{...}.DecModeWithTags(TagSet)
DecOptions{...}.DecModeWithSharedTags(TagSet)
Tag and RawTag are structs used to encode/decode CBOR tag number with tag content.
See docs and closed issues for more details.
Closed: #44Closed: #47Closed: #125Closed: #147Closed: #151
Implement v2.0 API for easier CBOR encoding/decoding. See issue #117 for summary.
Replaced EncOptions.TimeRFC3339 bool with TimeMode values:
* TimeUnix // secs, converted to smallest CBOR integer that fits
* TimeUnixMicro // μs, CBOR float with subsecs in fractional part
* TimeUnixDynamic // secs or μs, either int or float depending on empty subsecs
* TimeRFC3339 // secs, string
* TimeRFC3339Nano // ns, string with trailing zeros removed
Decode CBOR time NaN and Infinity values to Go's "zero time" value.
This is how CBOR Null values are decoded to time.Time.
Removed deprecated options (Canonical & CTAP2Canoical) in EncOptions.
Removed Valid() function.
Improved performance and memory alloc by
* using pointer receivers for types implementing sort.Interface and others.
* storing pointer in sync.Pool.
* storing pointer as map value in sync.Map.
Used roughly 20 linters and resolved many reported issues.
Switched to GitHub Actions for CI to lint, test, and check code coverage.
Extensive improvements to README.md.
Thanks @x448 for API design ideas, travis & github ci configs, filing issues,
and improving README.md.
Closes: #107Closes: #119Closes: #120Closes: #123Closes: #124Closes: #127
Grouped functions according to "Function Grouping and Ordering" rules:
- Functions should be sorted in rough call order.
Exported functions appears first and utility functions towards the end.
- Functions in a file should be be grouped by receiver.
This makes encoded data more compact and structs are easier to use.
type T struct {
_ struct{} `cbor:",toarray"`
A int `cbor:",omitempty"`
B string `cbor:",omitempty"`
}
v := T{A: 1, B: "hello"} // encoded to [1, "hello"]
Special field "_" is used to specify struct level options, such as
"toarray". Any value of T type is encoded as array of 2 elements.
"omitempty" is disabled by "toarray" to ensure that the same number
of elements are encoded every time.
If "toarray" is omitted, "omitempty" works just like encoding/json.
Closes: #30
This simplifies decoding COSE to struct since COSE uses map with
integer keys. Decoding to struct is 42.125% faster than to
map[int]interface{} and 42.105% less B/op. This also benefits
WebAuthn since it uses COSE.
Closes: #15
Struct field name is treated as integer if it has "keyasint" option in
its format string. The format string must specify an integer as its
field name.
```
type T struct {
F1 int `cbor:"1,keyasint"`
F2 int `cbor:"2"`
F3 int `cbor:"-1,keyasint"`
}
v := T{F1: 1, F2: 2, F3: 3}
```
Marshal encodes v as {1: 1, "2": 2, -1: 3}. Note that field F2 is
encoded as "2", not 2, because "keyasint" is not specified.
Benchmarks of decoding COSE to map[int]interface{} vs. struct:
```
BenchmarkDecodeCOSE/COSE_to_Go_map[int]interface_{}-2 1000000 1600 ns/op 456 B/op 13 allocs/op
BenchmarkDecodeCOSE/COSE_to_Go_cbor_test.coseKey-2 2000000 926 ns/op 264 B/op 13 allocs/op
```
Speed/mem improvements:
- Replace range loop with for loop to avoid mem copy when encoding struct.
- Change encodeState's scratch field from [64]byte to [16]byte.
- Change and reorder "field" struct's fields to reduce struct size.
Refactor:
- Rename varaibles and functions.
- Decouple encoding struct type cache and decoding struct type cache.
- Others.
benchmark old ns/op new ns/op delta
BenchmarkMarshal/Go_struct_to_CBOR_map-2 828 728 -12.08%
Adding Unmarshaler decreased decoding speed in commit 1a29187. This
affects all data types.
By caching the result of reflect pkg's Type.Implements() , decoding
speed is improved: slice 28%, struct 19%, map 15%.
I didn't do this for encoding because the gain was too minimal to
justify the added complexity.
To unmarshal a CBOR map into a struct, unmarshal matches CBOR map keys to the
keys in the following priority:
1. "cbor" key in struct field tag,
2. "json" key in struct field tag,
3. struct field name.
Marshalling a struct follows the same rule.
// Field appears in CBOR as key "a".
Field int `cbor:"a"`
// Field appears in CBOR as key "a".
Field int `json:"a"`
// Field appears in CBOR as key "b".
Field int `json:"a" cbor:"b"`
// Field is ignored.
Field int `json:"a" cbor:"-"`
// Field appears in CBOR as key "Field".
Field int