Commit Graph

26 Commits

Author SHA1 Message Date
Faye Amacker
dce29d6706 Replace code with StructField.IsExported()
This commit replaces custom code checking of StructField.PkgPath with
calling StructField.IsExported() added in Go 1.17.
2025-05-18 13:53:24 -05:00
Jordan Liggitt
167dc75c19
Add omitzero support
Signed-off-by: Jordan Liggitt <liggitt@google.com>
2025-03-26 09:55:53 -04:00
Faye Amacker
50b362d72f Replace reflect.Ptr with reflect.Pointer
This commit replaces reflect.Ptr with reflect.Pointer,
so go1.18 or newer is required to to build.
2025-02-22 14:20:19 -06:00
Faye Amacker
b426c3e8c6 Lint 2024-05-27 21:21:12 -05:00
Faye Amacker
03575b4950 Refactor code and lint 2024-05-27 15:33:34 -05:00
Ben Luddy
a29413c8fe
Add option to control the output CBOR type of struct field names.
Signed-off-by: Ben Luddy <bluddy@redhat.com>
2024-01-22 11:06:33 -05:00
Faye Amacker
a0ca59b719 Enable more linters 2023-11-11 19:18:43 -06:00
Faye Amacker
58b1cf4afc
Support omitempty for struct & BinaryMarshaler types (#243)
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
2020-08-18 13:19:54 -05:00
Faye Amacker
a26ad4a7e5
Refactor and remove Go's copyright notice in 1 file (#242)
Refactored getFields and other functions.

Removed Go's copyright notice in structfields.go.
2020-07-30 18:35:59 -05:00
Faye Amacker
58b82b5bfc
Add missing attribution (#239)
Added missing attribution in encode_test.go.

Refactored and renamed variables, functions, and types.

Modified documentation.

Closes #233
Closes #237
2020-05-25 22:19:12 -05:00
Faye Amacker
26582a92c4
Include Go's copyright notice to 2 files (#236)
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
2020-05-21 18:38:46 -05:00
Faye Amacker
6de2d8add3
v2.1 CBOR tags, faster CBOR decoding & less memory (#149)
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: #44
Closed: #47
Closed: #125
Closed: #147
Closed: #151
2020-02-14 18:43:04 -06:00
Faye Amacker
158e5313bc
Add v2.0 API, faster CBOR, fewer allocs
Some checks failed
ci / Test on ${{matrix.os}} (ubuntu-latest) (push) Has been cancelled
cover ≥97% / Coverage (push) Has been cancelled
ci / Test on ${{matrix.os}} (macos-latest) (push) Has been cancelled
linters / Lint (push) Has been cancelled
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: #107
Closes: #119
Closes: #120
Closes: #123 
Closes: #124 
Closes: #127
2020-02-02 23:24:18 -06:00
Faye Amacker
0bed4727aa Update copyright to only have year in LICENSE file
Each source file doesn't mention year and LICENSE file has "2019 - present".
2020-01-18 16:45:39 -06:00
Faye Amacker
1e745c3ca0 Rename variables/functions/types for readability
This makes code easier for others to follow.
2019-11-17 19:30:50 -06:00
Faye Amacker
ca1f6f19e3 Group functions by "Uber Go Style Guide"
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.
2019-11-16 22:20:54 -06:00
Faye Amacker
07c82265e1 Decode/encode CBOR array to Go struct
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
2019-11-14 22:32:33 -06:00
Faye Amacker
3cbdc269bc Decode/encode CBOR maps with int keys to Go struct
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
```
2019-11-13 20:53:23 -06:00
Faye Amacker
90423ebb6a Improve encoding speed by caching types
Comparison to last commit db2c0637aa:
benchmark                                               old ns/op     new ns/op     delta
BenchmarkMarshal/Go_bool_to_CBOR_bool-2                 93.4          88.5          -5.25%
BenchmarkMarshal/Go_uint64_to_CBOR_positive_int-2       104           99.2          -4.62%
BenchmarkMarshal/Go_int64_to_CBOR_negative_int-2        97.1          92.7          -4.53%
BenchmarkMarshal/Go_float64_to_CBOR_float-2             102           97.2          -4.71%
BenchmarkMarshal/Go_[]uint8_to_CBOR_bytes-2             131           121           -7.63%
BenchmarkMarshal/Go_string_to_CBOR_text-2               122           121           -0.82%
BenchmarkMarshal/Go_[]int_to_CBOR_array-2               529           480           -9.26%
BenchmarkMarshal/Go_map[string]string_to_CBOR_map-2     2254          2194          -2.66
2019-11-12 21:58:11 -06:00
Faye Amacker
8ea465d2fc Improve encoding speed, reduce mem, refactor
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%
2019-11-11 15:11:55 -06:00
Faye Amacker
726c4236fd Improve decoding speed affected by commit 1a29187
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.
2019-11-07 17:34:28 -06:00
Faye Amacker
29e05d7563 Improve encoding speed by 14%-50%
Cached encoding functions and struct field names to boost speed:
- map 14%
- struct 30%
- slice 50%
2019-10-17 21:20:45 -05:00
Faye Amacker
79019c25d2 Refactor
Replace mutex protected slice with sync.Map.
2019-10-02 21:25:51 -05:00
Faye Amacker
e5d2930fe8 Refactor and increase test coverage to 97.2%
Refactored and removed unreachable code (redundant error/bounds checking).  Added tests for edge cases.  Test coverage is 97.2% (`go test -cover`).
2019-09-15 12:58:07 -05:00
Faye Amacker
8117beb767 Add support for "json" struct field tag
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
2019-09-10 19:40:58 -05:00
Faye Amacker
0cf6159c0f Add go code, tests, benchmarks, and go module. 2019-05-15 21:32:15 -05:00