Repository: fxamacker/cbor
Pull request #108 (2020-01-23 05:29:53)

Change to v2.0 API to add options for decoding, CBOR tags, and more
- [x] Most frequently used functions have same params and return type as encoding/json like: Marshal(), Unmarshal(), NewEncoder(), NewDecoder(), encoder.Encode(), decoder.Decode().
- [x] Unmarshaler interface's UnmarshalCBOR() receives DecMode as a parameter.
- [x] Marshaler interface's MarshalCBOR() receives EncMode as a parameter.
- [x] EncOptions and DecOptions are only used to create modes.
- [x] EncOptions exports EncMode() to create encoding mode without tag support.
- [x] DecOptions exports DecMode() to create decoding mode without tag support.
- [x] EncMode and DecMode are interfaces with immutable options and tags.
- [x] EncMode has EncOptions() method to export options and similar for DecMode.
- [x] Code cleanup using around 20 linters.
- [x] Remove deprecated options
- [x] Make time related options more flexible in case something comes up in the future.

__API Summary__
EncMode and DecMode are interfaces created from EncOptions or DecOptions structs.

EncMode and DecMode use immutable options so their behavior doesn't accidentally change at runtime.  Modes are intended to be reused and are safe for concurrent use.

EncOptions.EncMode() returns new EncMode interface with immutable options.

In v2, more function signatures match encoding/json.

Examples:

* Marshal data with default options
```
b, err := cbor.Marshal(v)
```

* Marshal data with non-default options
```
em, _ := cbor.CanonicalEncOptions().EncMode()
b, err := em.Marshal(v)
```

See Issue #107 for initial v2 API design.  Issue #117 tracks release v2.0.

x448: As discussed, started fuzz testing for release v2.0 -- it won't be restarted if changes before tagging are limited to docs and tests.

Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5d15970..91cdbd6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,32 +1,10 @@
-# GitHub Actions - CI for Go to build & test.  See ci-go-cover.yml for code coverage.
+# GitHub Actions - CI for Go to build & test.  See ci-go-cover.yml and linters.yml for code coverage and linters.
 # https://github.com/fxamacker/cbor/workflows/ci.yml
 name: ci
 on: [push]
 jobs:
 
-  # Check linters on latest-ubuntu with default version of Go.
-  lint:
-    name: Lint
-    runs-on: ubuntu-latest
-    steps:
-    - name: Checkout code
-      uses: actions/checkout@v1
-      with:
-        fetch-depth: 2
-    - name: Install golangci-lint 
-      run: |
-        go version
-        curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.23.1
-    - name: Run required linters in .golangci.yml plus hard-coded ones here
-      # TODO: remove --issues-exit-code=0 after deciding which linters are required vs optional.
-      run: $(go env GOPATH)/bin/golangci-lint run --timeout=5m --issues-exit-code=0 -E deadcode -E errcheck -E gofmt -E golint -E gosec -E govet -E ineffassign -E maligned -E staticcheck -E structcheck -E unconvert -E varcheck
-    - name: Run optional linters (not required to pass)
-      run: $(go env GOPATH)/bin/golangci-lint run --timeout=5m --issues-exit-code=0 -E dupl -E gocritic -E gosimple -E lll -E prealloc -E deadcode -E errcheck -E gofmt -E golint -E gosec -E govet -E ineffassign -E maligned -E staticcheck -E structcheck -E unconvert -E varcheck
-
   # Test on various OS with default Go version. 
-  # As of January 26, 2020: 
-  # 1. Specifying Go version adds 10s because it gets installed. Someday, maybe latest 2-3 versions will be preinstalled + symlink used.
-  # 2. It takes windows-latest around 47s while others take 6s-16s.  Not sure if Nano is used or a more full-featured (slower) Windows.
   tests:
     name: Test on ${{matrix.os}}
     runs-on: ${{ matrix.os }}
diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml
new file mode 100644
index 0000000..3958f60
--- /dev/null
+++ b/.github/workflows/linters.yml
@@ -0,0 +1,21 @@
+# Go Linters - GitHub Actions
+name: linters
+on: [push]
+jobs:
+
+  # Check linters on latest-ubuntu with default version of Go.
+  lint:
+    name: Lint
+    runs-on: ubuntu-latest
+    steps:
+    - name: Checkout code
+      uses: actions/checkout@v2
+    - name: Install golangci-lint 
+      run: |
+        go version
+        curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.23.1
+    - name: Run required linters in .golangci.yml plus hard-coded ones here
+      run: $(go env GOPATH)/bin/golangci-lint run --timeout=5m -E deadcode -E errcheck -E gofmt -E golint -E gosec -E govet -E ineffassign -E maligned -E staticcheck -E structcheck -E unconvert -E varcheck
+    - name: Run optional linters (not required to pass)
+      run: $(go env GOPATH)/bin/golangci-lint run --timeout=5m --issues-exit-code=0 -E dupl -E gocritic -E gosimple -E lll -E prealloc -E deadcode -E errcheck -E gofmt -E golint -E gosec -E govet -E ineffassign -E maligned -E staticcheck -E structcheck -E unconvert -E varcheck
+
diff --git a/.golangci.yml b/.golangci.yml
index 1bb8b87..227fc40 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -8,7 +8,7 @@ linters-settings:
     statements: 50
   goconst:
     min-len: 2
-    min-occurrences: 2
+    min-occurrences: 3
   gocritic:
     enabled-tags:
       - diagnostic
@@ -62,6 +62,10 @@ linters:
 
 
 issues:
+  # max-issues-per-linter default is 50.  Set to 0 to disable limit.
+  max-issues-per-linter: 0
+  # max-same-issues default is 3.  Set to 0 to disable limit.
+  max-same-issues: 0
   # Excluding configuration per-path, per-linter, per-text and per-source
   exclude-rules:
     - path: _test\.go
diff --git a/CBOR_BENCHMARKS.md b/CBOR_BENCHMARKS.md
index e3dbe18..aaa4ee1 100644
--- a/CBOR_BENCHMARKS.md
+++ b/CBOR_BENCHMARKS.md
@@ -26,34 +26,34 @@ Benchmarks use data representing the following values:
 
 Decoding Benchmark | Time | Memory | Allocs 
 --- | ---: | ---: | ---:
-BenchmarkUnmarshal/CBOR_bool_to_Go_interface_{}-2 | 117 ns/op | 16 B/op | 1 allocs/op
-BenchmarkUnmarshal/CBOR_bool_to_Go_bool-2 | 91.4 ns/op | 1 B/op | 1 allocs/op
-BenchmarkUnmarshal/CBOR_positive_int_to_Go_interface_{}-2 | 140 ns/op | 24 B/op | 2 allocs/op
-BenchmarkUnmarshal/CBOR_positive_int_to_Go_uint64-2 | 103 ns/op | 8 B/op | 1 allocs/op
-BenchmarkUnmarshal/CBOR_negative_int_to_Go_interface_{}-2 | 139 ns/op | 24 B/op | 2 allocs/op
-BenchmarkUnmarshal/CBOR_negative_int_to_Go_int64-2 | 102 ns/op | 8 B/op | 1 allocs/op
-BenchmarkUnmarshal/CBOR_float_to_Go_interface_{}-2 | 141 ns/op | 24 B/op | 2 allocs/op
+BenchmarkUnmarshal/CBOR_bool_to_Go_interface_{}-2 | 115 ns/op | 16 B/op | 1 allocs/op
+BenchmarkUnmarshal/CBOR_bool_to_Go_bool-2 | 91.1 ns/op | 1 B/op | 1 allocs/op
+BenchmarkUnmarshal/CBOR_positive_int_to_Go_interface_{}-2 | 138 ns/op | 24 B/op | 2 allocs/op
+BenchmarkUnmarshal/CBOR_positive_int_to_Go_uint64-2 | 104 ns/op | 8 B/op | 1 allocs/op
+BenchmarkUnmarshal/CBOR_negative_int_to_Go_interface_{}-2 | 138 ns/op | 24 B/op | 2 allocs/op
+BenchmarkUnmarshal/CBOR_negative_int_to_Go_int64-2 | 104 ns/op | 8 B/op | 1 allocs/op
+BenchmarkUnmarshal/CBOR_float_to_Go_interface_{}-2 | 139 ns/op | 24 B/op | 2 allocs/op
 BenchmarkUnmarshal/CBOR_float_to_Go_float64-2 | 102 ns/op | 8 B/op | 1 allocs/op
-BenchmarkUnmarshal/CBOR_bytes_to_Go_interface_{}-2 | 186 ns/op | 80 B/op | 3 allocs/op
-BenchmarkUnmarshal/CBOR_bytes_to_Go_[]uint8-2 | 189 ns/op | 64 B/op | 2 allocs/op
-BenchmarkUnmarshal/CBOR_text_to_Go_interface_{}-2 | 220 ns/op | 80 B/op | 3 allocs/op
-BenchmarkUnmarshal/CBOR_text_to_Go_string-2 | 182 ns/op | 64 B/op | 2 allocs/op
-BenchmarkUnmarshal/CBOR_array_to_Go_interface_{}-2 |1190 ns/op | 672 B/op | 29 allocs/op
-BenchmarkUnmarshal/CBOR_array_to_Go_[]int-2 | 1177 ns/op | 272 B/op | 3 allocs/op
-BenchmarkUnmarshal/CBOR_map_to_Go_interface_{}-2 | 3021 ns/op | 1421 B/op | 30 allocs/op
-BenchmarkUnmarshal/CBOR_map_to_Go_map[string]interface_{}-2 | 3961 ns/op | 964 B/op | 19 allocs/op
-BenchmarkUnmarshal/CBOR_map_to_Go_map[string]string-2 | 2732 ns/op | 741 B/op | 5 allocs/op
+BenchmarkUnmarshal/CBOR_bytes_to_Go_interface_{}-2 | 181 ns/op | 80 B/op | 3 allocs/op
+BenchmarkUnmarshal/CBOR_bytes_to_Go_[]uint8-2 | 190 ns/op | 64 B/op | 2 allocs/op
+BenchmarkUnmarshal/CBOR_text_to_Go_interface_{}-2 | 211 ns/op | 80 B/op | 3 allocs/op
+BenchmarkUnmarshal/CBOR_text_to_Go_string-2 | 181 ns/op | 64 B/op | 2 allocs/op
+BenchmarkUnmarshal/CBOR_array_to_Go_interface_{}-2 |1147 ns/op | 672 B/op | 29 allocs/op
+BenchmarkUnmarshal/CBOR_array_to_Go_[]int-2 | 1138 ns/op | 272 B/op | 3 allocs/op
+BenchmarkUnmarshal/CBOR_map_to_Go_interface_{}-2 | 2962 ns/op | 1420 B/op | 30 allocs/op
+BenchmarkUnmarshal/CBOR_map_to_Go_map[string]interface_{}-2 | 3849 ns/op | 964 B/op | 19 allocs/op
+BenchmarkUnmarshal/CBOR_map_to_Go_map[string]string-2 | 2654 ns/op | 740 B/op | 5 allocs/op
 
 Encoding Benchmark | Time | Memory | Allocs 
 --- | ---: | ---: | ---:
-BenchmarkMarshal/Go_bool_to_CBOR_bool-2 | 89.2 ns/op	| 1 B/op | 1 allocs/op
-BenchmarkMarshal/Go_uint64_to_CBOR_positive_int-2 | 99.2 ns/op | 16 B/op | 1 allocs/op
-BenchmarkMarshal/Go_int64_to_CBOR_negative_int-2 | 92.6 ns/op | 3 B/op | 1 allocs/op
-BenchmarkMarshal/Go_float64_to_CBOR_float-2 | 99.5 ns/op	| 16 B/op | 1 allocs/op
-BenchmarkMarshal/Go_[]uint8_to_CBOR_bytes-2 | 124 ns/op | 32 B/op	| 1 allocs/op
-BenchmarkMarshal/Go_string_to_CBOR_text-2 | 121 ns/op | 48 B/op | 1 allocs/op
-BenchmarkMarshal/Go_[]int_to_CBOR_array-2 | 490 ns/op | 32 B/op	| 1 allocs/op
-BenchmarkMarshal/Go_map[string]string_to_CBOR_map-2 | 2189 ns/op | 576 B/op | 28 allocs/op
+BenchmarkMarshal/Go_bool_to_CBOR_bool-2 | 83.3 ns/op	| 1 B/op | 1 allocs/op
+BenchmarkMarshal/Go_uint64_to_CBOR_positive_int-2 | 93.4 ns/op | 16 B/op | 1 allocs/op
+BenchmarkMarshal/Go_int64_to_CBOR_negative_int-2 | 88.3 ns/op | 3 B/op | 1 allocs/op
+BenchmarkMarshal/Go_float64_to_CBOR_float-2 | 95.4 ns/op	| 16 B/op | 1 allocs/op
+BenchmarkMarshal/Go_[]uint8_to_CBOR_bytes-2 | 119 ns/op | 32 B/op	| 1 allocs/op
+BenchmarkMarshal/Go_string_to_CBOR_text-2 | 114 ns/op | 48 B/op | 1 allocs/op
+BenchmarkMarshal/Go_[]int_to_CBOR_array-2 | 470 ns/op | 32 B/op	| 1 allocs/op
+BenchmarkMarshal/Go_map[string]string_to_CBOR_map-2 | 2064 ns/op | 576 B/op | 28 allocs/op
 
 ## Go structs
 
@@ -74,13 +74,13 @@ Benchmarks use struct and map[string]interface{} representing the following valu
 
 Decoding Benchmark | Time | Memory | Allocs 
 --- | ---: | ---: | ---:
-BenchmarkUnmarshal/CBOR_map_to_Go_map[string]interface{}-2 | 6693 ns/op | 2621 B/op | 73 allocs/op
-BenchmarkUnmarshal/CBOR_map_to_Go_struct-2 | 4694 ns/op | 1172 B/op | 10 allocs/op
+BenchmarkUnmarshal/CBOR_map_to_Go_map[string]interface{}-2 | 6380 ns/op | 2620 B/op | 73 allocs/op
+BenchmarkUnmarshal/CBOR_map_to_Go_struct-2 | 4603 ns/op | 1173 B/op | 10 allocs/op
 
 Encoding Benchmark | Time | Memory | Allocs 
 --- | ---: | ---: | ---:
-BenchmarkMarshal/Go_map[string]interface{}_to_CBOR_map-2 | 4638 ns/op | 1072 B/op | 45 allocs/op
-BenchmarkMarshal/Go_struct_to_CBOR_map-2 | 2994 ns/op | 720 B/op | 28 allocs/op
+BenchmarkMarshal/Go_map[string]interface{}_to_CBOR_map-2 | 4394 ns/op | 1072 B/op | 45 allocs/op
+BenchmarkMarshal/Go_struct_to_CBOR_map-2 | 2770 ns/op | 720 B/op | 28 allocs/op
 
 ## Go structs with "keyasint" struct tag
 
@@ -116,13 +116,13 @@ type T struct {
 
 Decoding Benchmark | Time | Memory | Allocs 
 --- | ---: | ---: | ---:
-BenchmarkUnmarshal/CBOR_map_to_Go_map[int]interface{}-2| 6525 ns/op | 2516 B/op | 70 allocs/op
-BenchmarkUnmarshal/CBOR_map_to_Go_struct_keyasint-2 | 4881 ns/op | 1236 B/op | 18 allocs/op
+BenchmarkUnmarshal/CBOR_map_to_Go_map[int]interface{}-2| 6222 ns/op | 2516 B/op | 70 allocs/op
+BenchmarkUnmarshal/CBOR_map_to_Go_struct_keyasint-2 | 4782 ns/op | 1237 B/op | 18 allocs/op
 
 Encoding Benchmark | Time | Memory | Allocs 
 --- | ---: | ---: | ---:
-BenchmarkMarshal/Go_map[int]interface{}_to_CBOR_map-2 | 4469 ns/op | 992 B/op | 45 allocs/op
-BenchmarkMarshal/Go_struct_keyasint_to_CBOR_map-2 | 3011 ns/op | 704 B/op | 28 allocs/op
+BenchmarkMarshal/Go_map[int]interface{}_to_CBOR_map-2 | 4307 ns/op | 992 B/op | 45 allocs/op
+BenchmarkMarshal/Go_struct_keyasint_to_CBOR_map-2 | 2777 ns/op | 704 B/op | 28 allocs/op
 
 ## Go structs with "toarray" struct tag
 
@@ -159,13 +159,13 @@ type T struct {
 
 Decoding Benchmark | Time | Memory | Allocs 
 --- | ---: | ---: | ---:
-BenchmarkUnmarshal/CBOR_array_to_Go_[]interface{}-2 | 5186 ns/op | 2404 B/op | 67 allocs/op
-BenchmarkUnmarshal/CBOR_array_to_Go_struct_toarray-2 | 4443 ns/op | 1165 B/op | 9 allocs/op
+BenchmarkUnmarshal/CBOR_array_to_Go_[]interface{}-2 | 5010 ns/op | 2404 B/op | 67 allocs/op
+BenchmarkUnmarshal/CBOR_array_to_Go_struct_toarray-2 | 4301 ns/op | 1164 B/op | 9 allocs/op
 
 Encoding Benchmark | Time | Memory | Allocs 
 --- | ---: | ---: | ---:
-BenchmarkMarshal/Go_[]interface{}_to_CBOR_map-2 | 3352 ns/op | 704 B/op | 28 allocs/op
-BenchmarkMarshal/Go_struct_toarray_to_CBOR_array-2 | 3024 ns/op | 704 B/op | 28 allocs/op
+BenchmarkMarshal/Go_[]interface{}_to_CBOR_map-2 | 3128 ns/op | 704 B/op | 28 allocs/op
+BenchmarkMarshal/Go_struct_toarray_to_CBOR_array-2 | 2741 ns/op | 704 B/op | 28 allocs/op
 
 ## COSE data
 
@@ -205,15 +205,15 @@ Benchmarks use COSE data from https://tools.ietf.org/html/rfc8392#appendix-A sec
 
 Decoding Benchmark | Time | Memory | Allocs 
 --- | ---: | ---: | ---:
-BenchmarkUnmarshalCOSE/128-Bit_Symmetric_Key-2 | 763 ns/op | 280 B/op | 9 allocs/op
-BenchmarkUnmarshalCOSE/256-Bit_Symmetric_Key-2 | 765 ns/op | 296 B/op | 9 allocs/op
-BenchmarkUnmarshalCOSE/ECDSA_P256_256-Bit_Key-2 | 1388 ns/op | 448 B/op | 18 allocs/op
+BenchmarkUnmarshalCOSE/128-Bit_Symmetric_Key-2 | 761 ns/op | 280 B/op | 9 allocs/op
+BenchmarkUnmarshalCOSE/256-Bit_Symmetric_Key-2 | 768 ns/op | 296 B/op | 9 allocs/op
+BenchmarkUnmarshalCOSE/ECDSA_P256_256-Bit_Key-2 | 1385 ns/op | 448 B/op | 18 allocs/op
 
 Encoding Benchmark | Time | Memory | Allocs 
 --- | ---: | ---: | ---:
-BenchmarkMarshalCOSE/128-Bit_Symmetric_Key-2 | 537 ns/op | 224 B/op | 2 allocs/op
-BenchmarkMarshalCOSE/256-Bit_Symmetric_Key-2 | 538 ns/op | 240 B/op | 2 allocs/op
-BenchmarkMarshalCOSE/ECDSA_P256_256-Bit_Key-2 | 683 ns/op | 320 B/op | 2 allocs/op
+BenchmarkMarshalCOSE/128-Bit_Symmetric_Key-2 | 510 ns/op | 224 B/op | 2 allocs/op
+BenchmarkMarshalCOSE/256-Bit_Symmetric_Key-2 | 512 ns/op | 240 B/op | 2 allocs/op
+BenchmarkMarshalCOSE/ECDSA_P256_256-Bit_Key-2 | 674 ns/op | 320 B/op | 2 allocs/op
 
 ## CWT claims data
 
@@ -233,11 +233,11 @@ Benchmarks use CTW claims data from https://tools.ietf.org/html/rfc8392#appendix
 
 Decoding Benchmark | Time | Memory | Allocs 
 --- | ---: | ---: | ---:
-BenchmarkUnmarshalCWTClaims-2 | 1027 ns/op | 240 B/op | 13 allocs/op
+BenchmarkUnmarshalCWTClaims-2 | 1029 ns/op | 240 B/op | 13 allocs/op
 
 Encoding Benchmark | Time | Memory | Allocs 
 --- | ---: | ---: | ---:
-BenchmarkMarshalCWTClaims-2 | 474 ns/op | 176 B/op | 2 allocs/op
+BenchmarkMarshalCWTClaims-2 | 445 ns/op | 176 B/op | 2 allocs/op
 
 ## SenML data
 
@@ -257,8 +257,8 @@ Benchmarks use SenML data from https://tools.ietf.org/html/rfc8428#section-6
 
 Decoding Benchmark | Time | Memory | Allocs 
 --- | ---: | ---: | ---:
-BenchmarkUnmarshalSenML-2 | 4361 ns/op | 1720 B/op | 40 allocs/op
+BenchmarkUnmarshalSenML-2 | 4279 ns/op | 1720 B/op | 40 allocs/op
 
 Encoding Benchmark | Time | Memory | Allocs 
 --- | ---: | ---: | ---:
-BenchmarkMarshalSenML-2 | 2975 ns/op | 272 B/op	| 2 allocs/op
+BenchmarkMarshalSenML-2 | 2906 ns/op | 272 B/op	| 2 allocs/op
diff --git a/README.md b/README.md
index f54c697..cffed63 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,11 @@
-[![CBOR Library - Slideshow and Latest Docs.](https://github.com/fxamacker/images/raw/master/cbor/v1.5.0/cbor_slides.gif)](https://github.com/fxamacker/cbor/blob/master/README.md)
+[![CBOR Library - Slideshow and Latest Docs.](https://github.com/fxamacker/images/raw/master/cbor/v2.0.0/cbor_slides.gif)](https://github.com/fxamacker/cbor/blob/master/README.md)
 
 # CBOR library in Go
-This is a generic CBOR encoder and decoder.  It can encode integers and floats to their smallest forms (like float16) when values fit.  Each release passes 375+ tests and 250+ million execs fuzzing with 1100+ CBOR files.
+[__`fxamacker/cbor`__](https://github.com/fxamacker/cbor) is a CBOR encoder and decoder.  It can encode integers and floats to their smallest forms (like float16) when values fit.  Each release passes 375+ tests and 250+ million execs fuzzing with 1100+ CBOR files.
 
 [![](https://github.com/fxamacker/cbor/workflows/ci/badge.svg)](https://github.com/fxamacker/cbor/actions?query=workflow%3Aci)
 [![](https://github.com/fxamacker/cbor/workflows/cover%20%E2%89%A597%25/badge.svg)](https://github.com/fxamacker/cbor/actions?query=workflow%3A%22cover+%E2%89%A597%25%22)
+[![](https://github.com/fxamacker/cbor/workflows/linters/badge.svg)](https://github.com/fxamacker/cbor/actions?query=workflow%3Alinters)
 [![Go Report Card](https://goreportcard.com/badge/github.com/fxamacker/cbor)](https://goreportcard.com/report/github.com/fxamacker/cbor)
 [![Release](https://img.shields.io/github/release/fxamacker/cbor.svg?style=flat-square)](https://github.com/fxamacker/cbor/releases)
 [![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/fxamacker/cbor/master/LICENSE)
@@ -23,19 +24,22 @@ __Why this CBOR library?__ It doesn't crash and it has well-balanced qualities:
 
 * __Easy__ and saves time.  It has the same API as [Go](https://golang.org)'s [`encoding/json`](https://golang.org/pkg/encoding/json/) when possible.  Existing structs don't require changes.  Go struct tags like `` `cbor:"name,omitempty"` `` and `` `json:"name,omitempty"` `` work as expected.  
 
-__Predefined configs__ make it easier to comply with standards like Canonical CBOR, CTAP2 Canonical CBOR, etc.
+Function signatures identical to encoding/json, include:  
+`Marshal`, `Unmarshal`, `NewEncoder`, `NewDecoder`, `encoder.Encode`, and `decoder.Decode`.
 
-__Custom configs__ can be created by setting individual options.  E.g., EncOptions.NaNConvert can be set to NaNConvertNone, NaNConvert7e00, NaNConvertQuiet, or NaNConvertPreserveSignal.
+Predefined options make it easier to comply with standards like Canonical CBOR, CTAP2 Canonical CBOR, etc.
+
+Customized options are easy.  For example, `EncOptions.Time` can be set to `TimeUnix`, `TimeUnixMicro`, `TimeUnixDynamic`, `TimeRFC3339`, or `TimeRFC3339Nano`.
 
 Struct tags like __`keyasint`__ and __`toarray`__ make compact CBOR data such as COSE, CWT, and SenML easier to use.
 
 <hr>
 
-[![CBOR API](https://github.com/fxamacker/images/raw/master/cbor/v1.5.0/cbor_easy_api.png)](#usage)
+[![CBOR API](https://github.com/fxamacker/images/raw/master/cbor/v2.0.0/cbor_easy_api.png)](#usage)
 
 <hr>
 
-👉  [Comparisons](#comparisons) • [Status](#current-status) • [Design Goals](#design-goals) • [Features](#features) • [Standards](#standards) • [Fuzzing](#fuzzing-and-code-coverage) • [Usage](#usage) • [Security Policy](#security-policy) • [License](#license)
+👉  [Status](#current-status) • [Design Goals](#design-goals) • [Features](#features) • [Standards](#standards) • [API](#api) • [Usage](#usage) • [Fuzzing](#fuzzing-and-code-coverage) • [Security Policy](#security-policy) • [License](#license)
 
 ## Comparisons
 
@@ -43,41 +47,44 @@ Comparisons are between this newer library and a well-known library that had 1,0
 
 __This library is safer__.  Small malicious CBOR messages are rejected quickly before they exhaust system resources.
 
-![alt text](https://github.com/fxamacker/images/raw/master/cbor/v1.5.0/cbor_safety_comparison.png "CBOR library safety comparison")
+![alt text](https://github.com/fxamacker/images/raw/master/cbor/v2.0.0/cbor_safety_comparison.png "CBOR library safety comparison")
 
 __This library is smaller__. Programs like senmlCat can be 4 MB smaller by switching to this library.  Programs using more complex CBOR data types can be 9.2 MB smaller.
 
-![alt text](https://github.com/fxamacker/images/raw/master/cbor/v1.5.0/cbor_size_comparison.png "CBOR library and program size comparison chart")
+![alt text](https://github.com/fxamacker/images/raw/master/cbor/v2.0.0/cbor_size_comparison.png "CBOR library and program size comparison chart")
 
 __This library is faster__ for encoding and decoding CBOR Web Token (CWT).  However, speed is only one factor and it can vary depending on data types and sizes.  Unlike the other library, this one doesn't use Go's ```unsafe``` package or code gen.
 
-![alt text](https://github.com/fxamacker/images/raw/master/cbor/v1.5.0/cbor_speed_comparison.png "CBOR library speed comparison chart")
+![alt text](https://github.com/fxamacker/images/raw/master/cbor/v2.0.0/cbor_speed_comparison.png "CBOR library speed comparison chart")
 
 The resource intensive `codec.CborHandle` initialization (in the other library) was placed outside the benchmark loop to make sure their library wasn't penalized.
 
 Doing your own comparisons is highly recommended.  Use your most common message sizes and data types.
 
 ## Current Status
-Latest version is v1.5, which has:
+Latest version is v2.0, which has:
 
 * __Stable API__ – won't make breaking API changes except:
   * CoreDetEncOptions() is subject to change because it uses draft standard not yet approved by IETF.
   * PreferredUnsortedEncOptions() is subject to change because it uses draft standard not yet approved by IETF.
-* __Stable requirements__ – will support Go v1.12 (unless there's compelling reason to require newer).
-* __Passed all tests__ – v1.5 passed all 375+ tests on amd64, arm64, ppc64le and s390x with linux.
-* __Passed fuzzing__ – v1.5 passed 4.75 billion execs in coverage-guided fuzzing on linux_amd64.
+* __Requirements__ – Go v1.12+ on amd64, arm64, ppc64le or s390x. Other archs may also work.
+* __Passed all tests__ – v2.0 passed all 375+ tests on amd64, arm64, ppc64le and s390x with linux.
+* __Passed fuzzing__ – v2.0 passed 1+ billion execs in coverage-guided fuzzing on Feb. 2, 2020.
 
 Recent activity:
 
-* [x] [Release v1.3](https://github.com/fxamacker/cbor/releases) -- Faster encoding and decoding.
-* [x] [Release v1.3](https://github.com/fxamacker/cbor/releases) -- Add `toarray` struct tag to simplify using CBOR arrays.
-* [x] [Release v1.3](https://github.com/fxamacker/cbor/releases) -- Add `keyasint` struct tag to simplify using CBOR maps with int keys.
-* [x] [Release v1.3.4](https://github.com/fxamacker/cbor/releases) -- Bugfixes and refactoring.  Limit nested levels to 32 for arrays, maps, tags.
-* [x] [Release v1.4](https://github.com/fxamacker/cbor/releases) -- Deprecate bool encoding options and add int SortMode.  Use float16 to float32 conversion func that had all 65536 results verified to be correct. Fix decoding of float16 subnormal numbers.
 * [x] [Release v1.5](https://github.com/fxamacker/cbor/releases) -- Add option to shrink floating-point values to smaller sizes like float16 (if they preserve value).
 * [x] [Release v1.5](https://github.com/fxamacker/cbor/releases) -- Add options for encoding floating-point NaN values: NaNConvertNone, NaNConvert7e00, NaNConvertQuiet, or NaNConvertPreserveSignal.
+* [x] [Release v2.0](https://github.com/fxamacker/cbor/releases) -- Improved API, faster performance, less memory allocs, five options for encoding time and cleaner code. Decode NaN or Infinity time values as if they were NULL (to Go's "zero time".)
+
+__Why v2.0?__:
+
+v2 API was needed in order to simplify adding new features planned for v2.1 and v2.2.
 
-Coming soon: support for CBOR tags (major type 6). After that, options for handling duplicate map keys.
+__Roadmap__:
+
+ * v2.1 (Feb. 9, 2020) support for CBOR tags (major type 6) and some decoder optimizations.
+ * v2.2 (Feb. 2020) options for handling duplicate map keys.
 
 ## Design Goals 
 This library is designed to be a generic CBOR encoder and decoder.  It was initially created for a [WebAuthn (FIDO2) server library](https://github.com/fxamacker/webauthn), because existing CBOR libraries (in Go) didn't meet certain criteria in 2019.
@@ -103,43 +110,109 @@ Features not in Go's standard library are usually not added.  However, the __`to
 
 ## Features
 
-* API is like `encoding/json` plus extra struct tags:
-  * `cbor.Encoder` writes CBOR to `io.Writer`.  
-  * `cbor.Decoder` reads CBOR from `io.Reader`.
-  * `cbor.Marshal` writes CBOR to `[]byte`.  
-  * `cbor.Unmarshal` reads CBOR from `[]byte`.  
+* In v2, many function signatures are identical to encoding/json, including:  
+`Marshal`, `Unmarshal`, `NewEncoder`, `NewDecoder`, `encoder.Encode`, `decoder.Decode`.
+* Support customizable options to create encoding and decoding modes (interfaces) that are safe for concurrent use.  Once created, encoding and decoding modes cannot accidentally change their behavior at runtime.
 * Support "cbor" and "json" keys in Go's struct tags. If both are specified, then "cbor" is used.
 * `toarray` struct tag allows named struct fields for elements of CBOR arrays.
 * `keyasint` struct tag allows named struct fields for elements of CBOR maps with int keys.
-* Encoder has easy functions that create and return modifiable configurations:
-  * func CanonicalEncOptions() EncOptions
-  * func CTAP2EncOptions() EncOptions
-  * func CoreDetEncOptions() EncOptions
-  * func PreferredUnsortedEncOptions() EncOptions
-* For Go integers, encoder always uses "preferred serialization" which encodes their values to the smallest number of bytes.
-* Encoder floating-point option types: ShortestFloatMode, InfConvertMode, and NaNConvertMode.
-  * ShortestFloatMode: ShortestFloatNone or ShortestFloat16 (IEEE 754 binary16, etc. if value fits).
-  * InfConvertMode: InfConvertNone or InfConvertFloat16.
-  * NaNConvertMode: NaNConvertNone, NaNConvert7e00, NaNConvertQuiet, or NaNConvertPreserveSignal
-* Encoder sort options: SortNone, SortBytewiseLexical, SortCanonical, SortCTAP2, SortCoreDeterministic  
-* Support `encoding.BinaryMarshaler` and `encoding.BinaryUnmarshaler` interfaces.
+* Encoder has easy functions that return predefined configurations:  
+  `CanonicalEncOptions`, `CTAP2EncOptions`, `CoreDetEncOptions`, `PreferredUnsortedEncOptions`
+* Integers always encode to the smallest number of bytes.
+* Encoder floating-point options:
+  * ShortestFloatMode: `ShortestFloatNone` or `ShortestFloat16` (IEEE 754 binary16, etc. if value fits).
+  * InfConvertMode: `InfConvertNone` or `InfConvertFloat16`.
+  * NaNConvertMode: `NaNConvertNone`, `NaNConvert7e00`, `NaNConvertQuiet`, or `NaNConvertPreserveSignal`.
+* Encoder sort options: `SortNone`, `SortBytewiseLexical`, `SortCanonical`, `SortCTAP2`, `SortCoreDeterministic`.
+* Encoder time options: `TimeUnix`, `TimeUnixMicro`, `TimeUnixDynamic`, `TimeRFC3339`, `TimeRFC3339Nano`.
 * Support `cbor.RawMessage` which can delay CBOR decoding or precompute CBOR encoding.
+* Support Go's `encoding.BinaryMarshaler` and `encoding.BinaryUnmarshaler` interfaces.
 * Support `cbor.Marshaler` and `cbor.Unmarshaler` interfaces to allow user-defined types to have custom CBOR encoding and decoding.
-* Support `time.Time` as RFC 3339 formatted text string or Unix time.
 * Support indefinite length CBOR data (["streaming"](https://tools.ietf.org/html/rfc7049#section-2.2)).  For decoding, each indefinite length "container" must fit into memory to perform well-formedness checks that prevent exploits. Go's `io.LimitReader` can be used to limit sizes.
-* Encoder uses struct field visibility rules for anonymous struct fields (same rules as `encoding/json`.)
-* Encoder always uses smallest CBOR integer sizes for more compact data serialization.
 * Decoder always checks for invalid UTF-8 string errors.
 * Decoder always decodes in-place to slices, maps, and structs.
 * Decoder uses case-insensitive field name match when decoding to structs. 
 * Both encoder and decoder correctly handles nil slice, map, pointer, and interface values.
 
-Coming soon: support for CBOR tags (major type 6).  After that, options for handling duplicate map keys.
+See [milestones](https://github.com/fxamacker/cbor/milestones) for upcoming features.
 
 ## Standards
 This library implements CBOR as specified in [RFC 7049](https://tools.ietf.org/html/rfc7049) with minor [limitations](#limitations).
 
-For Go integers, encoder always uses "preferred serialization" which encodes their values to the smallest number of bytes.
+Integers are always encoded to the smallest number of bytes.  
+
+Encoding of other data types and map key sort order are determined by encoder options.
+
+* EncOptions.Sort - default is `SortNone` (3 settings + 3 aliases)
+* EncOptions.Time - default is `TimeUnix` (5 settings)
+* EncOptions.ShortestFloat - default is `ShortestFloatNone` (2 settings)
+* EncOptions.InfConvert - default is `InfConvertFloat16` (2 settings)
+* EncOptions.NaNConvert - default is `NaNConvert7e00` (4 settings)
+
+See [API section](#api) for more details on the above options.
+
+Float16 conversions use [x448/float16](https://github.com/x448/float16) maintained by the same team as this library.  All 4+ billion possible conversions are verified to be correct in that library on amd64, arm64, ppc64le and s390x.
+
+Go nil values for slices, maps, pointers, etc. are encoded as CBOR null.  Empty slices, maps, etc. are encoded as empty CBOR arrays and maps.
+
+Decoder checks for all required well-formedness errors, including all "subkinds" of syntax errors and too little data.
+
+After well-formedness is verified, basic validity errors are handled as follows:
+
+* Invalid UTF-8 string: Decoder always checks and returns invalid UTF-8 string error.
+* Duplicate keys in a map: By default, decoder decodes to a map with duplicate keys by overwriting previous value with the same key.  Options to handle duplicate map keys in different ways may be added as a feature.
+
+When decoding well-formed CBOR arrays and maps, decoder saves the first error it encounters and continues with the next item.  Options to handle this differently may be added in the future.
+
+## Limitations
+CBOR tags (type 6) is being added in the next release ([milestone v2.1](https://github.com/fxamacker/cbor/milestone/11)) and is coming soon.
+
+Known limitations:
+
+* Currently, CBOR tag numbers are ignored.  Decoder simply decodes tag content. Work is in progress to add support.
+* Currently, duplicate map keys are not checked during decoding.  Option to handle duplicate map keys in different ways will be added.
+* Nested levels for CBOR arrays, maps, and tags are limited to 32 to quickly reject potentially malicious data.  This limit will be reconsidered upon request.
+* CBOR negative int (type 1) that cannot fit into Go's int64 are not supported, such as RFC 7049 example -18446744073709551616.  Decoding these values returns `cbor.UnmarshalTypeError` like Go's `encoding/json`.
+* CBOR `Undefined` (0xf7) value decodes to Go's `nil` value.  CBOR `Null` (0xf6) more closely matches Go's `nil`.
+
+Like Go's `encoding/json`, data validation checks the entire message to prevent partially filled (corrupted) data. This library also prevents crashes and resource exhaustion attacks from malicious CBOR data. Use Go's `io.LimitReader` when decoding very large data to limit size.
+
+## System Requirements
+
+* Go 1.12 (or newer)
+* amd64, arm64, ppc64le and s390x. Other architectures may also work but they are not tested as frequently. 
+
+## Installation
+```
+$ GO111MODULE=on go get github.com/fxamacker/cbor/v2
+```
+
+```
+import (
+	"github.com/fxamacker/cbor/v2" // imports as package "cbor"
+)
+```
+
+[Released versions](https://github.com/fxamacker/cbor/releases) benefit from longer fuzz tests.
+
+## Versions and API Changes
+This project uses [Semantic Versioning](https://semver.org), so the API is always backwards compatible unless the major version number changes.  Newly added API documented as "subject to change" are excluded from this rule.
+
+## API 
+In v2, many function signatures are identical to encoding/json, including:  
+`Marshal`, `Unmarshal`, `NewEncoder`, `NewDecoder`, `encoder.Encode`, `decoder.Decode`.
+
+"Mode" in this API means definite way of encoding or decoding.
+
+EncMode and DecMode are interfaces created from EncOptions or DecOptions structs.
+
+EncMode and DecMode use immutable options so their behavior won't accidentally change at runtime.  Modes are intended to be reused and are safe for concurrent use.
+
+In addition to the function API, the `keyasint` and `toarray` struct tags are worth knowing.  They can reduce programming effort, improve system performance, and reduce the size of serialized data.  
+
+See [API docs (godoc.org)](https://godoc.org/github.com/fxamacker/cbor) for more details.  See [Usage section](#usage) for usage and code examples.  Options for the encoder are listed here.
+
+__Encoder Options__:
 
 Encoder has options that can be set individually to create custom configurations. Easy functions are also provided to create and return modifiable configurations (EncOptions):
 
@@ -150,150 +223,93 @@ Encoder has options that can be set individually to create custom configurations
 
 __EncOptions.Sort__:
 
-* SortNone: no sorting for map keys.
+* SortNone (default): no sorting for map keys.
 * SortLengthFirst: length-first map key ordering.
 * SortBytewiseLexical: bytewise lexicographic map key ordering.
 * SortCanonical: same as SortLengthFirst [(RFC 7049 Section 3.9)](https://tools.ietf.org/html/rfc7049#section-3.9)
 * SortCTAP2Canonical: same as SortBytewiseLexical  [(CTAP2 Canonical CBOR)](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#ctap2-canonical-cbor-encoding-form).
 * SortCoreDeterministic: same as SortBytewiseLexical.
 
+__EncOptions.Time__:  
+
+* TimeUnix (default): (seconds) encode as integer.
+* TimeUnixMicro: (microseconds) encode as floating-point.  ShortestFloat option determines size.
+* TimeUnixDynamic: (seconds or microseconds) encode as integer if time doesn't have fractional seconds, otherwise encode as floating-point rounded to microseconds.
+* TimeRFC3339: (seconds) encode as RFC 3339 formatted string.
+* TimeRFC3339Nano: (nanoseconds) encode as RFC3339 formatted string.
+
+By default, time values are encoded without tags.  Option to override this will be added in v2.1.
+
 Encoder has 3 types of options for floating-point data: ShortestFloatMode, InfConvertMode, and NaNConvertMode.
 
 __EncOptions.ShortestFloat__:
 
-* ShortestFloatNone: no conversion.
+* ShortestFloatNone (default): no conversion.
 * ShortestFloat16: uses float16 ([IEEE 754 binary16](https://en.wikipedia.org/wiki/Half-precision_floating-point_format)) as the shortest form that preserves value.
 
 With ShortestFloat16, each floating-point value (including subnormals) can encode float64 -> float32 -> float16 when values can round-trip.  Conversions for infinity and NaN use InfConvert and NaNConvert settings.
 
 __EncOptions.InfConvert__:
 
+* InfConvertFloat16 (default): convert +- infinity to float16 since they always preserve value (recommended)
 * InfConvertNone: don't convert +- infinity to other representations -- used by CTAP2 Canonical CBOR
-* InfConvertFloat16: convert +- infinity to float16 since they always preserve value (recommended)
 
 __EncOptions.NaNConvert__:
 
+* NaNConvert7e00 (default): encode to 0xf97e00 (CBOR float16 = 0x7e00) -- used by RFC 7049 Canonical CBOR.
 * NaNConvertNone: don't convert NaN to other representations -- used by CTAP2 Canonical CBOR.
-* NaNConvert7e00: encode to 0xf97e00 (CBOR float16 = 0x7e00) -- used by RFC 7049 Canonical CBOR.
 * NaNConvertQuiet: force quiet bit = 1 and use shortest form that preserves NaN payload.
 * NaNConvertPreserveSignal: convert to smallest form that preserves value (quit bit unmodified and NaN payload preserved).
 
-Float16 conversions use [x448/float16](https://github.com/x448/float16) maintained by the same team as this library.  All 4+ billion possible conversions are verified to be correct in that library.
-
-Go nil values for slices, maps, pointers, etc. are encoded as CBOR null.  Empty slices, maps, etc. are encoded as empty CBOR arrays and maps.
-
-Decoder checks for all required well-formedness errors, including all "subkinds" of syntax errors and too little data.
-
-After well-formedness is verified, basic validity errors are handled as follows:
-
-* Invalid UTF-8 string: Decoder always checks and returns invalid UTF-8 string error.
-* Duplicate keys in a map: By default, decoder decodes to a map with duplicate keys by overwriting previous value with the same key.  Options to handle duplicate map keys in different ways may be added as a feature.
-
-When decoding well-formed CBOR arrays and maps, decoder saves the first error it encounters and continues with the next item.  Options to handle this differently may be added in the future.
-
-## Limitations
-CBOR tags (type 6) is being added in the next release ([milestone v2.0](https://github.com/fxamacker/cbor/milestone/3)) and is coming soon.
-
-Known limitations:
-
-* Currently, CBOR tag numbers are ignored.  Decoder simply decodes tag content. Work is in progress to add support.
-* Currently, duplicate map keys are not checked during decoding.  Option to handle duplicate map keys in different ways will be added.
-* Nested levels for CBOR arrays, maps, and tags are limited to 32 to quickly reject potentially malicious data.  This limit will be reconsidered upon request.
-* CBOR negative int (type 1) that cannot fit into Go's int64 are not supported, such as RFC 7049 example -18446744073709551616.  Decoding these values returns `cbor.UnmarshalTypeError` like Go's `encoding/json`.
-* CBOR `Undefined` (0xf7) value decodes to Go's `nil` value.  CBOR `Null` (0xf6) more closely matches Go's `nil`.
-
-Like Go's `encoding/json`, data validation checks the entire message to prevent partially filled (corrupted) data. This library also prevents crashes and resource exhaustion attacks from malicious CBOR data. Use Go's `io.LimitReader` when decoding very large data to limit size.
-
-## Fuzzing and Code Coverage
+## Usage
+👉 Use Go's `io.LimitReader` to limit size when decoding very large data.
 
-__Over 375 tests__ must pass on 4 architectures before tagging a release.  They include all RFC 7049 examples, bugs found by fuzzing, 2 maliciously crafted CBOR data, and over 87 tests with malformed data.
+Functions with identical signatures to encoding/json include:  
+`Marshal`, `Unmarshal`, `NewEncoder`, `NewDecoder`, `encoder.Encode`, `decoder.Decode`.
 
-__Code coverage__ must not fall below 95% when tagging a release.  Code coverage is 97.9% (`go test -cover`) for cbor v1.5 which is among the highest for libraries (in Go) of this type.
+EncMode and DecMode are interfaces created from EncOptions or DecOptions structs.
 
-__Coverage-guided fuzzing__ must pass 250+ million execs before tagging a release.  E.g. v1.4 passed 532+ million execs in coverage-guided fuzzing at the time of release and reached 4+ billion execs 18 days later. Fuzzing uses [fxamacker/cbor-fuzz](https://github.com/fxamacker/cbor-fuzz).  Default corpus has:
+__Package Level Functions__  
 
-* 2 files related to WebAuthn (FIDO U2F key).
-* 3 files with custom struct.
-* 9 files with [CWT examples (RFC 8392 Appendix A)](https://tools.ietf.org/html/rfc8392#appendix-A)
-* 17 files with [COSE examples (RFC 8152 Appendix B & C)](https://github.com/cose-wg/Examples/tree/master/RFC8152).
-* 81 files with [CBOR examples (RFC 7049 Appendix A) ](https://tools.ietf.org/html/rfc7049#appendix-A). It excludes 1 errata first reported in [issue #46](https://github.com/fxamacker/cbor/issues/46).
+If default options are acceptable, package level functions can be used for encoding and decoding. Their API matches encoding/json.
 
-Over 1,100 files (corpus) are used for fuzzing because it includes fuzz-generated corpus.
+```
+b, err := cbor.Marshal(v)
+err := cbor.Unmarshal(b, &v)
+encoder := cbor.NewEncoder(w)
+decoder := cbor.NewDecoder(r)
+```
 
-## System Requirements
+__EncOptions and EncMode__
 
-* Go 1.12 (or newer)
-* amd64, arm64, ppc64le and s390x. Other architectures may also work but they are not tested as frequently. 
+EncMode and DecMode are interfaces and their functions are often identical to encoding/json.
 
-## Versions and API Changes
-This project uses [Semantic Versioning](https://semver.org), so the API is always backwards compatible unless the major version number changes.  Newly added API documented as "subject to change" are excluded from this rule.
+```
+// Create EncOptions, using either struct literal or a function.
+opts := cbor.CanonicalEncOptions()
 
-## API 
-The API is the same as `encoding/json` when possible.
+// If needed, modify options -- e.g. how time values should be encoded.
+opts.Time = cbor.TimeUnix
 
-In addition to the API, the `keyasint` and `toarray` struct tags are worth knowing.  They can reduce programming effort, improve system performance, and reduce the size of serialized data.  
+// Create reusable EncMode interface with immutable options, safe for concurrent use.
+em, err := opts.EncMode()   
 
+// Use EncMode like encoding/json, with same function signatures.
+b, err := em.Marshal(v)
+// or
+encoder := em.NewEncoder(w)
+err := encoder.Encode(v)
 ```
-package cbor // import "github.com/fxamacker/cbor"
-
-func Marshal(v interface{}, encOpts EncOptions) ([]byte, error)
-func Unmarshal(data []byte, v interface{}) error
-func Valid(data []byte) (rest []byte, err error)
-type Decoder struct{ ... }
-    func NewDecoder(r io.Reader) *Decoder
-    func (dec *Decoder) Decode(v interface{}) (err error)
-    func (dec *Decoder) NumBytesRead() int
-type EncOptions struct{ ... }
-    func CTAP2EncOptions() EncOptions
-    func CanonicalEncOptions() EncOptions
-    func CoreDetEncOptions() EncOptions
-    func PreferredUnsortedEncOptions() EncOptions
-type Encoder struct{ ... }
-    func NewEncoder(w io.Writer, encOpts EncOptions) *Encoder
-    func (enc *Encoder) Encode(v interface{}) error
-    func (enc *Encoder) StartIndefiniteByteString() error
-    func (enc *Encoder) StartIndefiniteTextString() error
-    func (enc *Encoder) StartIndefiniteArray() error
-    func (enc *Encoder) StartIndefiniteMap() error
-    func (enc *Encoder) EndIndefinite() error
-type InfConvertMode int
-    const InfConvertFloat16 InfConvertMode = iota ...
-type InvalidUnmarshalError struct{ ... }
-type Marshaler interface{ ... }
-type NaNConvertMode int
-    const NaNConvert7e00 NaNConvertMode = iota ...
-type RawMessage []byte
-type SemanticError struct{ ... }
-type ShortestFloatMode int
-    const ShortestFloatNone ShortestFloatMode = iota ...
-type SortMode int
-    const SortNone SortMode = 0 ...
-type SyntaxError struct{ ... }
-type UnmarshalTypeError struct{ ... }
-type Unmarshaler interface{ ... }
-type UnsupportedTypeError struct{ ... }
-```
-See [API docs](https://godoc.org/github.com/fxamacker/cbor) for more details.
 
-## Installation
-```
-go get github.com/fxamacker/cbor
-```
-[Released versions](https://github.com/fxamacker/cbor/releases) benefit from longer fuzz tests.
+__Struct Tags (keyasint, toarray, omitempty)__
 
-## Usage
-👉 Use Go's `io.LimitReader` when decoding very large data to limit size.
+The `keyasint`, `toarray`, and `omitempty` struct tags make it easy to use compact CBOR message formats.  Internet standards often use CBOR arrays and CBOR maps with int keys to save space.
 
-The API is the same as `encoding/json` when possible:
-
-* cbor.Marshal writes CBOR to []byte
-* cbor.Unmarshal reads CBOR from []byte
-* cbor.Encoder writes CBOR to io.Writer
-* cbor.Decoder reads CBOR from io.Reader
+<hr>
 
-The `keyasint` and `toarray` struct tags make it easy to use compact CBOR message formats.  Internet standards often use CBOR arrays and CBOR maps with int keys to save space.
+[![CBOR API](https://github.com/fxamacker/images/raw/master/cbor/v2.0.0/cbor_easy_api.png)](#usage)
 
-Using named struct fields instead of array elements or maps with int keys makes code more readable and less error prone.
+<hr>
 
 __Decoding CWT (CBOR Web Token)__ using `keyasint` and `toarray` struct tags:
 ```
@@ -327,7 +343,7 @@ __Encoding CWT (CBOR Web Token)__ using `keyasint` and `toarray` struct tags:
 
 var v signedCWT
 ...
-if data, err := cbor.Marshal(v, cbor.EncOptions{}); err != nil {
+if data, err := cbor.Marshal(v); err != nil {
 	return err
 }
 ```
@@ -357,7 +373,7 @@ type SenMLRecord struct {
 
 // data is a []byte containing SenML
 
-var v []SenMLRecord
+var v []*SenMLRecord
 if err := cbor.Unmarshal(data, &v); err != nil {
 	return err
 }
@@ -367,105 +383,53 @@ __Encoding SenML__ using `keyasint` struct tag and `ShortestFloat16` encoding op
 ```
 // use SenMLRecord struct defined in "Decoding SenML" example
 
-var v []SenMLRecord
+var v []*SenMLRecord
 ...
-if data, err := cbor.Marshal(v, cbor.EncOptions{ShortestFloat: cbor.ShortestFloat16}); err != nil {
+em, err := cbor.EncOptions{ShortestFloat: cbor.ShortestFloat16}.EncMode()
+if data, err := em.Marshal(v); err != nil {
 	return err
 }
 ```
 
-__Decoding__:
-
-```
-// create a decoder
-dec := cbor.NewDecoder(reader)
-
-// decode into empty interface
-var i interface{}
-err = dec.Decode(&i)
-
-// decode into struct 
-var stru ExampleStruct
-err = dec.Decode(&stru)
-
-// decode into map
-var m map[string]string
-err = dec.Decode(&m)
-
-// decode into primitive
-var f float32
-err = dec.Decode(&f)
-```
-
-__Encoding__:
-
-```
-// create an encoder with canonical CBOR encoding enabled
-enc := cbor.NewEncoder(writer, cbor.CanonicalEncOptions())
-
-// encode struct
-err = enc.Encode(stru)
-
-// encode map
-err = enc.Encode(m)
-
-// encode primitive
-err = enc.Encode(f)
-```
-
-__Encoding indefinite length array__:
-
-```
-enc := cbor.NewEncoder(writer, cbor.EncOptions{})
-
-// start indefinite length array encoding
-err = enc.StartIndefiniteArray()
-
-// encode array element
-err = enc.Encode(1)
-
-// encode array element
-err = enc.Encode([]int{2, 3})
-
-// start nested indefinite length array as array element
-err = enc.StartIndefiniteArray()
-
-// encode nested array element
-err = enc.Encode(4)
-
-// encode nested array element
-err = enc.Encode(5)
-
-// end nested indefinite length array
-err = enc.EndIndefinite()
-
-// end indefinite length array
-err = enc.EndIndefinite()
-```
-
-More [examples](example_test.go).
+For more examples, see [examples_test.go](example_test.go).
 
 ## Benchmarks
 
 Go structs are faster than maps with string keys:
 
-* decoding into struct is >29% faster than decoding into map.
-* encoding struct is >35% faster than encoding map.
+* decoding into struct is >27% faster than decoding into map.
+* encoding struct is >36% faster than encoding map.
 
 Go structs with `keyasint` struct tag are faster than maps with integer keys:
 
-* decoding into struct is >25% faster than decoding into map.
-* encoding struct is >32% faster than encoding map.
+* decoding into struct is >23% faster than decoding into map.
+* encoding struct is >35% faster than encoding map.
 
 Go structs with `toarray` struct tag are faster than slice:
 
 * decoding into struct is >14% faster than decoding into slice.
-* encoding struct is >9% faster than encoding slice.
+* encoding struct is >12% faster than encoding slice.
 
 Doing your own benchmarks is highly recommended.  Use your most common message sizes and data types.
 
 See [Benchmarks for fxamacker/cbor](CBOR_BENCHMARKS.md).
 
+## Fuzzing and Code Coverage
+
+__Over 375 tests__ must pass on 4 architectures before tagging a release.  They include all RFC 7049 examples, bugs found by fuzzing, 2 maliciously crafted CBOR data, and over 87 tests with malformed data.
+
+__Code coverage__ must not fall below 95% when tagging a release.  Code coverage is 97.9% (`go test -cover`) for cbor v2.0 which is among the highest for libraries (in Go) of this type.
+
+__Coverage-guided fuzzing__ must pass 250+ million execs before tagging a release.  E.g. v1.4 passed 532+ million execs in coverage-guided fuzzing at the time of release and reached 4+ billion execs 18 days later. Fuzzing uses [fxamacker/cbor-fuzz](https://github.com/fxamacker/cbor-fuzz).  Default corpus has:
+
+* 2 files related to WebAuthn (FIDO U2F key).
+* 3 files with custom struct.
+* 9 files with [CWT examples (RFC 8392 Appendix A)](https://tools.ietf.org/html/rfc8392#appendix-A)
+* 17 files with [COSE examples (RFC 8152 Appendix B & C)](https://github.com/cose-wg/Examples/tree/master/RFC8152).
+* 81 files with [CBOR examples (RFC 7049 Appendix A) ](https://tools.ietf.org/html/rfc7049#appendix-A). It excludes 1 errata first reported in [issue #46](https://github.com/fxamacker/cbor/issues/46).
+
+Over 1,100 files (corpus) are used for fuzzing because it includes fuzz-generated corpus.
+
 ## Code of Conduct 
 This project has adopted the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md).  Contact [faye.github@gmail.com](mailto:faye.github@gmail.com) with any questions or comments.
 
@@ -473,7 +437,7 @@ This project has adopted the [Contributor Covenant Code of Conduct](CODE_OF_COND
 Please refer to [How to Contribute](CONTRIBUTING.md).
 
 ## Security Policy
-For v1, security fixes are provided only for the latest released version since the API won't break compatibility.
+Security fixes are provided for the latest released version.
 
 To report security vulnerabilities, please email [faye.github@gmail.com](mailto:faye.github@gmail.com) and allow time for the problem to be resolved before reporting it to the public.
 
@@ -493,10 +457,10 @@ Please read the license for additional disclaimers and terms.
 * Jakob Borg for his words of encouragement about this library at Go Forum.
 
 ## License 
-Copyright (c) [Faye Amacker](https://github.com/fxamacker).  All rights reserved.
+Copyright © 2019-present [Faye Amacker](https://github.com/fxamacker).
 
-Licensed under the [MIT License](LICENSE).
+fxamacker/cbor is licensed under the MIT License.  See [LICENSE](LICENSE) for the full license text.
 
 <hr>
 
-👉  [Comparisons](#comparisons) • [Status](#current-status) • [Design Goals](#design-goals) • [Features](#features) • [Standards](#standards) • [Fuzzing](#fuzzing-and-code-coverage) • [Usage](#usage) • [Security Policy](#security-policy) • [License](#license)
+👉  [Status](#current-status) • [Design Goals](#design-goals) • [Features](#features) • [Standards](#standards) • [API](#api) • [Usage](#usage) • [Fuzzing](#fuzzing-and-code-coverage) • [Security Policy](#security-policy) • [License](#license)
diff --git a/cache.go b/cache.go
index 2f9f69d..326ff63 100644
--- a/cache.go
+++ b/cache.go
@@ -31,8 +31,8 @@ import (
 )
 
 var (
-	decodingStructTypeCache sync.Map // map[reflect.Type]decodingStructType
-	encodingStructTypeCache sync.Map // map[reflect.Type]encodingStructType
+	decodingStructTypeCache sync.Map // map[reflect.Type]*decodingStructType
+	encodingStructTypeCache sync.Map // map[reflect.Type]*encodingStructType
 	encodeFuncCache         sync.Map // map[reflect.Type]encodeFunc
 )
 
@@ -41,9 +41,9 @@ type decodingStructType struct {
 	toArray bool
 }
 
-func getDecodingStructType(t reflect.Type) decodingStructType {
+func getDecodingStructType(t reflect.Type) *decodingStructType {
 	if v, _ := decodingStructTypeCache.Load(t); v != nil {
-		return v.(decodingStructType)
+		return v.(*decodingStructType)
 	}
 
 	flds, structOptions := getFields(t)
@@ -54,53 +54,69 @@ func getDecodingStructType(t reflect.Type) decodingStructType {
 		flds[i].isUnmarshaler = implementsUnmarshaler(flds[i].typ)
 	}
 
-	structType := decodingStructType{fields: flds, toArray: toArray}
+	structType := &decodingStructType{fields: flds, toArray: toArray}
 	decodingStructTypeCache.Store(t, structType)
 	return structType
 }
 
 type encodingStructType struct {
-	fields                  fields
-	bytewiseCanonicalFields fields
-	lenFirstCanonicalFields fields
-	err                     error
-	toArray                 bool
-	omitEmpty               bool
-	hasAnonymousField       bool
-}
-
-func (st encodingStructType) getFields(opts EncOptions) fields {
-	switch opts.Sort {
-	case SortLengthFirst:
-		return st.lenFirstCanonicalFields
-	case SortBytewiseLexical:
-		return st.bytewiseCanonicalFields
+	fields            fields
+	bytewiseFields    fields
+	lengthFirstFields fields
+	err               error
+	toArray           bool
+	omitEmpty         bool
+	hasAnonymousField bool
+}
+
+func (st *encodingStructType) getFields(em *encMode) fields {
+	if em.sort == SortNone {
+		return st.fields
 	}
-	return st.fields
+	if em.sort == SortLengthFirst {
+		return st.lengthFirstFields
+	}
+	return st.bytewiseFields
+}
+
+type bytewiseFieldSorter struct {
+	fields fields
+}
+
+func (x *bytewiseFieldSorter) Len() int {
+	return len(x.fields)
 }
 
-type byBytewiseFields struct {
-	fields
+func (x *bytewiseFieldSorter) Swap(i, j int) {
+	x.fields[i], x.fields[j] = x.fields[j], x.fields[i]
 }
 
-func (x byBytewiseFields) Less(i, j int) bool {
+func (x *bytewiseFieldSorter) Less(i, j int) bool {
 	return bytes.Compare(x.fields[i].cborName, x.fields[j].cborName) <= 0
 }
 
-type byLengthFirstFields struct {
-	fields
+type lengthFirstFieldSorter struct {
+	fields fields
 }
 
-func (x byLengthFirstFields) Less(i, j int) bool {
+func (x *lengthFirstFieldSorter) Len() int {
+	return len(x.fields)
+}
+
+func (x *lengthFirstFieldSorter) Swap(i, j int) {
+	x.fields[i], x.fields[j] = x.fields[j], x.fields[i]
+}
+
+func (x *lengthFirstFieldSorter) Less(i, j int) bool {
 	if len(x.fields[i].cborName) != len(x.fields[j].cborName) {
 		return len(x.fields[i].cborName) < len(x.fields[j].cborName)
 	}
 	return bytes.Compare(x.fields[i].cborName, x.fields[j].cborName) <= 0
 }
 
-func getEncodingStructType(t reflect.Type) encodingStructType {
+func getEncodingStructType(t reflect.Type) *encodingStructType {
 	if v, _ := encodingStructTypeCache.Load(t); v != nil {
-		return v.(encodingStructType)
+		return v.(*encodingStructType)
 	}
 
 	flds, structOptions := getFields(t)
@@ -164,41 +180,41 @@ func getEncodingStructType(t reflect.Type) encodingStructType {
 	putEncodeState(e)
 
 	if err != nil {
-		structType := encodingStructType{err: err}
+		structType := &encodingStructType{err: err}
 		encodingStructTypeCache.Store(t, structType)
 		return structType
 	}
 
 	// Sort fields by canonical order
-	bytewiseCanonicalFields := make(fields, len(flds))
-	copy(bytewiseCanonicalFields, flds)
-	sort.Sort(byBytewiseFields{bytewiseCanonicalFields})
+	bytewiseFields := make(fields, len(flds))
+	copy(bytewiseFields, flds)
+	sort.Sort(&bytewiseFieldSorter{bytewiseFields})
 
-	lenFirstCanonicalFields := bytewiseCanonicalFields
+	lengthFirstFields := bytewiseFields
 	if hasKeyAsInt && hasKeyAsStr {
-		lenFirstCanonicalFields = make(fields, len(flds))
-		copy(lenFirstCanonicalFields, flds)
-		sort.Sort(byLengthFirstFields{lenFirstCanonicalFields})
+		lengthFirstFields = make(fields, len(flds))
+		copy(lengthFirstFields, flds)
+		sort.Sort(&lengthFirstFieldSorter{lengthFirstFields})
 	}
 
-	structType := encodingStructType{
-		fields:                  flds,
-		bytewiseCanonicalFields: bytewiseCanonicalFields,
-		lenFirstCanonicalFields: lenFirstCanonicalFields,
-		omitEmpty:               omitEmpty,
-		hasAnonymousField:       hasAnonymousField,
+	structType := &encodingStructType{
+		fields:            flds,
+		bytewiseFields:    bytewiseFields,
+		lengthFirstFields: lengthFirstFields,
+		omitEmpty:         omitEmpty,
+		hasAnonymousField: hasAnonymousField,
 	}
 	encodingStructTypeCache.Store(t, structType)
 	return structType
 }
 
-func getEncodingStructToArrayType(t reflect.Type, flds fields) encodingStructType {
+func getEncodingStructToArrayType(t reflect.Type, flds fields) *encodingStructType {
 	var hasAnonymousField bool
 	for i := 0; i < len(flds); i++ {
 		// Get field's encodeFunc
 		flds[i].ef = getEncodeFunc(flds[i].typ)
 		if flds[i].ef == nil {
-			structType := encodingStructType{err: &UnsupportedTypeError{t}}
+			structType := &encodingStructType{err: &UnsupportedTypeError{t}}
 			encodingStructTypeCache.Store(t, structType)
 			return structType
 		}
@@ -209,7 +225,7 @@ func getEncodingStructToArrayType(t reflect.Type, flds fields) encodingStructTyp
 		}
 	}
 
-	structType := encodingStructType{
+	structType := &encodingStructType{
 		fields:            flds,
 		toArray:           true,
 		hasAnonymousField: hasAnonymousField,
diff --git a/decode.go b/decode.go
index 83f0bc4..80bc452 100644
--- a/decode.go
+++ b/decode.go
@@ -7,6 +7,7 @@ import (
 	"encoding"
 	"encoding/binary"
 	"errors"
+	"io"
 	"math"
 	"reflect"
 	"strconv"
@@ -18,7 +19,8 @@ import (
 )
 
 // Unmarshal parses the CBOR-encoded data and stores the result in the value
-// pointed to by v.  If v is nil or not a pointer, Unmarshal returns an error.
+// pointed to by v using the default decoding options.  If v is nil or not a
+// pointer, Unmarshal returns an error.
 //
 // Unmarshal uses the inverse of the encodings that Marshal uses, allocating
 // maps, slices, and pointers as necessary, with the following additional rules:
@@ -92,8 +94,7 @@ import (
 //
 // Unmarshal ignores CBOR tag data and parses tagged data following CBOR tag.
 func Unmarshal(data []byte, v interface{}) error {
-	d := decodeState{data: data}
-	return d.value(v)
+	return defaultDecMode.Unmarshal(data, v)
 }
 
 // Unmarshaler is the interface implemented by types that can unmarshal a CBOR
@@ -101,7 +102,7 @@ func Unmarshal(data []byte, v interface{}) error {
 // of a CBOR value. UnmarshalCBOR must copy the CBOR data if it wishes to retain
 // the data after returning.
 type Unmarshaler interface {
-	UnmarshalCBOR([]byte) error
+	UnmarshalCBOR(DecMode, []byte) error
 }
 
 // InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
@@ -141,9 +142,52 @@ func (e *UnmarshalTypeError) Error() string {
 	return s
 }
 
+// DecOptions specifies decoding options.
+type DecOptions struct {
+}
+
+// DecMode returns a DecMode interface from DecOptions.
+func (opts DecOptions) DecMode() (DecMode, error) {
+	dm := decMode{}
+	return &dm, nil
+}
+
+// DecMode is the main interface for CBOR decoding.
+type DecMode interface {
+	Unmarshal(data []byte, v interface{}) error
+	NewDecoder(r io.Reader) *Decoder
+	DecOptions() DecOptions
+}
+
+type decMode struct {
+}
+
+var defaultDecMode = &decMode{}
+
+// DecOptions returns user specified options used to create this DecMode.
+func (dm *decMode) DecOptions() DecOptions {
+	return DecOptions{}
+}
+
+// Unmarshal parses the CBOR-encoded data and stores the result in the value
+// pointed to by v using dm DecMode.  If v is nil or not a pointer, Unmarshal
+// returns an error.
+//
+// See the documentation for Unmarshal for details.
+func (dm *decMode) Unmarshal(data []byte, v interface{}) error {
+	d := decodeState{data: data, dm: dm}
+	return d.value(v)
+}
+
+// NewDecoder returns a new decoder that reads from r using dm DecMode.
+func (dm *decMode) NewDecoder(r io.Reader) *Decoder {
+	return &Decoder{r: r, d: decodeState{dm: dm}}
+}
+
 type decodeState struct {
 	data []byte
 	off  int // next read offset in data
+	dm   *decMode
 }
 
 func (d *decodeState) value(v interface{}) error {
@@ -152,7 +196,7 @@ func (d *decodeState) value(v interface{}) error {
 		return &InvalidUnmarshalError{reflect.TypeOf(v)}
 	}
 
-	if _, err := Valid(d.data[d.off:]); err != nil {
+	if _, err := valid(d.data[d.off:]); err != nil {
 		return err
 	}
 
@@ -207,7 +251,8 @@ func (t cborType) String() string {
 }
 
 // parseToValue assumes data is well-formed, and does not perform bounds checking.
-func (d *decodeState) parseToValue(v reflect.Value, isUnmarshaler bool) error {
+// This function is complicated because it's the main function that decodes CBOR data to reflect.Value.
+func (d *decodeState) parseToValue(v reflect.Value, isUnmarshaler bool) error { //nolint:gocyclo
 	if isUnmarshaler {
 		return d.parseToUnmarshaler(v)
 	}
@@ -261,7 +306,7 @@ func (d *decodeState) parseToValue(v reflect.Value, isUnmarshaler bool) error {
 	case cborTypePrimitives:
 		_, ai, val := d.getHead()
 		if ai < 20 || ai == 24 {
-			return fillPositiveInt(t, uint64(val), v)
+			return fillPositiveInt(t, val, v)
 		}
 		switch ai {
 		case 20, 21:
@@ -313,11 +358,9 @@ func (d *decodeState) parseToUnmarshaler(v reflect.Value) error {
 			}
 			v = v.Elem()
 		}
-	} else {
-		if v.Kind() == reflect.Ptr && v.IsNil() {
-			d.skip()
-			return nil
-		}
+	} else if v.Kind() == reflect.Ptr && v.IsNil() {
+		d.skip()
+		return nil
 	}
 
 	if v.Kind() != reflect.Ptr && v.CanAddr() {
@@ -326,7 +369,7 @@ func (d *decodeState) parseToUnmarshaler(v reflect.Value) error {
 	if u, ok := v.Interface().(Unmarshaler); ok {
 		start := d.off
 		d.skip()
-		return u.UnmarshalCBOR(d.data[start:d.off])
+		return u.UnmarshalCBOR(d.dm, d.data[start:d.off])
 	}
 	d.skip()
 	return errors.New("cbor: failed to assert " + v.Type().String() + " as cbor.Unmarshaler")
@@ -342,7 +385,11 @@ func (d *decodeState) parse() (interface{}, error) {
 	case cborTypeNegativeInt:
 		_, _, val := d.getHead()
 		if val > math.MaxInt64 {
-			return nil, &UnmarshalTypeError{Value: t.String(), Type: reflect.TypeOf([]interface{}(nil)).Elem(), errMsg: "-1-" + strconv.FormatUint(val, 10) + " overflows Go's int64"}
+			return nil, &UnmarshalTypeError{
+				Value:  t.String(),
+				Type:   reflect.TypeOf([]interface{}(nil)).Elem(),
+				errMsg: "-1-" + strconv.FormatUint(val, 10) + " overflows Go's int64",
+			}
 		}
 		nValue := int64(-1) ^ int64(val)
 		return nValue, nil
@@ -360,7 +407,7 @@ func (d *decodeState) parse() (interface{}, error) {
 	case cborTypePrimitives:
 		_, ai, val := d.getHead()
 		if ai < 20 || ai == 24 {
-			return uint64(val), nil
+			return val, nil
 		}
 		switch ai {
 		case 20, 21:
@@ -621,7 +668,11 @@ func (d *decodeState) parseArrayToStruct(v reflect.Value) error {
 	if !structType.toArray {
 		t := d.nextCBORType()
 		d.skip()
-		return &UnmarshalTypeError{Value: t.String(), Type: v.Type(), errMsg: "cannot decode CBOR array to struct without toarray option"}
+		return &UnmarshalTypeError{
+			Value:  t.String(),
+			Type:   v.Type(),
+			errMsg: "cannot decode CBOR array to struct without toarray option",
+		}
 	}
 	start := d.off
 	t, ai, val := d.getHead()
@@ -633,7 +684,11 @@ func (d *decodeState) parseArrayToStruct(v reflect.Value) error {
 	if count != len(structType.fields) {
 		d.off = start
 		d.skip()
-		return &UnmarshalTypeError{Value: t.String(), Type: v.Type(), errMsg: "cannot decode CBOR array to struct with different number of elements"}
+		return &UnmarshalTypeError{
+			Value:  t.String(),
+			Type:   v.Type(),
+			errMsg: "cannot decode CBOR array to struct with different number of elements",
+		}
 	}
 	var err error
 	for i := 0; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ {
@@ -696,7 +751,11 @@ func (d *decodeState) parseMapToStruct(v reflect.Value) error {
 			}
 		} else {
 			if err == nil {
-				err = &UnmarshalTypeError{Value: t.String(), Type: reflect.TypeOf(""), errMsg: "map key is of type " + t.String() + " and cannot be used to match struct " + v.Type().String() + " field name"}
+				err = &UnmarshalTypeError{
+					Value:  t.String(),
+					Type:   reflect.TypeOf(""),
+					errMsg: "map key is of type " + t.String() + " and cannot be used to match struct " + v.Type().String() + " field name",
+				}
 			}
 			d.skip() // skip key
 			d.skip() // skip value
@@ -756,30 +815,12 @@ func (d *decodeState) parseMapToStruct(v reflect.Value) error {
 // skip moves data offset to the next item.  skip assumes data is well-formed,
 // and does not perform bounds checking.
 func (d *decodeState) skip() {
-	t := cborType(d.data[d.off] & 0xe0)
-	ai := d.data[d.off] & 0x1f
-	val := uint64(ai)
-	d.off++
-
-	switch ai {
-	case 24:
-		val = uint64(d.data[d.off])
-		d.off++
-	case 25:
-		val = uint64(binary.BigEndian.Uint16(d.data[d.off : d.off+2]))
-		d.off += 2
-	case 26:
-		val = uint64(binary.BigEndian.Uint32(d.data[d.off : d.off+4]))
-		d.off += 4
-	case 27:
-		val = binary.BigEndian.Uint64(d.data[d.off : d.off+8])
-		d.off += 8
-	}
+	t, ai, val := d.getHead()
 
 	if ai == 31 {
 		switch t {
 		case cborTypeByteString, cborTypeTextString, cborTypeArray, cborTypeMap:
-			for true {
+			for {
 				if d.data[d.off] == 0xff {
 					d.off++
 					return
@@ -945,12 +986,20 @@ func fillFloat(t cborType, val float64, v reflect.Value) error {
 	switch v.Kind() {
 	case reflect.Float32, reflect.Float64:
 		if v.OverflowFloat(val) {
-			return &UnmarshalTypeError{Value: t.String(), Type: v.Type(), errMsg: strconv.FormatFloat(val, 'E', -1, 64) + " overflows " + v.Type().String()}
+			return &UnmarshalTypeError{
+				Value:  t.String(),
+				Type:   v.Type(),
+				errMsg: strconv.FormatFloat(val, 'E', -1, 64) + " overflows " + v.Type().String(),
+			}
 		}
 		v.SetFloat(val)
 		return nil
 	}
 	if v.Type() == typeTime {
+		if math.IsNaN(val) || math.IsInf(val, 0) {
+			v.Set(reflect.ValueOf(time.Time{}))
+			return nil
+		}
 		f1, f2 := math.Modf(val)
 		tm := time.Unix(int64(f1), int64(f2*1e9))
 		v.Set(reflect.ValueOf(tm))
diff --git a/encode.go b/encode.go
index c7d8967..b443daa 100644
--- a/encode.go
+++ b/encode.go
@@ -8,6 +8,7 @@ import (
 	"encoding"
 	"encoding/binary"
 	"errors"
+	"io"
 	"math"
 	"reflect"
 	"sort"
@@ -18,7 +19,7 @@ import (
 	"github.com/x448/float16"
 )
 
-// Marshal returns the CBOR encoding of v.
+// Marshal returns the CBOR encoding of v using the default encoding options.
 //
 // Marshal uses the following type-dependent default encodings:
 //
@@ -68,7 +69,7 @@ import (
 // "omitempty" is disabled by "toarray" to ensure that the same number
 // of elements are encoded every time.
 //
-// Anonymous struct fields are usually marshalled as if their exported fields
+// Anonymous struct fields are usually marshaled as if their exported fields
 // were fields in the outer struct.  Marshal follows the same struct fields
 // visibility rules used by JSON encoding package.  An anonymous struct field
 // with a name given in its CBOR tag is treated as having that name, rather
@@ -80,26 +81,14 @@ import (
 //
 // Channel, complex, and functon values cannot be encoded in CBOR.  Attempting
 // to encode such a value causes Marshal to return an UnsupportedTypeError.
-func Marshal(v interface{}, encOpts EncOptions) ([]byte, error) {
-	e := getEncodeState()
-
-	err := e.marshal(v, encOpts)
-	if err != nil {
-		putEncodeState(e)
-		return nil, err
-	}
-
-	buf := make([]byte, e.Len())
-	copy(buf, e.Bytes())
-
-	putEncodeState(e)
-	return buf, nil
+func Marshal(v interface{}) ([]byte, error) {
+	return defaultEncMode.Marshal(v)
 }
 
 // Marshaler is the interface implemented by types that can marshal themselves
 // into valid CBOR.
 type Marshaler interface {
-	MarshalCBOR() ([]byte, error)
+	MarshalCBOR(EncMode) ([]byte, error)
 }
 
 // UnsupportedTypeError is returned by Marshal when attempting to encode an
@@ -161,7 +150,7 @@ const (
 	ShortestFloatNone ShortestFloatMode = iota
 
 	// ShortestFloat16 specifies float16 as the shortest form that preserves value.
-	// E.g. if float64 can convert to float32 while perserving value, then
+	// E.g. if float64 can convert to float32 while preserving value, then
 	// encoding will also try to convert float32 to float16.  So a float64 might
 	// encode as CBOR float64, float32 or float16 depending on the value.
 	ShortestFloat16
@@ -219,6 +208,33 @@ func (icm InfConvertMode) valid() bool {
 	return icm < maxInfConvert
 }
 
+// TimeMode specifies how to encode time.Time values.
+type TimeMode int
+
+const (
+	// TimeUnix causes time.Time to be encoded as epoch time in integer with second precision.
+	TimeUnix TimeMode = iota
+
+	// TimeUnixMicro causes time.Time to be encoded as epoch time in float-point rounded to microsecond precision.
+	TimeUnixMicro
+
+	// TimeUnixDynamic causes time.Time to be encoded as integer if time.Time doesn't have fractional seconds,
+	// otherwise float-point rounded to microsecond precision.
+	TimeUnixDynamic
+
+	// TimeRFC3339 causes time.Time to be encoded as RFC3339 formatted string with second precision.
+	TimeRFC3339
+
+	// TimeRFC3339Nano causes time.Time to be encoded as RFC3339 formatted string with nanosecond precision.
+	TimeRFC3339Nano
+
+	maxTimeMode
+)
+
+func (tm TimeMode) valid() bool {
+	return tm < maxTimeMode
+}
+
 // EncOptions specifies encoding options.
 type EncOptions struct {
 	// Sort specifies sorting order.
@@ -234,31 +250,8 @@ type EncOptions struct {
 	// InfConvert specifies how to encode Inf and it overrides ShortestFloatMode.
 	InfConvert InfConvertMode
 
-	// Canonical causes map and struct to be encoded in a predictable sequence
-	// of bytes by sorting map keys or struct fields according to canonical rules:
-	//     - If two keys have different lengths, the shorter one sorts earlier;
-	//     - If two keys have the same length, the one with the lower value in
-	//       (byte-wise) lexical order sorts earlier.
-	//
-	// Deprecated: Set Sort to SortCanonical instead.
-	Canonical bool
-
-	// CTAP2Canonical uses bytewise lexicographic order of map keys encodings:
-	//     - If the major types are different, the one with the lower value in
-	//       numerical order sorts earlier.
-	//     - If two keys have different lengths, the shorter one sorts earlier;
-	//     - If two keys have the same length, the one with the lower value in
-	//       (byte-wise) lexical order sorts earlier.
-	// Please note that when maps keys have the same data type, "canonical CBOR"
-	// AND "CTAP2 canonical CBOR" render the same sort order.
-	//
-	// Deprecated: Set Sort to SortCTAP2 instead.
-	CTAP2Canonical bool
-
-	// TimeRFC3339 causes time.Time to be encoded as string in RFC3339 format;
-	// otherwise, time.Time is encoded as numerical representation of seconds
-	// since January 1, 1970 UTC.
-	TimeRFC3339 bool
+	// Time specifies how to encode time.Time.
+	Time TimeMode
 
 	disableIndefiniteLength bool
 }
@@ -356,6 +349,88 @@ func PreferredUnsortedEncOptions() EncOptions {
 	}
 }
 
+// EncMode returns an EncMode interface from EncOptions.
+func (opts EncOptions) EncMode() (EncMode, error) {
+	if !opts.Sort.valid() {
+		return nil, errors.New("cbor: invalid SortMode " + strconv.Itoa(int(opts.Sort)))
+	}
+	if !opts.ShortestFloat.valid() {
+		return nil, errors.New("cbor: invalid ShortestFloatMode " + strconv.Itoa(int(opts.ShortestFloat)))
+	}
+	if !opts.NaNConvert.valid() {
+		return nil, errors.New("cbor: invalid NaNConvertMode " + strconv.Itoa(int(opts.NaNConvert)))
+	}
+	if !opts.InfConvert.valid() {
+		return nil, errors.New("cbor: invalid InfConvertMode " + strconv.Itoa(int(opts.InfConvert)))
+	}
+	if !opts.Time.valid() {
+		return nil, errors.New("cbor: invalid TimeMode " + strconv.Itoa(int(opts.Time)))
+	}
+	em := encMode{
+		sort:                    opts.Sort,
+		shortestFloat:           opts.ShortestFloat,
+		nanConvert:              opts.NaNConvert,
+		infConvert:              opts.InfConvert,
+		time:                    opts.Time,
+		disableIndefiniteLength: opts.disableIndefiniteLength,
+	}
+	return &em, nil
+}
+
+// EncMode is the main interface for CBOR encoding.
+type EncMode interface {
+	Marshal(v interface{}) ([]byte, error)
+	NewEncoder(w io.Writer) *Encoder
+	EncOptions() EncOptions
+}
+
+type encMode struct {
+	sort                    SortMode
+	shortestFloat           ShortestFloatMode
+	nanConvert              NaNConvertMode
+	infConvert              InfConvertMode
+	time                    TimeMode
+	disableIndefiniteLength bool
+}
+
+var defaultEncMode = &encMode{}
+
+// EncOptions returns user specified options used to create this EncMode.
+func (em *encMode) EncOptions() EncOptions {
+	return EncOptions{
+		Sort:                    em.sort,
+		ShortestFloat:           em.shortestFloat,
+		NaNConvert:              em.nanConvert,
+		InfConvert:              em.infConvert,
+		Time:                    em.time,
+		disableIndefiniteLength: em.disableIndefiniteLength,
+	}
+}
+
+// Marshal returns the CBOR encoding of v using em EncMode.
+//
+// See the documentation for Marshal for details.
+func (em *encMode) Marshal(v interface{}) ([]byte, error) {
+	e := getEncodeState()
+
+	_, err := encode(e, em, reflect.ValueOf(v))
+	if err != nil {
+		putEncodeState(e)
+		return nil, err
+	}
+
+	buf := make([]byte, e.Len())
+	copy(buf, e.Bytes())
+
+	putEncodeState(e)
+	return buf, nil
+}
+
+// NewEncoder returns a new encoder that writes to w using em EncMode.
+func (em *encMode) NewEncoder(w io.Writer) *Encoder {
+	return &Encoder{w: w, em: em, e: getEncodeState()}
+}
+
 // An encodeState encodes CBOR into a bytes.Buffer.
 type encodeState struct {
 	bytes.Buffer
@@ -381,47 +456,18 @@ func putEncodeState(e *encodeState) {
 	encodeStatePool.Put(e)
 }
 
-func (e *encodeState) marshal(v interface{}, opts EncOptions) error {
-	if !opts.Sort.valid() {
-		return errors.New("cbor: invalid SortMode " + strconv.Itoa(int(opts.Sort)))
-	}
-	if opts.Canonical {
-		if opts.Sort != SortNone && opts.Sort != SortCanonical {
-			return errors.New("cbor: conflicting sorting modes not allowed")
-		}
-		opts.Sort = SortCanonical
-	}
-	if opts.CTAP2Canonical {
-		if opts.Sort != SortNone && opts.Sort != SortCTAP2 {
-			return errors.New("cbor: conflicting sorting modes not allowed")
-		}
-		opts.Sort = SortCTAP2
-	}
-	if !opts.ShortestFloat.valid() {
-		return errors.New("cbor: invalid ShortestFloatMode " + strconv.Itoa(int(opts.ShortestFloat)))
-	}
-	if !opts.NaNConvert.valid() {
-		return errors.New("cbor: invalid NaNConvertMode " + strconv.Itoa(int(opts.NaNConvert)))
-	}
-	if !opts.InfConvert.valid() {
-		return errors.New("cbor: invalid InfConvertMode " + strconv.Itoa(int(opts.InfConvert)))
-	}
-	_, err := encode(e, reflect.ValueOf(v), opts)
-	return err
-}
-
-type encodeFunc func(e *encodeState, v reflect.Value, opts EncOptions) (int, error)
+type encodeFunc func(e *encodeState, em *encMode, v reflect.Value) (int, error)
 
 var (
 	cborFalse            = []byte{0xf4}
 	cborTrue             = []byte{0xf5}
 	cborNil              = []byte{0xf6}
-	cborNan              = []byte{0xf9, 0x7e, 0x00}
+	cborNaN              = []byte{0xf9, 0x7e, 0x00}
 	cborPositiveInfinity = []byte{0xf9, 0x7c, 0x00}
 	cborNegativeInfinity = []byte{0xf9, 0xfc, 0x00}
 )
 
-func encode(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+func encode(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 	if !v.IsValid() {
 		// v is zero value
 		e.Write(cborNil)
@@ -432,17 +478,17 @@ func encode(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
 		return 0, &UnsupportedTypeError{v.Type()}
 	}
 
-	return f(e, v, opts)
+	return f(e, em, v)
 }
 
-func encodeBool(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+func encodeBool(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 	if v.Bool() {
 		return e.Write(cborTrue)
 	}
 	return e.Write(cborFalse)
 }
 
-func encodeInt(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+func encodeInt(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 	i := v.Int()
 	if i >= 0 {
 		return encodeHead(e, byte(cborTypePositiveInt), uint64(i)), nil
@@ -451,19 +497,19 @@ func encodeInt(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
 	return encodeHead(e, byte(cborTypeNegativeInt), uint64(n)), nil
 }
 
-func encodeUint(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+func encodeUint(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 	return encodeHead(e, byte(cborTypePositiveInt), v.Uint()), nil
 }
 
-func encodeFloat(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+func encodeFloat(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 	f64 := v.Float()
 	if math.IsNaN(f64) {
-		return encodeNaN(e, v, opts)
+		return encodeNaN(e, em, v)
 	}
 	if math.IsInf(f64, 0) {
-		return encodeInf(e, v, opts)
+		return encodeInf(e, em, v)
 	}
-	fopt := opts.ShortestFloat
+	fopt := em.shortestFloat
 	if v.Kind() == reflect.Float64 && (fopt == ShortestFloatNone || cannotFitFloat32(f64)) {
 		// Encode float64
 		// Don't use encodeFloat64() because it cannot be inlined.
@@ -502,9 +548,9 @@ func encodeFloat(e *encodeState, v reflect.Value, opts EncOptions) (int, error)
 	return e.Write(e.scratch[:5])
 }
 
-func encodeInf(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+func encodeInf(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 	f64 := v.Float()
-	if opts.InfConvert == InfConvertFloat16 {
+	if em.infConvert == InfConvertFloat16 {
 		if f64 > 0 {
 			return e.Write(cborPositiveInfinity)
 		}
@@ -516,10 +562,10 @@ func encodeInf(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
 	return encodeFloat32(e, float32(f64))
 }
 
-func encodeNaN(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
-	switch opts.NaNConvert {
+func encodeNaN(e *encodeState, em *encMode, v reflect.Value) (int, error) {
+	switch em.nanConvert {
 	case NaNConvert7e00:
-		return e.Write(cborNan)
+		return e.Write(cborNaN)
 
 	case NaNConvertNone:
 		if v.Kind() == reflect.Float64 {
@@ -532,8 +578,8 @@ func encodeNaN(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
 		if v.Kind() == reflect.Float64 {
 			f64 := v.Float()
 			f64bits := math.Float64bits(f64)
-			if opts.NaNConvert == NaNConvertQuiet && f64bits&(1<<51) == 0 {
-				f64bits = f64bits | (1 << 51) // Set quiet bit = 1
+			if em.nanConvert == NaNConvertQuiet && f64bits&(1<<51) == 0 {
+				f64bits |= 1 << 51 // Set quiet bit = 1
 				f64 = math.Float64frombits(f64bits)
 			}
 			// The lower 29 bits are dropped when converting from float64 to float32.
@@ -559,8 +605,8 @@ func encodeNaN(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
 
 		f32 := float32NaNFromReflectValue(v)
 		f32bits := math.Float32bits(f32)
-		if opts.NaNConvert == NaNConvertQuiet && f32bits&(1<<22) == 0 {
-			f32bits = f32bits | (1 << 22) // Set quiet bit = 1
+		if em.nanConvert == NaNConvertQuiet && f32bits&(1<<22) == 0 {
+			f32bits |= 1 << 22 // Set quiet bit = 1
 			f32 = math.Float32frombits(f32bits)
 		}
 		// The lower 13 bits are dropped coef bits when converting from float32 to float16.
@@ -591,7 +637,7 @@ func encodeFloat64(e *encodeState, f64 float64) (int, error) {
 	return e.Write(e.scratch[:9])
 }
 
-func encodeByteString(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+func encodeByteString(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 	if v.Kind() == reflect.Slice && v.IsNil() {
 		return e.Write(cborNil)
 	}
@@ -610,11 +656,8 @@ func encodeByteString(e *encodeState, v reflect.Value, opts EncOptions) (int, er
 	return n1 + n2, nil
 }
 
-func encodeString(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
-	return encodeStringInternal(e, v.String(), opts)
-}
-
-func encodeStringInternal(e *encodeState, s string, opts EncOptions) (int, error) {
+func encodeString(e *encodeState, em *encMode, v reflect.Value) (int, error) {
+	s := v.String()
 	n1 := encodeHead(e, byte(cborTypeTextString), uint64(len(s)))
 	n2, _ := e.WriteString(s)
 	return n1 + n2, nil
@@ -624,7 +667,7 @@ type arrayEncoder struct {
 	f encodeFunc
 }
 
-func (ae arrayEncoder) encodeArray(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+func (ae arrayEncoder) encodeArray(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 	if ae.f == nil {
 		return 0, &UnsupportedTypeError{v.Type()}
 	}
@@ -637,7 +680,7 @@ func (ae arrayEncoder) encodeArray(e *encodeState, v reflect.Value, opts EncOpti
 	}
 	n := encodeHead(e, byte(cborTypeArray), uint64(alen))
 	for i := 0; i < alen; i++ {
-		n1, err := ae.f(e, v.Index(i), opts)
+		n1, err := ae.f(e, em, v.Index(i))
 		if err != nil {
 			return 0, err
 		}
@@ -650,9 +693,9 @@ type mapEncoder struct {
 	kf, ef encodeFunc
 }
 
-func (me mapEncoder) encodeMap(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
-	if opts.Sort != SortNone {
-		return me.encodeMapCanonical(e, v, opts)
+func (me mapEncoder) encodeMap(e *encodeState, em *encMode, v reflect.Value) (int, error) {
+	if em.sort != SortNone {
+		return me.encodeMapCanonical(e, em, v)
 	}
 	if me.kf == nil || me.ef == nil {
 		return 0, &UnsupportedTypeError{v.Type()}
@@ -667,11 +710,11 @@ func (me mapEncoder) encodeMap(e *encodeState, v reflect.Value, opts EncOptions)
 	n := encodeHead(e, byte(cborTypeMap), uint64(mlen))
 	iter := v.MapRange()
 	for iter.Next() {
-		n1, err := me.kf(e, iter.Key(), opts)
+		n1, err := me.kf(e, em, iter.Key())
 		if err != nil {
 			return 0, err
 		}
-		n2, err := me.ef(e, iter.Value(), opts)
+		n2, err := me.ef(e, em, iter.Value())
 		if err != nil {
 			return 0, err
 		}
@@ -685,58 +728,67 @@ type keyValue struct {
 	keyLen, keyValueLen           int
 }
 
-type pairs []keyValue
+type bytewiseKeyValueSorter struct {
+	kvs []keyValue
+}
+
+func (x *bytewiseKeyValueSorter) Len() int {
+	return len(x.kvs)
+}
 
-func (x pairs) Len() int {
-	return len(x)
+func (x *bytewiseKeyValueSorter) Swap(i, j int) {
+	x.kvs[i], x.kvs[j] = x.kvs[j], x.kvs[i]
 }
 
-func (x pairs) Swap(i, j int) {
-	x[i], x[j] = x[j], x[i]
+func (x *bytewiseKeyValueSorter) Less(i, j int) bool {
+	return bytes.Compare(x.kvs[i].keyCBORData, x.kvs[j].keyCBORData) <= 0
 }
 
-type byBytewiseKeyValues struct {
-	pairs
+type lengthFirstKeyValueSorter struct {
+	kvs []keyValue
 }
 
-func (x byBytewiseKeyValues) Less(i, j int) bool {
-	return bytes.Compare(x.pairs[i].keyCBORData, x.pairs[j].keyCBORData) <= 0
+func (x *lengthFirstKeyValueSorter) Len() int {
+	return len(x.kvs)
 }
 
-type byLengthFirstKeyValues struct {
-	pairs
+func (x *lengthFirstKeyValueSorter) Swap(i, j int) {
+	x.kvs[i], x.kvs[j] = x.kvs[j], x.kvs[i]
 }
 
-func (x byLengthFirstKeyValues) Less(i, j int) bool {
-	if len(x.pairs[i].keyCBORData) != len(x.pairs[j].keyCBORData) {
-		return len(x.pairs[i].keyCBORData) < len(x.pairs[j].keyCBORData)
+func (x *lengthFirstKeyValueSorter) Less(i, j int) bool {
+	if len(x.kvs[i].keyCBORData) != len(x.kvs[j].keyCBORData) {
+		return len(x.kvs[i].keyCBORData) < len(x.kvs[j].keyCBORData)
 	}
-	return bytes.Compare(x.pairs[i].keyCBORData, x.pairs[j].keyCBORData) <= 0
+	return bytes.Compare(x.kvs[i].keyCBORData, x.kvs[j].keyCBORData) <= 0
 }
 
 var keyValuePool = sync.Pool{}
 
-func getKeyValues(length int) []keyValue {
+func getKeyValues(length int) *[]keyValue {
 	v := keyValuePool.Get()
 	if v == nil {
-		return make([]keyValue, 0, length)
+		y := make([]keyValue, length)
+		return &y
 	}
-	x := v.([]keyValue)
-	if cap(x) < length {
-		// []keyValue from the pool does not have enough capacity.
-		// Return it back to the pool and create a new one.
-		keyValuePool.Put(x)
-		return make([]keyValue, 0, length)
+	x := v.(*[]keyValue)
+	if cap(*x) >= length {
+		*x = (*x)[:length]
+		return x
 	}
-	return x
+	// []keyValue from the pool does not have enough capacity.
+	// Return it back to the pool and create a new one.
+	keyValuePool.Put(x)
+	y := make([]keyValue, length)
+	return &y
 }
 
-func putKeyValues(x []keyValue) {
-	x = x[:0]
+func putKeyValues(x *[]keyValue) {
+	*x = (*x)[:0]
 	keyValuePool.Put(x)
 }
 
-func (me mapEncoder) encodeMapCanonical(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+func (me mapEncoder) encodeMapCanonical(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 	if me.kf == nil || me.ef == nil {
 		return 0, &UnsupportedTypeError{v.Type()}
 	}
@@ -747,23 +799,26 @@ func (me mapEncoder) encodeMapCanonical(e *encodeState, v reflect.Value, opts En
 		return 1, e.WriteByte(byte(cborTypeMap))
 	}
 
-	kve := getEncodeState()      // accumulated cbor encoded key-values
-	kvs := getKeyValues(v.Len()) // for sorting keys
+	kve := getEncodeState()       // accumulated cbor encoded key-values
+	kvsp := getKeyValues(v.Len()) // for sorting keys
+	kvs := *kvsp
 	iter := v.MapRange()
-	for iter.Next() {
-		n1, err := me.kf(kve, iter.Key(), opts)
+	for i := 0; iter.Next(); i++ {
+		n1, err := me.kf(kve, em, iter.Key())
 		if err != nil {
 			putEncodeState(kve)
-			putKeyValues(kvs)
+			putKeyValues(kvsp)
 			return 0, err
 		}
-		n2, err := me.ef(kve, iter.Value(), opts)
+		n2, err := me.ef(kve, em, iter.Value())
 		if err != nil {
 			putEncodeState(kve)
-			putKeyValues(kvs)
+			putKeyValues(kvsp)
 			return 0, err
 		}
-		kvs = append(kvs, keyValue{keyLen: n1, keyValueLen: n1 + n2})
+
+		// Save key and keyvalue length to create slice later.
+		kvs[i] = keyValue{keyLen: n1, keyValueLen: n1 + n2}
 	}
 
 	b := kve.Bytes()
@@ -773,10 +828,10 @@ func (me mapEncoder) encodeMapCanonical(e *encodeState, v reflect.Value, opts En
 		off += kvs[i].keyValueLen
 	}
 
-	if opts.Sort == SortBytewiseLexical {
-		sort.Sort(byBytewiseKeyValues{kvs})
+	if em.sort == SortBytewiseLexical {
+		sort.Sort(&bytewiseKeyValueSorter{kvs})
 	} else {
-		sort.Sort(byLengthFirstKeyValues{kvs})
+		sort.Sort(&lengthFirstKeyValueSorter{kvs})
 	}
 
 	n := encodeHead(e, byte(cborTypeMap), uint64(len(kvs)))
@@ -786,11 +841,11 @@ func (me mapEncoder) encodeMapCanonical(e *encodeState, v reflect.Value, opts En
 	}
 
 	putEncodeState(kve)
-	putKeyValues(kvs)
+	putKeyValues(kvsp)
 	return n, nil
 }
 
-func encodeStructToArray(e *encodeState, v reflect.Value, opts EncOptions, flds fields) (int, error) {
+func encodeStructToArray(e *encodeState, em *encMode, v reflect.Value, flds fields) (int, error) {
 	n := encodeHead(e, byte(cborTypeArray), uint64(len(flds)))
 FieldLoop:
 	for i := 0; i < len(flds); i++ {
@@ -808,7 +863,7 @@ FieldLoop:
 			}
 			fv = fv.Field(n)
 		}
-		n1, err := flds[i].ef(e, fv, opts)
+		n1, err := flds[i].ef(e, em, fv)
 		if err != nil {
 			return 0, err
 		}
@@ -817,14 +872,14 @@ FieldLoop:
 	return n, nil
 }
 
-func encodeFixedLengthStruct(e *encodeState, v reflect.Value, opts EncOptions, flds fields) (int, error) {
+func encodeFixedLengthStruct(e *encodeState, em *encMode, v reflect.Value, flds fields) (int, error) {
 	n := encodeHead(e, byte(cborTypeMap), uint64(len(flds)))
 
 	for i := 0; i < len(flds); i++ {
 		n1, _ := e.Write(flds[i].cborName)
 
 		fv := v.Field(flds[i].idx[0])
-		n2, err := flds[i].ef(e, fv, opts)
+		n2, err := flds[i].ef(e, em, fv)
 		if err != nil {
 			return 0, err
 		}
@@ -835,20 +890,20 @@ func encodeFixedLengthStruct(e *encodeState, v reflect.Value, opts EncOptions, f
 	return n, nil
 }
 
-func encodeStruct(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+func encodeStruct(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 	structType := getEncodingStructType(v.Type())
 	if structType.err != nil {
 		return 0, structType.err
 	}
 
 	if structType.toArray {
-		return encodeStructToArray(e, v, opts, structType.fields)
+		return encodeStructToArray(e, em, v, structType.fields)
 	}
 
-	flds := structType.getFields(opts)
+	flds := structType.getFields(em)
 
 	if !structType.hasAnonymousField && !structType.omitEmpty {
-		return encodeFixedLengthStruct(e, v, opts, flds)
+		return encodeFixedLengthStruct(e, em, v, flds)
 	}
 
 	kve := getEncodeState() // encode key-value pairs based on struct field tag options
@@ -874,7 +929,7 @@ FieldLoop:
 
 		kve.Write(flds[i].cborName)
 
-		if _, err := flds[i].ef(kve, fv, opts); err != nil {
+		if _, err := flds[i].ef(kve, em, fv); err != nil {
 			putEncodeState(kve)
 			return 0, err
 		}
@@ -888,31 +943,44 @@ FieldLoop:
 	return n1 + n2, err
 }
 
-func encodeIntf(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+func encodeIntf(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 	if v.IsNil() {
 		return e.Write(cborNil)
 	}
-	return encode(e, v.Elem(), opts)
+	return encode(e, em, v.Elem())
 }
 
-func encodeTime(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+func encodeTime(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 	t := v.Interface().(time.Time)
 	if t.IsZero() {
 		return e.Write(cborNil)
-	} else if opts.TimeRFC3339 {
-		return encodeStringInternal(e, t.Format(time.RFC3339Nano), opts)
-	} else {
+	}
+	switch em.time {
+	case TimeUnix:
+		secs := t.Unix()
+		return encodeInt(e, em, reflect.ValueOf(secs))
+	case TimeUnixMicro:
+		t = t.UTC().Round(time.Microsecond)
+		f := float64(t.UnixNano()) / 1e9
+		return encodeFloat(e, em, reflect.ValueOf(f))
+	case TimeUnixDynamic:
 		t = t.UTC().Round(time.Microsecond)
 		secs, nsecs := t.Unix(), uint64(t.Nanosecond())
 		if nsecs == 0 {
-			return encodeInt(e, reflect.ValueOf(secs), opts)
+			return encodeInt(e, em, reflect.ValueOf(secs))
 		}
 		f := float64(secs) + float64(nsecs)/1e9
-		return encodeFloat(e, reflect.ValueOf(f), opts)
+		return encodeFloat(e, em, reflect.ValueOf(f))
+	case TimeRFC3339:
+		s := t.Format(time.RFC3339)
+		return encodeString(e, em, reflect.ValueOf(s))
+	default: // TimeRFC3339Nano:
+		s := t.Format(time.RFC3339Nano)
+		return encodeString(e, em, reflect.ValueOf(s))
 	}
 }
 
-func encodeBinaryMarshalerType(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+func encodeBinaryMarshalerType(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 	m, ok := v.Interface().(encoding.BinaryMarshaler)
 	if !ok {
 		pv := reflect.New(v.Type())
@@ -928,14 +996,14 @@ func encodeBinaryMarshalerType(e *encodeState, v reflect.Value, opts EncOptions)
 	return n1 + n2, nil
 }
 
-func encodeMarshalerType(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+func encodeMarshalerType(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 	m, ok := v.Interface().(Marshaler)
 	if !ok {
 		pv := reflect.New(v.Type())
 		pv.Elem().Set(v)
 		m = pv.Interface().(Marshaler)
 	}
-	data, err := m.MarshalCBOR()
+	data, err := m.MarshalCBOR(em)
 	if err != nil {
 		return 0, err
 	}
@@ -966,7 +1034,7 @@ func encodeHead(e *encodeState, t byte, n uint64) int {
 		return 5
 	}
 	e.scratch[0] = t | byte(27)
-	binary.BigEndian.PutUint64(e.scratch[1:], uint64(n))
+	binary.BigEndian.PutUint64(e.scratch[1:], n)
 	e.Write(e.scratch[:9])
 	return 9
 }
@@ -1021,16 +1089,16 @@ func getEncodeIndirectValueFunc(t reflect.Type) encodeFunc {
 	}
 	f := getEncodeFunc(t)
 	if f == nil {
-		return f
+		return nil
 	}
-	return func(e *encodeState, v reflect.Value, opts EncOptions) (int, error) {
+	return func(e *encodeState, em *encMode, v reflect.Value) (int, error) {
 		for v.Kind() == reflect.Ptr && !v.IsNil() {
 			v = v.Elem()
 		}
 		if v.Kind() == reflect.Ptr && v.IsNil() {
 			return e.Write(cborNil)
 		}
-		return f(e, v, opts)
+		return f(e, em, v)
 	}
 }
 
diff --git a/go.mod b/go.mod
index 586fbcd..49d74db 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module github.com/fxamacker/cbor
+module github.com/fxamacker/cbor/v2
 
 go 1.12
 
diff --git a/stream.go b/stream.go
index f94920d..378897b 100644
--- a/stream.go
+++ b/stream.go
@@ -18,9 +18,9 @@ type Decoder struct {
 	bytesRead int
 }
 
-// NewDecoder returns a new decoder that reads from r.
+// NewDecoder returns a new decoder that reads from r using the default decoding options.
 func NewDecoder(r io.Reader) *Decoder {
-	return &Decoder{r: r}
+	return defaultDecMode.NewDecoder(r)
 }
 
 // Decode reads the next CBOR-encoded value from its input and stores it in
@@ -37,14 +37,14 @@ func (dec *Decoder) Decode(v interface{}) error {
 	dec.off += dec.d.off
 	dec.bytesRead += dec.d.off
 	if err != nil {
-		if err == io.ErrUnexpectedEOF {
-			// Need to read more data.
-			if n, err := dec.read(); n == 0 {
-				return err
-			}
-			return dec.Decode(v)
+		if err != io.ErrUnexpectedEOF {
+			return err
+		}
+		// Need to read more data.
+		if n, e := dec.read(); n == 0 {
+			return e
 		}
-		return err
+		return dec.Decode(v)
 	}
 	return nil
 }
@@ -79,14 +79,14 @@ func (dec *Decoder) read() (int, error) {
 // Encoder writes CBOR values to an output stream.
 type Encoder struct {
 	w          io.Writer
-	opts       EncOptions
-	e          encodeState
+	em         *encMode
+	e          *encodeState
 	indefTypes []cborType
 }
 
-// NewEncoder returns a new encoder that writes to w.
-func NewEncoder(w io.Writer, encOpts EncOptions) *Encoder {
-	return &Encoder{w: w, opts: encOpts, e: encodeState{}}
+// NewEncoder returns a new encoder that writes to w using the default encoding options.
+func NewEncoder(w io.Writer) *Encoder {
+	return defaultEncMode.NewEncoder(w)
 }
 
 // Encode writes the CBOR encoding of v to the stream.
@@ -107,7 +107,7 @@ func (enc *Encoder) Encode(v interface{}) error {
 		}
 	}
 
-	err := enc.e.marshal(v, enc.opts)
+	_, err := encode(enc.e, enc.em, reflect.ValueOf(v))
 	if err == nil {
 		_, err = enc.e.WriteTo(enc.w)
 	}
@@ -163,7 +163,7 @@ var cborIndefHeader = map[cborType][]byte{
 }
 
 func (enc *Encoder) startIndefinite(typ cborType) error {
-	if enc.opts.disableIndefiniteLength {
+	if enc.em.disableIndefiniteLength {
 		return errors.New("cbor: indefinite-length items are not allowed")
 	}
 	_, err := enc.w.Write(cborIndefHeader[typ])
@@ -179,7 +179,7 @@ func (enc *Encoder) startIndefinite(typ cborType) error {
 type RawMessage []byte
 
 // MarshalCBOR returns m as the CBOR encoding of m.
-func (m RawMessage) MarshalCBOR() ([]byte, error) {
+func (m RawMessage) MarshalCBOR(em EncMode) ([]byte, error) {
 	if len(m) == 0 {
 		return cborNil, nil
 	}
@@ -187,7 +187,7 @@ func (m RawMessage) MarshalCBOR() ([]byte, error) {
 }
 
 // UnmarshalCBOR sets *m to a copy of data.
-func (m *RawMessage) UnmarshalCBOR(data []byte) error {
+func (m *RawMessage) UnmarshalCBOR(dm DecMode, data []byte) error {
 	if m == nil {
 		return errors.New("cbor.RawMessage: UnmarshalCBOR on nil pointer")
 	}
diff --git a/structfields.go b/structfields.go
index fe43885..86305c3 100644
--- a/structfields.go
+++ b/structfields.go
@@ -23,20 +23,20 @@ type field struct {
 
 type fields []field
 
-func (x fields) Len() int {
-	return len(x)
+// indexFieldSorter sorts fields by field idx at each level, breaking ties with idx depth.
+type indexFieldSorter struct {
+	fields fields
 }
 
-func (x fields) Swap(i, j int) {
-	x[i], x[j] = x[j], x[i]
+func (x *indexFieldSorter) Len() int {
+	return len(x.fields)
 }
 
-// byIndex sorts fields by field idx at each level, breaking ties with idx depth.
-type byIndex struct {
-	fields
+func (x *indexFieldSorter) Swap(i, j int) {
+	x.fields[i], x.fields[j] = x.fields[j], x.fields[i]
 }
 
-func (x byIndex) Less(i, j int) bool {
+func (x *indexFieldSorter) Less(i, j int) bool {
 	iIdx := x.fields[i].idx
 	jIdx := x.fields[j].idx
 	for k, d := range iIdx {
@@ -53,12 +53,20 @@ func (x byIndex) Less(i, j int) bool {
 	return true
 }
 
-// byNameLevelAndTag sorts fields by field name, idx depth, and presence of tag.
-type byNameLevelAndTag struct {
-	fields
+// nameLevelAndTagFieldSorter sorts fields by field name, idx depth, and presence of tag.
+type nameLevelAndTagFieldSorter struct {
+	fields fields
 }
 
-func (x byNameLevelAndTag) Less(i, j int) bool {
+func (x *nameLevelAndTagFieldSorter) Len() int {
+	return len(x.fields)
+}
+
+func (x *nameLevelAndTagFieldSorter) Swap(i, j int) {
+	x.fields[i], x.fields[j] = x.fields[j], x.fields[i]
+}
+
+func (x *nameLevelAndTagFieldSorter) Less(i, j int) bool {
 	if x.fields[i].name != x.fields[j].name {
 		return x.fields[i].name < x.fields[j].name
 	}
@@ -156,7 +164,7 @@ func getFields(typ reflect.Type) (flds fields, structOptions string) {
 		}
 	}
 
-	sort.Sort(byNameLevelAndTag{flds})
+	sort.Sort(&nameLevelAndTagFieldSorter{flds})
 
 	// Keep visible fields.
 	visibleFields := flds[:0]
@@ -172,13 +180,13 @@ func getFields(typ reflect.Type) (flds fields, structOptions string) {
 		}
 	}
 
-	sort.Sort(byIndex{visibleFields})
+	sort.Sort(&indexFieldSorter{visibleFields})
 
 	return visibleFields, structOptions
 }
 
 func getFieldNameAndOptionsFromTag(tag string) (name string, omitEmpty bool, keyAsInt bool) {
-	if len(tag) == 0 {
+	if tag == "" {
 		return
 	}
 	idx := strings.Index(tag, ",")
diff --git a/valid.go b/valid.go
index 574a064..46022f4 100644
--- a/valid.go
+++ b/valid.go
@@ -24,12 +24,12 @@ type SemanticError struct {
 
 func (e *SemanticError) Error() string { return e.msg }
 
-// Valid checks whether CBOR data is complete and well-formed.
-func Valid(data []byte) (rest []byte, err error) {
+// valid checks whether CBOR data is complete and well-formed.
+func valid(data []byte) (rest []byte, err error) {
 	if len(data) == 0 {
 		return nil, io.EOF
 	}
-	offset, _, err := valid(data, 0, 1)
+	offset, _, err := validInternal(data, 0, 1)
 	if err != nil {
 		return nil, err
 	}
@@ -40,7 +40,8 @@ const (
 	maxNestingLevel = 32
 )
 
-func valid(data []byte, off int, depth int) (int, int, error) {
+// validInternal checks data's well-formedness and returns data's next offset, max depth, and error.
+func validInternal(data []byte, off int, depth int) (int, int, error) {
 	if depth > maxNestingLevel {
 		return 0, 0, errors.New("cbor: reached max depth " + strconv.Itoa(maxNestingLevel))
 	}
@@ -80,7 +81,7 @@ func valid(data []byte, off int, depth int) (int, int, error) {
 		for j := 0; j < count; j++ {
 			for i := 0; i < valInt; i++ {
 				var d int
-				if off, d, err = valid(data, off, depth+1); err != nil {
+				if off, d, err = validInternal(data, off, depth+1); err != nil {
 					return 0, 0, err
 				}
 				if d > maxDepth {
@@ -91,7 +92,7 @@ func valid(data []byte, off int, depth int) (int, int, error) {
 		depth = maxDepth
 	case cborTypeTag:
 		// Scan nested tag numbers to avoid recursion.
-		for true {
+		for {
 			if len(data)-off < 1 { // Tag number must be followed by tag content.
 				return 0, 0, io.ErrUnexpectedEOF
 			}
@@ -104,16 +105,17 @@ func valid(data []byte, off int, depth int) (int, int, error) {
 			depth++
 		}
 		// Check tag content.
-		if off, depth, err = valid(data, off, depth); err != nil {
+		if off, depth, err = validInternal(data, off, depth); err != nil {
 			return 0, 0, err
 		}
 	}
 	return off, depth, nil
 }
 
+// validIndefiniteString checks indefinite length byte/text string's well-formedness and returns data's next offset, max depth, and error.
 func validIndefiniteString(data []byte, off int, t cborType, depth int) (int, int, error) {
 	var err error
-	for true {
+	for {
 		if len(data)-off < 1 {
 			return 0, 0, io.ErrUnexpectedEOF
 		}
@@ -129,18 +131,19 @@ func validIndefiniteString(data []byte, off int, t cborType, depth int) (int, in
 		if (data[off] & 0x1f) == 31 {
 			return 0, 0, &SyntaxError{"cbor: indefinite-length " + t.String() + " chunk is not definite-length"}
 		}
-		if off, depth, err = valid(data, off, depth); err != nil {
+		if off, depth, err = validInternal(data, off, depth); err != nil {
 			return 0, 0, err
 		}
 	}
 	return off, depth, nil
 }
 
+// validIndefiniteArrOrMap checks indefinite length array/map's well-formedness and returns data's next offset, max depth, and error.
 func validIndefiniteArrOrMap(data []byte, off int, t cborType, depth int) (int, int, error) {
 	var err error
 	maxDepth := depth
 	i := 0
-	for ; true; i++ {
+	for {
 		if len(data)-off < 1 {
 			return 0, 0, io.ErrUnexpectedEOF
 		}
@@ -149,12 +152,13 @@ func validIndefiniteArrOrMap(data []byte, off int, t cborType, depth int) (int,
 			break
 		}
 		var d int
-		if off, d, err = valid(data, off, depth+1); err != nil {
+		if off, d, err = validInternal(data, off, depth+1); err != nil {
 			return 0, 0, err
 		}
 		if d > maxDepth {
 			maxDepth = d
 		}
+		i++
 	}
 	if t == cborTypeMap && i%2 == 1 {
 		return 0, 0, &SyntaxError{"cbor: unexpected \"break\" code"}


Test patch:
diff --git a/bench_test.go b/bench_test.go
index 200cdec..564dd89 100644
--- a/bench_test.go
+++ b/bench_test.go
@@ -1,15 +1,13 @@
 // Copyright (c) Faye Amacker. All rights reserved.
 // Licensed under the MIT License. See LICENSE in the project root for license information.
 
-package cbor_test
+package cbor
 
 import (
 	"bytes"
 	"io/ioutil"
 	"reflect"
 	"testing"
-
-	"github.com/fxamacker/cbor"
 )
 
 const rounds = 100
@@ -25,21 +23,21 @@ type claims struct {
 }
 
 type coseKey struct {
-	Kty       int             `cbor:"1,keyasint,omitempty"`
-	Kid       []byte          `cbor:"2,keyasint,omitempty"`
-	Alg       int             `cbor:"3,keyasint,omitempty"`
-	KeyOpts   int             `cbor:"4,keyasint,omitempty"`
-	IV        []byte          `cbor:"5,keyasint,omitempty"`
-	CrvOrNOrK cbor.RawMessage `cbor:"-1,keyasint,omitempty"` // K for symmetric keys, Crv for elliptic curve keys, N for RSA modulus
-	XOrE      cbor.RawMessage `cbor:"-2,keyasint,omitempty"` // X for curve x-coordinate, E for RSA public exponent
-	Y         cbor.RawMessage `cbor:"-3,keyasint,omitempty"` // Y for curve y-cooridate
-	D         []byte          `cbor:"-4,keyasint,omitempty"`
+	Kty       int        `cbor:"1,keyasint,omitempty"`
+	Kid       []byte     `cbor:"2,keyasint,omitempty"`
+	Alg       int        `cbor:"3,keyasint,omitempty"`
+	KeyOpts   int        `cbor:"4,keyasint,omitempty"`
+	IV        []byte     `cbor:"5,keyasint,omitempty"`
+	CrvOrNOrK RawMessage `cbor:"-1,keyasint,omitempty"` // K for symmetric keys, Crv for elliptic curve keys, N for RSA modulus
+	XOrE      RawMessage `cbor:"-2,keyasint,omitempty"` // X for curve x-coordinate, E for RSA public exponent
+	Y         RawMessage `cbor:"-3,keyasint,omitempty"` // Y for curve y-cooridate
+	D         []byte     `cbor:"-4,keyasint,omitempty"`
 }
 
 type attestationObject struct {
-	AuthnData []byte          `cbor:"authData"`
-	Fmt       string          `cbor:"fmt"`
-	AttStmt   cbor.RawMessage `cbor:"attStmt"`
+	AuthnData []byte     `cbor:"authData"`
+	Fmt       string     `cbor:"fmt"`
+	AttStmt   RawMessage `cbor:"attStmt"`
 }
 
 type SenMLRecord struct {
@@ -62,7 +60,7 @@ type SenMLRecord struct {
 
 type T1 struct {
 	T    bool
-	Ui   uint
+	UI   uint
 	I    int
 	F    float64
 	B    []byte
@@ -73,7 +71,7 @@ type T1 struct {
 
 type T2 struct {
 	T    bool              `cbor:"1,keyasint"`
-	Ui   uint              `cbor:"2,keyasint"`
+	UI   uint              `cbor:"2,keyasint"`
 	I    int               `cbor:"3,keyasint"`
 	F    float64           `cbor:"4,keyasint"`
 	B    []byte            `cbor:"5,keyasint"`
@@ -85,7 +83,7 @@ type T2 struct {
 type T3 struct {
 	_    struct{} `cbor:",toarray"`
 	T    bool
-	Ui   uint
+	UI   uint
 	I    int
 	F    float64
 	B    []byte
@@ -138,7 +136,7 @@ func BenchmarkUnmarshal(b *testing.B) {
 			b.Run(name, func(b *testing.B) {
 				for i := 0; i < b.N; i++ {
 					vPtr := reflect.New(t).Interface()
-					if err := cbor.Unmarshal(bm.cborData, vPtr); err != nil {
+					if err := Unmarshal(bm.cborData, vPtr); err != nil {
 						b.Fatal("Unmarshal:", err)
 					}
 				}
@@ -159,7 +157,7 @@ func BenchmarkUnmarshal(b *testing.B) {
 		// Unmarshal CBOR map with string key to struct.
 		{
 			"CBOR map to Go struct",
-			hexDecode("a86154f56255691bffffffffffffffff61493903e76146fbc0106666666666666142581a0102030405060708090a0b0c0d0e0f101112131415161718191a6153782b54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f6764536c6369981a0102030405060708090a0b0c0d0e0f101112131415161718181819181a634d7373ad6163614361656145616661466167614761686148616e614e616d614d61616141616261426164614461696149616a614a616c614c"),
+			hexDecode("a86154f56255491bffffffffffffffff61493903e76146fbc0106666666666666142581a0102030405060708090a0b0c0d0e0f101112131415161718191a6153782b54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f6764536c6369981a0102030405060708090a0b0c0d0e0f101112131415161718181819181a634d7373ad6163614361656145616661466167614761686148616e614e616d614d61616141616261426164614461696149616a614a616c614c"),
 			reflect.TypeOf(T1{}),
 		},
 		// Unmarshal CBOR map with integer key, such as COSE Key and SenML, to map[int]interface{}.
@@ -191,7 +189,7 @@ func BenchmarkUnmarshal(b *testing.B) {
 		b.Run(bm.name, func(b *testing.B) {
 			for i := 0; i < b.N; i++ {
 				vPtr := reflect.New(bm.decodeToType).Interface()
-				if err := cbor.Unmarshal(bm.cborData, vPtr); err != nil {
+				if err := Unmarshal(bm.cborData, vPtr); err != nil {
 					b.Fatal("Unmarshal:", err)
 				}
 			}
@@ -207,14 +205,14 @@ func BenchmarkDecode(b *testing.B) {
 				name = "CBOR " + bm.name + " to Go " + t.Kind().String()
 			}
 			buf := bytes.NewReader(bm.cborData)
-			decoder := cbor.NewDecoder(buf)
+			decoder := NewDecoder(buf)
 			b.Run(name, func(b *testing.B) {
 				for i := 0; i < b.N; i++ {
 					vPtr := reflect.New(t).Interface()
 					if err := decoder.Decode(vPtr); err != nil {
 						b.Fatal("Decode:", err)
 					}
-					buf.Seek(0, 0)
+					buf.Seek(0, 0) //nolint:errcheck
 				}
 			})
 		}
@@ -232,7 +230,7 @@ func BenchmarkDecodeStream(b *testing.B) {
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
 		buf := bytes.NewReader(cborData)
-		decoder := cbor.NewDecoder(buf)
+		decoder := NewDecoder(buf)
 		for j := 0; j < rounds; j++ {
 			for _, bm := range decodeBenchmarks {
 				for _, t := range bm.decodeToTypes {
@@ -242,7 +240,7 @@ func BenchmarkDecodeStream(b *testing.B) {
 					}
 				}
 			}
-			buf.Seek(0, 0)
+			buf.Seek(0, 0) //nolint:errcheck
 		}
 	}
 }
@@ -256,7 +254,7 @@ func BenchmarkMarshal(b *testing.B) {
 			}
 			b.Run(name, func(b *testing.B) {
 				for i := 0; i < b.N; i++ {
-					if _, err := cbor.Marshal(v, cbor.EncOptions{}); err != nil {
+					if _, err := Marshal(v); err != nil {
 						b.Fatal("Marshal:", err)
 					}
 				}
@@ -264,9 +262,9 @@ func BenchmarkMarshal(b *testing.B) {
 		}
 	}
 	// Marshal map[string]interface{} to CBOR map
-	m1 := map[string]interface{}{
+	m1 := map[string]interface{}{ //nolint:dupl
 		"T":    true,
-		"Ui":   uint(18446744073709551615),
+		"UI":   uint(18446744073709551615),
 		"I":    -1000,
 		"F":    -4.1,
 		"B":    []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
@@ -275,9 +273,9 @@ func BenchmarkMarshal(b *testing.B) {
 		"Mss":  map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"},
 	}
 	// Marshal struct to CBOR map
-	v1 := T1{
+	v1 := T1{ //nolint:dupl
 		T:    true,
-		Ui:   18446744073709551615,
+		UI:   18446744073709551615,
 		I:    -1000,
 		F:    -4.1,
 		B:    []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
@@ -286,7 +284,7 @@ func BenchmarkMarshal(b *testing.B) {
 		Mss:  map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"},
 	}
 	// Marshal map[int]interface{} to CBOR map
-	m2 := map[int]interface{}{
+	m2 := map[int]interface{}{ //nolint:dupl
 		1: true,
 		2: uint(18446744073709551615),
 		3: -1000,
@@ -297,9 +295,9 @@ func BenchmarkMarshal(b *testing.B) {
 		8: map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"},
 	}
 	// Marshal struct keyasint, such as COSE Key and SenML
-	v2 := T2{
+	v2 := T2{ //nolint:dupl
 		T:    true,
-		Ui:   18446744073709551615,
+		UI:   18446744073709551615,
 		I:    -1000,
 		F:    -4.1,
 		B:    []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
@@ -319,9 +317,9 @@ func BenchmarkMarshal(b *testing.B) {
 		map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"},
 	}
 	// Marshal struct toarray to CBOR array, such as signed/maced/encrypted CWT.
-	v3 := T3{
+	v3 := T3{ //nolint:dupl
 		T:    true,
-		Ui:   18446744073709551615,
+		UI:   18446744073709551615,
 		I:    -1000,
 		F:    -4.1,
 		B:    []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
@@ -343,7 +341,7 @@ func BenchmarkMarshal(b *testing.B) {
 	for _, bm := range moreBenchmarks {
 		b.Run(bm.name, func(b *testing.B) {
 			for i := 0; i < b.N; i++ {
-				if _, err := cbor.Marshal(bm.value, cbor.EncOptions{}); err != nil {
+				if _, err := Marshal(bm.value); err != nil {
 					b.Fatal("Marshal:", err)
 				}
 			}
@@ -381,7 +379,7 @@ func BenchmarkMarshalCanonical(b *testing.B) {
 			}
 			b.Run(name, func(b *testing.B) {
 				for i := 0; i < b.N; i++ {
-					if _, err := cbor.Marshal(v, cbor.EncOptions{}); err != nil {
+					if _, err := Marshal(v); err != nil {
 						b.Fatal("Marshal:", err)
 					}
 				}
@@ -391,9 +389,10 @@ func BenchmarkMarshalCanonical(b *testing.B) {
 			if reflect.TypeOf(v).Kind() == reflect.Struct {
 				name = "Go " + reflect.TypeOf(v).Kind().String() + " to CBOR " + bm.name + " canonical"
 			}
+			em, _ := EncOptions{Sort: SortCanonical}.EncMode()
 			b.Run(name, func(b *testing.B) {
 				for i := 0; i < b.N; i++ {
-					if _, err := cbor.Marshal(v, cbor.EncOptions{Sort: cbor.SortCanonical}); err != nil {
+					if _, err := em.Marshal(v); err != nil {
 						b.Fatal("Marshal:", err)
 					}
 				}
@@ -410,7 +409,7 @@ func BenchmarkEncode(b *testing.B) {
 				name = "Go " + reflect.TypeOf(v).Kind().String() + " to CBOR " + bm.name
 			}
 			b.Run(name, func(b *testing.B) {
-				encoder := cbor.NewEncoder(ioutil.Discard, cbor.EncOptions{})
+				encoder := NewEncoder(ioutil.Discard)
 				b.ResetTimer()
 				for i := 0; i < b.N; i++ {
 					if err := encoder.Encode(v); err != nil {
@@ -424,7 +423,7 @@ func BenchmarkEncode(b *testing.B) {
 
 func BenchmarkEncodeStream(b *testing.B) {
 	for i := 0; i < b.N; i++ {
-		encoder := cbor.NewEncoder(ioutil.Discard, cbor.EncOptions{})
+		encoder := NewEncoder(ioutil.Discard)
 		for i := 0; i < rounds; i++ {
 			for _, bm := range encodeBenchmarks {
 				for _, v := range bm.values {
@@ -451,7 +450,7 @@ func BenchmarkUnmarshalCOSE(b *testing.B) {
 		b.Run(tc.name, func(b *testing.B) {
 			for i := 0; i < b.N; i++ {
 				var v coseKey
-				if err := cbor.Unmarshal(tc.cborData, &v); err != nil {
+				if err := Unmarshal(tc.cborData, &v); err != nil {
 					b.Fatal("Unmarshal:", err)
 				}
 			}
@@ -471,12 +470,12 @@ func BenchmarkMarshalCOSE(b *testing.B) {
 	}
 	for _, tc := range testCases {
 		var v coseKey
-		if err := cbor.Unmarshal(tc.cborData, &v); err != nil {
+		if err := Unmarshal(tc.cborData, &v); err != nil {
 			b.Fatal("Unmarshal:", err)
 		}
 		b.Run(tc.name, func(b *testing.B) {
 			for i := 0; i < b.N; i++ {
-				if _, err := cbor.Marshal(v, cbor.EncOptions{}); err != nil {
+				if _, err := Marshal(v); err != nil {
 					b.Fatal("Marshal:", err)
 				}
 			}
@@ -489,7 +488,7 @@ func BenchmarkUnmarshalCWTClaims(b *testing.B) {
 	cborData := hexDecode("a70175636f61703a2f2f61732e6578616d706c652e636f6d02656572696b77037818636f61703a2f2f6c696768742e6578616d706c652e636f6d041a5612aeb0051a5610d9f0061a5610d9f007420b71")
 	for i := 0; i < b.N; i++ {
 		var v claims
-		if err := cbor.Unmarshal(cborData, &v); err != nil {
+		if err := Unmarshal(cborData, &v); err != nil {
 			b.Fatal("Unmarshal:", err)
 		}
 	}
@@ -499,11 +498,11 @@ func BenchmarkMarshalCWTClaims(b *testing.B) {
 	// Data from https://tools.ietf.org/html/rfc8392#appendix-A section A.1
 	cborData := hexDecode("a70175636f61703a2f2f61732e6578616d706c652e636f6d02656572696b77037818636f61703a2f2f6c696768742e6578616d706c652e636f6d041a5612aeb0051a5610d9f0061a5610d9f007420b71")
 	var v claims
-	if err := cbor.Unmarshal(cborData, &v); err != nil {
+	if err := Unmarshal(cborData, &v); err != nil {
 		b.Fatal("Unmarshal:", err)
 	}
 	for i := 0; i < b.N; i++ {
-		if _, err := cbor.Marshal(v, cbor.EncOptions{}); err != nil {
+		if _, err := Marshal(v); err != nil {
 			b.Fatal("Unmarshal:", err)
 		}
 	}
@@ -514,7 +513,7 @@ func BenchmarkUnmarshalSenML(b *testing.B) {
 	cborData := hexDecode("87a721781b75726e3a6465763a6f773a3130653230373361303130383030363a22fb41d303a15b00106223614120050067766f6c7461676501615602fb405e066666666666a3006763757272656e74062402fb3ff3333333333333a3006763757272656e74062302fb3ff4cccccccccccda3006763757272656e74062202fb3ff6666666666666a3006763757272656e74062102f93e00a3006763757272656e74062002fb3ff999999999999aa3006763757272656e74060002fb3ffb333333333333")
 	for i := 0; i < b.N; i++ {
 		var v []SenMLRecord
-		if err := cbor.Unmarshal(cborData, &v); err != nil {
+		if err := Unmarshal(cborData, &v); err != nil {
 			b.Fatal("Unmarshal:", err)
 		}
 	}
@@ -524,11 +523,11 @@ func BenchmarkMarshalSenML(b *testing.B) {
 	// Data from https://tools.ietf.org/html/rfc8428#section-6
 	cborData := hexDecode("87a721781b75726e3a6465763a6f773a3130653230373361303130383030363a22fb41d303a15b00106223614120050067766f6c7461676501615602fb405e066666666666a3006763757272656e74062402fb3ff3333333333333a3006763757272656e74062302fb3ff4cccccccccccda3006763757272656e74062202fb3ff6666666666666a3006763757272656e74062102f93e00a3006763757272656e74062002fb3ff999999999999aa3006763757272656e74060002fb3ffb333333333333")
 	var v []SenMLRecord
-	if err := cbor.Unmarshal(cborData, &v); err != nil {
+	if err := Unmarshal(cborData, &v); err != nil {
 		b.Fatal("Unmarshal:", err)
 	}
 	for i := 0; i < b.N; i++ {
-		if _, err := cbor.Marshal(v, cbor.EncOptions{}); err != nil {
+		if _, err := Marshal(v); err != nil {
 			b.Fatal("Unmarshal:", err)
 		}
 	}
@@ -538,11 +537,12 @@ func BenchmarkMarshalSenMLShortestFloat16(b *testing.B) {
 	// Data from https://tools.ietf.org/html/rfc8428#section-6
 	cborData := hexDecode("87a721781b75726e3a6465763a6f773a3130653230373361303130383030363a22fb41d303a15b00106223614120050067766f6c7461676501615602fb405e066666666666a3006763757272656e74062402fb3ff3333333333333a3006763757272656e74062302fb3ff4cccccccccccda3006763757272656e74062202fb3ff6666666666666a3006763757272656e74062102f93e00a3006763757272656e74062002fb3ff999999999999aa3006763757272656e74060002fb3ffb333333333333")
 	var v []SenMLRecord
-	if err := cbor.Unmarshal(cborData, &v); err != nil {
+	if err := Unmarshal(cborData, &v); err != nil {
 		b.Fatal("Unmarshal:", err)
 	}
+	em, _ := EncOptions{ShortestFloat: ShortestFloat16}.EncMode()
 	for i := 0; i < b.N; i++ {
-		if _, err := cbor.Marshal(v, cbor.EncOptions{ShortestFloat: cbor.ShortestFloat16}); err != nil {
+		if _, err := em.Marshal(v); err != nil {
 			b.Fatal("Unmarshal:", err)
 		}
 	}
@@ -553,7 +553,7 @@ func BenchmarkUnmarshalWebAuthn(b *testing.B) {
 	cborData := hexDecode("a363666d74686669646f2d7532666761747453746d74a26373696758483046022100e7ab373cfbd99fcd55fd59b0f6f17fef5b77a20ddec3db7f7e4d55174e366236022100828336b4822125fb56541fb14a8a273876acd339395ec2dad95cf41c1dd2a9ae637835638159024e3082024a30820132a0030201020204124a72fe300d06092a864886f70d01010b0500302e312c302a0603550403132359756269636f2055324620526f6f742043412053657269616c203435373230303633313020170d3134303830313030303030305a180f32303530303930343030303030305a302c312a302806035504030c2159756269636f205532462045452053657269616c203234393431343937323135383059301306072a8648ce3d020106082a8648ce3d030107034200043d8b1bbd2fcbf6086e107471601468484153c1c6d3b4b68a5e855e6e40757ee22bcd8988bf3befd7cdf21cb0bf5d7a150d844afe98103c6c6607d9faae287c02a33b3039302206092b0601040182c40a020415312e332e362e312e342e312e34313438322e312e313013060b2b0601040182e51c020101040403020520300d06092a864886f70d01010b05000382010100a14f1eea0076f6b8476a10a2be72e60d0271bb465b2dfbfc7c1bd12d351989917032631d795d097fa30a26a325634e85721bc2d01a86303f6bc075e5997319e122148b0496eec8d1f4f94cf4110de626c289443d1f0f5bbb239ca13e81d1d5aa9df5af8e36126475bfc23af06283157252762ff68879bcf0ef578d55d67f951b4f32b63c8aea5b0f99c67d7d814a7ff5a6f52df83e894a3a5d9c8b82e7f8bc8daf4c80175ff8972fda79333ec465d806eacc948f1bab22045a95558a48c20226dac003d41fbc9e05ea28a6bb5e10a49de060a0a4f6a2676a34d68c4abe8c61874355b9027e828ca9e064b002d62e8d8cf0744921753d35e3c87c5d5779453e7768617574684461746158c449960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976341000000000000000000000000000000000000000000408903fd7dfd2c9770e98cae0123b13a2c27828a106349bc6277140e7290b7e9eb7976aa3c04ed347027caf7da3a2fa76304751c02208acfc4e7fc6c7ebbc375c8a5010203262001215820ad7f7992c335b90d882b2802061b97a4fabca7e2ee3e7a51e728b8055e4eb9c7225820e0966ba7005987fece6f0e0e13447aa98cec248e4000a594b01b74c1cb1d40b3")
 	for i := 0; i < b.N; i++ {
 		var v attestationObject
-		if err := cbor.Unmarshal(cborData, &v); err != nil {
+		if err := Unmarshal(cborData, &v); err != nil {
 			b.Fatal("Unmarshal:", err)
 		}
 	}
@@ -563,11 +563,11 @@ func BenchmarkMarshalWebAuthn(b *testing.B) {
 	// Data generated from Yubico security key
 	cborData := hexDecode("a363666d74686669646f2d7532666761747453746d74a26373696758483046022100e7ab373cfbd99fcd55fd59b0f6f17fef5b77a20ddec3db7f7e4d55174e366236022100828336b4822125fb56541fb14a8a273876acd339395ec2dad95cf41c1dd2a9ae637835638159024e3082024a30820132a0030201020204124a72fe300d06092a864886f70d01010b0500302e312c302a0603550403132359756269636f2055324620526f6f742043412053657269616c203435373230303633313020170d3134303830313030303030305a180f32303530303930343030303030305a302c312a302806035504030c2159756269636f205532462045452053657269616c203234393431343937323135383059301306072a8648ce3d020106082a8648ce3d030107034200043d8b1bbd2fcbf6086e107471601468484153c1c6d3b4b68a5e855e6e40757ee22bcd8988bf3befd7cdf21cb0bf5d7a150d844afe98103c6c6607d9faae287c02a33b3039302206092b0601040182c40a020415312e332e362e312e342e312e34313438322e312e313013060b2b0601040182e51c020101040403020520300d06092a864886f70d01010b05000382010100a14f1eea0076f6b8476a10a2be72e60d0271bb465b2dfbfc7c1bd12d351989917032631d795d097fa30a26a325634e85721bc2d01a86303f6bc075e5997319e122148b0496eec8d1f4f94cf4110de626c289443d1f0f5bbb239ca13e81d1d5aa9df5af8e36126475bfc23af06283157252762ff68879bcf0ef578d55d67f951b4f32b63c8aea5b0f99c67d7d814a7ff5a6f52df83e894a3a5d9c8b82e7f8bc8daf4c80175ff8972fda79333ec465d806eacc948f1bab22045a95558a48c20226dac003d41fbc9e05ea28a6bb5e10a49de060a0a4f6a2676a34d68c4abe8c61874355b9027e828ca9e064b002d62e8d8cf0744921753d35e3c87c5d5779453e7768617574684461746158c449960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976341000000000000000000000000000000000000000000408903fd7dfd2c9770e98cae0123b13a2c27828a106349bc6277140e7290b7e9eb7976aa3c04ed347027caf7da3a2fa76304751c02208acfc4e7fc6c7ebbc375c8a5010203262001215820ad7f7992c335b90d882b2802061b97a4fabca7e2ee3e7a51e728b8055e4eb9c7225820e0966ba7005987fece6f0e0e13447aa98cec248e4000a594b01b74c1cb1d40b3")
 	var v attestationObject
-	if err := cbor.Unmarshal(cborData, &v); err != nil {
+	if err := Unmarshal(cborData, &v); err != nil {
 		b.Fatal("Unmarshal:", err)
 	}
 	for i := 0; i < b.N; i++ {
-		if _, err := cbor.Marshal(v, cbor.EncOptions{}); err != nil {
+		if _, err := Marshal(v); err != nil {
 			b.Fatal("Marshal:", err)
 		}
 	}
diff --git a/decode_test.go b/decode_test.go
index 42f0499..f53a264 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -1,7 +1,7 @@
 // Copyright (c) Faye Amacker. All rights reserved.
 // Licensed under the MIT License. See LICENSE in the project root for license information.
 
-package cbor_test
+package cbor
 
 import (
 	"bytes"
@@ -14,13 +14,10 @@ import (
 	"strings"
 	"testing"
 	"time"
-
-	"github.com/fxamacker/cbor"
 )
 
 var (
 	typeBool            = reflect.TypeOf(true)
-	typeUint            = reflect.TypeOf(uint(0))
 	typeUint8           = reflect.TypeOf(uint8(0))
 	typeUint16          = reflect.TypeOf(uint16(0))
 	typeUint32          = reflect.TypeOf(uint32(0))
@@ -39,7 +36,7 @@ var (
 	typeMapStringInt    = reflect.TypeOf(map[string]int{})
 	typeMapStringString = reflect.TypeOf(map[string]string{})
 	typeMapStringIntf   = reflect.TypeOf(map[string]interface{}{})
-	typeIntf            = reflect.TypeOf([]interface{}(nil)).Elem()
+	// typeIntf            = reflect.TypeOf([]interface{}(nil)).Elem()
 )
 
 type unmarshalTest struct {
@@ -143,7 +140,7 @@ var unmarshalTests = []unmarshalTest{
 		[]interface{}{int16(-1000), int32(-1000), int64(-1000), int(-1000), float32(-1000), float64(-1000)},
 		[]reflect.Type{typeUint8, typeUint16, typeUint32, typeUint64, typeInt8, typeString, typeBool, typeIntSlice, typeMapStringInt},
 	},
-	//{"3bffffffffffffffff", int64(-18446744073709551616)}, // CBOR value -18446744073709551616 overflows Go's int64, see TestNegIntOverflow
+	// {"3bffffffffffffffff", int64(-18446744073709551616)}, // CBOR value -18446744073709551616 overflows Go's int64, see TestNegIntOverflow
 	// byte string
 	{
 		hexDecode("40"),
@@ -538,21 +535,21 @@ var unmarshalFloatTests = []unmarshalFloatTest{
 	{
 		hexDecode("f97c00"),
 		math.Inf(1),
-		[]interface{}{float32(math.Float32frombits(0x7f800000)), float64(math.Inf(1))},
+		[]interface{}{math.Float32frombits(0x7f800000), math.Inf(1)},
 		[]reflect.Type{typeUint8, typeUint16, typeUint32, typeUint64, typeInt8, typeInt16, typeInt32, typeInt64, typeByteSlice, typeString, typeBool, typeIntSlice, typeMapStringInt},
 		0.0,
 	},
 	{
 		hexDecode("f97e00"),
 		math.NaN(),
-		[]interface{}{float32(math.Float32frombits(0x7fc00000)), float64(math.NaN())},
+		[]interface{}{math.Float32frombits(0x7fc00000), math.NaN()},
 		[]reflect.Type{typeUint8, typeUint16, typeUint32, typeUint64, typeInt8, typeInt16, typeInt32, typeInt64, typeByteSlice, typeString, typeBool, typeIntSlice, typeMapStringInt},
 		0.0,
 	},
 	{
 		hexDecode("f9fc00"),
 		math.Inf(-1),
-		[]interface{}{float32(math.Float32frombits(0xff800000)), float64(math.Inf(-1))},
+		[]interface{}{math.Float32frombits(0xff800000), math.Inf(-1)},
 		[]reflect.Type{typeUint8, typeUint16, typeUint32, typeUint64, typeInt8, typeInt16, typeInt32, typeInt64, typeByteSlice, typeString, typeBool, typeIntSlice, typeMapStringInt},
 		0.0,
 	},
@@ -574,21 +571,21 @@ var unmarshalFloatTests = []unmarshalFloatTest{
 	{
 		hexDecode("fa7f800000"),
 		math.Inf(1),
-		[]interface{}{float32(math.Float32frombits(0x7f800000)), float64(math.Inf(1))},
+		[]interface{}{math.Float32frombits(0x7f800000), math.Inf(1)},
 		[]reflect.Type{typeUint8, typeUint16, typeUint32, typeUint64, typeInt8, typeInt16, typeInt32, typeInt64, typeByteSlice, typeString, typeBool, typeIntSlice, typeMapStringInt},
 		0.0,
 	},
 	{
 		hexDecode("fa7fc00000"),
 		math.NaN(),
-		[]interface{}{float32(math.Float32frombits(0x7fc00000)), float64(math.NaN())},
+		[]interface{}{math.Float32frombits(0x7fc00000), math.NaN()},
 		[]reflect.Type{typeUint8, typeUint16, typeUint32, typeUint64, typeInt8, typeInt16, typeInt32, typeInt64, typeByteSlice, typeString, typeBool, typeIntSlice, typeMapStringInt},
 		0.0,
 	},
 	{
 		hexDecode("faff800000"),
 		math.Inf(-1),
-		[]interface{}{float32(math.Float32frombits(0xff800000)), float64(math.Inf(-1))},
+		[]interface{}{math.Float32frombits(0xff800000), math.Inf(-1)},
 		[]reflect.Type{typeUint8, typeUint16, typeUint32, typeUint64, typeInt8, typeInt16, typeInt32, typeInt64, typeByteSlice, typeString, typeBool, typeIntSlice, typeMapStringInt},
 		0.0,
 	},
@@ -617,21 +614,21 @@ var unmarshalFloatTests = []unmarshalFloatTest{
 	{
 		hexDecode("fb7ff0000000000000"),
 		math.Inf(1),
-		[]interface{}{float32(math.Float32frombits(0x7f800000)), float64(math.Inf(1))},
+		[]interface{}{math.Float32frombits(0x7f800000), math.Inf(1)},
 		[]reflect.Type{typeUint8, typeUint16, typeUint32, typeUint64, typeInt8, typeInt16, typeInt32, typeInt64, typeByteSlice, typeString, typeBool, typeIntSlice, typeMapStringInt},
 		0.0,
 	},
 	{
 		hexDecode("fb7ff8000000000000"),
 		math.NaN(),
-		[]interface{}{float32(math.Float32frombits(0x7fc00000)), float64(math.NaN())},
+		[]interface{}{math.Float32frombits(0x7fc00000), math.NaN()},
 		[]reflect.Type{typeUint8, typeUint16, typeUint32, typeUint64, typeInt8, typeInt16, typeInt32, typeInt64, typeByteSlice, typeString, typeBool, typeIntSlice, typeMapStringInt},
 		0.0,
 	},
 	{
 		hexDecode("fbfff0000000000000"),
 		math.Inf(-1),
-		[]interface{}{float32(math.Float32frombits(0xff800000)), float64(math.Inf(-1))},
+		[]interface{}{math.Float32frombits(0xff800000), math.Inf(-1)},
 		[]reflect.Type{typeUint8, typeUint16, typeUint32, typeUint64, typeInt8, typeInt16, typeInt32, typeInt64, typeByteSlice, typeString, typeBool, typeIntSlice, typeMapStringInt},
 		0.0,
 	},
@@ -738,6 +735,8 @@ var unmarshalFloatTests = []unmarshalFloatTest{
 	},
 }
 
+const invalidUTF8ErrorMsg = "cbor: invalid UTF-8 string"
+
 func hexDecode(s string) []byte {
 	data, err := hex.DecodeString(s)
 	if err != nil {
@@ -750,14 +749,14 @@ func TestUnmarshal(t *testing.T) {
 	for _, tc := range unmarshalTests {
 		// Test unmarshalling CBOR into empty interface.
 		var v interface{}
-		if err := cbor.Unmarshal(tc.cborData, &v); err != nil {
+		if err := Unmarshal(tc.cborData, &v); err != nil {
 			t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborData, err)
 		} else if !reflect.DeepEqual(v, tc.emptyInterfaceValue) {
 			t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.cborData, v, v, tc.emptyInterfaceValue, tc.emptyInterfaceValue)
 		}
 		// Test unmarshalling CBOR into RawMessage.
-		var r cbor.RawMessage
-		if err := cbor.Unmarshal(tc.cborData, &r); err != nil {
+		var r RawMessage
+		if err := Unmarshal(tc.cborData, &r); err != nil {
 			t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborData, err)
 		} else if !bytes.Equal(r, tc.cborData) {
 			t.Errorf("Unmarshal(0x%x) returned RawMessage %v, want %v", tc.cborData, r, tc.cborData)
@@ -766,7 +765,7 @@ func TestUnmarshal(t *testing.T) {
 		for _, value := range tc.values {
 			v := reflect.New(reflect.TypeOf(value))
 			vPtr := v.Interface()
-			if err := cbor.Unmarshal(tc.cborData, vPtr); err != nil {
+			if err := Unmarshal(tc.cborData, vPtr); err != nil {
 				t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborData, err)
 			} else if !reflect.DeepEqual(v.Elem().Interface(), value) {
 				t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.cborData, v.Elem().Interface(), v.Elem().Interface(), value, value)
@@ -776,10 +775,10 @@ func TestUnmarshal(t *testing.T) {
 		for _, typ := range tc.wrongTypes {
 			v := reflect.New(typ)
 			vPtr := v.Interface()
-			if err := cbor.Unmarshal(tc.cborData, vPtr); err == nil {
+			if err := Unmarshal(tc.cborData, vPtr); err == nil {
 				t.Errorf("Unmarshal(0x%x) didn't return an error", tc.cborData)
-			} else if _, ok := err.(*cbor.UnmarshalTypeError); !ok {
-				t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*cbor.UnmarshalTypeError)", tc.cborData, err)
+			} else if _, ok := err.(*UnmarshalTypeError); !ok {
+				t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", tc.cborData, err)
 			} else if !strings.Contains(err.Error(), "cannot unmarshal") {
 				t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", tc.cborData, err.Error(), "cannot unmarshal")
 			}
@@ -791,14 +790,14 @@ func TestUnmarshalFloat(t *testing.T) {
 	for _, tc := range unmarshalFloatTests {
 		// Test unmarshalling CBOR into empty interface.
 		var v interface{}
-		if err := cbor.Unmarshal(tc.cborData, &v); err != nil {
+		if err := Unmarshal(tc.cborData, &v); err != nil {
 			t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborData, err)
 		} else {
 			testFloat(t, tc.cborData, v, tc.emptyInterfaceValue, tc.equalityThreshold)
 		}
 		// Test unmarshalling CBOR into RawMessage.
-		var r cbor.RawMessage
-		if err := cbor.Unmarshal(tc.cborData, &r); err != nil {
+		var r RawMessage
+		if err := Unmarshal(tc.cborData, &r); err != nil {
 			t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborData, err)
 		} else if !bytes.Equal(r, tc.cborData) {
 			t.Errorf("Unmarshal(0x%x) returned RawMessage %v, want %v", tc.cborData, r, tc.cborData)
@@ -807,7 +806,7 @@ func TestUnmarshalFloat(t *testing.T) {
 		for _, value := range tc.values {
 			v := reflect.New(reflect.TypeOf(value))
 			vPtr := v.Interface()
-			if err := cbor.Unmarshal(tc.cborData, vPtr); err != nil {
+			if err := Unmarshal(tc.cborData, vPtr); err != nil {
 				t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborData, err)
 			} else {
 				testFloat(t, tc.cborData, v.Elem().Interface(), value, tc.equalityThreshold)
@@ -817,10 +816,10 @@ func TestUnmarshalFloat(t *testing.T) {
 		for _, typ := range tc.wrongTypes {
 			v := reflect.New(typ)
 			vPtr := v.Interface()
-			if err := cbor.Unmarshal(tc.cborData, vPtr); err == nil {
+			if err := Unmarshal(tc.cborData, vPtr); err == nil {
 				t.Errorf("Unmarshal(0x%x) didn't return an error", tc.cborData)
-			} else if _, ok := err.(*cbor.UnmarshalTypeError); !ok {
-				t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*cbor.UnmarshalTypeError)", tc.cborData, err)
+			} else if _, ok := err.(*UnmarshalTypeError); !ok {
+				t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", tc.cborData, err)
 			} else if !strings.Contains(err.Error(), "cannot unmarshal") {
 				t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", tc.cborData, err.Error(), "cannot unmarshal")
 			}
@@ -876,10 +875,10 @@ func TestNegIntOverflow(t *testing.T) {
 		{hexDecode("3bffffffffffffffff"), new(int64)},
 	}
 	for _, tc := range testCases {
-		if err := cbor.Unmarshal(tc.cborData, tc.v); err == nil {
+		if err := Unmarshal(tc.cborData, tc.v); err == nil {
 			t.Errorf("Unmarshal(0x%x) didn't return an error", tc.cborData)
-		} else if _, ok := err.(*cbor.UnmarshalTypeError); !ok {
-			t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*cbor.UnmarshalTypeError)", tc.cborData, err)
+		} else if _, ok := err.(*UnmarshalTypeError); !ok {
+			t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", tc.cborData, err)
 		} else if !strings.Contains(err.Error(), "cannot unmarshal") {
 			t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", tc.cborData, err.Error(), "cannot unmarshal")
 		}
@@ -889,10 +888,12 @@ func TestNegIntOverflow(t *testing.T) {
 func TestUnmarshalIntoPointer(t *testing.T) {
 	cborDataInt := []byte{0x18, 0x18}                                                                      // 24
 	cborDataString := []byte{0x7f, 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x67, 0xff} // "streaming"
+	const wantInt = 24
+	const wantString = "streaming"
 
 	var p1 *int
 	var p2 *string
-	var p3 *cbor.RawMessage
+	var p3 *RawMessage
 
 	var i int
 	pi := &i
@@ -902,44 +903,44 @@ func TestUnmarshalIntoPointer(t *testing.T) {
 	ps := &s
 	pps := &ps
 
-	var r cbor.RawMessage
+	var r RawMessage
 	pr := &r
 	ppr := &pr
 
 	// Unmarshal CBOR integer into a non-nil pointer.
-	if err := cbor.Unmarshal(cborDataInt, &ppi); err != nil {
+	if err := Unmarshal(cborDataInt, &ppi); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborDataInt, err)
-	} else if i != 24 {
-		t.Errorf("Unmarshal(0x%x) = %v (%T), want 24", cborDataInt, i, i)
+	} else if i != wantInt {
+		t.Errorf("Unmarshal(0x%x) = %v (%T), want %d", cborDataInt, i, i, wantInt)
 	}
 	// Unmarshal CBOR integer into a nil pointer.
-	if err := cbor.Unmarshal(cborDataInt, &p1); err != nil {
+	if err := Unmarshal(cborDataInt, &p1); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborDataInt, err)
-	} else if *p1 != 24 {
-		t.Errorf("Unmarshal(0x%x) = %v (%T), want 24", cborDataInt, *pi, pi)
+	} else if *p1 != wantInt {
+		t.Errorf("Unmarshal(0x%x) = %v (%T), want %d", cborDataInt, *pi, pi, wantInt)
 	}
 
 	// Unmarshal CBOR string into a non-nil pointer.
-	if err := cbor.Unmarshal(cborDataString, &pps); err != nil {
+	if err := Unmarshal(cborDataString, &pps); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborDataString, err)
-	} else if s != "streaming" {
-		t.Errorf("Unmarshal(0x%x) = %v (%T), want \"streaming\"", cborDataString, s, s)
+	} else if s != wantString {
+		t.Errorf("Unmarshal(0x%x) = %v (%T), want %q", cborDataString, s, s, wantString)
 	}
 	// Unmarshal CBOR string into a nil pointer.
-	if err := cbor.Unmarshal(cborDataString, &p2); err != nil {
+	if err := Unmarshal(cborDataString, &p2); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborDataString, err)
-	} else if *p2 != "streaming" {
-		t.Errorf("Unmarshal(0x%x) = %v (%T), want \"streaming\"", cborDataString, *p2, p2)
+	} else if *p2 != wantString {
+		t.Errorf("Unmarshal(0x%x) = %v (%T), want %q", cborDataString, *p2, p2, wantString)
 	}
 
-	// Unmarshal CBOR string into a non-nil cbor.RawMessage.
-	if err := cbor.Unmarshal(cborDataString, &ppr); err != nil {
+	// Unmarshal CBOR string into a non-nil RawMessage.
+	if err := Unmarshal(cborDataString, &ppr); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborDataString, err)
 	} else if !bytes.Equal(r, cborDataString) {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want %v", cborDataString, r, r, cborDataString)
 	}
-	// Unmarshal CBOR string into a nil pointer to cbor.RawMessage.
-	if err := cbor.Unmarshal(cborDataString, &p3); err != nil {
+	// Unmarshal CBOR string into a nil pointer to RawMessage.
+	if err := Unmarshal(cborDataString, &p3); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborDataString, err)
 	} else if !bytes.Equal(*p3, cborDataString) {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want %v", cborDataString, *p3, p3, cborDataString)
@@ -951,7 +952,7 @@ func TestUnmarshalIntoArray(t *testing.T) {
 
 	// Unmarshal CBOR array into Go array.
 	var arr1 [3]int
-	if err := cbor.Unmarshal(cborData, &arr1); err != nil {
+	if err := Unmarshal(cborData, &arr1); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	} else if arr1 != [3]int{1, 2, 3} {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want [3]int{1, 2, 3}", cborData, arr1, arr1)
@@ -959,7 +960,7 @@ func TestUnmarshalIntoArray(t *testing.T) {
 
 	// Unmarshal CBOR array into Go array with more elements.
 	var arr2 [5]int
-	if err := cbor.Unmarshal(cborData, &arr2); err != nil {
+	if err := Unmarshal(cborData, &arr2); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	} else if arr2 != [5]int{1, 2, 3, 0, 0} {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want [5]int{1, 2, 3, 0, 0}", cborData, arr2, arr2)
@@ -967,7 +968,7 @@ func TestUnmarshalIntoArray(t *testing.T) {
 
 	// Unmarshal CBOR array into Go array with less elements.
 	var arr3 [1]int
-	if err := cbor.Unmarshal(cborData, &arr3); err != nil {
+	if err := Unmarshal(cborData, &arr3); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	} else if arr3 != [1]int{1} {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want [0]int{1}", cborData, arr3, arr3)
@@ -994,14 +995,14 @@ func TestUnmarshalNil(t *testing.T) {
 		// Unmarshal CBOR nil into nil pointers.
 		{"*int", (*int)(nil), (*int)(nil)},
 		{"*string", (*string)(nil), (*string)(nil)},
-		{"*cbor.RawMessage", (*cbor.RawMessage)(nil), (*cbor.RawMessage)(nil)},
+		{"*RawMessage", (*RawMessage)(nil), (*RawMessage)(nil)},
 	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			for _, data := range cborData {
 				v := reflect.New(reflect.TypeOf(tc.value))
 				v.Elem().Set(reflect.ValueOf(tc.value))
-				if err := cbor.Unmarshal(data, v.Interface()); err != nil {
+				if err := Unmarshal(data, v.Interface()); err != nil {
 					t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
 				} else if !reflect.DeepEqual(v.Elem().Interface(), tc.wantValue) {
 					t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", data, v.Elem().Interface(), v.Elem().Interface(), tc.wantValue, tc.wantValue)
@@ -1026,11 +1027,11 @@ func TestInvalidUnmarshal(t *testing.T) {
 
 	for _, tc := range invalidUnmarshalTests {
 		t.Run(tc.name, func(t *testing.T) {
-			err := cbor.Unmarshal(cborData, tc.v)
+			err := Unmarshal(cborData, tc.v)
 			if err == nil {
 				t.Errorf("Unmarshal(0x%x, %v) didn't return an error", cborData, tc.v)
-			} else if _, ok := err.(*cbor.InvalidUnmarshalError); !ok {
-				t.Errorf("Unmarshal(0x%x, %v) error type %T, want *cbor.InvalidUnmarshalError", cborData, tc.v, err)
+			} else if _, ok := err.(*InvalidUnmarshalError); !ok {
+				t.Errorf("Unmarshal(0x%x, %v) error type %T, want *InvalidUnmarshalError", cborData, tc.v, err)
 			} else if err.Error() != tc.wantErrorMsg {
 				t.Errorf("Unmarshal(0x%x, %v) error %q, want %q", cborData, tc.v, err.Error(), tc.wantErrorMsg)
 			}
@@ -1147,7 +1148,7 @@ func TestInvalidCBORUnmarshal(t *testing.T) {
 	for _, tc := range invalidCBORUnmarshalTests {
 		t.Run(tc.name, func(t *testing.T) {
 			var i interface{}
-			err := cbor.Unmarshal(tc.cborData, &i)
+			err := Unmarshal(tc.cborData, &i)
 			if err == nil {
 				t.Errorf("Unmarshal(0x%x) didn't return an error", tc.cborData)
 			} else if !tc.errorMsgPartialMatch && err.Error() != tc.wantErrorMsg {
@@ -1165,20 +1166,20 @@ func TestInvalidUTF8TextString(t *testing.T) {
 		cborData     []byte
 		wantErrorMsg string
 	}{
-		{"definite length text string", hexDecode("61fe"), "cbor: invalid UTF-8 string"},
-		{"indefinite length text string", hexDecode("7f62e6b061b4ff"), "cbor: invalid UTF-8 string"},
+		{"definite length text string", hexDecode("61fe"), invalidUTF8ErrorMsg},
+		{"indefinite length text string", hexDecode("7f62e6b061b4ff"), invalidUTF8ErrorMsg},
 	}
 	for _, tc := range invalidUTF8TextStringTests {
 		t.Run(tc.name, func(t *testing.T) {
 			var i interface{}
-			if err := cbor.Unmarshal(tc.cborData, &i); err == nil {
+			if err := Unmarshal(tc.cborData, &i); err == nil {
 				t.Errorf("Unmarshal(0x%x) didn't return an error", tc.cborData)
 			} else if err.Error() != tc.wantErrorMsg {
 				t.Errorf("Unmarshal(0x%x) error %q, want %q", tc.cborData, err.Error(), tc.wantErrorMsg)
 			}
 
 			var s string
-			if err := cbor.Unmarshal(tc.cborData, &s); err == nil {
+			if err := Unmarshal(tc.cborData, &s); err == nil {
 				t.Errorf("Unmarshal(0x%x) didn't return an error", tc.cborData)
 			} else if err.Error() != tc.wantErrorMsg {
 				t.Errorf("Unmarshal(0x%x) error %q, want %q", tc.cborData, err.Error(), tc.wantErrorMsg)
@@ -1187,7 +1188,7 @@ func TestInvalidUTF8TextString(t *testing.T) {
 	}
 	// Test decoding of mixed invalid text string and valid text string
 	cborData := hexDecode("7f62e6b061b4ff7f657374726561646d696e67ff")
-	dec := cbor.NewDecoder(bytes.NewReader(cborData))
+	dec := NewDecoder(bytes.NewReader(cborData))
 	var s string
 	if err := dec.Decode(&s); err == nil {
 		t.Errorf("Decode() didn't return an error")
@@ -1225,7 +1226,7 @@ func TestUnmarshalStruct(t *testing.T) {
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
 			var v outer
-			if err := cbor.Unmarshal(tc.cborData, &v); err != nil {
+			if err := Unmarshal(tc.cborData, &v); err != nil {
 				t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborData, err)
 			} else if !reflect.DeepEqual(v, want) {
 				t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.cborData, v, v, want, want)
@@ -1259,25 +1260,26 @@ func TestUnmarshalStructError1(t *testing.T) {
 	}
 
 	cborData := hexDecode("a868496e744669656c64187b6a466c6f61744669656c64fa47c3500069426f6f6c4669656c64f56b537472696e674669656c6464746573746f42797465537472696e674669656c64430103056a41727261794669656c64826568656c6c6f65776f726c64684d61704669656c64a2676d6f726e696e67f56961667465726e6f6f6ef4714e65737465645374727563744669656c64a261581903e861591a000f4240")
+	const wantUnmarshalTypeErrorType = "UTF-8 text string"
 
 	var v outer2
-	if err := cbor.Unmarshal(cborData, &v); err == nil {
+	if err := Unmarshal(cborData, &v); err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error", cborData)
 	} else {
-		if typeError, ok := err.(*cbor.UnmarshalTypeError); !ok {
-			t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*cbor.UnmarshalTypeError)", cborData, err)
+		if typeError, ok := err.(*UnmarshalTypeError); !ok {
+			t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*UnmarshalTypeError)", cborData, err)
 		} else {
-			if typeError.Value != "UTF-8 text string" {
-				t.Errorf("Unmarshal(0x%x) (*cbor.UnmarshalTypeError).Value %s, want %s", cborData, typeError.Value, "UTF-8 text string")
+			if typeError.Value != wantUnmarshalTypeErrorType {
+				t.Errorf("Unmarshal(0x%x) (*UnmarshalTypeError).Value %s, want %s", cborData, typeError.Value, wantUnmarshalTypeErrorType)
 			}
 			if typeError.Type != typeInt {
-				t.Errorf("Unmarshal(0x%x) (*cbor.UnmarshalTypeError).Type %s, want %s", cborData, typeError.Type.String(), typeInt.String())
+				t.Errorf("Unmarshal(0x%x) (*UnmarshalTypeError).Type %s, want %s", cborData, typeError.Type.String(), typeInt.String())
 			}
-			if typeError.Struct != "cbor_test.outer2" {
-				t.Errorf("Unmarshal(0x%x) (*cbor.UnmarshalTypeError).Struct %s, want %s", cborData, typeError.Struct, "cbor_test.outer2")
+			if typeError.Struct != "cbor.outer2" {
+				t.Errorf("Unmarshal(0x%x) (*UnmarshalTypeError).Struct %s, want %s", cborData, typeError.Struct, "cbor.outer2")
 			}
 			if typeError.Field != "ArrayField" {
-				t.Errorf("Unmarshal(0x%x) (*cbor.UnmarshalTypeError).Field %s, want %s", cborData, typeError.Field, "ArrayField")
+				t.Errorf("Unmarshal(0x%x) (*UnmarshalTypeError).Field %s, want %s", cborData, typeError.Field, "ArrayField")
 			}
 			if !strings.Contains(err.Error(), "cannot unmarshal UTF-8 text string into Go struct field") {
 				t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", cborData, err.Error(), "cannot unmarshal UTF-8 text string into Go struct field")
@@ -1300,23 +1302,25 @@ func TestUnmarshalStructError2(t *testing.T) {
 		A: "A",
 	}
 
-	// Unmarshal returns first error encountered, which is *cbor.UnmarshalTypeError (failed to unmarshal int into Go string)
+	// Unmarshal returns first error encountered, which is *UnmarshalTypeError (failed to unmarshal int into Go string)
 	cborData := hexDecode("a3fa47c35000026161614161fe6142") // {100000.0:2, "a":"A", 0xfe: B}
+	const wantUnmarshalTypeErrorMsg = "cannot unmarshal primitives into Go value of type string"
+	const wantUnmarshalTypeErrorType = "primitives"
 	v := strc{}
-	if err := cbor.Unmarshal(cborData, &v); err == nil {
+	if err := Unmarshal(cborData, &v); err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error", cborData)
 	} else {
-		if typeError, ok := err.(*cbor.UnmarshalTypeError); !ok {
-			t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*cbor.UnmarshalTypeError)", cborData, err)
+		if typeError, ok := err.(*UnmarshalTypeError); !ok {
+			t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*UnmarshalTypeError)", cborData, err)
 		} else {
-			if typeError.Value != "primitives" {
-				t.Errorf("Unmarshal(0x%x) (*cbor.UnmarshalTypeError).Value %s, want %s", cborData, typeError.Value, "primitives")
+			if typeError.Value != wantUnmarshalTypeErrorType {
+				t.Errorf("Unmarshal(0x%x) (*UnmarshalTypeError).Value %s, want %s", cborData, typeError.Value, wantUnmarshalTypeErrorType)
 			}
 			if typeError.Type != typeString {
-				t.Errorf("Unmarshal(0x%x) (*cbor.UnmarshalTypeError).Type %s, want %s", cborData, typeError.Type, typeString)
+				t.Errorf("Unmarshal(0x%x) (*UnmarshalTypeError).Type %s, want %s", cborData, typeError.Type, typeString)
 			}
-			if !strings.Contains(err.Error(), "cannot unmarshal primitives into Go value of type string") {
-				t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", cborData, err.Error(), "cannot unmarshal float into Go value of type string")
+			if !strings.Contains(err.Error(), wantUnmarshalTypeErrorMsg) {
+				t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", cborData, err.Error(), wantUnmarshalTypeErrorMsg)
 			}
 		}
 	}
@@ -1327,13 +1331,13 @@ func TestUnmarshalStructError2(t *testing.T) {
 	// Unmarshal returns first error encountered, which is *cbor.SemanticError (invalid UTF8 string)
 	cborData = hexDecode("a361fe6142010261616141") // {0xfe: B, 1:2, "a":"A"}
 	v = strc{}
-	if err := cbor.Unmarshal(cborData, &v); err == nil {
+	if err := Unmarshal(cborData, &v); err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error", cborData)
 	} else {
-		if _, ok := err.(*cbor.SemanticError); !ok {
-			t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*cbor.SemanticError)", cborData, err)
-		} else if err.Error() != "cbor: invalid UTF-8 string" {
-			t.Errorf("Unmarshal(0x%x) returned error %q, want error %q", cborData, err.Error(), "cbor: invalid UTF-8 string")
+		if _, ok := err.(*SemanticError); !ok {
+			t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*SemanticError)", cborData, err)
+		} else if err.Error() != invalidUTF8ErrorMsg {
+			t.Errorf("Unmarshal(0x%x) returned error %q, want error %q", cborData, err.Error(), invalidUTF8ErrorMsg)
 		}
 	}
 	if !reflect.DeepEqual(v, want) {
@@ -1343,13 +1347,13 @@ func TestUnmarshalStructError2(t *testing.T) {
 	// Unmarshal returns first error encountered, which is *cbor.SemanticError (invalid UTF8 string)
 	cborData = hexDecode("a3616261fe010261616141") // {"b": 0xfe, 1:2, "a":"A"}
 	v = strc{}
-	if err := cbor.Unmarshal(cborData, &v); err == nil {
+	if err := Unmarshal(cborData, &v); err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error", cborData)
 	} else {
-		if _, ok := err.(*cbor.SemanticError); !ok {
-			t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*cbor.SemanticError)", cborData, err)
-		} else if err.Error() != "cbor: invalid UTF-8 string" {
-			t.Errorf("Unmarshal(0x%x) returned error %q, want error %q", cborData, err.Error(), "cbor: invalid UTF-8 string")
+		if _, ok := err.(*SemanticError); !ok {
+			t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*SemanticError)", cborData, err)
+		} else if err.Error() != invalidUTF8ErrorMsg {
+			t.Errorf("Unmarshal(0x%x) returned error %q, want error %q", cborData, err.Error(), invalidUTF8ErrorMsg)
 		}
 	}
 	if !reflect.DeepEqual(v, want) {
@@ -1361,7 +1365,7 @@ func TestUnmarshalPrefilledArray(t *testing.T) {
 	prefilledArr := []int{1, 2, 3, 4, 5}
 	want := []int{10, 11, 3, 4, 5}
 	cborData := hexDecode("820a0b") // []int{10, 11}
-	if err := cbor.Unmarshal(cborData, &prefilledArr); err != nil {
+	if err := Unmarshal(cborData, &prefilledArr); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	}
 	if len(prefilledArr) != 2 || cap(prefilledArr) != 5 {
@@ -1372,7 +1376,7 @@ func TestUnmarshalPrefilledArray(t *testing.T) {
 	}
 
 	cborData = hexDecode("80") // empty array
-	if err := cbor.Unmarshal(cborData, &prefilledArr); err != nil {
+	if err := Unmarshal(cborData, &prefilledArr); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	}
 	if len(prefilledArr) != 0 || cap(prefilledArr) != 0 {
@@ -1384,7 +1388,7 @@ func TestUnmarshalPrefilledMap(t *testing.T) {
 	prefilledMap := map[string]string{"key": "value", "a": "1"}
 	want := map[string]string{"key": "value", "a": "A", "b": "B", "c": "C", "d": "D", "e": "E"}
 	cborData := hexDecode("a56161614161626142616361436164614461656145") // map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"}
-	if err := cbor.Unmarshal(cborData, &prefilledMap); err != nil {
+	if err := Unmarshal(cborData, &prefilledMap); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	}
 	if !reflect.DeepEqual(prefilledMap, want) {
@@ -1394,7 +1398,7 @@ func TestUnmarshalPrefilledMap(t *testing.T) {
 	prefilledMap = map[string]string{"key": "value"}
 	want = map[string]string{"key": "value"}
 	cborData = hexDecode("a0") // map[string]string{}
-	if err := cbor.Unmarshal(cborData, &prefilledMap); err != nil {
+	if err := Unmarshal(cborData, &prefilledMap); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	}
 	if !reflect.DeepEqual(prefilledMap, want) {
@@ -1411,7 +1415,7 @@ func TestUnmarshalPrefilledStruct(t *testing.T) {
 	prefilledStruct := s{a: 100, B: []int{200, 300, 400, 500}, C: true}
 	want := s{a: 100, B: []int{2, 3}, C: true}
 	cborData := hexDecode("a26161016162820203") // map[string]interface{} {"a": 1, "b": []int{2, 3}}
-	if err := cbor.Unmarshal(cborData, &prefilledStruct); err != nil {
+	if err := Unmarshal(cborData, &prefilledStruct); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	}
 	if !reflect.DeepEqual(prefilledStruct, want) {
@@ -1433,7 +1437,7 @@ func TestValid(t *testing.T) {
 	cborData := buf.Bytes()
 	var err error
 	for i := 0; i < len(marshalTests); i++ {
-		if cborData, err = cbor.Valid(cborData); err != nil {
+		if cborData, err = valid(cborData); err != nil {
 			t.Errorf("Valid() returned error %v", err)
 		}
 	}
@@ -1449,12 +1453,12 @@ func TestStructFieldNil(t *testing.T) {
 		PPI **int
 	}
 	var struc TestStruct
-	cborData, err := cbor.Marshal(struc, cbor.EncOptions{})
+	cborData, err := Marshal(struc)
 	if err != nil {
 		t.Fatalf("Marshal(%+v) returned error %v", struc, err)
 	}
 	var struc2 TestStruct
-	err = cbor.Unmarshal(cborData, &struc2)
+	err = Unmarshal(cborData, &struc2)
 	if err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	} else if !reflect.DeepEqual(struc, struc2) {
@@ -1472,7 +1476,7 @@ func TestLengthOverflowsInt(t *testing.T) {
 	wantErrorMsg := "is too large"
 	for _, data := range cborData {
 		var intf interface{}
-		if err := cbor.Unmarshal(data, &intf); err == nil {
+		if err := Unmarshal(data, &intf); err == nil {
 			t.Errorf("Unmarshal(0x%x) didn't return an error, want error containing substring %q", data, wantErrorMsg)
 		} else if !strings.Contains(err.Error(), wantErrorMsg) {
 			t.Errorf("Unmarshal(0x%x) returned error %q, want error containing substring %q", data, err.Error(), wantErrorMsg)
@@ -1499,14 +1503,14 @@ func TestMapKeyUnhashable(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			var v interface{}
-			if err := cbor.Unmarshal(tc.cborData, &v); err == nil {
+			if err := Unmarshal(tc.cborData, &v); err == nil {
 				t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", tc.cborData, tc.wantErrorMsg)
 			} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
 				t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.cborData, err.Error(), tc.wantErrorMsg)
 			}
 			if _, ok := v.(map[interface{}]interface{}); ok {
 				var v map[interface{}]interface{}
-				if err := cbor.Unmarshal(tc.cborData, &v); err == nil {
+				if err := Unmarshal(tc.cborData, &v); err == nil {
 					t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", tc.cborData, tc.wantErrorMsg)
 				} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
 					t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.cborData, err.Error(), tc.wantErrorMsg)
@@ -1520,10 +1524,14 @@ func TestMapKeyNaN(t *testing.T) {
 	// Data is generating by go-fuzz.
 	cborData := hexDecode("b0303030303030303030303030303030303038303030faffff30303030303030303030303030") // {-17: -17, NaN: -17}
 	var intf interface{}
-	if err := cbor.Unmarshal(cborData, &intf); err != nil {
+	if err := Unmarshal(cborData, &intf); err != nil {
 		t.Fatalf("Unmarshal(0x%x) returned error %v", cborData, err)
 	}
-	if _, err := cbor.Marshal(intf, cbor.EncOptions{Sort: cbor.SortCanonical}); err != nil {
+	em, err := EncOptions{Sort: SortCanonical}.EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
+	}
+	if _, err := em.Marshal(intf); err != nil {
 		t.Errorf("Marshal(%v) returned error %v", intf, err)
 	}
 }
@@ -1533,7 +1541,7 @@ func TestUnmarshalUndefinedElement(t *testing.T) {
 	cborData := hexDecode("bfd1a388f730303030303030303030303030ff") // {17({[undefined, -17, -17, -17, -17, -17, -17, -17]: -17, -17: -17}): -17}
 	var intf interface{}
 	wantErrorMsg := "invalid map key type"
-	if err := cbor.Unmarshal(cborData, &intf); err == nil {
+	if err := Unmarshal(cborData, &intf); err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error, want error containing substring %q", cborData, wantErrorMsg)
 	} else if !strings.Contains(err.Error(), wantErrorMsg) {
 		t.Errorf("Unmarshal(0x%x) returned error %q, want error containing substring %q", cborData, err.Error(), wantErrorMsg)
@@ -1547,22 +1555,22 @@ func TestMapKeyNil(t *testing.T) {
 	want := map[interface{}]interface{}{nil: int64(-17)}
 	for _, data := range testData {
 		var intf interface{}
-		if err := cbor.Unmarshal(data, &intf); err != nil {
+		if err := Unmarshal(data, &intf); err != nil {
 			t.Fatalf("Unmarshal(0x%x) returned error %v", data, err)
 		} else if !reflect.DeepEqual(intf, want) {
 			t.Errorf("Unmarshal(0x%x) returned %+v, want %+v", data, intf, want)
 		}
-		if _, err := cbor.Marshal(intf, cbor.EncOptions{Sort: cbor.SortCanonical}); err != nil {
+		if _, err := Marshal(intf); err != nil {
 			t.Errorf("Marshal(%v) returned error %v", intf, err)
 		}
 
 		var v map[interface{}]interface{}
-		if err := cbor.Unmarshal(data, &v); err != nil {
+		if err := Unmarshal(data, &v); err != nil {
 			t.Errorf("Unmarshal(0x%x) returned error %v", data, err)
 		} else if !reflect.DeepEqual(v, want) {
 			t.Errorf("Unmarshal(0x%x) returned %+v, want %+v", data, v, want)
 		}
-		if _, err := cbor.Marshal(v, cbor.EncOptions{Sort: cbor.SortCanonical}); err != nil {
+		if _, err := Marshal(v); err != nil {
 			t.Errorf("Marshal(%v) returned error %v", v, err)
 		}
 	}
@@ -1581,6 +1589,24 @@ func TestDecodeTime(t *testing.T) {
 			cborUnixTime:    hexDecode("f6"),
 			wantTime:        time.Time{},
 		},
+		{
+			name:            "NaN",
+			cborRFC3339Time: hexDecode("f97e00"),
+			cborUnixTime:    hexDecode("f97e00"),
+			wantTime:        time.Time{},
+		},
+		{
+			name:            "positive infinity",
+			cborRFC3339Time: hexDecode("f97c00"),
+			cborUnixTime:    hexDecode("f97c00"),
+			wantTime:        time.Time{},
+		},
+		{
+			name:            "negative infinity",
+			cborRFC3339Time: hexDecode("f9fc00"),
+			cborUnixTime:    hexDecode("f9fc00"),
+			wantTime:        time.Time{},
+		},
 		{
 			name:            "time without fractional seconds", // positive integer
 			cborRFC3339Time: hexDecode("74323031332d30332d32315432303a30343a30305a"),
@@ -1603,13 +1629,13 @@ func TestDecodeTime(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			tm := time.Now()
-			if err := cbor.Unmarshal(tc.cborRFC3339Time, &tm); err != nil {
+			if err := Unmarshal(tc.cborRFC3339Time, &tm); err != nil {
 				t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborRFC3339Time, err)
 			} else if !tc.wantTime.Equal(tm) {
 				t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.cborRFC3339Time, tm, tm, tc.wantTime, tc.wantTime)
 			}
 			tm = time.Now()
-			if err := cbor.Unmarshal(tc.cborUnixTime, &tm); err != nil {
+			if err := Unmarshal(tc.cborUnixTime, &tm); err != nil {
 				t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborUnixTime, err)
 			} else if !tc.wantTime.Equal(tm) {
 				t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", tc.cborUnixTime, tm, tm, tc.wantTime, tc.wantTime)
@@ -1638,7 +1664,7 @@ func TestDecodeTimeError(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			tm := time.Now()
-			if err := cbor.Unmarshal(tc.cborData, &tm); err == nil {
+			if err := Unmarshal(tc.cborData, &tm); err == nil {
 				t.Errorf("Unmarshal(0x%x) didn't return an error, want error msg %q", tc.cborData, tc.wantErrorMsg)
 			} else if err.Error() != tc.wantErrorMsg {
 				t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.cborData, err.Error(), tc.wantErrorMsg)
@@ -1661,7 +1687,7 @@ func TestUnmarshalStructTag1(t *testing.T) {
 	cborData := hexDecode("a3616161416162614261636143") // {"a":"A", "b":"B", "c":"C"}
 
 	var v strc
-	if err := cbor.Unmarshal(cborData, &v); err != nil {
+	if err := Unmarshal(cborData, &v); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	}
 	if !reflect.DeepEqual(v, want) {
@@ -1683,7 +1709,7 @@ func TestUnmarshalStructTag2(t *testing.T) {
 	cborData := hexDecode("a3616161416162614261636143") // {"a":"A", "b":"B", "c":"C"}
 
 	var v strc
-	if err := cbor.Unmarshal(cborData, &v); err != nil {
+	if err := Unmarshal(cborData, &v); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	}
 	if !reflect.DeepEqual(v, want) {
@@ -1705,7 +1731,7 @@ func TestUnmarshalStructTag3(t *testing.T) {
 	cborData := hexDecode("a36161614161626142617a6143") // {"a":"A", "b":"B", "z":"C"}
 
 	var v strc
-	if err := cbor.Unmarshal(cborData, &v); err != nil {
+	if err := Unmarshal(cborData, &v); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	}
 	if !reflect.DeepEqual(v, want) {
@@ -1726,7 +1752,7 @@ func TestUnmarshalStructTag4(t *testing.T) {
 	cborData := hexDecode("a3616161416162614261636143") // {"a":"A", "b":"B", "c":"C"}
 
 	var v strc
-	if err := cbor.Unmarshal(cborData, &v); err != nil {
+	if err := Unmarshal(cborData, &v); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	}
 	if !reflect.DeepEqual(v, want) {
@@ -1773,12 +1799,8 @@ func (n marshalBinaryError) MarshalBinary() (data []byte, err error) {
 	return nil, errors.New(string(n))
 }
 
-func TestBinaryUnmarshal(t *testing.T) {
-	testCases := []struct {
-		name         string
-		obj          interface{}
-		wantCborData []byte
-	}{
+func TestBinaryMarshalerUnmarshaler(t *testing.T) {
+	testCases := []roundTripTest{
 		{
 			name:         "primitive obj",
 			obj:          number(1234567890),
@@ -1790,27 +1812,12 @@ func TestBinaryUnmarshal(t *testing.T) {
 			wantCborData: hexDecode("45612C622C63"),
 		},
 	}
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(tc.obj, cbor.EncOptions{})
-			if err != nil {
-				t.Errorf("Marshal(%+v) returned error %v", tc.obj, err)
-			}
-			if !bytes.Equal(b, tc.wantCborData) {
-				t.Errorf("Marshal(%+v) = 0x%x, want 0x%x", tc.obj, b, tc.wantCborData)
-			}
-			v := reflect.New(reflect.TypeOf(tc.obj))
-			if err := cbor.Unmarshal(b, v.Interface()); err != nil {
-				t.Errorf("Unmarshal() returned error %v", err)
-			}
-			if !reflect.DeepEqual(tc.obj, v.Elem().Interface()) {
-				t.Errorf("Marshal-Unmarshal returned different values: %v, %v", tc.obj, v.Elem().Interface())
-			}
-		})
-	}
+	em, _ := EncOptions{}.EncMode()
+	dm, _ := DecOptions{}.DecMode()
+	testRoundTrip(t, testCases, em, dm)
 }
 
-func TestBinaryUnmarshalError(t *testing.T) {
+func TestBinaryUnmarshalerError(t *testing.T) { //nolint:dupl
 	testCases := []struct {
 		name         string
 		typ          reflect.Type
@@ -1833,7 +1840,7 @@ func TestBinaryUnmarshalError(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			v := reflect.New(tc.typ)
-			if err := cbor.Unmarshal(tc.cborData, v.Interface()); err == nil {
+			if err := Unmarshal(tc.cborData, v.Interface()); err == nil {
 				t.Errorf("Unmarshal(0x%x) didn't return an error, want error msg %q", tc.cborData, tc.wantErrorMsg)
 			} else if err.Error() != tc.wantErrorMsg {
 				t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.cborData, err.Error(), tc.wantErrorMsg)
@@ -1842,10 +1849,10 @@ func TestBinaryUnmarshalError(t *testing.T) {
 	}
 }
 
-func TestBinaryMarshalError(t *testing.T) {
+func TestBinaryMarshalerError(t *testing.T) {
 	wantErrorMsg := "MarshalBinary: error"
 	v := marshalBinaryError(wantErrorMsg)
-	if _, err := cbor.Marshal(v, cbor.EncOptions{}); err == nil {
+	if _, err := Marshal(v); err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error, want error msg %q", v, wantErrorMsg)
 	} else if err.Error() != wantErrorMsg {
 		t.Errorf("Unmarshal(0x%x) returned error %q, want %q", v, err.Error(), wantErrorMsg)
@@ -1854,14 +1861,14 @@ func TestBinaryMarshalError(t *testing.T) {
 
 type number2 uint64
 
-func (n number2) MarshalCBOR() (data []byte, err error) {
+func (n number2) MarshalCBOR(em EncMode) (data []byte, err error) {
 	m := map[string]uint64{"num": uint64(n)}
-	return cbor.Marshal(m, cbor.EncOptions{})
+	return em.Marshal(m)
 }
 
-func (n *number2) UnmarshalCBOR(data []byte) (err error) {
+func (n *number2) UnmarshalCBOR(dm DecMode, data []byte) (err error) {
 	var v map[string]uint64
-	if err := cbor.Unmarshal(data, &v); err != nil {
+	if err := dm.Unmarshal(data, &v); err != nil {
 		return err
 	}
 	*n = number2(v["num"])
@@ -1872,14 +1879,14 @@ type stru2 struct {
 	a, b, c string
 }
 
-func (s *stru2) MarshalCBOR() ([]byte, error) {
+func (s *stru2) MarshalCBOR(em EncMode) ([]byte, error) {
 	v := []string{s.a, s.b, s.c}
-	return cbor.Marshal(v, cbor.EncOptions{})
+	return em.Marshal(v)
 }
 
-func (s *stru2) UnmarshalCBOR(data []byte) (err error) {
+func (s *stru2) UnmarshalCBOR(dm DecMode, data []byte) (err error) {
 	var v []string
-	if err := cbor.Unmarshal(data, &v); err != nil {
+	if err := dm.Unmarshal(data, &v); err != nil {
 		return err
 	}
 	if len(v) > 0 {
@@ -1896,16 +1903,12 @@ func (s *stru2) UnmarshalCBOR(data []byte) (err error) {
 
 type marshalCBORError string
 
-func (n marshalCBORError) MarshalCBOR() (data []byte, err error) {
+func (n marshalCBORError) MarshalCBOR(em EncMode) (data []byte, err error) {
 	return nil, errors.New(string(n))
 }
 
-func TestUnmarshalCBOR(t *testing.T) {
-	testCases := []struct {
-		name         string
-		obj          interface{}
-		wantCborData []byte
-	}{
+func TestMarshalerUnmarshaler(t *testing.T) {
+	testCases := []roundTripTest{
 		{
 			name:         "primitive obj",
 			obj:          number2(1),
@@ -1917,27 +1920,12 @@ func TestUnmarshalCBOR(t *testing.T) {
 			wantCborData: hexDecode("83616161626163"),
 		},
 	}
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(tc.obj, cbor.EncOptions{})
-			if err != nil {
-				t.Errorf("Marshal(%+v) returned error %v", tc.obj, err)
-			}
-			if !bytes.Equal(b, tc.wantCborData) {
-				t.Errorf("Marshal(%+v) = 0x%x, want 0x%x", tc.obj, b, tc.wantCborData)
-			}
-			v := reflect.New(reflect.TypeOf(tc.obj))
-			if err := cbor.Unmarshal(b, v.Interface()); err != nil {
-				t.Errorf("Unmarshal() returned error %v", err)
-			}
-			if !reflect.DeepEqual(tc.obj, v.Elem().Interface()) {
-				t.Errorf("Marshal-Unmarshal returned different values: %v, %v", tc.obj, v.Elem().Interface())
-			}
-		})
-	}
+	em, _ := EncOptions{}.EncMode()
+	dm, _ := DecOptions{}.DecMode()
+	testRoundTrip(t, testCases, em, dm)
 }
 
-func TestUnmarshalCBORError(t *testing.T) {
+func TestUnmarshalerError(t *testing.T) { //nolint:dupl
 	testCases := []struct {
 		name         string
 		typ          reflect.Type
@@ -1960,7 +1948,7 @@ func TestUnmarshalCBORError(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			v := reflect.New(tc.typ)
-			if err := cbor.Unmarshal(tc.cborData, v.Interface()); err == nil {
+			if err := Unmarshal(tc.cborData, v.Interface()); err == nil {
 				t.Errorf("Unmarshal(0x%x) didn't return an error, want error msg %q", tc.cborData, tc.wantErrorMsg)
 			} else if err.Error() != tc.wantErrorMsg {
 				t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.cborData, err.Error(), tc.wantErrorMsg)
@@ -1969,10 +1957,10 @@ func TestUnmarshalCBORError(t *testing.T) {
 	}
 }
 
-func TestMarshalCBORError(t *testing.T) {
+func TestMarshalerError(t *testing.T) {
 	wantErrorMsg := "MarshalCBOR: error"
 	v := marshalCBORError(wantErrorMsg)
-	if _, err := cbor.Marshal(v, cbor.EncOptions{}); err == nil {
+	if _, err := Marshal(v); err == nil {
 		t.Errorf("Marshal(%+v) didn't return an error, want error msg %q", v, wantErrorMsg)
 	} else if err.Error() != wantErrorMsg {
 		t.Errorf("Marshal(%+v) returned error %q, want %q", v, err.Error(), wantErrorMsg)
@@ -1983,7 +1971,7 @@ func TestMarshalCBORError(t *testing.T) {
 func TestOutOfMem1(t *testing.T) {
 	cborData := []byte("\x9b\x00\x00000000")
 	var f []byte
-	if err := cbor.Unmarshal(cborData, &f); err == nil {
+	if err := Unmarshal(cborData, &f); err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error", cborData)
 	}
 }
@@ -1992,7 +1980,7 @@ func TestOutOfMem1(t *testing.T) {
 func TestOutOfMem2(t *testing.T) {
 	cborData := []byte("\x9b\x00\x00\x81112233")
 	var f []byte
-	if err := cbor.Unmarshal(cborData, &f); err == nil {
+	if err := Unmarshal(cborData, &f); err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error", cborData)
 	}
 }
@@ -2020,7 +2008,7 @@ func TestCOSEExamples(t *testing.T) {
 	}
 	for _, d := range cborData {
 		var v interface{}
-		if err := cbor.Unmarshal(d, &v); err != nil {
+		if err := Unmarshal(d, &v); err != nil {
 			t.Errorf("Unmarshal(0x%x) returned error %v", d, err)
 		}
 	}
@@ -2032,10 +2020,10 @@ func TestUnmarshalStructKeyAsIntError(t *testing.T) {
 	}
 	cborData := hexDecode("a13bffffffffffffffff01") // {1: -18446744073709551616}
 	var v T1
-	if err := cbor.Unmarshal(cborData, &v); err == nil {
+	if err := Unmarshal(cborData, &v); err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error", cborData)
-	} else if _, ok := err.(*cbor.UnmarshalTypeError); !ok {
-		t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*cbor.UnmarshalTypeError)", cborData, err)
+	} else if _, ok := err.(*UnmarshalTypeError); !ok {
+		t.Errorf("Unmarshal(0x%x) returned wrong error type %T, want (*UnmarshalTypeError)", cborData, err)
 	} else if !strings.Contains(err.Error(), "cannot unmarshal") {
 		t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", cborData, err.Error(), "cannot unmarshal")
 	}
@@ -2058,7 +2046,7 @@ func TestUnmarshalArrayToStruct(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			var v T
-			if err := cbor.Unmarshal(tc.cborData, &v); err != nil {
+			if err := Unmarshal(tc.cborData, &v); err != nil {
 				t.Errorf("Unmarshal(0x%x) returned error %v", tc.cborData, err)
 			}
 		})
@@ -2074,11 +2062,11 @@ func TestUnmarshalArrayToStructNoToArrayOptionError(t *testing.T) {
 	cborData := hexDecode("8301020383010203")
 	var v1 T
 	wantT := T{}
-	dec := cbor.NewDecoder(bytes.NewReader(cborData))
+	dec := NewDecoder(bytes.NewReader(cborData))
 	if err := dec.Decode(&v1); err == nil {
 		t.Errorf("Decode(%+v) didn't return an error", v1)
-	} else if _, ok := err.(*cbor.UnmarshalTypeError); !ok {
-		t.Errorf("Decode(%+v) returned wrong error type %T, want (*cbor.UnmarshalTypeError)", v1, err)
+	} else if _, ok := err.(*UnmarshalTypeError); !ok {
+		t.Errorf("Decode(%+v) returned wrong error type %T, want (*UnmarshalTypeError)", v1, err)
 	} else if !strings.Contains(err.Error(), "cannot unmarshal") {
 		t.Errorf("Decode(%+v) returned error %q, want error containing %q", err.Error(), v1, "cannot unmarshal")
 	}
@@ -2104,11 +2092,11 @@ func TestUnmarshalArrayToStructWrongSizeError(t *testing.T) {
 	cborData := hexDecode("8301020383010203")
 	var v1 T
 	wantT := T{}
-	dec := cbor.NewDecoder(bytes.NewReader(cborData))
+	dec := NewDecoder(bytes.NewReader(cborData))
 	if err := dec.Decode(&v1); err == nil {
 		t.Errorf("Decode(%+v) didn't return an error", v1)
-	} else if _, ok := err.(*cbor.UnmarshalTypeError); !ok {
-		t.Errorf("Decode(%+v) returned wrong error type %T, want (*cbor.UnmarshalTypeError)", v1, err)
+	} else if _, ok := err.(*UnmarshalTypeError); !ok {
+		t.Errorf("Decode(%+v) returned wrong error type %T, want (*UnmarshalTypeError)", v1, err)
 	} else if !strings.Contains(err.Error(), "cannot unmarshal") {
 		t.Errorf("Decode(%+v) returned error %q, want error containing %q", v1, err.Error(), "cannot unmarshal")
 	}
@@ -2141,12 +2129,12 @@ func TestUnmarshalArrayToStructWrongFieldTypeError(t *testing.T) {
 		// [1, 2, 3]
 		{"wrong field type", hexDecode("83010203"), "cannot unmarshal", T{A: 1, C: 3}},
 		// [1, 0xfe, 3]
-		{"invalid UTF-8 string", hexDecode("830161fe03"), "cbor: invalid UTF-8 string", T{A: 1, C: 3}},
+		{"invalid UTF-8 string", hexDecode("830161fe03"), invalidUTF8ErrorMsg, T{A: 1, C: 3}},
 	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			var v T
-			if err := cbor.Unmarshal(tc.cborData, &v); err == nil {
+			if err := Unmarshal(tc.cborData, &v); err == nil {
 				t.Errorf("Unmarshal(0x%x) didn't return an error", tc.cborData)
 			} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
 				t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", tc.cborData, err.Error(), tc.wantErrorMsg)
@@ -2160,19 +2148,25 @@ func TestUnmarshalArrayToStructWrongFieldTypeError(t *testing.T) {
 
 func TestUnmarshalArrayToStructCannotSetEmbeddedPointerError(t *testing.T) {
 	type (
-		s1 struct{ x, X int }
-		S2 struct{ y, Y int }
-		S  struct {
+		s1 struct {
+			x int //nolint:unused,structcheck
+			X int
+		}
+		S2 struct {
+			y int //nolint:unused,structcheck
+			Y int
+		}
+		S struct {
 			_ struct{} `cbor:",toarray"`
 			*s1
 			*S2
 		}
 	)
 	cborData := []byte{0x82, 0x02, 0x04} // [2, 4]
-	wantErrorMsg := "cannot set embedded pointer to unexported struct"
+	const wantErrorMsg = "cannot set embedded pointer to unexported struct"
 	wantV := S{S2: &S2{Y: 4}}
 	var v S
-	err := cbor.Unmarshal(cborData, &v)
+	err := Unmarshal(cborData, &v)
 	if err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error, want error %q", cborData, wantErrorMsg)
 	} else if !strings.Contains(err.Error(), wantErrorMsg) {
@@ -2185,13 +2179,13 @@ func TestUnmarshalArrayToStructCannotSetEmbeddedPointerError(t *testing.T) {
 
 func TestUnmarshalIntoSliceError(t *testing.T) {
 	cborData := []byte{0x83, 0x61, 0x61, 0x61, 0xfe, 0x61, 0x62} // ["a", 0xfe, "b"]
-	wantErrorMsg := "cbor: invalid UTF-8 string"
+	wantErrorMsg := invalidUTF8ErrorMsg
 	var want interface{}
 
 	// Unmarshal CBOR array into Go empty interface.
 	var v1 interface{}
 	want = []interface{}{"a", interface{}(nil), "b"}
-	if err := cbor.Unmarshal(cborData, &v1); err == nil {
+	if err := Unmarshal(cborData, &v1); err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", cborData, wantErrorMsg)
 	} else if err.Error() != wantErrorMsg {
 		t.Errorf("Unmarshal(0x%x) returned error %q, want %q", cborData, err.Error(), wantErrorMsg)
@@ -2203,7 +2197,7 @@ func TestUnmarshalIntoSliceError(t *testing.T) {
 	// Unmarshal CBOR array into Go slice.
 	var v2 []string
 	want = []string{"a", "", "b"}
-	if err := cbor.Unmarshal(cborData, &v2); err == nil {
+	if err := Unmarshal(cborData, &v2); err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", cborData, wantErrorMsg)
 	} else if err.Error() != wantErrorMsg {
 		t.Errorf("Unmarshal(0x%x) returned error %q, want %q", cborData, err.Error(), wantErrorMsg)
@@ -2215,7 +2209,7 @@ func TestUnmarshalIntoSliceError(t *testing.T) {
 	// Unmarshal CBOR array into Go array.
 	var v3 [3]string
 	want = [3]string{"a", "", "b"}
-	if err := cbor.Unmarshal(cborData, &v3); err == nil {
+	if err := Unmarshal(cborData, &v3); err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", cborData, wantErrorMsg)
 	} else if err.Error() != wantErrorMsg {
 		t.Errorf("Unmarshal(0x%x) returned error %q, want %q", cborData, err.Error(), wantErrorMsg)
@@ -2227,7 +2221,7 @@ func TestUnmarshalIntoSliceError(t *testing.T) {
 	// Unmarshal CBOR array into populated Go slice.
 	v4 := []string{"hello", "to", "you"}
 	want = []string{"a", "to", "b"}
-	if err := cbor.Unmarshal(cborData, &v4); err == nil {
+	if err := Unmarshal(cborData, &v4); err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", cborData, wantErrorMsg)
 	} else if err.Error() != wantErrorMsg {
 		t.Errorf("Unmarshal(0x%x) returned error %q, want %q", cborData, err.Error(), wantErrorMsg)
@@ -2242,14 +2236,14 @@ func TestUnmarshalIntoMapError(t *testing.T) {
 		{0xa3, 0x61, 0x61, 0x61, 0x41, 0x61, 0xfe, 0x61, 0x43, 0x61, 0x62, 0x61, 0x42}, // {"a":"A", 0xfe: "C", "b":"B"}
 		{0xa3, 0x61, 0x61, 0x61, 0x41, 0x61, 0x63, 0x61, 0xfe, 0x61, 0x62, 0x61, 0x42}, // {"a":"A", "c": 0xfe, "b":"B"}
 	}
-	wantErrorMsg := "cbor: invalid UTF-8 string"
+	wantErrorMsg := invalidUTF8ErrorMsg
 	var want interface{}
 
 	for _, data := range cborData {
 		// Unmarshal CBOR map into Go empty interface.
 		var v1 interface{}
 		want = map[interface{}]interface{}{"a": "A", "b": "B"}
-		if err := cbor.Unmarshal(data, &v1); err == nil {
+		if err := Unmarshal(data, &v1); err == nil {
 			t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", data, wantErrorMsg)
 		} else if err.Error() != wantErrorMsg {
 			t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err.Error(), wantErrorMsg)
@@ -2261,7 +2255,7 @@ func TestUnmarshalIntoMapError(t *testing.T) {
 		// Unmarshal CBOR map into Go map[interface{}]interface{}.
 		var v2 map[interface{}]interface{}
 		want = map[interface{}]interface{}{"a": "A", "b": "B"}
-		if err := cbor.Unmarshal(data, &v2); err == nil {
+		if err := Unmarshal(data, &v2); err == nil {
 			t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", data, wantErrorMsg)
 		} else if err.Error() != wantErrorMsg {
 			t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err.Error(), wantErrorMsg)
@@ -2273,7 +2267,7 @@ func TestUnmarshalIntoMapError(t *testing.T) {
 		// Unmarshal CBOR array into Go map[string]string.
 		var v3 map[string]string
 		want = map[string]string{"a": "A", "b": "B"}
-		if err := cbor.Unmarshal(data, &v3); err == nil {
+		if err := Unmarshal(data, &v3); err == nil {
 			t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", data, wantErrorMsg)
 		} else if err.Error() != wantErrorMsg {
 			t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err.Error(), wantErrorMsg)
@@ -2285,7 +2279,7 @@ func TestUnmarshalIntoMapError(t *testing.T) {
 		// Unmarshal CBOR array into populated Go map[string]string.
 		v4 := map[string]string{"c": "D"}
 		want = map[string]string{"a": "A", "b": "B", "c": "D"}
-		if err := cbor.Unmarshal(data, &v4); err == nil {
+		if err := Unmarshal(data, &v4); err == nil {
 			t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", data, wantErrorMsg)
 		} else if err.Error() != wantErrorMsg {
 			t.Errorf("Unmarshal(0x%x) returned error %q, want %q", data, err.Error(), wantErrorMsg)
@@ -2313,12 +2307,12 @@ func TestStructToArrayError(t *testing.T) {
 		wantErrorMsg string
 	}{
 		// [-17, [-17, -17], -17]
-		{hexDecode("9f3082303030ff"), "cbor: cannot unmarshal negative integer into Go struct field cbor_test.nestedCWT.Protected of type []uint8"},
+		{hexDecode("9f3082303030ff"), "cbor: cannot unmarshal negative integer into Go struct field cbor.nestedCWT.Protected of type []uint8"},
 		// [[], [], ["\x930000", -17]]
-		{hexDecode("9f9fff9fff9f65933030303030ffff"), "cbor: cannot unmarshal array into Go struct field cbor_test.nestedCWT.Unprotected of type cbor_test.coseHeader (cannot decode CBOR array to struct without toarray option)"},
+		{hexDecode("9f9fff9fff9f65933030303030ffff"), "cbor: cannot unmarshal array into Go struct field cbor.nestedCWT.Unprotected of type cbor.coseHeader (cannot decode CBOR array to struct without toarray option)"},
 	} {
 		var v nestedCWT
-		if err := cbor.Unmarshal(tc.cborData, &v); err == nil {
+		if err := Unmarshal(tc.cborData, &v); err == nil {
 			t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", tc.cborData, tc.wantErrorMsg)
 		} else if err.Error() != tc.wantErrorMsg {
 			t.Errorf("Unmarshal(0x%x) returned error %q, want %q", tc.cborData, err.Error(), tc.wantErrorMsg)
@@ -2337,10 +2331,10 @@ func TestStructKeyAsIntError(t *testing.T) {
 		Cti []byte  `cbor:"7,keyasint"`
 	}
 	cborData := hexDecode("bf0783e662f03030ff") // {7: [simple(6), "\xF00", -17]}
-	wantErrorMsg := "cbor: invalid UTF-8 string"
+	wantErrorMsg := invalidUTF8ErrorMsg
 	wantV := claims{Cti: []byte{6, 0, 0}}
 	var v claims
-	if err := cbor.Unmarshal(cborData, &v); err == nil {
+	if err := Unmarshal(cborData, &v); err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error, want %q", cborData, wantErrorMsg)
 	} else if err.Error() != wantErrorMsg {
 		t.Errorf("Unmarshal(0x%x) returned error %q, want %q", cborData, err.Error(), wantErrorMsg)
@@ -2352,10 +2346,10 @@ func TestStructKeyAsIntError(t *testing.T) {
 
 func TestUnmarshalToNotNilInterface(t *testing.T) {
 	cborData := hexDecode("83010203") // []uint64{1, 2, 3}
-	s := "hello"
-	var v interface{} = s // Unmarshal() sees v as type inteface{} and sets CBOR data as default Go type.  s is unmodified.  Same behavior as encoding/json.
+	s := "hello"                      //nolint:goconst
+	var v interface{} = s             // Unmarshal() sees v as type inteface{} and sets CBOR data as default Go type.  s is unmodified.  Same behavior as encoding/json.
 	wantV := []interface{}{uint64(1), uint64(2), uint64(3)}
-	if err := cbor.Unmarshal(cborData, &v); err != nil {
+	if err := Unmarshal(cborData, &v); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	} else if !reflect.DeepEqual(v, wantV) {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", cborData, v, v, wantV, wantV)
@@ -2369,15 +2363,55 @@ func TestDuplicateMapKeys(t *testing.T) {
 	wantV := map[interface{}]interface{}{"a": "A", "b": "B", "c": "F", "d": "D", "e": "E"}
 	wantM := map[string]string{"a": "A", "b": "B", "c": "F", "d": "D", "e": "E"}
 	var v interface{}
-	if err := cbor.Unmarshal(cborData, &v); err != nil {
+	if err := Unmarshal(cborData, &v); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	} else if !reflect.DeepEqual(v, wantV) {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", cborData, v, v, wantV, wantV)
 	}
 	var m map[string]string
-	if err := cbor.Unmarshal(cborData, &m); err != nil {
+	if err := Unmarshal(cborData, &m); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", cborData, err)
 	} else if !reflect.DeepEqual(m, wantM) {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", cborData, m, m, wantM, wantM)
 	}
 }
+
+func TestDecOptions(t *testing.T) {
+	opts1 := DecOptions{}
+	dm, err := opts1.DecMode()
+	if err != nil {
+		t.Errorf("DecMode() returned an error %v", err)
+	} else {
+		opts2 := dm.DecOptions()
+		if !reflect.DeepEqual(opts1, opts2) {
+			t.Errorf("DecOptions->DecMode->DecOptions returned different values: %v, %v", opts1, opts2)
+		}
+	}
+}
+
+type roundTripTest struct {
+	name         string
+	obj          interface{}
+	wantCborData []byte
+}
+
+func testRoundTrip(t *testing.T, testCases []roundTripTest, em EncMode, dm DecMode) {
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			b, err := em.Marshal(tc.obj)
+			if err != nil {
+				t.Errorf("Marshal(%+v) returned error %v", tc.obj, err)
+			}
+			if !bytes.Equal(b, tc.wantCborData) {
+				t.Errorf("Marshal(%+v) = 0x%x, want 0x%x", tc.obj, b, tc.wantCborData)
+			}
+			v := reflect.New(reflect.TypeOf(tc.obj))
+			if err := dm.Unmarshal(b, v.Interface()); err != nil {
+				t.Errorf("Unmarshal() returned error %v", err)
+			}
+			if !reflect.DeepEqual(tc.obj, v.Elem().Interface()) {
+				t.Errorf("Marshal-Unmarshal returned different values: %v, %v", tc.obj, v.Elem().Interface())
+			}
+		})
+	}
+}
diff --git a/encode_test.go b/encode_test.go
index 055bf36..d290690 100644
--- a/encode_test.go
+++ b/encode_test.go
@@ -1,7 +1,7 @@
 // Copyright (c) Faye Amacker. All rights reserved.
 // Licensed under the MIT License. See LICENSE in the project root for license information.
 
-package cbor_test
+package cbor
 
 import (
 	"bytes"
@@ -15,19 +15,6 @@ import (
 	"strings"
 	"testing"
 	"time"
-
-	"github.com/fxamacker/cbor"
-)
-
-const (
-	cborPositiveIntType byte = 0x00
-	cborNegativeIntType byte = 0x20
-	cborByteStringType  byte = 0x40
-	cborTextStringType  byte = 0x60
-	cborArrayType       byte = 0x80
-	cborMapType         byte = 0xa0
-	cborTagType         byte = 0xc0
-	cborPrimitivesType  byte = 0xe0
 )
 
 type marshalTest struct {
@@ -57,6 +44,10 @@ type outer struct {
 	unexportedField   int64
 }
 
+const (
+	wantIndefiniteLengthErrorMsg = "cbor: indefinite-length items are not allowed"
+)
+
 // CBOR test data are from https://tools.ietf.org/html/rfc7049#appendix-A.
 var marshalTests = []marshalTest{
 	// positive integer
@@ -105,7 +96,7 @@ var marshalTests = []marshalTest{
 		[]interface{}{
 			[0]int{},
 			[]uint{},
-			//[]uint8{},
+			// []uint8{},
 			[]uint16{},
 			[]uint32{},
 			[]uint64{},
@@ -123,7 +114,7 @@ var marshalTests = []marshalTest{
 		[]interface{}{
 			[...]int{1, 2, 3},
 			[]uint{1, 2, 3},
-			//[]uint8{1, 2, 3},
+			// []uint8{1, 2, 3},
 			[]uint16{1, 2, 3},
 			[]uint32{1, 2, 3},
 			[]uint64{1, 2, 3},
@@ -140,7 +131,7 @@ var marshalTests = []marshalTest{
 		[]interface{}{
 			[...]interface{}{1, [...]int{2, 3}, [...]int{4, 5}},
 			[]interface{}{1, []uint{2, 3}, []uint{4, 5}},
-			//[]interface{}{1, []uint8{2, 3}, []uint8{4, 5}},
+			// []interface{}{1, []uint8{2, 3}, []uint8{4, 5}},
 			[]interface{}{1, []uint16{2, 3}, []uint16{4, 5}},
 			[]interface{}{1, []uint32{2, 3}, []uint32{4, 5}},
 			[]interface{}{1, []uint64{2, 3}, []uint64{4, 5}},
@@ -157,7 +148,7 @@ var marshalTests = []marshalTest{
 		[]interface{}{
 			[...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
 			[]uint{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
-			//[]uint8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
+			// []uint8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
 			[]uint16{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
 			[]uint32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
 			[]uint64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
@@ -269,112 +260,111 @@ func TestInvalidTypeMarshal(t *testing.T) {
 		Chan chan bool
 	}
 	var marshalErrorTests = []marshalErrorTest{
-		{"channel can't be marshalled", make(chan bool), "cbor: unsupported type: chan bool"},
-		{"slice of channel can't be marshalled", make([]chan bool, 10), "cbor: unsupported type: []chan bool"},
-		{"slice of pointer to channel can't be marshalled", make([]*chan bool, 10), "cbor: unsupported type: []*chan bool"},
-		{"map of channel can't be marshalled", make(map[string]chan bool), "cbor: unsupported type: map[string]chan bool"},
-		{"struct of channel can't be marshalled", s1{}, "cbor: unsupported type: cbor_test.s1"},
-		{"struct of channel can't be marshalled", s2{}, "cbor: unsupported type: cbor_test.s2"},
-		{"function can't be marshalled", func(i int) int { return i * i }, "cbor: unsupported type: func(int) int"},
-		{"complex can't be marshalled", complex(100, 8), "cbor: unsupported type: complex128"},
+		{"channel can't be marshaled", make(chan bool), "cbor: unsupported type: chan bool"},
+		{"slice of channel can't be marshaled", make([]chan bool, 10), "cbor: unsupported type: []chan bool"},
+		{"slice of pointer to channel can't be marshaled", make([]*chan bool, 10), "cbor: unsupported type: []*chan bool"},
+		{"map of channel can't be marshaled", make(map[string]chan bool), "cbor: unsupported type: map[string]chan bool"},
+		{"struct of channel can't be marshaled", s1{}, "cbor: unsupported type: cbor.s1"},
+		{"struct of channel can't be marshaled", s2{}, "cbor: unsupported type: cbor.s2"},
+		{"function can't be marshaled", func(i int) int { return i * i }, "cbor: unsupported type: func(int) int"},
+		{"complex can't be marshaled", complex(100, 8), "cbor: unsupported type: complex128"},
+	}
+	em, err := EncOptions{Sort: SortCanonical}.EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
 	}
-
 	for _, tc := range marshalErrorTests {
 		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(&tc.value, cbor.EncOptions{})
+			b, err := Marshal(&tc.value)
 			if err == nil {
-				t.Errorf("Marshal(%v, cbor.EncOptions{}) didn't return an error, want error %q", tc.value, tc.wantErrorMsg)
-			} else if _, ok := err.(*cbor.UnsupportedTypeError); !ok {
-				t.Errorf("Marshal(%v, cbor.EncOptions{}) error type %T, want *cbor.UnsupportedTypeError", tc.value, err)
+				t.Errorf("Marshal(%v) didn't return an error, want error %q", tc.value, tc.wantErrorMsg)
+			} else if _, ok := err.(*UnsupportedTypeError); !ok {
+				t.Errorf("Marshal(%v) error type %T, want *UnsupportedTypeError", tc.value, err)
 			} else if err.Error() != tc.wantErrorMsg {
-				t.Errorf("Marshal(%v, cbor.EncOptions{}) error %q, want %q", tc.value, err.Error(), tc.wantErrorMsg)
+				t.Errorf("Marshal(%v) error %q, want %q", tc.value, err.Error(), tc.wantErrorMsg)
 			} else if b != nil {
-				t.Errorf("Marshal(%v, cbor.EncOptions{}) = 0x%x, want nil", tc.value, b)
+				t.Errorf("Marshal(%v) = 0x%x, want nil", tc.value, b)
 			}
 
-			b, err = cbor.Marshal(&tc.value, cbor.EncOptions{Sort: cbor.SortCanonical})
+			b, err = em.Marshal(&tc.value)
 			if err == nil {
-				t.Errorf("Marshal(%v, cbor.EncOptions{Sort: cbor.SortCanonical}) didn't return an error, want error %q", tc.value, tc.wantErrorMsg)
-			} else if _, ok := err.(*cbor.UnsupportedTypeError); !ok {
-				t.Errorf("Marshal(%v, cbor.EncOptions{Sort: cbor.SortCanonical}) error type %T, want *cbor.UnsupportedTypeError", tc.value, err)
+				t.Errorf("Marshal(%v) didn't return an error, want error %q", tc.value, tc.wantErrorMsg)
+			} else if _, ok := err.(*UnsupportedTypeError); !ok {
+				t.Errorf("Marshal(%v) error type %T, want *UnsupportedTypeError", tc.value, err)
 			} else if err.Error() != tc.wantErrorMsg {
-				t.Errorf("Marshal(%v, cbor.EncOptions{Sort: cbor.SortCanonical}) error %q, want %q", tc.value, err.Error(), tc.wantErrorMsg)
+				t.Errorf("Marshal(%v) error %q, want %q", tc.value, err.Error(), tc.wantErrorMsg)
 			} else if b != nil {
-				t.Errorf("Marshal(%v, cbor.EncOptions{Sort: cbor.SortCanonical}) = 0x%x, want nil", tc.value, b)
+				t.Errorf("Marshal(%v) = 0x%x, want nil", tc.value, b)
 			}
 		})
 	}
 }
 
 func TestMarshalLargeByteString(t *testing.T) {
-	var tests []marshalTest
-
 	// []byte{100, 100, 100, ...}
-	lengths := []int{0, 1, 2, 22, 23, 24, 254, 255, 256, 65534, 65535, 65536, 4294967294, 4294967295, 4294967296}
-	for length := range lengths {
-		cborData := bytes.NewBuffer(encodeCborHeader(cborByteStringType, uint64(length)))
+	lengths := []int{0, 1, 2, 22, 23, 24, 254, 255, 256, 65534, 65535, 65536, 10000000}
+	tests := make([]marshalTest, len(lengths))
+	for i, length := range lengths {
+		cborData := bytes.NewBuffer(encodeCborHeader(cborTypeByteString, uint64(length)))
 		value := make([]byte, length)
-		for i := 0; i < length; i++ {
+		for j := 0; j < length; j++ {
 			cborData.WriteByte(100)
-			value[i] = 100
+			value[j] = 100
 		}
-		tests = append(tests, marshalTest{cborData.Bytes(), []interface{}{value}})
+		tests[i] = marshalTest{cborData.Bytes(), []interface{}{value}}
 	}
 
 	testMarshal(t, tests)
 }
 
 func TestMarshalLargeTextString(t *testing.T) {
-	var tests []marshalTest
-
 	// "ddd..."
-	lengths := []int{0, 1, 2, 22, 23, 24, 254, 255, 256, 65534, 65535, 65536, 4294967294, 4294967295, 4294967296}
-	for length := range lengths {
-		cborData := bytes.NewBuffer(encodeCborHeader(cborTextStringType, uint64(length)))
+	lengths := []int{0, 1, 2, 22, 23, 24, 254, 255, 256, 65534, 65535, 65536, 10000000}
+	tests := make([]marshalTest, len(lengths))
+	for i, length := range lengths {
+		cborData := bytes.NewBuffer(encodeCborHeader(cborTypeTextString, uint64(length)))
 		value := make([]byte, length)
-		for i := 0; i < length; i++ {
+		for j := 0; j < length; j++ {
 			cborData.WriteByte(100)
-			value[i] = 100
+			value[j] = 100
 		}
-		tests = append(tests, marshalTest{cborData.Bytes(), []interface{}{string(value)}})
+		tests[i] = marshalTest{cborData.Bytes(), []interface{}{string(value)}}
 	}
 
 	testMarshal(t, tests)
 }
 
 func TestMarshalLargeArray(t *testing.T) {
-	var tests []marshalTest
-
 	// []string{"水", "水", "水", ...}
-	lengths := []int{0, 1, 2, 22, 23, 24, 254, 255, 256, 65534, 65535, 65536, 4294967294, 4294967295, 4294967296}
-	for length := range lengths {
-		cborData := bytes.NewBuffer(encodeCborHeader(cborArrayType, uint64(length)))
+	lengths := []int{0, 1, 2, 22, 23, 24, 254, 255, 256, 65534, 65535, 65536, 10000000}
+	tests := make([]marshalTest, len(lengths))
+	for i, length := range lengths {
+		cborData := bytes.NewBuffer(encodeCborHeader(cborTypeArray, uint64(length)))
 		value := make([]string, length)
-		for i := 0; i < length; i++ {
+		for j := 0; j < length; j++ {
 			cborData.Write([]byte{0x63, 0xe6, 0xb0, 0xb4})
-			value[i] = "水"
+			value[j] = "水"
 		}
-		tests = append(tests, marshalTest{cborData.Bytes(), []interface{}{value}})
+		tests[i] = marshalTest{cborData.Bytes(), []interface{}{value}}
 	}
 
 	testMarshal(t, tests)
 }
 
 func TestMarshalLargeMapCanonical(t *testing.T) {
-	var tests []marshalTest
-
 	// map[int]int {0:0, 1:1, 2:2, ...}
-	lengths := []int{0, 1, 2, 22, 23, 24, 254, 255, 256, 65534, 65535, 65536, 4294967294, 4294967295, 4294967296}
-	for length := range lengths {
-		cborData := bytes.NewBuffer(encodeCborHeader(cborMapType, uint64(length)))
+	lengths := []int{0, 1, 2, 22, 23, 24, 254, 255, 256, 65534, 65535, 65536, 1000000}
+	tests := make([]marshalTest, len(lengths))
+	for i, length := range lengths {
+		cborData := bytes.NewBuffer(encodeCborHeader(cborTypeMap, uint64(length)))
 		value := make(map[int]int, length)
-		for i := 0; i < length; i++ {
-			d := encodeCborHeader(cborPositiveIntType, uint64(i))
+		for j := 0; j < length; j++ {
+			d := encodeCborHeader(cborTypePositiveInt, uint64(j))
 			cborData.Write(d)
 			cborData.Write(d)
-			value[i] = i
+			value[j] = j
 		}
-		tests = append(tests, marshalTest{cborData.Bytes(), []interface{}{value}})
+		tests[i] = marshalTest{cborData.Bytes(), []interface{}{value}}
 	}
 
 	testMarshal(t, tests)
@@ -382,20 +372,20 @@ func TestMarshalLargeMapCanonical(t *testing.T) {
 
 func TestMarshalLargeMap(t *testing.T) {
 	// map[int]int {0:0, 1:1, 2:2, ...}
-	lengths := []int{0, 1, 2, 22, 23, 24, 254, 255, 256, 65534, 65535, 65536, 4294967294, 4294967295, 4294967296}
-	for length := range lengths {
+	lengths := []int{0, 1, 2, 22, 23, 24, 254, 255, 256, 65534, 65535, 65536, 1000000}
+	for _, length := range lengths {
 		m1 := make(map[int]int, length)
 		for i := 0; i < length; i++ {
 			m1[i] = i
 		}
 
-		cborData, err := cbor.Marshal(m1, cbor.EncOptions{})
+		cborData, err := Marshal(m1)
 		if err != nil {
 			t.Fatalf("Marshal(%v) returned error %v", m1, err)
 		}
 
 		m2 := make(map[int]int)
-		if err = cbor.Unmarshal(cborData, &m2); err != nil {
+		if err = Unmarshal(cborData, &m2); err != nil {
 			t.Fatalf("Unmarshal(0x%x) returned error %v", cborData, err)
 		}
 
@@ -405,47 +395,51 @@ func TestMarshalLargeMap(t *testing.T) {
 	}
 }
 
-func encodeCborHeader(t byte, n uint64) []byte {
+func encodeCborHeader(t cborType, n uint64) []byte {
 	b := make([]byte, 9)
 	if n <= 23 {
-		b[0] = t | byte(n)
+		b[0] = byte(t) | byte(n)
 		return b[:1]
 	} else if n <= math.MaxUint8 {
-		b[0] = t | byte(24)
+		b[0] = byte(t) | byte(24)
 		b[1] = byte(n)
 		return b[:2]
 	} else if n <= math.MaxUint16 {
-		b[0] = t | byte(25)
+		b[0] = byte(t) | byte(25)
 		binary.BigEndian.PutUint16(b[1:], uint16(n))
 		return b[:3]
 	} else if n <= math.MaxUint32 {
-		b[0] = t | byte(26)
+		b[0] = byte(t) | byte(26)
 		binary.BigEndian.PutUint32(b[1:], uint32(n))
 		return b[:5]
 	} else {
-		b[0] = t | byte(27)
-		binary.BigEndian.PutUint64(b[1:], uint64(n))
+		b[0] = byte(t) | byte(27)
+		binary.BigEndian.PutUint64(b[1:], n)
 		return b[:9]
 	}
 }
 
 func testMarshal(t *testing.T, testCases []marshalTest) {
+	em, err := EncOptions{Sort: SortCanonical}.EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
+	}
 	for _, tc := range testCases {
 		for _, value := range tc.values {
-			if _, err := cbor.Marshal(value, cbor.EncOptions{}); err != nil {
-				t.Errorf("Marshal(%v, cbor.EncOptions{}) returned error %v", value, err)
+			if _, err := Marshal(value); err != nil {
+				t.Errorf("Marshal(%v) returned error %v", value, err)
 			}
-			if b, err := cbor.Marshal(value, cbor.EncOptions{Sort: cbor.SortCanonical}); err != nil {
-				t.Errorf("Marshal(%v, cbor.EncOptions{Sort: cbor.SortCanonical}) returned error %v", value, err)
+			if b, err := em.Marshal(value); err != nil {
+				t.Errorf("Marshal(%v) returned error %v", value, err)
 			} else if !bytes.Equal(b, tc.cborData) {
-				t.Errorf("Marshal(%v, cbor.EncOptions{Sort: cbor.SortCanonical}) = 0x%x, want 0x%x", value, b, tc.cborData)
+				t.Errorf("Marshal(%v) = 0x%x, want 0x%x", value, b, tc.cborData)
 			}
 		}
-		r := cbor.RawMessage(tc.cborData)
-		if b, err := cbor.Marshal(r, cbor.EncOptions{}); err != nil {
-			t.Errorf("Marshal(%v, cbor.EncOptions{}) returned error %v", r, err)
+		r := RawMessage(tc.cborData)
+		if b, err := Marshal(r); err != nil {
+			t.Errorf("Marshal(%v) returned error %v", r, err)
 		} else if !bytes.Equal(b, r) {
-			t.Errorf("Marshal(%v, cbor.EncOptions{}) returned %v, want %v", r, b, r)
+			t.Errorf("Marshal(%v) returned %v, want %v", r, b, r)
 		}
 	}
 }
@@ -473,13 +467,13 @@ func TestMarshalStruct(t *testing.T) {
 		NestedStructField: &inner{X: 1000, Y: 1000000},
 	}
 
-	cborData, err := cbor.Marshal(v1, cbor.EncOptions{})
+	cborData, err := Marshal(v1)
 	if err != nil {
 		t.Fatalf("Marshal(%v) returned error %v", v1, err)
 	}
 
 	var v2 outer
-	if err = cbor.Unmarshal(cborData, &v2); err != nil {
+	if err = Unmarshal(cborData, &v2); err != nil {
 		t.Fatalf("Unmarshal(0x%x) returned error %v", cborData, err)
 	}
 
@@ -500,66 +494,70 @@ func TestMarshalStructCanonical(t *testing.T) {
 		unexportedField:   6,
 	}
 	var cborData bytes.Buffer
-	cborData.WriteByte(byte(cborMapType) | 8) // CBOR header: map type with 8 items (exported fields)
+	cborData.WriteByte(byte(cborTypeMap) | 8) // CBOR header: map type with 8 items (exported fields)
 
-	cborData.WriteByte(byte(cborTextStringType) | 8) // "IntField"
+	cborData.WriteByte(byte(cborTypeTextString) | 8) // "IntField"
 	cborData.WriteString("IntField")
-	cborData.WriteByte(byte(cborPositiveIntType) | 24)
+	cborData.WriteByte(byte(cborTypePositiveInt) | 24)
 	cborData.WriteByte(123)
 
-	cborData.WriteByte(byte(cborTextStringType) | 8) // "MapField"
+	cborData.WriteByte(byte(cborTypeTextString) | 8) // "MapField"
 	cborData.WriteString("MapField")
-	cborData.WriteByte(byte(cborMapType) | 2)
-	cborData.WriteByte(byte(cborTextStringType) | 7)
+	cborData.WriteByte(byte(cborTypeMap) | 2)
+	cborData.WriteByte(byte(cborTypeTextString) | 7)
 	cborData.WriteString("morning")
-	cborData.WriteByte(byte(cborPrimitivesType) | 21)
-	cborData.WriteByte(byte(cborTextStringType) | 9)
+	cborData.WriteByte(byte(cborTypePrimitives) | 21)
+	cborData.WriteByte(byte(cborTypeTextString) | 9)
 	cborData.WriteString("afternoon")
-	cborData.WriteByte(byte(cborPrimitivesType) | 20)
+	cborData.WriteByte(byte(cborTypePrimitives) | 20)
 
-	cborData.WriteByte(byte(cborTextStringType) | 9) // "BoolField"
+	cborData.WriteByte(byte(cborTypeTextString) | 9) // "BoolField"
 	cborData.WriteString("BoolField")
-	cborData.WriteByte(byte(cborPrimitivesType) | 21)
+	cborData.WriteByte(byte(cborTypePrimitives) | 21)
 
-	cborData.WriteByte(byte(cborTextStringType) | 10) // "ArrayField"
+	cborData.WriteByte(byte(cborTypeTextString) | 10) // "ArrayField"
 	cborData.WriteString("ArrayField")
-	cborData.WriteByte(byte(cborArrayType) | 2)
-	cborData.WriteByte(byte(cborTextStringType) | 5)
+	cborData.WriteByte(byte(cborTypeArray) | 2)
+	cborData.WriteByte(byte(cborTypeTextString) | 5)
 	cborData.WriteString("hello")
-	cborData.WriteByte(byte(cborTextStringType) | 5)
+	cborData.WriteByte(byte(cborTypeTextString) | 5)
 	cborData.WriteString("world")
 
-	cborData.WriteByte(byte(cborTextStringType) | 10) // "FloatField"
+	cborData.WriteByte(byte(cborTypeTextString) | 10) // "FloatField"
 	cborData.WriteString("FloatField")
 	cborData.Write([]byte{0xfa, 0x47, 0xc3, 0x50, 0x00})
 
-	cborData.WriteByte(byte(cborTextStringType) | 11) // "StringField"
+	cborData.WriteByte(byte(cborTypeTextString) | 11) // "StringField"
 	cborData.WriteString("StringField")
-	cborData.WriteByte(byte(cborTextStringType) | 4)
+	cborData.WriteByte(byte(cborTypeTextString) | 4)
 	cborData.WriteString("test")
 
-	cborData.WriteByte(byte(cborTextStringType) | 15) // "ByteStringField"
+	cborData.WriteByte(byte(cborTypeTextString) | 15) // "ByteStringField"
 	cborData.WriteString("ByteStringField")
-	cborData.WriteByte(byte(cborByteStringType) | 3)
+	cborData.WriteByte(byte(cborTypeByteString) | 3)
 	cborData.Write([]byte{1, 3, 5})
 
-	cborData.WriteByte(byte(cborTextStringType) | 17) // "NestedStructField"
+	cborData.WriteByte(byte(cborTypeTextString) | 17) // "NestedStructField"
 	cborData.WriteString("NestedStructField")
-	cborData.WriteByte(byte(cborMapType) | 2)
-	cborData.WriteByte(byte(cborTextStringType) | 1)
+	cborData.WriteByte(byte(cborTypeMap) | 2)
+	cborData.WriteByte(byte(cborTypeTextString) | 1)
 	cborData.WriteString("X")
-	cborData.WriteByte(byte(cborPositiveIntType) | 25)
+	cborData.WriteByte(byte(cborTypePositiveInt) | 25)
 	b := make([]byte, 2)
 	binary.BigEndian.PutUint16(b, uint16(1000))
 	cborData.Write(b)
-	cborData.WriteByte(byte(cborTextStringType) | 1)
+	cborData.WriteByte(byte(cborTypeTextString) | 1)
 	cborData.WriteString("Y")
-	cborData.WriteByte(byte(cborPositiveIntType) | 26)
+	cborData.WriteByte(byte(cborTypePositiveInt) | 26)
 	b = make([]byte, 4)
 	binary.BigEndian.PutUint32(b, uint32(1000000))
 	cborData.Write(b)
 
-	if b, err := cbor.Marshal(v, cbor.EncOptions{Sort: cbor.SortCanonical}); err != nil {
+	em, err := EncOptions{Sort: SortCanonical}.EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %q", err)
+	}
+	if b, err := em.Marshal(v); err != nil {
 		t.Errorf("Marshal(%v) returned error %v", v, err)
 	} else if !bytes.Equal(b, cborData.Bytes()) {
 		t.Errorf("Marshal(%v) = 0x%x, want 0x%x", v, b, cborData.Bytes())
@@ -577,7 +575,7 @@ func TestMarshalNullPointerToEmbeddedStruct(t *testing.T) {
 	)
 	v := T2{}
 	wantCborData := []byte{0xa0} // {}
-	cborData, err := cbor.Marshal(v, cbor.EncOptions{})
+	cborData, err := Marshal(v)
 	if err != nil {
 		t.Fatalf("Marshal(%v) returned error %v", v, err)
 	}
@@ -597,7 +595,7 @@ func TestMarshalNullPointerToStruct(t *testing.T) {
 	)
 	v := T2{}
 	wantCborData := []byte{0xa1, 0x61, 0x54, 0xf6} // {T: nil}
-	cborData, err := cbor.Marshal(v, cbor.EncOptions{})
+	cborData, err := Marshal(v)
 	if err != nil {
 		t.Fatalf("Marshal(%v) returned error %v", v, err)
 	}
@@ -618,7 +616,7 @@ func TestAnonymousFields1(t *testing.T) {
 	)
 	s := S{S1{1, 2}, S2{3, 4}}
 	want := []byte{0xa0} // {}
-	b, err := cbor.Marshal(s, cbor.EncOptions{})
+	b, err := Marshal(s)
 	if err != nil {
 		t.Errorf("Marshal(%v) returned error %v", s, err)
 	} else if !bytes.Equal(b, want) {
@@ -639,7 +637,7 @@ func TestAnonymousFields2(t *testing.T) {
 	)
 	s := S{S1{1, 2}, S2{3, 4}, 5, 6}
 	want := []byte{0xa1, 0x61, 0x58, 0x06} // {X:6}
-	b, err := cbor.Marshal(s, cbor.EncOptions{})
+	b, err := Marshal(s)
 	if err != nil {
 		t.Errorf("Marshal(%v) returned error %v", s, err)
 	} else if !bytes.Equal(b, want) {
@@ -648,7 +646,7 @@ func TestAnonymousFields2(t *testing.T) {
 
 	var v S
 	unmarshalWant := S{X: 6}
-	if err := cbor.Unmarshal(b, &v); err != nil {
+	if err := Unmarshal(b, &v); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 	} else if !reflect.DeepEqual(v, unmarshalWant) {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", b, v, v, unmarshalWant, unmarshalWant)
@@ -665,7 +663,7 @@ func TestAnonymousFields3(t *testing.T) {
 	)
 	s := S{5}
 	want := []byte{0xa0} // {}
-	b, err := cbor.Marshal(s, cbor.EncOptions{})
+	b, err := Marshal(s)
 	if err != nil {
 		t.Errorf("Marshal(%v) returned error %v", s, err)
 	} else if !bytes.Equal(b, want) {
@@ -683,7 +681,7 @@ func TestAnonymousFields4(t *testing.T) {
 	)
 	s := S{5}
 	want := []byte{0xa1, 0x65, 0x4d, 0x79, 0x49, 0x6e, 0x74, 0x05} // {MyInt: 5}
-	b, err := cbor.Marshal(s, cbor.EncOptions{})
+	b, err := Marshal(s)
 	if err != nil {
 		t.Errorf("Marshal(%v) returned error %v", s, err)
 	} else if !bytes.Equal(b, want) {
@@ -691,7 +689,7 @@ func TestAnonymousFields4(t *testing.T) {
 	}
 
 	var v S
-	if err = cbor.Unmarshal(b, &v); err != nil {
+	if err = Unmarshal(b, &v); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 	} else if !reflect.DeepEqual(v, s) {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", b, v, v, s, s)
@@ -709,7 +707,7 @@ func TestAnonymousFields5(t *testing.T) {
 	s := S{new(myInt)}
 	*s.myInt = 5
 	want := []byte{0xa0} // {}
-	b, err := cbor.Marshal(s, cbor.EncOptions{})
+	b, err := Marshal(s)
 	if err != nil {
 		t.Errorf("Marshal(%v) returned error %v", s, err)
 	} else if !bytes.Equal(b, want) {
@@ -728,7 +726,7 @@ func TestAnonymousFields6(t *testing.T) {
 	s := S{new(MyInt)}
 	*s.MyInt = 5
 	want := []byte{0xa1, 0x65, 0x4d, 0x79, 0x49, 0x6e, 0x74, 0x05} // {MyInt: 5}
-	b, err := cbor.Marshal(s, cbor.EncOptions{})
+	b, err := Marshal(s)
 	if err != nil {
 		t.Errorf("Marshal(%v) returned error %v", s, err)
 	} else if !bytes.Equal(b, want) {
@@ -736,7 +734,7 @@ func TestAnonymousFields6(t *testing.T) {
 	}
 
 	var v S
-	if err = cbor.Unmarshal(b, &v); err != nil {
+	if err = Unmarshal(b, &v); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 	} else if !reflect.DeepEqual(v, s) {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", b, v, v, s, s)
@@ -755,7 +753,7 @@ func TestAnonymousFields7(t *testing.T) {
 	)
 	s := S{s1{1, 2}, S2{3, 4}}
 	want := []byte{0xa2, 0x61, 0x58, 0x02, 0x61, 0x59, 0x04} // {X:2, Y:4}
-	b, err := cbor.Marshal(s, cbor.EncOptions{})
+	b, err := Marshal(s)
 	if err != nil {
 		t.Errorf("Marshal(%v) returned error %v", s, err)
 	} else if !bytes.Equal(b, want) {
@@ -764,7 +762,7 @@ func TestAnonymousFields7(t *testing.T) {
 
 	var v S
 	unmarshalWant := S{s1{X: 2}, S2{Y: 4}}
-	if err = cbor.Unmarshal(b, &v); err != nil {
+	if err = Unmarshal(b, &v); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 	} else if !reflect.DeepEqual(v, unmarshalWant) {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", b, v, v, unmarshalWant, unmarshalWant)
@@ -783,7 +781,7 @@ func TestAnonymousFields8(t *testing.T) {
 	)
 	s := S{&s1{1, 2}, &S2{3, 4}}
 	want := []byte{0xa2, 0x61, 0x58, 0x02, 0x61, 0x59, 0x04} // {X:2, Y:4}
-	b, err := cbor.Marshal(s, cbor.EncOptions{})
+	b, err := Marshal(s)
 	if err != nil {
 		t.Errorf("Marshal(%v) returned error %v", s, err)
 	} else if !bytes.Equal(b, want) {
@@ -794,7 +792,7 @@ func TestAnonymousFields8(t *testing.T) {
 	var v1 S
 	wantErrorMsg := "cannot set embedded pointer to unexported struct"
 	wantV := S{S2: &S2{Y: 4}}
-	err = cbor.Unmarshal(b, &v1)
+	err = Unmarshal(b, &v1)
 	if err == nil {
 		t.Errorf("Unmarshal(0x%x) didn't return an error, want error %q", b, wantErrorMsg)
 	} else if !strings.Contains(err.Error(), wantErrorMsg) {
@@ -808,7 +806,7 @@ func TestAnonymousFields8(t *testing.T) {
 	var v2 S
 	v2.s1 = &s1{}
 	unmarshalWant := S{&s1{X: 2}, &S2{Y: 4}}
-	if err = cbor.Unmarshal(b, &v2); err != nil {
+	if err = Unmarshal(b, &v2); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 	} else if !reflect.DeepEqual(v2, unmarshalWant) {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", b, v2, v2, unmarshalWant, unmarshalWant)
@@ -837,7 +835,7 @@ func TestAnonymousFields9(t *testing.T) {
 	)
 	s := S{s1{1, 2, s2{3, 4}}, 6}
 	want := []byte{0xa2, 0x66, 0x4d, 0x79, 0x49, 0x6e, 0x74, 0x31, 0x01, 0x66, 0x4d, 0x79, 0x49, 0x6e, 0x74, 0x32, 0x03} // {MyInt1: 1, MyInt2: 3}
-	b, err := cbor.Marshal(s, cbor.EncOptions{})
+	b, err := Marshal(s)
 	if err != nil {
 		t.Errorf("Marshal(%v) returned error %v", s, err)
 	} else if !bytes.Equal(b, want) {
@@ -846,7 +844,7 @@ func TestAnonymousFields9(t *testing.T) {
 
 	var v S
 	unmarshalWant := S{s1: s1{MyInt1: 1, s2: s2{MyInt2: 3}}}
-	if err = cbor.Unmarshal(b, &v); err != nil {
+	if err = Unmarshal(b, &v); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 	} else if !reflect.DeepEqual(v, unmarshalWant) {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", b, v, v, unmarshalWant, unmarshalWant)
@@ -874,7 +872,7 @@ func TestAnonymousFields10(t *testing.T) {
 	)
 	s := S{s1{1, s3{2}}, s2{3, s3{4}}}
 	want := []byte{0xa2, 0x61, 0x58, 0x01, 0x61, 0x59, 0x03} // {X: 1, Y: 3}
-	b, err := cbor.Marshal(s, cbor.EncOptions{})
+	b, err := Marshal(s)
 	if err != nil {
 		t.Errorf("Marshal(%v) returned error %v", s, err)
 	} else if !bytes.Equal(b, want) {
@@ -883,7 +881,7 @@ func TestAnonymousFields10(t *testing.T) {
 
 	var v S
 	unmarshalWant := S{s1: s1{X: 1}, s2: s2{Y: 3}}
-	if err = cbor.Unmarshal(b, &v); err != nil {
+	if err = Unmarshal(b, &v); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 	} else if !reflect.DeepEqual(v, unmarshalWant) {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", b, v, v, unmarshalWant, unmarshalWant)
@@ -907,7 +905,7 @@ func TestAnonymousFields11(t *testing.T) {
 	)
 	s := S{s1{1, s2{2}}, s2{3}}
 	want := []byte{0xa2, 0x61, 0x59, 0x01, 0x61, 0x58, 0x03} // {Y: 1, X: 3}
-	b, err := cbor.Marshal(s, cbor.EncOptions{})
+	b, err := Marshal(s)
 	if err != nil {
 		t.Errorf("Marshal(%v) returned error %v", s, err)
 	} else if !bytes.Equal(b, want) {
@@ -916,7 +914,7 @@ func TestAnonymousFields11(t *testing.T) {
 
 	var v S
 	unmarshalWant := S{s1: s1{Y: 1}, s2: s2{X: 3}}
-	if err = cbor.Unmarshal(b, &v); err != nil {
+	if err = Unmarshal(b, &v); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 	} else if !reflect.DeepEqual(v, unmarshalWant) {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", b, v, v, unmarshalWant, unmarshalWant)
@@ -947,7 +945,7 @@ func TestOmitEmpty(t *testing.T) {
 		Po  *int                   `cbor:"po,omitempty"`
 	}
 
-	//{"sr": "", "omitempty": 0, "slr": null, "mr": {}, "Ms": {"a": true}, "fr": 0, "br": false, "ur": 0, "str": {}, "sto": {}, "pr": nil }
+	// {"sr": "", "omitempty": 0, "slr": null, "mr": {}, "Ms": {"a": true}, "fr": 0, "br": false, "ur": 0, "str": {}, "sto": {}, "pr": nil }
 	want := []byte{0xab,
 		0x62, 0x73, 0x72, 0x60,
 		0x69, 0x6f, 0x6d, 0x69, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x00,
@@ -967,7 +965,7 @@ func TestOmitEmpty(t *testing.T) {
 	v.Mo = map[string]interface{}{}
 	v.Ms = map[string]interface{}{"a": true}
 
-	b, err := cbor.Marshal(v, cbor.EncOptions{})
+	b, err := Marshal(v)
 	if err != nil {
 		t.Errorf("Marshal(%v) returned error %v", v, err)
 	} else if !bytes.Equal(b, want) {
@@ -1006,8 +1004,8 @@ func TestTaggedFieldDominates(t *testing.T) {
 		StructA{"StructA"},
 		StructD{"StructD"},
 	}
-	want := []byte{0xa1, 0x61, 0x53, 0x67, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x44} //{"S":"StructD"}
-	b, err := cbor.Marshal(v, cbor.EncOptions{})
+	want := []byte{0xa1, 0x61, 0x53, 0x67, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x44} // {"S":"StructD"}
+	b, err := Marshal(v)
 	if err != nil {
 		t.Errorf("Marshal(%v) returned error %v", v, err)
 	} else if !bytes.Equal(b, want) {
@@ -1016,7 +1014,7 @@ func TestTaggedFieldDominates(t *testing.T) {
 
 	var v2 StructY
 	unmarshalWant := StructY{StructD: StructD{"StructD"}}
-	if err = cbor.Unmarshal(b, &v2); err != nil {
+	if err = Unmarshal(b, &v2); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 	} else if !reflect.DeepEqual(v2, unmarshalWant) {
 		t.Errorf("Unmarshal(0x%x) = %v (%T), want %v (%T)", b, v2, v2, unmarshalWant, unmarshalWant)
@@ -1032,8 +1030,8 @@ func TestDuplicatedFieldDisappears(t *testing.T) {
 			StructD{"nested StructD"},
 		},
 	}
-	want := []byte{0xa0} //{}
-	b, err := cbor.Marshal(v, cbor.EncOptions{})
+	want := []byte{0xa0} // {}
+	b, err := Marshal(v)
 	if err != nil {
 		t.Errorf("Marshal(%v) returned error %v", v, err)
 	} else if !bytes.Equal(b, want) {
@@ -1066,7 +1064,7 @@ func TestTaggedAnonymousField(t *testing.T) {
 	// Test that an anonymous field with a name given in its CBOR tag is treated as having that name, rather than being anonymous.
 	s := S3{X: 1, S1: S1{X: 2}}
 	want := []byte{0xa2, 0x61, 0x58, 0x01, 0x62, 0x53, 0x31, 0xa1, 0x61, 0x58, 0x02} // {X: 1, S1: {X:2}}
-	b, err := cbor.Marshal(s, cbor.EncOptions{Sort: cbor.SortCanonical})
+	b, err := Marshal(s)
 	if err != nil {
 		t.Errorf("Marshal(%+v) returned error %v", s, err)
 	} else if !bytes.Equal(b, want) {
@@ -1075,7 +1073,7 @@ func TestTaggedAnonymousField(t *testing.T) {
 
 	var v S3
 	unmarshalWant := S3{X: 1, S1: S1{X: 2}}
-	if err = cbor.Unmarshal(b, &v); err != nil {
+	if err = Unmarshal(b, &v); err != nil {
 		t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 	} else if !reflect.DeepEqual(v, unmarshalWant) {
 		t.Errorf("Unmarshal(0x%x) = %+v (%T), want %+v (%T)", b, v, v, unmarshalWant, unmarshalWant)
@@ -1086,7 +1084,7 @@ func TestAnonymousInterfaceField(t *testing.T) {
 	// Test that an anonymous struct field of interface type is treated the same as having that type as its name, rather than being anonymous.
 	s := S4{X: 1, Reader: S2{X: 2}}
 	want := []byte{0xa2, 0x61, 0x58, 0x01, 0x66, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0xa1, 0x61, 0x58, 0x02} // {X: 1, Reader: {X:2}}
-	b, err := cbor.Marshal(s, cbor.EncOptions{Sort: cbor.SortCanonical})
+	b, err := Marshal(s)
 	if err != nil {
 		t.Errorf("Marshal(%+v) returned error %v", s, err)
 	} else if !bytes.Equal(b, want) {
@@ -1094,24 +1092,22 @@ func TestAnonymousInterfaceField(t *testing.T) {
 	}
 
 	var v S4
-	if err = cbor.Unmarshal(b, &v); err == nil {
-		t.Errorf("Unmarshal(0x%x) didn't return an error, want error (*cbor.UnmarshalTypeError)", b)
+	const wantErrorMsg = "cannot unmarshal map into Go struct field cbor.S4.Reader of type io.Reader"
+	if err = Unmarshal(b, &v); err == nil {
+		t.Errorf("Unmarshal(0x%x) didn't return an error, want error (*UnmarshalTypeError)", b)
 	} else {
-		if typeError, ok := err.(*cbor.UnmarshalTypeError); !ok {
-			t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*cbor.UnmarshalTypeError)", b, err)
-		} else {
-			if !strings.Contains(typeError.Error(), "cannot unmarshal map into Go struct field cbor_test.S4.Reader of type io.Reader") {
-				t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", b, err.Error(), "cannot unmarshal map into Go struct field cbor_test.S4.Reader of type io.Reader")
-			}
+		if typeError, ok := err.(*UnmarshalTypeError); !ok {
+			t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*UnmarshalTypeError)", b, err)
+		} else if !strings.Contains(typeError.Error(), wantErrorMsg) {
+			t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", b, err.Error(), wantErrorMsg)
 		}
 	}
 }
 
 func TestEncodeInterface(t *testing.T) {
-	var r io.Reader
-	r = S2{X: 2}
+	var r io.Reader = S2{X: 2}
 	want := []byte{0xa1, 0x61, 0x58, 0x02} // {X:2}
-	b, err := cbor.Marshal(r, cbor.EncOptions{Sort: cbor.SortCanonical})
+	b, err := Marshal(r)
 	if err != nil {
 		t.Errorf("Marshal(%+v) returned error %v", r, err)
 	} else if !bytes.Equal(b, want) {
@@ -1119,68 +1115,168 @@ func TestEncodeInterface(t *testing.T) {
 	}
 
 	var v io.Reader
-	if err = cbor.Unmarshal(b, &v); err == nil {
-		t.Errorf("Unmarshal(0x%x) didn't return an error, want error (*cbor.UnmarshalTypeError)", b)
+	const wantErrorMsg = "cannot unmarshal map into Go value of type io.Reader"
+	if err = Unmarshal(b, &v); err == nil {
+		t.Errorf("Unmarshal(0x%x) didn't return an error, want error (*UnmarshalTypeError)", b)
 	} else {
-		if typeError, ok := err.(*cbor.UnmarshalTypeError); !ok {
-			t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*cbor.UnmarshalTypeError)", b, err)
-		} else {
-			if !strings.Contains(typeError.Error(), "cannot unmarshal map into Go value of type io.Reader") {
-				t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", b, err.Error(), "cannot unmarshal map into Go value of type io.Reader")
-			}
+		if typeError, ok := err.(*UnmarshalTypeError); !ok {
+			t.Errorf("Unmarshal(0x%x) returned wrong type of error %T, want (*UnmarshalTypeError)", b, err)
+		} else if !strings.Contains(typeError.Error(), wantErrorMsg) {
+			t.Errorf("Unmarshal(0x%x) returned error %q, want error containing %q", b, err.Error(), wantErrorMsg)
 		}
 	}
 }
 
 func TestEncodeTime(t *testing.T) {
+	timeUnixOpt := EncOptions{Time: TimeUnix}
+	timeUnixMicroOpt := EncOptions{Time: TimeUnixMicro}
+	timeUnixDynamicOpt := EncOptions{Time: TimeUnixDynamic}
+	timeRFC3339Opt := EncOptions{Time: TimeRFC3339}
+	timeRFC3339NanoOpt := EncOptions{Time: TimeRFC3339Nano}
+
+	type timeConvert struct {
+		opt          EncOptions
+		wantCborData []byte
+	}
 	testCases := []struct {
-		name                string
-		tm                  time.Time
-		wantCborRFC3339Time []byte
-		wantCborUnixTime    []byte
+		name    string
+		tm      time.Time
+		convert []timeConvert
 	}{
 		{
-			name:                "zero time",
-			tm:                  time.Time{},
-			wantCborRFC3339Time: hexDecode("f6"), // encode as nil
-			wantCborUnixTime:    hexDecode("f6"), // encode as nil
+			name: "zero time",
+			tm:   time.Time{},
+			convert: []timeConvert{
+				{
+					opt:          timeUnixOpt,
+					wantCborData: hexDecode("f6"), // encode as CBOR null
+				},
+				{
+					opt:          timeUnixMicroOpt,
+					wantCborData: hexDecode("f6"), // encode as CBOR null
+				},
+				{
+					opt:          timeUnixDynamicOpt,
+					wantCborData: hexDecode("f6"), // encode as CBOR null
+				},
+				{
+					opt:          timeRFC3339Opt,
+					wantCborData: hexDecode("f6"), // encode as CBOR null
+				},
+				{
+					opt:          timeRFC3339NanoOpt,
+					wantCborData: hexDecode("f6"), // encode as CBOR null
+				},
+			},
 		},
 		{
-			name:                "time without fractional seconds",
-			tm:                  parseTime(time.RFC3339Nano, "2013-03-21T20:04:00Z"),
-			wantCborRFC3339Time: hexDecode("74323031332d30332d32315432303a30343a30305a"),
-			wantCborUnixTime:    hexDecode("1a514b67b0"), // encode as positive integer
+			name: "time without fractional seconds",
+			tm:   parseTime(time.RFC3339Nano, "2013-03-21T20:04:00Z"),
+			convert: []timeConvert{
+				{
+					opt:          timeUnixOpt,
+					wantCborData: hexDecode("1a514b67b0"), // 1363896240
+				},
+				{
+					opt:          timeUnixMicroOpt,
+					wantCborData: hexDecode("fb41d452d9ec000000"), // 1363896240.0
+				},
+				{
+					opt:          timeUnixDynamicOpt,
+					wantCborData: hexDecode("1a514b67b0"), // 1363896240
+				},
+				{
+					opt:          timeRFC3339Opt,
+					wantCborData: hexDecode("74323031332d30332d32315432303a30343a30305a"), // "2013-03-21T20:04:00Z"
+				},
+				{
+					opt:          timeRFC3339NanoOpt,
+					wantCborData: hexDecode("74323031332d30332d32315432303a30343a30305a"), // "2013-03-21T20:04:00Z"
+				},
+			},
 		},
 		{
-			name:                "time with fractional seconds",
-			tm:                  parseTime(time.RFC3339Nano, "2013-03-21T20:04:00.5Z"),
-			wantCborRFC3339Time: hexDecode("76323031332d30332d32315432303a30343a30302e355a"),
-			wantCborUnixTime:    hexDecode("fb41d452d9ec200000"), // encode as float
+			name: "time with fractional seconds",
+			tm:   parseTime(time.RFC3339Nano, "2013-03-21T20:04:00.5Z"),
+			convert: []timeConvert{
+				{
+					opt:          timeUnixOpt,
+					wantCborData: hexDecode("1a514b67b0"), // 1363896240
+				},
+				{
+					opt:          timeUnixMicroOpt,
+					wantCborData: hexDecode("fb41d452d9ec200000"), // 1363896240.5
+				},
+				{
+					opt:          timeUnixDynamicOpt,
+					wantCborData: hexDecode("fb41d452d9ec200000"), // 1363896240.5
+				},
+				{
+					opt:          timeRFC3339Opt,
+					wantCborData: hexDecode("74323031332d30332d32315432303a30343a30305a"), // "2013-03-21T20:04:00Z"
+				},
+				{
+					opt:          timeRFC3339NanoOpt,
+					wantCborData: hexDecode("76323031332d30332d32315432303a30343a30302e355a"), // "2013-03-21T20:04:00.5Z"
+				},
+			},
 		},
 		{
-			name:                "time before January 1, 1970 UTC without fractional seconds",
-			tm:                  parseTime(time.RFC3339Nano, "1969-03-21T20:04:00Z"),
-			wantCborRFC3339Time: hexDecode("74313936392d30332d32315432303a30343a30305a"),
-			wantCborUnixTime:    hexDecode("3a0177f2cf"), // encode as negative integer
+			name: "time before January 1, 1970 UTC without fractional seconds",
+			tm:   parseTime(time.RFC3339Nano, "1969-03-21T20:04:00Z"),
+			convert: []timeConvert{
+				{
+					opt:          timeUnixOpt,
+					wantCborData: hexDecode("3a0177f2cf"), // -24638160
+				},
+				{
+					opt:          timeUnixMicroOpt,
+					wantCborData: hexDecode("fbc1777f2d00000000"), // -24638160.0
+				},
+				{
+					opt:          timeUnixDynamicOpt,
+					wantCborData: hexDecode("3a0177f2cf"), // -24638160
+				},
+				{
+					opt:          timeRFC3339Opt,
+					wantCborData: hexDecode("74313936392d30332d32315432303a30343a30305a"), // "1969-03-21T20:04:00Z"
+				},
+				{
+					opt:          timeRFC3339NanoOpt,
+					wantCborData: hexDecode("74313936392d30332d32315432303a30343a30305a"), // "1969-03-21T20:04:00Z"
+				},
+			},
 		},
 	}
 	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			// Encode time as string in RFC3339 format.
-			b, err := cbor.Marshal(tc.tm, cbor.EncOptions{TimeRFC3339: true})
-			if err != nil {
-				t.Errorf("Marshal(%+v) as string in RFC3339 format returned error %v", tc.tm, err)
-			} else if !bytes.Equal(b, tc.wantCborRFC3339Time) {
-				t.Errorf("Marshal(%+v) as string in RFC3339 format = 0x%x, want 0x%x", tc.tm, b, tc.wantCborRFC3339Time)
-			}
-			// Encode time as numerical representation of seconds since January 1, 1970 UTC.
-			b, err = cbor.Marshal(tc.tm, cbor.EncOptions{TimeRFC3339: false})
-			if err != nil {
-				t.Errorf("Marshal(%+v) as unix time returned error %v", tc.tm, err)
-			} else if !bytes.Equal(b, tc.wantCborUnixTime) {
-				t.Errorf("Marshal(%+v) as unix time = 0x%x, want 0x%x", tc.tm, b, tc.wantCborUnixTime)
+		for _, convert := range tc.convert {
+			var convertName string
+			switch convert.opt.Time {
+			case TimeUnix:
+				convertName = "TimeUnix"
+			case TimeUnixMicro:
+				convertName = "TimeUnixMicro"
+			case TimeUnixDynamic:
+				convertName = "TimeUnixDynamic"
+			case TimeRFC3339:
+				convertName = "TimeRFC3339"
+			case TimeRFC3339Nano:
+				convertName = "TimeRFC3339Nano"
 			}
-		})
+			name := tc.name + " with " + convertName + " option"
+			t.Run(name, func(t *testing.T) {
+				em, err := convert.opt.EncMode()
+				if err != nil {
+					t.Errorf("EncMode() returned error %v", err)
+				}
+				b, err := em.Marshal(tc.tm)
+				if err != nil {
+					t.Errorf("Marshal(%+v) returned error %v", tc.tm, err)
+				} else if !bytes.Equal(b, convert.wantCborData) {
+					t.Errorf("Marshal(%+v) = 0x%x, want 0x%x", tc.tm, b, convert.wantCborData)
+				}
+			})
+		}
 	}
 }
 
@@ -1192,6 +1288,16 @@ func parseTime(layout string, value string) time.Time {
 	return tm
 }
 
+func TestInvalidTimeMode(t *testing.T) {
+	wantErrorMsg := "cbor: invalid TimeMode 100"
+	_, err := EncOptions{Time: TimeMode(100)}.EncMode()
+	if err == nil {
+		t.Errorf("EncMode() didn't return an error")
+	} else if err.Error() != wantErrorMsg {
+		t.Errorf("EncMode() returned error %q, want %q", err.Error(), wantErrorMsg)
+	}
+}
+
 func TestMarshalStructTag1(t *testing.T) {
 	type strc struct {
 		A string `cbor:"a"`
@@ -1204,8 +1310,7 @@ func TestMarshalStructTag1(t *testing.T) {
 		C: "C",
 	}
 	want := hexDecode("a3616161416162614261636143") // {"a":"A", "b":"B", "c":"C"}
-
-	if b, err := cbor.Marshal(v, cbor.EncOptions{Sort: cbor.SortCanonical}); err != nil {
+	if b, err := Marshal(v); err != nil {
 		t.Errorf("Marshal(%+v) returned error %v", v, err)
 	} else if !bytes.Equal(b, want) {
 		t.Errorf("Marshal(%+v) = %v, want %v", v, b, want)
@@ -1224,8 +1329,7 @@ func TestMarshalStructTag2(t *testing.T) {
 		C: "C",
 	}
 	want := hexDecode("a3616161416162614261636143") // {"a":"A", "b":"B", "c":"C"}
-
-	if b, err := cbor.Marshal(v, cbor.EncOptions{Sort: cbor.SortCanonical}); err != nil {
+	if b, err := Marshal(v); err != nil {
 		t.Errorf("Marshal(%+v) returned error %v", v, err)
 	} else if !bytes.Equal(b, want) {
 		t.Errorf("Marshal(%+v) = %v, want %v", v, b, want)
@@ -1244,8 +1348,7 @@ func TestMarshalStructTag3(t *testing.T) {
 		C: "C",
 	}
 	want := hexDecode("a36161614161626142617a6143") // {"a":"A", "b":"B", "z":"C"}
-
-	if b, err := cbor.Marshal(v, cbor.EncOptions{Sort: cbor.SortCanonical}); err != nil {
+	if b, err := Marshal(v); err != nil {
 		t.Errorf("Marshal(%+v) returned error %v", v, err)
 	} else if !bytes.Equal(b, want) {
 		t.Errorf("Marshal(%+v) = %v, want %v", v, b, want)
@@ -1264,8 +1367,7 @@ func TestMarshalStructTag4(t *testing.T) {
 		C: "C",
 	}
 	want := hexDecode("a26161614161626142") // {"a":"A", "b":"B"}
-
-	if b, err := cbor.Marshal(v, cbor.EncOptions{Sort: cbor.SortCanonical}); err != nil {
+	if b, err := Marshal(v); err != nil {
 		t.Errorf("Marshal(%+v) returned error %v", v, err)
 	} else if !bytes.Equal(b, want) {
 		t.Errorf("Marshal(%+v) = %v, want %v", v, b, want)
@@ -1284,8 +1386,7 @@ func TestMarshalStructLongFieldName(t *testing.T) {
 		C: "C",
 	}
 	want := hexDecode("a361616141781a6162636465666768696a6b6c6d6e6f707172737475767778797a614278426162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6143") // {"a":"A", "abcdefghijklmnopqrstuvwxyz":"B", "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn":"C"}
-
-	if b, err := cbor.Marshal(v, cbor.EncOptions{Sort: cbor.SortCanonical}); err != nil {
+	if b, err := Marshal(v); err != nil {
 		t.Errorf("Marshal(%+v) returned error %v", v, err)
 	} else if !bytes.Equal(b, want) {
 		t.Errorf("Marshal(%+v) = %v, want %v", v, b, want)
@@ -1295,17 +1396,17 @@ func TestMarshalStructLongFieldName(t *testing.T) {
 func TestMarshalRawMessageValue(t *testing.T) {
 	type (
 		T1 struct {
-			M cbor.RawMessage `cbor:",omitempty"`
+			M RawMessage `cbor:",omitempty"`
 		}
 		T2 struct {
-			M *cbor.RawMessage `cbor:",omitempty"`
+			M *RawMessage `cbor:",omitempty"`
 		}
 	)
 
 	var (
-		rawNil   = cbor.RawMessage(nil)
-		rawEmpty = cbor.RawMessage([]byte{})
-		raw      = cbor.RawMessage([]byte{0x01})
+		rawNil   = RawMessage(nil)
+		rawEmpty = RawMessage([]byte{})
+		raw      = RawMessage([]byte{0x01})
 	)
 
 	tests := []struct {
@@ -1319,10 +1420,10 @@ func TestMarshalRawMessageValue(t *testing.T) {
 		{&[]interface{}{rawNil}, []byte{0x81, 0xf6}},
 		{[]interface{}{&rawNil}, []byte{0x81, 0xf6}},
 		{&[]interface{}{&rawNil}, []byte{0x81, 0xf6}},
-		{struct{ M cbor.RawMessage }{rawNil}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
-		{&struct{ M cbor.RawMessage }{rawNil}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
-		{struct{ M *cbor.RawMessage }{&rawNil}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
-		{&struct{ M *cbor.RawMessage }{&rawNil}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
+		{struct{ M RawMessage }{rawNil}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
+		{&struct{ M RawMessage }{rawNil}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
+		{struct{ M *RawMessage }{&rawNil}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
+		{&struct{ M *RawMessage }{&rawNil}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
 		{map[string]interface{}{"M": rawNil}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
 		{&map[string]interface{}{"M": rawNil}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
 		{map[string]interface{}{"M": &rawNil}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
@@ -1339,10 +1440,10 @@ func TestMarshalRawMessageValue(t *testing.T) {
 		{&[]interface{}{rawEmpty}, []byte{0x81, 0xf6}},
 		{[]interface{}{&rawEmpty}, []byte{0x81, 0xf6}},
 		{&[]interface{}{&rawEmpty}, []byte{0x81, 0xf6}},
-		{struct{ M cbor.RawMessage }{rawEmpty}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
-		{&struct{ M cbor.RawMessage }{rawEmpty}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
-		{struct{ M *cbor.RawMessage }{&rawEmpty}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
-		{&struct{ M *cbor.RawMessage }{&rawEmpty}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
+		{struct{ M RawMessage }{rawEmpty}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
+		{&struct{ M RawMessage }{rawEmpty}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
+		{struct{ M *RawMessage }{&rawEmpty}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
+		{&struct{ M *RawMessage }{&rawEmpty}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
 		{map[string]interface{}{"M": rawEmpty}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
 		{&map[string]interface{}{"M": rawEmpty}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
 		{map[string]interface{}{"M": &rawEmpty}, []byte{0xa1, 0x61, 0x4d, 0xf6}},
@@ -1359,10 +1460,10 @@ func TestMarshalRawMessageValue(t *testing.T) {
 		{&[]interface{}{raw}, []byte{0x81, 0x01}},
 		{[]interface{}{&raw}, []byte{0x81, 0x01}},
 		{&[]interface{}{&raw}, []byte{0x81, 0x01}},
-		{struct{ M cbor.RawMessage }{raw}, []byte{0xa1, 0x61, 0x4d, 0x01}},
-		{&struct{ M cbor.RawMessage }{raw}, []byte{0xa1, 0x61, 0x4d, 0x01}},
-		{struct{ M *cbor.RawMessage }{&raw}, []byte{0xa1, 0x61, 0x4d, 0x01}},
-		{&struct{ M *cbor.RawMessage }{&raw}, []byte{0xa1, 0x61, 0x4d, 0x01}},
+		{struct{ M RawMessage }{raw}, []byte{0xa1, 0x61, 0x4d, 0x01}},
+		{&struct{ M RawMessage }{raw}, []byte{0xa1, 0x61, 0x4d, 0x01}},
+		{struct{ M *RawMessage }{&raw}, []byte{0xa1, 0x61, 0x4d, 0x01}},
+		{&struct{ M *RawMessage }{&raw}, []byte{0xa1, 0x61, 0x4d, 0x01}},
 		{map[string]interface{}{"M": raw}, []byte{0xa1, 0x61, 0x4d, 0x01}},
 		{&map[string]interface{}{"M": raw}, []byte{0xa1, 0x61, 0x4d, 0x01}},
 		{map[string]interface{}{"M": &raw}, []byte{0xa1, 0x61, 0x4d, 0x01}},
@@ -1374,7 +1475,7 @@ func TestMarshalRawMessageValue(t *testing.T) {
 	}
 
 	for _, tc := range tests {
-		b, err := cbor.Marshal(tc.obj, cbor.EncOptions{})
+		b, err := Marshal(tc.obj)
 		if err != nil {
 			t.Errorf("Marshal(%+v) returned error %v", tc.obj, err)
 		}
@@ -1391,7 +1492,7 @@ func TestCyclicDataStructure(t *testing.T) {
 	}
 	v := Node{1, &Node{2, &Node{3, nil}}}                                                                                  // linked list: 1, 2, 3
 	wantCborData := []byte{0xa2, 0x61, 0x76, 0x01, 0x61, 0x6e, 0xa2, 0x61, 0x76, 0x02, 0x61, 0x6e, 0xa1, 0x61, 0x76, 0x03} // {v: 1, n: {v: 2, n: {v: 3}}}
-	cborData, err := cbor.Marshal(v, cbor.EncOptions{})
+	cborData, err := Marshal(v)
 	if err != nil {
 		t.Fatalf("Marshal(%v) returned error %v", v, err)
 	}
@@ -1399,7 +1500,7 @@ func TestCyclicDataStructure(t *testing.T) {
 		t.Errorf("Marshal(%v) = 0x%x, want 0x%x", v, cborData, wantCborData)
 	}
 	var v1 Node
-	if err = cbor.Unmarshal(cborData, &v1); err != nil {
+	if err = Unmarshal(cborData, &v1); err != nil {
 		t.Fatalf("Unmarshal(0x%x) returned error %v", cborData, err)
 	}
 	if !reflect.DeepEqual(v, v1) {
@@ -1429,9 +1530,13 @@ func TestMarshalUnmarshalStructKeyAsInt(t *testing.T) {
 			hexDecode("a301012203613202"), // {1: 1, -3: 3, "2": 2}
 		},
 	}
+	em, err := EncOptions{Sort: SortCanonical}.EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned error %v", err)
+	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(tc.obj, cbor.EncOptions{Sort: cbor.SortCanonical})
+			b, err := em.Marshal(tc.obj)
 			if err != nil {
 				t.Errorf("Marshal(%+v) returned error %v", tc.obj, err)
 			}
@@ -1440,7 +1545,7 @@ func TestMarshalUnmarshalStructKeyAsInt(t *testing.T) {
 			}
 
 			var v2 T
-			if err := cbor.Unmarshal(b, &v2); err != nil {
+			if err := Unmarshal(b, &v2); err != nil {
 				t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 			}
 			if !reflect.DeepEqual(tc.obj, v2) {
@@ -1475,15 +1580,15 @@ func TestMarshalStructKeyAsIntNumError(t *testing.T) {
 	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(tc.obj, cbor.EncOptions{})
+			b, err := Marshal(tc.obj)
 			if err == nil {
-				t.Errorf("Marshal(%+v, cbor.EncOptions{}) didn't return an error, want error %q", tc.obj, tc.wantErrorMsg)
+				t.Errorf("Marshal(%+v) didn't return an error, want error %q", tc.obj, tc.wantErrorMsg)
 			} else if _, ok := err.(*strconv.NumError); !ok {
-				t.Errorf("Marshal(%v, cbor.EncOptions{}) error type %T, want *strconv.NumError", tc.obj, err)
+				t.Errorf("Marshal(%v) error type %T, want *strconv.NumError", tc.obj, err)
 			} else if !strings.Contains(err.Error(), tc.wantErrorMsg) {
-				t.Errorf("Marshal(%v, cbor.EncOptions{}) error %v, want %v", tc.obj, err.Error(), tc.wantErrorMsg)
+				t.Errorf("Marshal(%v) error %v, want %v", tc.obj, err.Error(), tc.wantErrorMsg)
 			} else if b != nil {
-				t.Errorf("Marshal(%v, cbor.EncOptions{}) = 0x%x, want nil", tc.obj, b)
+				t.Errorf("Marshal(%v) = 0x%x, want nil", tc.obj, b)
 			}
 		})
 	}
@@ -1527,7 +1632,7 @@ func TestMarshalUnmarshalStructToArray(t *testing.T) {
 	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(tc.obj, cbor.EncOptions{})
+			b, err := Marshal(tc.obj)
 			if err != nil {
 				t.Errorf("Marshal(%+v) returned error %v", tc.obj, err)
 			}
@@ -1536,7 +1641,11 @@ func TestMarshalUnmarshalStructToArray(t *testing.T) {
 			}
 
 			// SortMode should be ignored for struct to array encoding
-			b, err = cbor.Marshal(tc.obj, cbor.EncOptions{Sort: cbor.SortCanonical})
+			em, err := EncOptions{Sort: SortCanonical}.EncMode()
+			if err != nil {
+				t.Errorf("EncMode() returned error %v", err)
+			}
+			b, err = em.Marshal(tc.obj)
 			if err != nil {
 				t.Errorf("Marshal(%+v) returned error %v", tc.obj, err)
 			}
@@ -1545,7 +1654,7 @@ func TestMarshalUnmarshalStructToArray(t *testing.T) {
 			}
 
 			var v2 T
-			if err := cbor.Unmarshal(b, &v2); err != nil {
+			if err := Unmarshal(b, &v2); err != nil {
 				t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 			}
 			if tc.obj.T2 == nil {
@@ -1577,24 +1686,22 @@ func TestMapSort(t *testing.T) {
 
 	testCases := []struct {
 		name         string
-		opts         cbor.EncOptions
+		opts         EncOptions
 		wantCborData []byte
 	}{
-		{"Length first sort", cbor.EncOptions{Sort: cbor.SortLengthFirst}, lenFirstSortedCborData},
-		{"Bytewise sort", cbor.EncOptions{Sort: cbor.SortBytewiseLexical}, bytewiseSortedCborData},
-		{"CBOR canonical sort", cbor.EncOptions{Sort: cbor.SortCanonical}, lenFirstSortedCborData},
-		{"CTAP2 canonical sort", cbor.EncOptions{Sort: cbor.SortCTAP2}, bytewiseSortedCborData},
-		{"Core deterministic sort", cbor.EncOptions{Sort: cbor.SortCoreDeterministic}, bytewiseSortedCborData},
-		{"CBOR canonical sort (deprecated option)", cbor.EncOptions{Canonical: true}, lenFirstSortedCborData},
-		{"CBOR canonical sort (deprecated option)", cbor.EncOptions{Sort: cbor.SortNone, Canonical: true}, lenFirstSortedCborData},
-		{"CBOR canonical sort (deprecated option)", cbor.EncOptions{Sort: cbor.SortCanonical, Canonical: true}, lenFirstSortedCborData},
-		{"CTAP2 canonical sort (deprecated option)", cbor.EncOptions{CTAP2Canonical: true}, bytewiseSortedCborData},
-		{"CTAP2 canonical sort (deprecated option)", cbor.EncOptions{Sort: cbor.SortNone, CTAP2Canonical: true}, bytewiseSortedCborData},
-		{"CTAP2 canonical sort (deprecated option)", cbor.EncOptions{Sort: cbor.SortCTAP2, CTAP2Canonical: true}, bytewiseSortedCborData},
+		{"Length first sort", EncOptions{Sort: SortLengthFirst}, lenFirstSortedCborData},
+		{"Bytewise sort", EncOptions{Sort: SortBytewiseLexical}, bytewiseSortedCborData},
+		{"CBOR canonical sort", EncOptions{Sort: SortCanonical}, lenFirstSortedCborData},
+		{"CTAP2 canonical sort", EncOptions{Sort: SortCTAP2}, bytewiseSortedCborData},
+		{"Core deterministic sort", EncOptions{Sort: SortCoreDeterministic}, bytewiseSortedCborData},
 	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(m, tc.opts)
+			em, err := tc.opts.EncMode()
+			if err != nil {
+				t.Errorf("EncMode() returned error %v", err)
+			}
+			b, err := em.Marshal(m)
 			if err != nil {
 				t.Errorf("Marshal(%v) returned error %v", m, err)
 			}
@@ -1621,26 +1728,24 @@ func TestStructSort(t *testing.T) {
 
 	testCases := []struct {
 		name         string
-		opts         cbor.EncOptions
+		opts         EncOptions
 		wantCborData []byte
 	}{
-		{"No sort", cbor.EncOptions{}, unsortedCborData},
-		{"No sort", cbor.EncOptions{Sort: cbor.SortNone}, unsortedCborData},
-		{"Length first sort", cbor.EncOptions{Sort: cbor.SortLengthFirst}, lenFirstSortedCborData},
-		{"Bytewise sort", cbor.EncOptions{Sort: cbor.SortBytewiseLexical}, bytewiseSortedCborData},
-		{"CBOR canonical sort", cbor.EncOptions{Sort: cbor.SortCanonical}, lenFirstSortedCborData},
-		{"CTAP2 canonical sort", cbor.EncOptions{Sort: cbor.SortCTAP2}, bytewiseSortedCborData},
-		{"Core deterministic sort", cbor.EncOptions{Sort: cbor.SortCoreDeterministic}, bytewiseSortedCborData},
-		{"CBOR canonical sort (deprecated option)", cbor.EncOptions{Canonical: true}, lenFirstSortedCborData},
-		{"CBOR canonical sort (deprecated option)", cbor.EncOptions{Sort: cbor.SortNone, Canonical: true}, lenFirstSortedCborData},
-		{"CBOR canonical sort (deprecated option)", cbor.EncOptions{Sort: cbor.SortCanonical, Canonical: true}, lenFirstSortedCborData},
-		{"CTAP2 canonical sort (deprecated option)", cbor.EncOptions{CTAP2Canonical: true}, bytewiseSortedCborData},
-		{"CTAP2 canonical sort (deprecated option)", cbor.EncOptions{Sort: cbor.SortNone, CTAP2Canonical: true}, bytewiseSortedCborData},
-		{"CTAP2 canonical sort (deprecated option)", cbor.EncOptions{Sort: cbor.SortCTAP2, CTAP2Canonical: true}, bytewiseSortedCborData},
+		{"No sort", EncOptions{}, unsortedCborData},
+		{"No sort", EncOptions{Sort: SortNone}, unsortedCborData},
+		{"Length first sort", EncOptions{Sort: SortLengthFirst}, lenFirstSortedCborData},
+		{"Bytewise sort", EncOptions{Sort: SortBytewiseLexical}, bytewiseSortedCborData},
+		{"CBOR canonical sort", EncOptions{Sort: SortCanonical}, lenFirstSortedCborData},
+		{"CTAP2 canonical sort", EncOptions{Sort: SortCTAP2}, bytewiseSortedCborData},
+		{"Core deterministic sort", EncOptions{Sort: SortCoreDeterministic}, bytewiseSortedCborData},
 	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(v, tc.opts)
+			em, err := tc.opts.EncMode()
+			if err != nil {
+				t.Errorf("EncMode() returned error %v", err)
+			}
+			b, err := em.Marshal(v)
 			if err != nil {
 				t.Errorf("Marshal(%v) returned error %v", v, err)
 			}
@@ -1652,31 +1757,16 @@ func TestStructSort(t *testing.T) {
 }
 
 func TestInvalidSort(t *testing.T) {
-	m := map[string]bool{"hello": true}
-	testCases := []struct {
-		name         string
-		opts         cbor.EncOptions
-		wantErrorMsg string
-	}{
-		{"Invalid SortMode value", cbor.EncOptions{Sort: cbor.SortMode(100)}, "cbor: invalid SortMode 100"},
-		{"Deprecated Canonical conflicting with SortMode value", cbor.EncOptions{Sort: cbor.SortBytewiseLexical, Canonical: true}, "cbor: conflicting sorting modes not allowed"},
-		{"Deprecated Canonical conflicting with SortMode value", cbor.EncOptions{Sort: cbor.SortCTAP2, Canonical: true}, "cbor: conflicting sorting modes not allowed"},
-		{"Deprecated Canonical conflicting with SortMode value", cbor.EncOptions{Sort: cbor.SortCoreDeterministic, Canonical: true}, "cbor: conflicting sorting modes not allowed"},
-		{"Deprecated CTAP2Canonical conflicting with SortMode value", cbor.EncOptions{Sort: cbor.SortLengthFirst, CTAP2Canonical: true}, "cbor: conflicting sorting modes not allowed"},
-		{"Deprecated CTAP2Canonical conflicting with SortMode value", cbor.EncOptions{Sort: cbor.SortCanonical, CTAP2Canonical: true}, "cbor: conflicting sorting modes not allowed"},
-	}
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			if _, err := cbor.Marshal(m, tc.opts); err == nil {
-				t.Errorf("Marshal() didn't return an error")
-			} else if err.Error() != tc.wantErrorMsg {
-				t.Errorf("Marshal() returned error %q, want %q", err.Error(), tc.wantErrorMsg)
-			}
-		})
+	wantErrorMsg := "cbor: invalid SortMode 100"
+	_, err := EncOptions{Sort: SortMode(100)}.EncMode()
+	if err == nil {
+		t.Errorf("EncMode() didn't return an error")
+	} else if err.Error() != wantErrorMsg {
+		t.Errorf("EncMode() returned error %q, want %q", err.Error(), wantErrorMsg)
 	}
 }
 
-func TestTypeAlias(t *testing.T) {
+func TestTypeAlias(t *testing.T) { //nolint:dupl,unconvert
 	type myBool = bool
 	type myUint = uint
 	type myUint8 = uint8
@@ -1696,11 +1786,7 @@ func TestTypeAlias(t *testing.T) {
 	type myIntArray = [4]int
 	type myMapIntInt = map[int]int
 
-	testCases := []struct {
-		name         string
-		obj          interface{}
-		wantCborData []byte
-	}{
+	testCases := []roundTripTest{
 		{
 			name:         "bool alias",
 			obj:          myBool(true),
@@ -1773,46 +1859,37 @@ func TestTypeAlias(t *testing.T) {
 		},
 		{
 			name:         "[]byte alias",
-			obj:          myByteSlice([]byte{1, 2, 3, 4}),
+			obj:          myByteSlice([]byte{1, 2, 3, 4}), //nolint:unconvert
 			wantCborData: hexDecode("4401020304"),
 		},
 		{
 			name:         "[]int alias",
-			obj:          myIntSlice([]int{1, 2, 3, 4}),
+			obj:          myIntSlice([]int{1, 2, 3, 4}), //nolint:unconvert
 			wantCborData: hexDecode("8401020304"),
 		},
 		{
 			name:         "[4]int alias",
-			obj:          myIntArray([...]int{1, 2, 3, 4}),
+			obj:          myIntArray([...]int{1, 2, 3, 4}), //nolint:unconvert
 			wantCborData: hexDecode("8401020304"),
 		},
 		{
 			name:         "map[int]int alias",
-			obj:          myMapIntInt(map[int]int{1: 2, 3: 4}),
+			obj:          myMapIntInt(map[int]int{1: 2, 3: 4}), //nolint:unconvert
 			wantCborData: hexDecode("a201020304"),
 		},
 	}
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(tc.obj, cbor.EncOptions{Sort: cbor.SortCanonical})
-			if err != nil {
-				t.Errorf("Marshal(%+v) returned error %v", tc.obj, err)
-			}
-			if !bytes.Equal(b, tc.wantCborData) {
-				t.Errorf("Marshal(%+v) = 0x%x, want 0x%x", tc.obj, b, tc.wantCborData)
-			}
-			v := reflect.New(reflect.TypeOf(tc.obj))
-			if err := cbor.Unmarshal(b, v.Interface()); err != nil {
-				t.Errorf("Unmarshal() returned error %v", err)
-			}
-			if !reflect.DeepEqual(tc.obj, v.Elem().Interface()) {
-				t.Errorf("Marshal-Unmarshal returned different values: %v, %v", tc.obj, v.Elem().Interface())
-			}
-		})
+	em, err := EncOptions{Sort: SortCanonical}.EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
 	}
+	dm, err := DecOptions{}.DecMode()
+	if err != nil {
+		t.Errorf("DecMode() returned an error %v", err)
+	}
+	testRoundTrip(t, testCases, em, dm)
 }
 
-func TestNewTypeWithBuiltinUnderlyingType(t *testing.T) {
+func TestNewTypeWithBuiltinUnderlyingType(t *testing.T) { //nolint:dupl
 	type myBool bool
 	type myUint uint
 	type myUint8 uint8
@@ -1832,11 +1909,7 @@ func TestNewTypeWithBuiltinUnderlyingType(t *testing.T) {
 	type myIntArray [4]int
 	type myMapIntInt map[int]int
 
-	testCases := []struct {
-		name         string
-		obj          interface{}
-		wantCborData []byte
-	}{
+	testCases := []roundTripTest{
 		{
 			name:         "bool alias",
 			obj:          myBool(true),
@@ -1928,24 +2001,15 @@ func TestNewTypeWithBuiltinUnderlyingType(t *testing.T) {
 			wantCborData: hexDecode("a201020304"),
 		},
 	}
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(tc.obj, cbor.EncOptions{Sort: cbor.SortCanonical})
-			if err != nil {
-				t.Errorf("Marshal(%+v) returned error %v", tc.obj, err)
-			}
-			if !bytes.Equal(b, tc.wantCborData) {
-				t.Errorf("Marshal(%+v) = 0x%x, want 0x%x", tc.obj, b, tc.wantCborData)
-			}
-			v := reflect.New(reflect.TypeOf(tc.obj))
-			if err := cbor.Unmarshal(b, v.Interface()); err != nil {
-				t.Errorf("Unmarshal() returned error %v", err)
-			}
-			if !reflect.DeepEqual(tc.obj, v.Elem().Interface()) {
-				t.Errorf("Marshal-Unmarshal returned different values: %v, %v", tc.obj, v.Elem().Interface())
-			}
-		})
+	em, err := EncOptions{Sort: SortCanonical}.EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
+	}
+	dm, err := DecOptions{}.DecMode()
+	if err != nil {
+		t.Errorf("DecMode() returned an error %v", err)
 	}
+	testRoundTrip(t, testCases, em, dm)
 }
 
 func TestShortestFloat16(t *testing.T) {
@@ -1975,17 +2039,20 @@ func TestShortestFloat16(t *testing.T) {
 		// Data from RFC 7049 appendix A
 		{"Shrink to float64", 1.0e+300, hexDecode("fb7e37e43c8800759c")},
 	}
-	opts := cbor.EncOptions{ShortestFloat: cbor.ShortestFloat16}
+	em, err := EncOptions{ShortestFloat: ShortestFloat16}.EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
+	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(tc.f64, opts)
+			b, err := em.Marshal(tc.f64)
 			if err != nil {
 				t.Errorf("Marshal(%v) returned error %v", tc.f64, err)
 			} else if !bytes.Equal(b, tc.wantCborData) {
 				t.Errorf("Marshal(%v) = 0x%x, want 0x%x", tc.f64, b, tc.wantCborData)
 			}
 			var f64 float64
-			if err = cbor.Unmarshal(b, &f64); err != nil {
+			if err = Unmarshal(b, &f64); err != nil {
 				t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 			} else if f64 != tc.f64 {
 				t.Errorf("Unmarshal(0x%x) = %f, want %f", b, f64, tc.f64)
@@ -2022,17 +2089,20 @@ func TestShortestFloat32(t *testing.T) {
 		// Data from RFC 7049 appendix A
 		{"Shrink to float64", 1.0e+300, hexDecode("fb7e37e43c8800759c")},
 	}
-	opts := cbor.EncOptions{ShortestFloat: cbor.ShortestFloat32}
+	em, err := EncOptions{ShortestFloat: ShortestFloat32}.EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
+	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(tc.f64, opts)
+			b, err := em.Marshal(tc.f64)
 			if err != nil {
 				t.Errorf("Marshal(%v) returned error %v", tc.f64, err)
 			} else if !bytes.Equal(b, tc.wantCborData) {
 				t.Errorf("Marshal(%v) = 0x%x, want 0x%x", tc.f64, b, tc.wantCborData)
 			}
 			var f64 float64
-			if err = cbor.Unmarshal(b, &f64); err != nil {
+			if err = Unmarshal(b, &f64); err != nil {
 				t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 			} else if f64 != tc.f64 {
 				t.Errorf("Unmarshal(0x%x) = %f, want %f", b, f64, tc.f64)
@@ -2068,17 +2138,20 @@ func TestShortestFloat64(t *testing.T) {
 		// Data from RFC 7049 appendix A
 		{"Shrink to float64", 1.0e+300, hexDecode("fb7e37e43c8800759c")},
 	}
-	opts := cbor.EncOptions{ShortestFloat: cbor.ShortestFloat64}
+	em, err := EncOptions{ShortestFloat: ShortestFloat64}.EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
+	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(tc.f64, opts)
+			b, err := em.Marshal(tc.f64)
 			if err != nil {
 				t.Errorf("Marshal(%v) returned error %v", tc.f64, err)
 			} else if !bytes.Equal(b, tc.wantCborData) {
 				t.Errorf("Marshal(%v) = 0x%x, want 0x%x", tc.f64, b, tc.wantCborData)
 			}
 			var f64 float64
-			if err = cbor.Unmarshal(b, &f64); err != nil {
+			if err = Unmarshal(b, &f64); err != nil {
 				t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 			} else if f64 != tc.f64 {
 				t.Errorf("Unmarshal(0x%x) = %f, want %f", b, f64, tc.f64)
@@ -2126,10 +2199,13 @@ func TestShortestFloatNone(t *testing.T) {
 		{"float64", float64(1000000.5), hexDecode("fb412e848100000000")},
 		{"float64", float64(1.0e+300), hexDecode("fb7e37e43c8800759c")},
 	}
-	opts := cbor.EncOptions{ShortestFloat: cbor.ShortestFloatNone}
+	em, err := EncOptions{ShortestFloat: ShortestFloatNone}.EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
+	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(tc.f, opts)
+			b, err := em.Marshal(tc.f)
 			if err != nil {
 				t.Errorf("Marshal(%v) returned error %v", tc.f, err)
 			} else if !bytes.Equal(b, tc.wantCborData) {
@@ -2137,14 +2213,14 @@ func TestShortestFloatNone(t *testing.T) {
 			}
 			if reflect.ValueOf(tc.f).Kind() == reflect.Float32 {
 				var f32 float32
-				if err = cbor.Unmarshal(b, &f32); err != nil {
+				if err = Unmarshal(b, &f32); err != nil {
 					t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 				} else if f32 != tc.f {
 					t.Errorf("Unmarshal(0x%x) = %f, want %f", b, f32, tc.f)
 				}
 			} else {
 				var f64 float64
-				if err = cbor.Unmarshal(b, &f64); err != nil {
+				if err = Unmarshal(b, &f64); err != nil {
 					t.Errorf("Unmarshal(0x%x) returned error %v", b, err)
 				} else if f64 != tc.f {
 					t.Errorf("Unmarshal(0x%x) = %f, want %f", b, f64, tc.f)
@@ -2155,22 +2231,22 @@ func TestShortestFloatNone(t *testing.T) {
 }
 
 func TestInvalidShortestFloat(t *testing.T) {
-	var i int
 	wantErrorMsg := "cbor: invalid ShortestFloatMode 100"
-	if _, err := cbor.Marshal(i, cbor.EncOptions{ShortestFloat: cbor.ShortestFloatMode(100)}); err == nil {
-		t.Errorf("Marshal() didn't return an error")
+	_, err := EncOptions{ShortestFloat: ShortestFloatMode(100)}.EncMode()
+	if err == nil {
+		t.Errorf("EncMode() didn't return an error")
 	} else if err.Error() != wantErrorMsg {
-		t.Errorf("Marshal() returned error %q, want %q", err.Error(), wantErrorMsg)
+		t.Errorf("EncMode() returned error %q, want %q", err.Error(), wantErrorMsg)
 	}
 }
 
 func TestInfConvert(t *testing.T) {
-	infConvertNoneOpt := cbor.EncOptions{InfConvert: cbor.InfConvertNone}
-	infConvertFloat16Opt := cbor.EncOptions{InfConvert: cbor.InfConvertFloat16}
+	infConvertNoneOpt := EncOptions{InfConvert: InfConvertNone}
+	infConvertFloat16Opt := EncOptions{InfConvert: InfConvertFloat16}
 	testCases := []struct {
 		name         string
 		v            interface{}
-		opts         cbor.EncOptions
+		opts         EncOptions
 		wantCborData []byte
 	}{
 		{"float32 -inf no conversion", float32(math.Inf(-1)), infConvertNoneOpt, hexDecode("faff800000")},
@@ -2184,7 +2260,11 @@ func TestInfConvert(t *testing.T) {
 	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			b, err := cbor.Marshal(tc.v, tc.opts)
+			em, err := tc.opts.EncMode()
+			if err != nil {
+				t.Errorf("EncMode() returned an error %v", err)
+			}
+			b, err := em.Marshal(tc.v)
 			if err != nil {
 				t.Errorf("Marshal(%v) returned error %v", tc.v, err)
 			} else if !bytes.Equal(b, tc.wantCborData) {
@@ -2195,12 +2275,12 @@ func TestInfConvert(t *testing.T) {
 }
 
 func TestInvalidInfConvert(t *testing.T) {
-	var i int
 	wantErrorMsg := "cbor: invalid InfConvertMode 100"
-	if _, err := cbor.Marshal(i, cbor.EncOptions{InfConvert: cbor.InfConvertMode(100)}); err == nil {
-		t.Errorf("Marshal() didn't return an error")
+	_, err := EncOptions{InfConvert: InfConvertMode(100)}.EncMode()
+	if err == nil {
+		t.Errorf("EncMode() didn't return an error")
 	} else if err.Error() != wantErrorMsg {
-		t.Errorf("Marshal() returned error %q, want %q", err.Error(), wantErrorMsg)
+		t.Errorf("EncMode() returned error %q, want %q", err.Error(), wantErrorMsg)
 	}
 }
 
@@ -2260,13 +2340,13 @@ var (
 )
 
 func TestNaNConvert(t *testing.T) {
-	nanConvert7e00Opt := cbor.EncOptions{NaNConvert: cbor.NaNConvert7e00}
-	nanConvertNoneOpt := cbor.EncOptions{NaNConvert: cbor.NaNConvertNone}
-	nanConvertPreserveSignalOpt := cbor.EncOptions{NaNConvert: cbor.NaNConvertPreserveSignal}
-	nanConvertQuietOpt := cbor.EncOptions{NaNConvert: cbor.NaNConvertQuiet}
+	nanConvert7e00Opt := EncOptions{NaNConvert: NaNConvert7e00}
+	nanConvertNoneOpt := EncOptions{NaNConvert: NaNConvertNone}
+	nanConvertPreserveSignalOpt := EncOptions{NaNConvert: NaNConvertPreserveSignal}
+	nanConvertQuietOpt := EncOptions{NaNConvert: NaNConvertQuiet}
 
 	type nanConvert struct {
-		opt          cbor.EncOptions
+		opt          EncOptions
 		wantCborData []byte
 	}
 	testCases := []struct {
@@ -2418,13 +2498,13 @@ func TestNaNConvert(t *testing.T) {
 		for _, convert := range tc.convert {
 			var convertName string
 			switch convert.opt.NaNConvert {
-			case cbor.NaNConvert7e00:
+			case NaNConvert7e00:
 				convertName = "Convert7e00"
-			case cbor.NaNConvertNone:
+			case NaNConvertNone:
 				convertName = "ConvertNone"
-			case cbor.NaNConvertPreserveSignal:
+			case NaNConvertPreserveSignal:
 				convertName = "ConvertPreserveSignal"
-			case cbor.NaNConvertQuiet:
+			case NaNConvertQuiet:
 				convertName = "ConvertQuiet"
 			}
 			var vName string
@@ -2436,7 +2516,11 @@ func TestNaNConvert(t *testing.T) {
 			}
 			name := convertName + "_" + vName
 			t.Run(name, func(t *testing.T) {
-				b, err := cbor.Marshal(tc.v, convert.opt)
+				em, err := convert.opt.EncMode()
+				if err != nil {
+					t.Errorf("EncMode() returned an error %v", err)
+				}
+				b, err := em.Marshal(tc.v)
 				if err != nil {
 					t.Errorf("Marshal(%v) returned error %v", tc.v, err)
 				} else if !bytes.Equal(b, convert.wantCborData) {
@@ -2448,12 +2532,12 @@ func TestNaNConvert(t *testing.T) {
 }
 
 func TestInvalidNaNConvert(t *testing.T) {
-	var i int
 	wantErrorMsg := "cbor: invalid NaNConvertMode 100"
-	if _, err := cbor.Marshal(i, cbor.EncOptions{NaNConvert: cbor.NaNConvertMode(100)}); err == nil {
-		t.Errorf("Marshal() didn't return an error")
+	_, err := EncOptions{NaNConvert: NaNConvertMode(100)}.EncMode()
+	if err == nil {
+		t.Errorf("EncMode() didn't return an error")
 	} else if err.Error() != wantErrorMsg {
-		t.Errorf("Marshal() returned error %q, want %q", err.Error(), wantErrorMsg)
+		t.Errorf("EncMode() returned error %q, want %q", err.Error(), wantErrorMsg)
 	}
 }
 
@@ -2463,25 +2547,27 @@ func TestMarshalSenML(t *testing.T) {
 	cborData := hexDecode("87a721781b75726e3a6465763a6f773a3130653230373361303130383030363a22fb41d303a15b00106223614120050067766f6c7461676501615602fb405e066666666666a3006763757272656e74062402fb3ff3333333333333a3006763757272656e74062302fb3ff4cccccccccccda3006763757272656e74062202fb3ff6666666666666a3006763757272656e74062102f93e00a3006763757272656e74062002fb3ff999999999999aa3006763757272656e74060002fb3ffb333333333333")
 	testCases := []struct {
 		name string
-		opts cbor.EncOptions
+		opts EncOptions
 	}{
-		{"EncOptions ShortestFloatNone", cbor.EncOptions{}},
-		{"EncOptions ShortestFloat16", cbor.EncOptions{ShortestFloat: cbor.ShortestFloat16}},
-		//{"EncOptions ShortestFloat32", cbor.EncOptions{ShortestFloat: cbor.ShortestFloat32}},
-		//{"EncOptions ShortestFloat64", cbor.EncOptions{ShortestFloat: cbor.ShortestFloat64}},
+		{"EncOptions ShortestFloatNone", EncOptions{}},
+		{"EncOptions ShortestFloat16", EncOptions{ShortestFloat: ShortestFloat16}},
 	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			var v []SenMLRecord
-			if err := cbor.Unmarshal(cborData, &v); err != nil {
+			if err := Unmarshal(cborData, &v); err != nil {
 				t.Errorf("Marshal() returned error %v", err)
 			}
-			b, err := cbor.Marshal(v, tc.opts)
+			em, err := tc.opts.EncMode()
+			if err != nil {
+				t.Errorf("EncMode() returned an error %v", err)
+			}
+			b, err := em.Marshal(v)
 			if err != nil {
 				t.Errorf("Unmarshal() returned error %v ", err)
 			}
 			var v2 []SenMLRecord
-			if err := cbor.Unmarshal(b, &v2); err != nil {
+			if err := Unmarshal(b, &v2); err != nil {
 				t.Errorf("Marshal() returned error %v", err)
 			}
 			if !reflect.DeepEqual(v, v2) {
@@ -2491,13 +2577,16 @@ func TestMarshalSenML(t *testing.T) {
 	}
 }
 
-func TestCanonicalEncOptions(t *testing.T) {
-	wantSortMode := cbor.SortCanonical
-	wantShortestFloat := cbor.ShortestFloat16
-	wantNaNConvert := cbor.NaNConvert7e00
-	wantInfConvert := cbor.InfConvertFloat16
-	wantIndefiniteLengthErrorMsg := "cbor: indefinite-length items are not allowed"
-	opts := cbor.CanonicalEncOptions()
+func TestCanonicalEncOptions(t *testing.T) { //nolint:dupl
+	wantSortMode := SortCanonical
+	wantShortestFloat := ShortestFloat16
+	wantNaNConvert := NaNConvert7e00
+	wantInfConvert := InfConvertFloat16
+	em, err := CanonicalEncOptions().EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
+	}
+	opts := em.EncOptions()
 	if opts.Sort != wantSortMode {
 		t.Errorf("CanonicalEncOptions() returned EncOptions with Sort %d, want %d", opts.Sort, wantSortMode)
 	}
@@ -2510,7 +2599,7 @@ func TestCanonicalEncOptions(t *testing.T) {
 	if opts.InfConvert != wantInfConvert {
 		t.Errorf("CanonicalEncOptions() returned EncOptions with InfConvert %d, want %d", opts.InfConvert, wantInfConvert)
 	}
-	enc := cbor.NewEncoder(ioutil.Discard, opts)
+	enc := em.NewEncoder(ioutil.Discard)
 	if err := enc.StartIndefiniteArray(); err == nil {
 		t.Errorf("StartIndefiniteArray() didn't return an error")
 	} else if err.Error() != wantIndefiniteLengthErrorMsg {
@@ -2518,13 +2607,16 @@ func TestCanonicalEncOptions(t *testing.T) {
 	}
 }
 
-func TestCTAP2EncOptions(t *testing.T) {
-	wantSortMode := cbor.SortCTAP2
-	wantShortestFloat := cbor.ShortestFloatNone
-	wantNaNConvert := cbor.NaNConvertNone
-	wantInfConvert := cbor.InfConvertNone
-	wantIndefiniteLengthErrorMsg := "cbor: indefinite-length items are not allowed"
-	opts := cbor.CTAP2EncOptions()
+func TestCTAP2EncOptions(t *testing.T) { //nolint:dupl
+	wantSortMode := SortCTAP2
+	wantShortestFloat := ShortestFloatNone
+	wantNaNConvert := NaNConvertNone
+	wantInfConvert := InfConvertNone
+	em, err := CTAP2EncOptions().EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
+	}
+	opts := em.EncOptions()
 	if opts.Sort != wantSortMode {
 		t.Errorf("CTAP2EncOptions() returned EncOptions with Sort %d, want %d", opts.Sort, wantSortMode)
 	}
@@ -2537,7 +2629,7 @@ func TestCTAP2EncOptions(t *testing.T) {
 	if opts.InfConvert != wantInfConvert {
 		t.Errorf("CTAP2EncOptions() returned EncOptions with InfConvert %d, want %d", opts.InfConvert, wantInfConvert)
 	}
-	enc := cbor.NewEncoder(ioutil.Discard, opts)
+	enc := em.NewEncoder(ioutil.Discard)
 	if err := enc.StartIndefiniteArray(); err == nil {
 		t.Errorf("StartIndefiniteArray() didn't return an error")
 	} else if err.Error() != wantIndefiniteLengthErrorMsg {
@@ -2545,13 +2637,16 @@ func TestCTAP2EncOptions(t *testing.T) {
 	}
 }
 
-func TestCoreDetEncOptions(t *testing.T) {
-	wantSortMode := cbor.SortCoreDeterministic
-	wantShortestFloat := cbor.ShortestFloat16
-	wantNaNConvert := cbor.NaNConvert7e00
-	wantInfConvert := cbor.InfConvertFloat16
-	wantIndefiniteLengthErrorMsg := "cbor: indefinite-length items are not allowed"
-	opts := cbor.CoreDetEncOptions()
+func TestCoreDetEncOptions(t *testing.T) { //nolint:dupl
+	wantSortMode := SortCoreDeterministic
+	wantShortestFloat := ShortestFloat16
+	wantNaNConvert := NaNConvert7e00
+	wantInfConvert := InfConvertFloat16
+	em, err := CoreDetEncOptions().EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
+	}
+	opts := em.EncOptions()
 	if opts.Sort != wantSortMode {
 		t.Errorf("CoreDetEncOptions() returned EncOptions with Sort %d, want %d", opts.Sort, wantSortMode)
 	}
@@ -2564,7 +2659,7 @@ func TestCoreDetEncOptions(t *testing.T) {
 	if opts.InfConvert != wantInfConvert {
 		t.Errorf("CoreDetEncOptions() returned EncOptions with InfConvert %d, want %d", opts.InfConvert, wantInfConvert)
 	}
-	enc := cbor.NewEncoder(ioutil.Discard, opts)
+	enc := em.NewEncoder(ioutil.Discard)
 	if err := enc.StartIndefiniteArray(); err == nil {
 		t.Errorf("StartIndefiniteArray() didn't return an error")
 	} else if err.Error() != wantIndefiniteLengthErrorMsg {
@@ -2573,11 +2668,15 @@ func TestCoreDetEncOptions(t *testing.T) {
 }
 
 func TestPreferredUnsortedEncOptions(t *testing.T) {
-	wantSortMode := cbor.SortNone
-	wantShortestFloat := cbor.ShortestFloat16
-	wantNaNConvert := cbor.NaNConvert7e00
-	wantInfConvert := cbor.InfConvertFloat16
-	opts := cbor.PreferredUnsortedEncOptions()
+	wantSortMode := SortNone
+	wantShortestFloat := ShortestFloat16
+	wantNaNConvert := NaNConvert7e00
+	wantInfConvert := InfConvertFloat16
+	em, err := PreferredUnsortedEncOptions().EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
+	}
+	opts := em.EncOptions()
 	if opts.Sort != wantSortMode {
 		t.Errorf("PreferredUnsortedEncOptions() returned EncOptions with Sort %d, want %d", opts.Sort, wantSortMode)
 	}
@@ -2590,8 +2689,21 @@ func TestPreferredUnsortedEncOptions(t *testing.T) {
 	if opts.InfConvert != wantInfConvert {
 		t.Errorf("PreferredUnsortedEncOptions() returned EncOptions with InfConvert %d, want %d", opts.InfConvert, wantInfConvert)
 	}
-	enc := cbor.NewEncoder(ioutil.Discard, opts)
+	enc := em.NewEncoder(ioutil.Discard)
 	if err := enc.StartIndefiniteArray(); err != nil {
 		t.Errorf("StartIndefiniteArray() returned error %v", err)
 	}
 }
+
+func TestEncOptions(t *testing.T) {
+	opts1 := EncOptions{}
+	em, err := opts1.EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
+	} else {
+		opts2 := em.EncOptions()
+		if !reflect.DeepEqual(opts1, opts2) {
+			t.Errorf("EncOptions->EncMode->EncOptions returned different values: %v, %v", opts1, opts2)
+		}
+	}
+}
diff --git a/example_test.go b/example_test.go
index ea7c023..7dec9b0 100644
--- a/example_test.go
+++ b/example_test.go
@@ -10,7 +10,7 @@ import (
 	"io"
 	"time"
 
-	"github.com/fxamacker/cbor"
+	"github.com/fxamacker/cbor/v2"
 )
 
 func ExampleMarshal() {
@@ -21,7 +21,7 @@ func ExampleMarshal() {
 		Male   bool
 	}
 	animal := Animal{Age: 4, Name: "Candy", Owners: []string{"Mary", "Joe"}}
-	b, err := cbor.Marshal(animal, cbor.EncOptions{})
+	b, err := cbor.Marshal(animal)
 	if err != nil {
 		fmt.Println("error:", err)
 	}
@@ -31,15 +31,25 @@ func ExampleMarshal() {
 }
 
 func ExampleMarshal_time() {
-	tm, _ := time.Parse(time.RFC3339Nano, "2013-03-21T20:04:00Z")
-	// Encode time as string in RFC3339 format.
-	b, err := cbor.Marshal(tm, cbor.EncOptions{TimeRFC3339: true})
+	tm, _ := time.Parse(time.RFC3339, "2013-03-21T20:04:00Z")
+
+	// Encode time as string in RFC3339 format with second precision.
+	em, err := cbor.EncOptions{Time: cbor.TimeRFC3339}.EncMode()
+	if err != nil {
+		fmt.Println("error:", err)
+	}
+	b, err := em.Marshal(tm)
 	if err != nil {
 		fmt.Println("error:", err)
 	}
 	fmt.Printf("%x\n", b)
+
 	// Encode time as numerical representation of seconds since January 1, 1970 UTC.
-	b, err = cbor.Marshal(tm, cbor.EncOptions{TimeRFC3339: false})
+	em, err = cbor.EncOptions{Time: cbor.TimeUnix}.EncMode()
+	if err != nil {
+		fmt.Println("error:", err)
+	}
+	b, err = em.Marshal(tm)
 	if err != nil {
 		fmt.Println("error:", err)
 	}
@@ -58,7 +68,11 @@ func ExampleMarshal_canonical() {
 		Male     bool
 	}
 	animal := Animal{Age: 4, Name: "Candy", Contacts: map[string]string{"Mary": "111-111-1111", "Joe": "222-222-2222"}}
-	b, err := cbor.Marshal(animal, cbor.CanonicalEncOptions())
+	em, err := cbor.CanonicalEncOptions().EncMode()
+	if err != nil {
+		fmt.Println("error:", err)
+	}
+	b, err := em.Marshal(animal)
 	if err != nil {
 		fmt.Println("error:", err)
 	}
@@ -76,7 +90,7 @@ func ExampleMarshal_toarray() {
 		Measurement int
 	}
 	rec := Record{Name: "current", Unit: "V", Measurement: 1}
-	b, err := cbor.Marshal(rec, cbor.EncOptions{})
+	b, err := cbor.Marshal(rec)
 	if err != nil {
 		fmt.Println("error:", err)
 	}
@@ -94,7 +108,7 @@ func ExampleMarshal_keyasint() {
 		Measurement int    `cbor:"3,keyasint"`
 	}
 	rec := Record{Name: "current", Unit: "V", Measurement: 1}
-	b, err := cbor.Marshal(rec, cbor.EncOptions{})
+	b, err := cbor.Marshal(rec)
 	if err != nil {
 		fmt.Println("error:", err)
 	}
@@ -152,7 +166,11 @@ func ExampleEncoder() {
 		{Age: 2, Name: "Duke", Owners: []string{"Norton"}, Male: true},
 	}
 	var buf bytes.Buffer
-	enc := cbor.NewEncoder(&buf, cbor.CanonicalEncOptions())
+	em, err := cbor.CanonicalEncOptions().EncMode()
+	if err != nil {
+		fmt.Println("error:", err)
+	}
+	enc := em.NewEncoder(&buf)
 	for _, animal := range animals {
 		err := enc.Encode(animal)
 		if err != nil {
@@ -168,7 +186,7 @@ func ExampleEncoder() {
 // length byte string ("chunks") as an indefinite length byte string.
 func ExampleEncoder_indefiniteLengthByteString() {
 	var buf bytes.Buffer
-	encoder := cbor.NewEncoder(&buf, cbor.EncOptions{})
+	encoder := cbor.NewEncoder(&buf)
 	// Start indefinite length byte string encoding.
 	if err := encoder.StartIndefiniteByteString(); err != nil {
 		fmt.Println("error:", err)
@@ -194,7 +212,7 @@ func ExampleEncoder_indefiniteLengthByteString() {
 // length text string ("chunks") as an indefinite length text string.
 func ExampleEncoder_indefiniteLengthTextString() {
 	var buf bytes.Buffer
-	encoder := cbor.NewEncoder(&buf, cbor.EncOptions{})
+	encoder := cbor.NewEncoder(&buf)
 	// Start indefinite length text string encoding.
 	if err := encoder.StartIndefiniteTextString(); err != nil {
 		fmt.Println("error:", err)
@@ -220,7 +238,7 @@ func ExampleEncoder_indefiniteLengthTextString() {
 // indefinite length array.  Encoder supports nested indefinite length values.
 func ExampleEncoder_indefiniteLengthArray() {
 	var buf bytes.Buffer
-	enc := cbor.NewEncoder(&buf, cbor.EncOptions{})
+	enc := cbor.NewEncoder(&buf)
 	// Start indefinite length array encoding.
 	if err := enc.StartIndefiniteArray(); err != nil {
 		fmt.Println("error:", err)
@@ -262,7 +280,11 @@ func ExampleEncoder_indefiniteLengthArray() {
 // indefinite length map.  Encoder supports nested indefinite length values.
 func ExampleEncoder_indefiniteLengthMap() {
 	var buf bytes.Buffer
-	enc := cbor.NewEncoder(&buf, cbor.EncOptions{Sort: cbor.SortCanonical})
+	em, err := cbor.EncOptions{Sort: cbor.SortCanonical}.EncMode()
+	if err != nil {
+		fmt.Println("error:", err)
+	}
+	enc := em.NewEncoder(&buf)
 	// Start indefinite length map encoding.
 	if err := enc.StartIndefiniteMap(); err != nil {
 		fmt.Println("error:", err)
@@ -346,7 +368,7 @@ func Example_cWT() {
 	if err := cbor.Unmarshal(cborData, &v); err != nil {
 		fmt.Println("error:", err)
 	}
-	if _, err := cbor.Marshal(v, cbor.EncOptions{}); err != nil {
+	if _, err := cbor.Marshal(v); err != nil {
 		fmt.Println("error:", err)
 	}
 	fmt.Printf("%+v", v)
@@ -376,7 +398,7 @@ func Example_signedCWT() {
 	if err := cbor.Unmarshal(cborData, &v); err != nil {
 		fmt.Println("error:", err)
 	}
-	if _, err := cbor.Marshal(v, cbor.EncOptions{}); err != nil {
+	if _, err := cbor.Marshal(v); err != nil {
 		fmt.Println("error:", err)
 	}
 	fmt.Printf("%+v", v)
@@ -405,7 +427,7 @@ func Example_cOSE() {
 	if err := cbor.Unmarshal(cborData, &v); err != nil {
 		fmt.Println("error:", err)
 	}
-	if _, err := cbor.Marshal(v, cbor.EncOptions{}); err != nil {
+	if _, err := cbor.Marshal(v); err != nil {
 		fmt.Println("error:", err)
 	}
 	fmt.Printf("%+v", v)
@@ -434,16 +456,20 @@ func Example_senML() {
 	}
 	// Data from https://tools.ietf.org/html/rfc8428#section-6
 	cborData, _ := hex.DecodeString("87a721781b75726e3a6465763a6f773a3130653230373361303130383030363a22fb41d303a15b00106223614120050067766f6c7461676501615602fb405e066666666666a3006763757272656e74062402fb3ff3333333333333a3006763757272656e74062302fb3ff4cccccccccccda3006763757272656e74062202fb3ff6666666666666a3006763757272656e74062102f93e00a3006763757272656e74062002fb3ff999999999999aa3006763757272656e74060002fb3ffb333333333333")
-	var v []SenMLRecord
+	var v []*SenMLRecord
 	if err := cbor.Unmarshal(cborData, &v); err != nil {
 		fmt.Println("error:", err)
 	}
 	// Encoder uses ShortestFloat16 option to use float16 as the shortest form that preserves floating-point value.
-	if _, err := cbor.Marshal(v, cbor.EncOptions{ShortestFloat: cbor.ShortestFloat16}); err != nil {
+	em, err := cbor.EncOptions{ShortestFloat: cbor.ShortestFloat16}.EncMode()
+	if err != nil {
+		fmt.Println("error:", err)
+	}
+	if _, err := em.Marshal(v); err != nil {
 		fmt.Println("error:", err)
 	}
 	for _, rec := range v {
-		fmt.Printf("%+v\n", rec)
+		fmt.Printf("%+v\n", *rec)
 	}
 	// Output:
 	// {BaseName:urn:dev:ow:10e2073a0108006: BaseTime:1.276020076001e+09 BaseUnit:A BaseValue:0 BaseSum:0 BaseVersion:5 Name:voltage Unit:V Time:0 UpdateTime:0 Value:120.1 ValueS: ValueB:false ValueD: Sum:0}
@@ -467,7 +493,7 @@ func Example_webAuthn() {
 	if err := cbor.Unmarshal(cborData, &v); err != nil {
 		fmt.Println("error:", err)
 	}
-	if _, err := cbor.Marshal(v, cbor.EncOptions{}); err != nil {
+	if _, err := cbor.Marshal(v); err != nil {
 		fmt.Println("error:", err)
 	}
 	fmt.Printf("%+v", v)
diff --git a/maxdepth_test.go b/maxdepth_test.go
index dba0502..9c7d7f3 100644
--- a/maxdepth_test.go
+++ b/maxdepth_test.go
@@ -4,7 +4,6 @@
 package cbor
 
 import (
-	"encoding/hex"
 	"testing"
 )
 
@@ -48,7 +47,7 @@ func TestDepth(t *testing.T) {
 	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			_, depth, err := valid(tc.cborData, 0, 1)
+			_, depth, err := validInternal(tc.cborData, 0, 1)
 			if err != nil {
 				t.Errorf("valid(0x%x) returned error %v", tc.cborData, err)
 			}
@@ -73,7 +72,7 @@ func TestDepthError(t *testing.T) {
 	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			_, _, err := valid(tc.cborData, 0, 1)
+			_, _, err := validInternal(tc.cborData, 0, 1)
 			if err == nil {
 				t.Errorf("valid(0x%x) didn't return an error, want %q", tc.cborData, tc.wantErrorMsg)
 			} else if err.Error() != tc.wantErrorMsg {
@@ -82,11 +81,3 @@ func TestDepthError(t *testing.T) {
 		})
 	}
 }
-
-func hexDecode(s string) []byte {
-	data, err := hex.DecodeString(s)
-	if err != nil {
-		panic(err)
-	}
-	return data
-}
diff --git a/stream_test.go b/stream_test.go
index 13ebd4a..4a20c84 100644
--- a/stream_test.go
+++ b/stream_test.go
@@ -1,15 +1,13 @@
 // Copyright (c) Faye Amacker. All rights reserved.
 // Licensed under the MIT License. See LICENSE in the project root for license information.
 
-package cbor_test
+package cbor
 
 import (
 	"bytes"
 	"io"
 	"reflect"
 	"testing"
-
-	"github.com/fxamacker/cbor"
 )
 
 func TestDecoder(t *testing.T) {
@@ -19,7 +17,7 @@ func TestDecoder(t *testing.T) {
 			buf.Write(tc.cborData)
 		}
 	}
-	decoder := cbor.NewDecoder(&buf)
+	decoder := NewDecoder(&buf)
 	bytesRead := 0
 	for i := 0; i < 5; i++ {
 		for _, tc := range unmarshalTests {
@@ -56,7 +54,7 @@ func TestDecoderUnmarshalTypeError(t *testing.T) {
 			}
 		}
 	}
-	decoder := cbor.NewDecoder(&buf)
+	decoder := NewDecoder(&buf)
 	bytesRead := 0
 	for i := 0; i < 5; i++ {
 		for _, tc := range unmarshalTests {
@@ -64,7 +62,7 @@ func TestDecoderUnmarshalTypeError(t *testing.T) {
 				v := reflect.New(typ)
 				if err := decoder.Decode(v.Interface()); err == nil {
 					t.Errorf("Decode(0x%x) didn't return an error, want UnmarshalTypeError", tc.cborData)
-				} else if _, ok := err.(*cbor.UnmarshalTypeError); !ok {
+				} else if _, ok := err.(*UnmarshalTypeError); !ok {
 					t.Errorf("Decode(0x%x) returned wrong error type %T, want UnmarshalTypeError", tc.cborData, err)
 				}
 				bytesRead += len(tc.cborData)
@@ -111,7 +109,7 @@ func TestDecoderStructTag(t *testing.T) {
 	cborData := hexDecode("a36161614161626142617a6143") // {"a":"A", "b":"B", "z":"C"}
 
 	var v strc
-	dec := cbor.NewDecoder(bytes.NewReader(cborData))
+	dec := NewDecoder(bytes.NewReader(cborData))
 	if err := dec.Decode(&v); err != nil {
 		t.Errorf("Decode() returned error %v", err)
 	}
@@ -123,7 +121,11 @@ func TestDecoderStructTag(t *testing.T) {
 func TestEncoder(t *testing.T) {
 	var want bytes.Buffer
 	var w bytes.Buffer
-	encoder := cbor.NewEncoder(&w, cbor.EncOptions{Sort: cbor.SortCanonical})
+	em, err := CanonicalEncOptions().EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
+	}
+	encoder := em.NewEncoder(&w)
 	for _, tc := range marshalTests {
 		for _, value := range tc.values {
 			want.Write(tc.cborData)
@@ -144,19 +146,19 @@ func TestEncoderError(t *testing.T) {
 		value        interface{}
 		wantErrorMsg string
 	}{
-		{"channel can't be marshalled", make(chan bool), "cbor: unsupported type: chan bool"},
-		{"function can't be marshalled", func(i int) int { return i * i }, "cbor: unsupported type: func(int) int"},
-		{"complex can't be marshalled", complex(100, 8), "cbor: unsupported type: complex128"},
+		{"channel can't be marshaled", make(chan bool), "cbor: unsupported type: chan bool"},
+		{"function can't be marshaled", func(i int) int { return i * i }, "cbor: unsupported type: func(int) int"},
+		{"complex can't be marshaled", complex(100, 8), "cbor: unsupported type: complex128"},
 	}
 	var w bytes.Buffer
-	encoder := cbor.NewEncoder(&w, cbor.EncOptions{})
+	encoder := NewEncoder(&w)
 	for _, tc := range testcases {
 		t.Run(tc.name, func(t *testing.T) {
 			err := encoder.Encode(&tc.value)
 			if err == nil {
 				t.Errorf("Encode(%v) didn't return an error, want error %q", tc.value, tc.wantErrorMsg)
-			} else if _, ok := err.(*cbor.UnsupportedTypeError); !ok {
-				t.Errorf("Encode(%v) error type %T, want *cbor.UnsupportedTypeError", tc.value, err)
+			} else if _, ok := err.(*UnsupportedTypeError); !ok {
+				t.Errorf("Encode(%v) error type %T, want *UnsupportedTypeError", tc.value, err)
 			} else if err.Error() != tc.wantErrorMsg {
 				t.Errorf("Encode(%v) error %q, want %q", tc.value, err.Error(), tc.wantErrorMsg)
 			}
@@ -170,7 +172,7 @@ func TestEncoderError(t *testing.T) {
 func TestIndefiniteByteString(t *testing.T) {
 	want := hexDecode("5f42010243030405ff")
 	var w bytes.Buffer
-	encoder := cbor.NewEncoder(&w, cbor.EncOptions{})
+	encoder := NewEncoder(&w)
 	if err := encoder.StartIndefiniteByteString(); err != nil {
 		t.Fatalf("StartIndefiniteByteString() returned error %v", err)
 	}
@@ -190,7 +192,7 @@ func TestIndefiniteByteString(t *testing.T) {
 
 func TestIndefiniteByteStringError(t *testing.T) {
 	var w bytes.Buffer
-	encoder := cbor.NewEncoder(&w, cbor.EncOptions{})
+	encoder := NewEncoder(&w)
 	if err := encoder.StartIndefiniteByteString(); err != nil {
 		t.Fatalf("StartIndefiniteByteString() returned error %v", err)
 	}
@@ -209,7 +211,7 @@ func TestIndefiniteByteStringError(t *testing.T) {
 func TestIndefiniteTextString(t *testing.T) {
 	want := hexDecode("7f657374726561646d696e67ff")
 	var w bytes.Buffer
-	encoder := cbor.NewEncoder(&w, cbor.EncOptions{})
+	encoder := NewEncoder(&w)
 	if err := encoder.StartIndefiniteTextString(); err != nil {
 		t.Fatalf("StartIndefiniteTextString() returned error %v", err)
 	}
@@ -229,7 +231,7 @@ func TestIndefiniteTextString(t *testing.T) {
 
 func TestIndefiniteTextStringError(t *testing.T) {
 	var w bytes.Buffer
-	encoder := cbor.NewEncoder(&w, cbor.EncOptions{})
+	encoder := NewEncoder(&w)
 	if err := encoder.StartIndefiniteTextString(); err != nil {
 		t.Fatalf("StartIndefiniteTextString() returned error %v", err)
 	}
@@ -243,7 +245,7 @@ func TestIndefiniteTextStringError(t *testing.T) {
 func TestIndefiniteArray(t *testing.T) {
 	want := hexDecode("9f018202039f0405ffff")
 	var w bytes.Buffer
-	encoder := cbor.NewEncoder(&w, cbor.EncOptions{})
+	encoder := NewEncoder(&w)
 	if err := encoder.StartIndefiniteArray(); err != nil {
 		t.Fatalf("StartIndefiniteArray() returned error %v", err)
 	}
@@ -276,7 +278,11 @@ func TestIndefiniteArray(t *testing.T) {
 func TestIndefiniteMap(t *testing.T) {
 	want := hexDecode("bf61610161629f0203ffff")
 	var w bytes.Buffer
-	encoder := cbor.NewEncoder(&w, cbor.EncOptions{Sort: cbor.SortCanonical})
+	em, err := EncOptions{Sort: SortCanonical}.EncMode()
+	if err != nil {
+		t.Errorf("EncMode() returned an error %v", err)
+	}
+	encoder := em.NewEncoder(&w)
 	if err := encoder.StartIndefiniteMap(); err != nil {
 		t.Fatalf("StartIndefiniteMap() returned error %v", err)
 	}
@@ -311,7 +317,7 @@ func TestIndefiniteMap(t *testing.T) {
 
 func TestIndefiniteLengthError(t *testing.T) {
 	var w bytes.Buffer
-	encoder := cbor.NewEncoder(&w, cbor.EncOptions{})
+	encoder := NewEncoder(&w)
 	if err := encoder.StartIndefiniteByteString(); err != nil {
 		t.Fatalf("StartIndefiniteByteString() returned error %v", err)
 	}
@@ -337,7 +343,7 @@ func TestEncoderStructTag(t *testing.T) {
 	want := hexDecode("a36161614161626142617a6143") // {"a":"A", "b":"B", "z":"C"}
 
 	var w bytes.Buffer
-	encoder := cbor.NewEncoder(&w, cbor.EncOptions{Sort: cbor.SortCanonical})
+	encoder := NewEncoder(&w)
 	if err := encoder.Encode(v); err != nil {
 		t.Errorf("Encode(%+v) returned error %v", v, err)
 	}
@@ -348,24 +354,24 @@ func TestEncoderStructTag(t *testing.T) {
 
 func TestRawMessage(t *testing.T) {
 	type strc struct {
-		A cbor.RawMessage  `cbor:"a"`
-		B *cbor.RawMessage `cbor:"b"`
-		C *cbor.RawMessage `cbor:"c"`
+		A RawMessage  `cbor:"a"`
+		B *RawMessage `cbor:"b"`
+		C *RawMessage `cbor:"c"`
 	}
 	cborData := hexDecode("a361610161628202036163f6") // {"a": 1, "b": [2, 3], "c": nil},
-	r := cbor.RawMessage(hexDecode("820203"))
+	r := RawMessage(hexDecode("820203"))
 	want := strc{
-		A: cbor.RawMessage([]byte{0x01}),
+		A: RawMessage([]byte{0x01}),
 		B: &r,
 	}
 	var v strc
-	if err := cbor.Unmarshal(cborData, &v); err != nil {
+	if err := Unmarshal(cborData, &v); err != nil {
 		t.Fatalf("Unmarshal(0x%x) returned error %v", cborData, err)
 	}
 	if !reflect.DeepEqual(v, want) {
 		t.Errorf("Unmarshal(0x%x) returned v %v, want %v", cborData, v, want)
 	}
-	b, err := cbor.Marshal(v, cbor.EncOptions{Sort: cbor.SortCanonical})
+	b, err := Marshal(v)
 	if err != nil {
 		t.Fatalf("Marshal(%+v) returned error %v", v, err)
 	}
@@ -375,9 +381,9 @@ func TestRawMessage(t *testing.T) {
 }
 
 func TestNullRawMessage(t *testing.T) {
-	r := cbor.RawMessage(nil)
+	r := RawMessage(nil)
 	wantCborData := []byte{0xf6}
-	b, err := cbor.Marshal(r, cbor.EncOptions{})
+	b, err := Marshal(r)
 	if err != nil {
 		t.Errorf("Marshal(%+v) returned error %v", r, err)
 	}
@@ -387,9 +393,9 @@ func TestNullRawMessage(t *testing.T) {
 }
 
 func TestEmptyRawMessage(t *testing.T) {
-	var r cbor.RawMessage
+	var r RawMessage
 	wantCborData := []byte{0xf6}
-	b, err := cbor.Marshal(r, cbor.EncOptions{})
+	b, err := Marshal(r)
 	if err != nil {
 		t.Errorf("Marshal(%+v) returned error %v", r, err)
 	}