diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-02-05 00:37:32 +0100 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-02-05 00:37:32 +0100 |
| commit | 6960aecc25400320adee1b8802a86839326e15b6 (patch) | |
| tree | 334f7ca9491080a5e6f9a9747da77281c4958ba2 /vendor/github.com/neilotoole/jsoncolor | |
| download | hepi-6960aecc25400320adee1b8802a86839326e15b6.tar.gz | |
Engage!
Diffstat (limited to 'vendor/github.com/neilotoole/jsoncolor')
19 files changed, 6029 insertions, 0 deletions
diff --git a/vendor/github.com/neilotoole/jsoncolor/.gitignore b/vendor/github.com/neilotoole/jsoncolor/.gitignore new file mode 100644 index 0000000..97fe1d6 --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/.gitignore | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | # Binaries for programs and plugins | ||
| 2 | *.exe | ||
| 3 | *.exe~ | ||
| 4 | *.dll | ||
| 5 | *.so | ||
| 6 | *.dylib | ||
| 7 | |||
| 8 | # Test binary, built with `go test -c` | ||
| 9 | *.test | ||
| 10 | |||
| 11 | # Output of the go coverage tool, specifically when used with LiteIDE | ||
| 12 | *.out | ||
| 13 | |||
| 14 | # Dependency directories (remove the comment below to include it) | ||
| 15 | # vendor/ | ||
| 16 | |||
| 17 | *.iml | ||
| 18 | .idea | ||
| 19 | TODO.md | ||
| 20 | **/.DS_Store | ||
| 21 | /scratch/ | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/.golangci.yml b/vendor/github.com/neilotoole/jsoncolor/.golangci.yml new file mode 100644 index 0000000..a53fb78 --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/.golangci.yml | |||
| @@ -0,0 +1,334 @@ | |||
| 1 | # This code is licensed under the terms of the MIT license. | ||
| 2 | |||
| 3 | ## Golden config for golangci-lint v1.54 | ||
| 4 | # | ||
| 5 | # This is the best config for golangci-lint based on my experience and opinion. | ||
| 6 | # It is very strict, but not extremely strict. | ||
| 7 | # Feel free to adopt and change it for your needs. | ||
| 8 | # | ||
| 9 | # @neilotoole: ^^ Well, it's less strict now! | ||
| 10 | # Based on: https://gist.github.com/maratori/47a4d00457a92aa426dbd48a18776322 | ||
| 11 | |||
| 12 | run: | ||
| 13 | # Timeout for analysis, e.g. 30s, 5m. | ||
| 14 | # Default: 1m | ||
| 15 | timeout: 5m | ||
| 16 | |||
| 17 | tests: false | ||
| 18 | |||
| 19 | skip-dirs: | ||
| 20 | - scratch | ||
| 21 | |||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | |||
| 26 | output: | ||
| 27 | sort-results: true | ||
| 28 | |||
| 29 | # This file contains only configs which differ from defaults. | ||
| 30 | # All possible options can be found here https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml | ||
| 31 | linters-settings: | ||
| 32 | cyclop: | ||
| 33 | # The maximal code complexity to report. | ||
| 34 | # Default: 10 | ||
| 35 | max-complexity: 50 | ||
| 36 | # The maximal average package complexity. | ||
| 37 | # If it's higher than 0.0 (float) the check is enabled | ||
| 38 | # Default: 0.0 | ||
| 39 | package-average: 10.0 | ||
| 40 | |||
| 41 | errcheck: | ||
| 42 | # Report about not checking of errors in type assertions: `a := b.(MyStruct)`. | ||
| 43 | # Such cases aren't reported by default. | ||
| 44 | # Default: false | ||
| 45 | check-type-assertions: true | ||
| 46 | |||
| 47 | exhaustive: | ||
| 48 | # Program elements to check for exhaustiveness. | ||
| 49 | # Default: [ switch ] | ||
| 50 | check: | ||
| 51 | - switch | ||
| 52 | - map | ||
| 53 | |||
| 54 | funlen: | ||
| 55 | # Checks the number of lines in a function. | ||
| 56 | # If lower than 0, disable the check. | ||
| 57 | # Default: 60 | ||
| 58 | lines: 150 | ||
| 59 | # Checks the number of statements in a function. | ||
| 60 | # If lower than 0, disable the check. | ||
| 61 | # Default: 40 | ||
| 62 | statements: 100 | ||
| 63 | |||
| 64 | gocognit: | ||
| 65 | # Minimal code complexity to report | ||
| 66 | # Default: 30 (but we recommend 10-20) | ||
| 67 | min-complexity: 50 | ||
| 68 | |||
| 69 | gocritic: | ||
| 70 | # Settings passed to gocritic. | ||
| 71 | # The settings key is the name of a supported gocritic checker. | ||
| 72 | # The list of supported checkers can be find in https://go-critic.github.io/overview. | ||
| 73 | settings: | ||
| 74 | captLocal: | ||
| 75 | # Whether to restrict checker to params only. | ||
| 76 | # Default: true | ||
| 77 | paramsOnly: false | ||
| 78 | underef: | ||
| 79 | # Whether to skip (*x).method() calls where x is a pointer receiver. | ||
| 80 | # Default: true | ||
| 81 | skipRecvDeref: false | ||
| 82 | |||
| 83 | gocyclo: | ||
| 84 | # Minimal code complexity to report. | ||
| 85 | # Default: 30 (but we recommend 10-20) | ||
| 86 | min-complexity: 50 | ||
| 87 | |||
| 88 | gofumpt: | ||
| 89 | # Module path which contains the source code being formatted. | ||
| 90 | # Default: "" | ||
| 91 | module-path: github.com/neilotoole/jsoncolor | ||
| 92 | # Choose whether to use the extra rules. | ||
| 93 | # Default: false | ||
| 94 | extra-rules: true | ||
| 95 | |||
| 96 | gomnd: | ||
| 97 | # List of function patterns to exclude from analysis. | ||
| 98 | # Values always ignored: `time.Date`, | ||
| 99 | # `strconv.FormatInt`, `strconv.FormatUint`, `strconv.FormatFloat`, | ||
| 100 | # `strconv.ParseInt`, `strconv.ParseUint`, `strconv.ParseFloat`. | ||
| 101 | # Default: [] | ||
| 102 | ignored-functions: | ||
| 103 | - make | ||
| 104 | - os.Chmod | ||
| 105 | - os.Mkdir | ||
| 106 | - os.MkdirAll | ||
| 107 | - os.OpenFile | ||
| 108 | - os.WriteFile | ||
| 109 | - prometheus.ExponentialBuckets | ||
| 110 | - prometheus.ExponentialBucketsRange | ||
| 111 | - prometheus.LinearBuckets | ||
| 112 | ignored-numbers: | ||
| 113 | - "2" | ||
| 114 | - "3" | ||
| 115 | |||
| 116 | gomodguard: | ||
| 117 | blocked: | ||
| 118 | # List of blocked modules. | ||
| 119 | # Default: [] | ||
| 120 | modules: | ||
| 121 | - github.com/golang/protobuf: | ||
| 122 | recommendations: | ||
| 123 | - google.golang.org/protobuf | ||
| 124 | reason: "see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules" | ||
| 125 | - github.com/satori/go.uuid: | ||
| 126 | recommendations: | ||
| 127 | - github.com/google/uuid | ||
| 128 | reason: "satori's package is not maintained" | ||
| 129 | - github.com/gofrs/uuid: | ||
| 130 | recommendations: | ||
| 131 | - github.com/google/uuid | ||
| 132 | reason: "gofrs' package is not go module" | ||
| 133 | |||
| 134 | govet: | ||
| 135 | # Enable all analyzers. | ||
| 136 | # Default: false | ||
| 137 | enable-all: true | ||
| 138 | # Disable analyzers by name. | ||
| 139 | # Run `go tool vet help` to see all analyzers. | ||
| 140 | # Default: [] | ||
| 141 | disable: | ||
| 142 | - fieldalignment # too strict | ||
| 143 | # Settings per analyzer. | ||
| 144 | settings: | ||
| 145 | shadow: | ||
| 146 | # Whether to be strict about shadowing; can be noisy. | ||
| 147 | # Default: false | ||
| 148 | strict: false | ||
| 149 | |||
| 150 | lll: | ||
| 151 | # Max line length, lines longer will be reported. | ||
| 152 | # '\t' is counted as 1 character by default, and can be changed with the tab-width option. | ||
| 153 | # Default: 120. | ||
| 154 | line-length: 120 | ||
| 155 | # Tab width in spaces. | ||
| 156 | # Default: 1 | ||
| 157 | tab-width: 1 | ||
| 158 | |||
| 159 | nakedret: | ||
| 160 | # Make an issue if func has more lines of code than this setting, and it has naked returns. | ||
| 161 | # Default: 30 | ||
| 162 | max-func-lines: 0 | ||
| 163 | |||
| 164 | nestif: | ||
| 165 | # Minimal complexity of if statements to report. | ||
| 166 | # Default: 5 | ||
| 167 | min-complexity: 20 | ||
| 168 | |||
| 169 | nolintlint: | ||
| 170 | # Exclude following linters from requiring an explanation. | ||
| 171 | # Default: [] | ||
| 172 | allow-no-explanation: [ funlen, gocognit, lll ] | ||
| 173 | # Enable to require an explanation of nonzero length after each nolint directive. | ||
| 174 | # Default: false | ||
| 175 | require-explanation: false | ||
| 176 | # Enable to require nolint directives to mention the specific linter being suppressed. | ||
| 177 | # Default: false | ||
| 178 | require-specific: true | ||
| 179 | |||
| 180 | rowserrcheck: | ||
| 181 | # database/sql is always checked | ||
| 182 | # Default: [] | ||
| 183 | packages: | ||
| 184 | # - github.com/jmoiron/sqlx | ||
| 185 | |||
| 186 | tenv: | ||
| 187 | # The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures. | ||
| 188 | # Otherwise, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked. | ||
| 189 | # Default: false | ||
| 190 | all: true | ||
| 191 | |||
| 192 | |||
| 193 | linters: | ||
| 194 | disable-all: true | ||
| 195 | |||
| 196 | enable: | ||
| 197 | ## enabled by default | ||
| 198 | - errcheck # checking for unchecked errors, these unchecked errors can be critical bugs in some cases | ||
| 199 | - gosimple # specializes in simplifying a code | ||
| 200 | - govet # reports suspicious constructs, such as Printf calls whose arguments do not align with the format string | ||
| 201 | - ineffassign # detects when assignments to existing variables are not used | ||
| 202 | - staticcheck # is a go vet on steroids, applying a ton of static analysis checks | ||
| 203 | - typecheck # like the front-end of a Go compiler, parses and type-checks Go code | ||
| 204 | - unused # checks for unused constants, variables, functions and types | ||
| 205 | |||
| 206 | |||
| 207 | # ## disabled by default | ||
| 208 | - asasalint # checks for pass []any as any in variadic func(...any) | ||
| 209 | - asciicheck # checks that your code does not contain non-ASCII identifiers | ||
| 210 | - bidichk # checks for dangerous unicode character sequences | ||
| 211 | - bodyclose # checks whether HTTP response body is closed successfully | ||
| 212 | - cyclop # checks function and package cyclomatic complexity | ||
| 213 | - dupl # tool for code clone detection | ||
| 214 | - durationcheck # checks for two durations multiplied together | ||
| 215 | - errname # checks that sentinel errors are prefixed with the Err and error types are suffixed with the Error | ||
| 216 | - errorlint # finds code that will cause problems with the error wrapping scheme introduced in Go 1.13 | ||
| 217 | - execinquery # checks query string in Query function which reads your Go src files and warning it finds | ||
| 218 | - exhaustive # checks exhaustiveness of enum switch statements | ||
| 219 | - exportloopref # checks for pointers to enclosing loop variables | ||
| 220 | - forbidigo # forbids identifiers | ||
| 221 | - funlen # tool for detection of long functions | ||
| 222 | - gochecknoinits # checks that no init functions are present in Go code | ||
| 223 | - gocognit # computes and checks the cognitive complexity of functions | ||
| 224 | - goconst # finds repeated strings that could be replaced by a constant | ||
| 225 | - gocritic # provides diagnostics that check for bugs, performance and style issues | ||
| 226 | - gocyclo # computes and checks the cyclomatic complexity of functions | ||
| 227 | - godot # checks if comments end in a period | ||
| 228 | - gofumpt | ||
| 229 | - goimports # in addition to fixing imports, goimports also formats your code in the same style as gofmt | ||
| 230 | # - gomoddirectives # manages the use of 'replace', 'retract', and 'excludes' directives in go.mod | ||
| 231 | - gomodguard # allow and block lists linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations | ||
| 232 | - goprintffuncname # checks that printf-like functions are named with f at the end | ||
| 233 | - gosec # inspects source code for security problems | ||
| 234 | - lll # reports long lines | ||
| 235 | - loggercheck # checks key value pairs for common logger libraries (kitlog,klog,logr,zap) | ||
| 236 | - makezero # finds slice declarations with non-zero initial length | ||
| 237 | - nakedret # finds naked returns in functions greater than a specified function length | ||
| 238 | - nestif # reports deeply nested if statements | ||
| 239 | - nilerr # finds the code that returns nil even if it checks that the error is not nil | ||
| 240 | - nilnil # checks that there is no simultaneous return of nil error and an invalid value | ||
| 241 | - noctx # finds sending http request without context.Context | ||
| 242 | - nolintlint # reports ill-formed or insufficient nolint directives | ||
| 243 | - nosprintfhostport # checks for misuse of Sprintf to construct a host with port in a URL | ||
| 244 | - predeclared # finds code that shadows one of Go's predeclared identifiers | ||
| 245 | - promlinter # checks Prometheus metrics naming via promlint | ||
| 246 | - reassign # checks that package variables are not reassigned | ||
| 247 | - revive # fast, configurable, extensible, flexible, and beautiful linter for Go, drop-in replacement of golint | ||
| 248 | - stylecheck # is a replacement for golint | ||
| 249 | - tenv # detects using os.Setenv instead of t.Setenv since Go1.17 | ||
| 250 | - testableexamples # checks if examples are testable (have an expected output) | ||
| 251 | - tparallel # detects inappropriate usage of t.Parallel() method in your Go test codes | ||
| 252 | - unconvert # removes unnecessary type conversions | ||
| 253 | - unparam # reports unused function parameters | ||
| 254 | - usestdlibvars # detects the possibility to use variables/constants from the Go standard library | ||
| 255 | - whitespace # detects leading and trailing whitespace | ||
| 256 | |||
| 257 | ## These three linters are disabled for now due to generics: https://github.com/golangci/golangci-lint/issues/2649 | ||
| 258 | #- rowserrcheck # checks whether Err of rows is checked successfully # Disabled because: https://github.com/golangci/golangci-lint/issues/2649 | ||
| 259 | #- sqlclosecheck # checks that sql.Rows and sql.Stmt are closed | ||
| 260 | #- wastedassign # finds wasted assignment statements | ||
| 261 | |||
| 262 | |||
| 263 | ## you may want to enable | ||
| 264 | #- decorder # checks declaration order and count of types, constants, variables and functions | ||
| 265 | #- exhaustruct # checks if all structure fields are initialized | ||
| 266 | #- gochecknoglobals # checks that no global variables exist | ||
| 267 | #- godox # detects FIXME, TODO and other comment keywords | ||
| 268 | #- goheader # checks is file header matches to pattern | ||
| 269 | #- gomnd # detects magic numbers | ||
| 270 | #- interfacebloat # checks the number of methods inside an interface | ||
| 271 | #- ireturn # accept interfaces, return concrete types | ||
| 272 | #- prealloc # [premature optimization, but can be used in some cases] finds slice declarations that could potentially be preallocated | ||
| 273 | #- varnamelen # [great idea, but too many false positives] checks that the length of a variable's name matches its scope | ||
| 274 | #- wrapcheck # checks that errors returned from external packages are wrapped | ||
| 275 | |||
| 276 | ## disabled | ||
| 277 | #- containedctx # detects struct contained context.Context field | ||
| 278 | #- contextcheck # [too many false positives] checks the function whether use a non-inherited context | ||
| 279 | #- depguard # [replaced by gomodguard] checks if package imports are in a list of acceptable packages | ||
| 280 | #- dogsled # checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) | ||
| 281 | #- dupword # [useless without config] checks for duplicate words in the source code | ||
| 282 | #- errchkjson # [don't see profit + I'm against of omitting errors like in the first example https://github.com/breml/errchkjson] checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted | ||
| 283 | #- forcetypeassert # [replaced by errcheck] finds forced type assertions | ||
| 284 | #- goerr113 # [too strict] checks the errors handling expressions | ||
| 285 | #- gofmt # [replaced by goimports] checks whether code was gofmt-ed | ||
| 286 | #- gofumpt # [replaced by goimports, gofumports is not available yet] checks whether code was gofumpt-ed | ||
| 287 | #- grouper # analyzes expression groups | ||
| 288 | #- importas # enforces consistent import aliases | ||
| 289 | #- maintidx # measures the maintainability index of each function | ||
| 290 | #- misspell # [useless] finds commonly misspelled English words in comments | ||
| 291 | #- nlreturn # [too strict and mostly code is not more readable] checks for a new line before return and branch statements to increase code clarity | ||
| 292 | #- paralleltest # [too many false positives] detects missing usage of t.Parallel() method in your Go test | ||
| 293 | #- tagliatelle # checks the struct tags | ||
| 294 | #- thelper # detects golang test helpers without t.Helper() call and checks the consistency of test helpers | ||
| 295 | #- wsl # [too strict and mostly code is not more readable] whitespace linter forces you to use empty lines | ||
| 296 | |||
| 297 | ## deprecated | ||
| 298 | #- deadcode # [deprecated, replaced by unused] finds unused code | ||
| 299 | #- exhaustivestruct # [deprecated, replaced by exhaustruct] checks if all struct's fields are initialized | ||
| 300 | #- golint # [deprecated, replaced by revive] golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes | ||
| 301 | #- ifshort # [deprecated] checks that your code uses short syntax for if-statements whenever possible | ||
| 302 | #- interfacer # [deprecated] suggests narrower interface types | ||
| 303 | #- maligned # [deprecated, replaced by govet fieldalignment] detects Go structs that would take less memory if their fields were sorted | ||
| 304 | #- nosnakecase # [deprecated, replaced by revive var-naming] detects snake case of variable naming and function name | ||
| 305 | #- scopelint # [deprecated, replaced by exportloopref] checks for unpinned variables in go programs | ||
| 306 | #- structcheck # [deprecated, replaced by unused] finds unused struct fields | ||
| 307 | #- varcheck # [deprecated, replaced by unused] finds unused global variables and constants | ||
| 308 | |||
| 309 | |||
| 310 | issues: | ||
| 311 | # Maximum count of issues with the same text. | ||
| 312 | # Set to 0 to disable. | ||
| 313 | # Default: 3 | ||
| 314 | max-same-issues: 3 | ||
| 315 | |||
| 316 | exclude-rules: | ||
| 317 | - source: "^//\\s*go:generate\\s" | ||
| 318 | linters: [ lll ] | ||
| 319 | - source: "(noinspection|TODO)" | ||
| 320 | linters: [ godot ] | ||
| 321 | - source: "//noinspection" | ||
| 322 | linters: [ gocritic ] | ||
| 323 | - source: "^\\s+if _, ok := err\\.\\([^.]+\\.InternalError\\); ok {" | ||
| 324 | linters: [ errorlint ] | ||
| 325 | - path: "_test\\.go" | ||
| 326 | linters: | ||
| 327 | - bodyclose | ||
| 328 | - dupl | ||
| 329 | - funlen | ||
| 330 | - goconst | ||
| 331 | - gosec | ||
| 332 | - noctx | ||
| 333 | - wrapcheck | ||
| 334 | |||
diff --git a/vendor/github.com/neilotoole/jsoncolor/LICENSE b/vendor/github.com/neilotoole/jsoncolor/LICENSE new file mode 100644 index 0000000..76e1f9c --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/LICENSE | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | MIT License | ||
| 2 | |||
| 3 | Copyright (c) 2023 Neil O'Toole | ||
| 4 | |||
| 5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 6 | of this software and associated documentation files (the "Software"), to deal | ||
| 7 | in the Software without restriction, including without limitation the rights | ||
| 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 9 | copies of the Software, and to permit persons to whom the Software is | ||
| 10 | furnished to do so, subject to the following conditions: | ||
| 11 | |||
| 12 | The above copyright notice and this permission notice shall be included in all | ||
| 13 | copies or substantial portions of the Software. | ||
| 14 | |||
| 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 21 | SOFTWARE. | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/README.md b/vendor/github.com/neilotoole/jsoncolor/README.md new file mode 100644 index 0000000..a8da54c --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/README.md | |||
| @@ -0,0 +1,241 @@ | |||
| 1 | [](https://github.com/neilotoole/jsoncolor/actions?query=workflow%3AGo) | ||
| 2 | [](https://goreportcard.com/report/neilotoole/jsoncolor) | ||
| 3 | [](https://github.com/neilotoole/jsoncolor/releases/tag/v0.7.0) | ||
| 4 | [](https://pkg.go.dev/github.com/neilotoole/jsoncolor) | ||
| 5 | [](./LICENSE) | ||
| 6 | |||
| 7 | # jsoncolor | ||
| 8 | |||
| 9 | Package `neilotoole/jsoncolor` is a drop-in replacement for stdlib | ||
| 10 | [`encoding/json`](https://pkg.go.dev/encoding/json) that outputs colorized JSON. | ||
| 11 | |||
| 12 | Why? Well, [`jq`](https://jqlang.github.io/jq/) colorizes its output by default, and color output | ||
| 13 | is desirable for many Go CLIs. This package performs colorization (and indentation) inline | ||
| 14 | in the encoder, and is significantly faster than stdlib at indentation. | ||
| 15 | |||
| 16 | From the example [`jc`](./cmd/jc/main.go) app: | ||
| 17 | |||
| 18 |  | ||
| 19 | |||
| 20 | ## Usage | ||
| 21 | |||
| 22 | Get the package per the normal mechanism (requires Go 1.16+): | ||
| 23 | |||
| 24 | ```shell | ||
| 25 | go get -u github.com/neilotoole/jsoncolor | ||
| 26 | ``` | ||
| 27 | |||
| 28 | Then: | ||
| 29 | |||
| 30 | ```go | ||
| 31 | package main | ||
| 32 | |||
| 33 | import ( | ||
| 34 | "fmt" | ||
| 35 | "github.com/mattn/go-colorable" | ||
| 36 | json "github.com/neilotoole/jsoncolor" | ||
| 37 | "os" | ||
| 38 | ) | ||
| 39 | |||
| 40 | func main() { | ||
| 41 | var enc *json.Encoder | ||
| 42 | |||
| 43 | // Note: this check will fail if running inside Goland (and | ||
| 44 | // other IDEs?) as IsColorTerminal will return false. | ||
| 45 | if json.IsColorTerminal(os.Stdout) { | ||
| 46 | // Safe to use color | ||
| 47 | out := colorable.NewColorable(os.Stdout) // needed for Windows | ||
| 48 | enc = json.NewEncoder(out) | ||
| 49 | |||
| 50 | // DefaultColors are similar to jq | ||
| 51 | clrs := json.DefaultColors() | ||
| 52 | |||
| 53 | // Change some values, just for fun | ||
| 54 | clrs.Bool = json.Color("\x1b[36m") // Change the bool color | ||
| 55 | clrs.String = json.Color{} // Disable the string color | ||
| 56 | |||
| 57 | enc.SetColors(clrs) | ||
| 58 | } else { | ||
| 59 | // Can't use color; but the encoder will still work | ||
| 60 | enc = json.NewEncoder(os.Stdout) | ||
| 61 | } | ||
| 62 | |||
| 63 | m := map[string]interface{}{ | ||
| 64 | "a": 1, | ||
| 65 | "b": true, | ||
| 66 | "c": "hello", | ||
| 67 | } | ||
| 68 | |||
| 69 | if err := enc.Encode(m); err != nil { | ||
| 70 | fmt.Fprintln(os.Stderr, err) | ||
| 71 | os.Exit(1) | ||
| 72 | } | ||
| 73 | } | ||
| 74 | ``` | ||
| 75 | |||
| 76 | ### Configuration | ||
| 77 | |||
| 78 | To enable colorization, invoke [`enc.SetColors`](https://pkg.go.dev/github.com/neilotoole/jsoncolor#Encoder.SetColors). | ||
| 79 | |||
| 80 | The [`Colors`](https://pkg.go.dev/github.com/neilotoole/jsoncolor#Colors) struct | ||
| 81 | holds color config. The zero value and `nil` are both safe for use (resulting in no colorization). | ||
| 82 | |||
| 83 | The [`DefaultColors`](https://pkg.go.dev/github.com/neilotoole/jsoncolor#DefaultColors) func | ||
| 84 | returns a `Colors` struct that produces results similar to `jq`: | ||
| 85 | |||
| 86 | ```go | ||
| 87 | // DefaultColors returns the default Colors configuration. | ||
| 88 | // These colors largely follow jq's default colorization, | ||
| 89 | // with some deviation. | ||
| 90 | func DefaultColors() *Colors { | ||
| 91 | return &Colors{ | ||
| 92 | Null: Color("\x1b[2m"), | ||
| 93 | Bool: Color("\x1b[1m"), | ||
| 94 | Number: Color("\x1b[36m"), | ||
| 95 | String: Color("\x1b[32m"), | ||
| 96 | Key: Color("\x1b[34;1m"), | ||
| 97 | Bytes: Color("\x1b[2m"), | ||
| 98 | Time: Color("\x1b[32;2m"), | ||
| 99 | Punc: Color{}, // No colorization | ||
| 100 | } | ||
| 101 | } | ||
| 102 | ``` | ||
| 103 | |||
| 104 | As seen above, use the `Color` zero value (`Color{}`) to | ||
| 105 | disable colorization for that JSON element. | ||
| 106 | |||
| 107 | ### Helper for `fatih/color` | ||
| 108 | |||
| 109 | It can be inconvenient to use terminal codes, e.g. `json.Color("\x1b[36m")`. | ||
| 110 | A helper package provides an adapter for [`fatih/color`](https://github.com/fatih/color). | ||
| 111 | |||
| 112 | ```go | ||
| 113 | // import "github.com/neilotoole/jsoncolor/helper/fatihcolor" | ||
| 114 | // import "github.com/fatih/color" | ||
| 115 | // import "github.com/mattn/go-colorable" | ||
| 116 | |||
| 117 | out := colorable.NewColorable(os.Stdout) // needed for Windows | ||
| 118 | enc = json.NewEncoder(out) | ||
| 119 | |||
| 120 | fclrs := fatihcolor.DefaultColors() | ||
| 121 | // Change some values, just for fun | ||
| 122 | fclrs.Number = color.New(color.FgBlue) | ||
| 123 | fclrs.String = color.New(color.FgCyan) | ||
| 124 | |||
| 125 | clrs := fatihcolor.ToCoreColors(fclrs) | ||
| 126 | enc.SetColors(clrs) | ||
| 127 | ``` | ||
| 128 | |||
| 129 | ### Drop-in for `encoding/json` | ||
| 130 | |||
| 131 | This package is a full drop-in for stdlib [`encoding/json`](https://pkg.go.dev/encoding/json) | ||
| 132 | (thanks to the ancestral [`segmentio/encoding/json`](https://pkg.go.dev/github.com/segmentio/encoding/json) | ||
| 133 | pkg being a full drop-in). | ||
| 134 | |||
| 135 | To drop-in, just use an import alias: | ||
| 136 | |||
| 137 | ```go | ||
| 138 | import json "github.com/neilotoole/jsoncolor" | ||
| 139 | ``` | ||
| 140 | |||
| 141 | ## Example app: `jc` | ||
| 142 | |||
| 143 | See [`cmd/jc`](cmd/jc/main.go) for a trivial CLI implementation that can accept JSON input, | ||
| 144 | and output that JSON in color. | ||
| 145 | |||
| 146 | ```shell | ||
| 147 | # From project root | ||
| 148 | $ go install ./cmd/jc | ||
| 149 | $ cat ./testdata/sakila_actor.json | jc | ||
| 150 | ``` | ||
| 151 | |||
| 152 | ## Benchmarks | ||
| 153 | |||
| 154 | Note that this package contains [`golang_bench_test.go`](./golang_bench_test.go), which | ||
| 155 | is inherited from `segmentj`. But here we're interested in [`benchmark_test.go:BenchmarkEncode`](./benchmark_test.go), | ||
| 156 | which benchmarks encoding performance versus other JSON encoder packages. | ||
| 157 | The results below benchmark the following: | ||
| 158 | |||
| 159 | - Stdlib [`encoding/json`](https://pkg.go.dev/encoding/json) (`go1.17.1`). | ||
| 160 | - [`segmentj`](https://github.com/segmentio/encoding): `v0.1.14`, which was when `jsoncolor` was forked. The newer `segmentj` code performs even better. | ||
| 161 | - `neilotoole/jsoncolor`: (this package) `v0.6.0`. | ||
| 162 | - [`nwidger/jsoncolor`](https://github.com/nwidger/jsoncolor): `v0.3.0`, latest at time of benchmarks. | ||
| 163 | |||
| 164 | Note that two other Go JSON colorization packages ([`hokaccha/go-prettyjson`](https://github.com/hokaccha/go-prettyjson) and | ||
| 165 | [`TylerBrock/colorjson`](https://github.com/TylerBrock/colorjson)) are excluded from | ||
| 166 | these benchmarks because they do not provide a stdlib-compatible `Encoder` impl. | ||
| 167 | |||
| 168 | ``` | ||
| 169 | $ go test -bench=BenchmarkEncode -benchtime="5s" | ||
| 170 | goarch: amd64 | ||
| 171 | pkg: github.com/neilotoole/jsoncolor | ||
| 172 | cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz | ||
| 173 | BenchmarkEncode/stdlib_NoIndent-16 181 33047390 ns/op 8870685 B/op 120022 allocs/op | ||
| 174 | BenchmarkEncode/stdlib_Indent-16 124 48093178 ns/op 10470366 B/op 120033 allocs/op | ||
| 175 | BenchmarkEncode/segmentj_NoIndent-16 415 14658699 ns/op 3788911 B/op 10020 allocs/op | ||
| 176 | BenchmarkEncode/segmentj_Indent-16 195 30628798 ns/op 5404492 B/op 10025 allocs/op | ||
| 177 | BenchmarkEncode/neilotoole_NoIndent_NoColor-16 362 16522399 ns/op 3789034 B/op 10020 allocs/op | ||
| 178 | BenchmarkEncode/neilotoole_Indent_NoColor-16 303 20146856 ns/op 5460753 B/op 10021 allocs/op | ||
| 179 | BenchmarkEncode/neilotoole_NoIndent_Color-16 295 19989420 ns/op 10326019 B/op 10029 allocs/op | ||
| 180 | BenchmarkEncode/neilotoole_Indent_Color-16 246 24714163 ns/op 11996890 B/op 10030 allocs/op | ||
| 181 | BenchmarkEncode/nwidger_NoIndent_NoColor-16 10 541107983 ns/op 92934231 B/op 4490210 allocs/op | ||
| 182 | BenchmarkEncode/nwidger_Indent_NoColor-16 7 798088086 ns/op 117258321 B/op 6290213 allocs/op | ||
| 183 | BenchmarkEncode/nwidger_indent_NoIndent_Colo-16 10 542002051 ns/op 92935639 B/op 4490224 allocs/op | ||
| 184 | BenchmarkEncode/nwidger_indent_Indent_Color-16 7 799928353 ns/op 117259195 B/op 6290220 allocs/op | ||
| 185 | ``` | ||
| 186 | |||
| 187 | As always, take benchmarks with a large grain of salt, as they're based on a (small) synthetic benchmark. | ||
| 188 | More benchmarks would give a better picture (and note as well that the benchmarked `segmentj` is an older version, `v0.1.14`). | ||
| 189 | |||
| 190 | All that having been said, what can we surmise from these particular results? | ||
| 191 | |||
| 192 | - `segmentj` performs better than `stdlib` at all encoding tasks. | ||
| 193 | - `jsoncolor` performs better than `segmentj` for indentation (which makes sense, as indentation is performed inline). | ||
| 194 | - `jsoncolor` performs better than `stdlib` at all encoding tasks. | ||
| 195 | |||
| 196 | Again, trust these benchmarks at your peril. Create your own benchmarks for your own workload. | ||
| 197 | |||
| 198 | ## Notes | ||
| 199 | |||
| 200 | - The [`.golangci.yml`](./.golangci.yml) linter settings have been fiddled with to hush some | ||
| 201 | linting issues inherited from the `segmentio` codebase at the time of forking. Thus, the linter report | ||
| 202 | may not be of great use. In an ideal world, the `jsoncolor` functionality would be [ported](https://github.com/neilotoole/jsoncolor/issues/15) to a | ||
| 203 | more recent (and better-linted) version of the `segementio` codebase. | ||
| 204 | - The `segmentio` encoder (at least as of `v0.1.14`) encodes `time.Duration` as string, while `stdlib` outputs as `int64`. | ||
| 205 | This package follows `stdlib`. | ||
| 206 | - The [`Colors.Punc`](https://pkg.go.dev/github.com/neilotoole/jsoncolor#Colors) field controls all | ||
| 207 | punctuation colorization, i.e. `[]{},:"`. It is probably worthwhile to [separate](https://github.com/neilotoole/jsoncolor/issues/16) | ||
| 208 | these out into individually-configurable elements. | ||
| 209 | |||
| 210 | <a name="history"></a> | ||
| 211 | ## CHANGELOG | ||
| 212 | |||
| 213 | History: this package is an extract of [`sq`](https://github.com/neilotoole/sq)'s JSON encoding package, which itself is a fork of the | ||
| 214 | [`segmentio/encoding`](https://github.com/segmentio/encoding) JSON encoding package. Note that the | ||
| 215 | original `sq` JSON encoder was forked from Segment's codebase at `v0.1.14`, so | ||
| 216 | the codebases have drifted significantly by now. | ||
| 217 | |||
| 218 | ### [v0.7.1](https://github.com/neilotoole/jsoncolor/releases/tag/v0.7.1) | ||
| 219 | |||
| 220 | - [#27](https://github.com/neilotoole/jsoncolor/pull/27): Improved Windows terminal color support checking. | ||
| 221 | |||
| 222 | ### [v0.7.0](https://github.com/neilotoole/jsoncolor/releases/tag/v0.7.0) | ||
| 223 | |||
| 224 | - [#21](https://github.com/neilotoole/jsoncolor/pull/21): Support for [`encoding.TextMarshaler`](https://pkg.go.dev/encoding#TextMarshaler). | ||
| 225 | - [#22](https://github.com/neilotoole/jsoncolor/pull/22): Removed redundant dependencies. | ||
| 226 | - [#26](https://github.com/neilotoole/jsoncolor/pull/26): Updated dependencies. | ||
| 227 | |||
| 228 | ## Acknowledgments | ||
| 229 | |||
| 230 | - [`jq`](https://stedolan.github.io/jq/): sine qua non. | ||
| 231 | - [`segmentio/encoding`](https://github.com/segmentio/encoding): `jsoncolor` is layered into Segment's JSON encoder. They did the hard work. Much gratitude to that team. | ||
| 232 | - [`sq`](https://github.com/neilotoole/sq): `jsoncolor` is effectively an extract of code created specifically for `sq`. | ||
| 233 | - [`mattn/go-colorable`](https://github.com/mattn/go-colorable): no project is complete without `mattn` having played a role. | ||
| 234 | - [`fatih/color`](https://github.com/fatih/color): the color library. | ||
| 235 | - [`@hermannm`](https://github.com/hermannm): for several PRs. | ||
| 236 | |||
| 237 | ### Related | ||
| 238 | |||
| 239 | - [`nwidger/jsoncolor`](https://github.com/nwidger/jsoncolor) | ||
| 240 | - [`hokaccha/go-prettyjson`](https://github.com/hokaccha/go-prettyjson) | ||
| 241 | - [`TylerBrock/colorjson`](https://github.com/TylerBrock/colorjson) | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/SECURITY.md b/vendor/github.com/neilotoole/jsoncolor/SECURITY.md new file mode 100644 index 0000000..af83493 --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/SECURITY.md | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | # Security Policy | ||
| 2 | |||
| 3 | ## Supported Versions | ||
| 4 | |||
| 5 | |||
| 6 | | Version | Supported | | ||
| 7 | | ------- | ------------------ | | ||
| 8 | | v0.7.0 | :white_check_mark: | | ||
| 9 | | v0.6.0 | :x: | | ||
| 10 | |||
| 11 | |||
| 12 | ## Reporting a Vulnerability | ||
| 13 | |||
| 14 | Open an [issue](https://github.com/neilotoole/jsoncolor/issues/new). | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/SEGMENTIO_README.md b/vendor/github.com/neilotoole/jsoncolor/SEGMENTIO_README.md new file mode 100644 index 0000000..c5ed94b --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/SEGMENTIO_README.md | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | # encoding/json [](https://godoc.org/github.com/segmentio/encoding/json) | ||
| 2 | |||
| 3 | Go package offering a replacement implementation of the standard library's | ||
| 4 | [`encoding/json`](https://golang.org/pkg/encoding/json/) package, with much | ||
| 5 | better performance. | ||
| 6 | |||
| 7 | ## Usage | ||
| 8 | |||
| 9 | The exported API of this package mirrors the standard library's | ||
| 10 | [`encoding/json`](https://golang.org/pkg/encoding/json/) package, the only | ||
| 11 | change needed to take advantage of the performance improvements is the import | ||
| 12 | path of the `json` package, from: | ||
| 13 | ```go | ||
| 14 | import ( | ||
| 15 | "encoding/json" | ||
| 16 | ) | ||
| 17 | ``` | ||
| 18 | to | ||
| 19 | ```go | ||
| 20 | import ( | ||
| 21 | "github.com/segmentio/encoding/json" | ||
| 22 | ) | ||
| 23 | ``` | ||
| 24 | |||
| 25 | One way to gain higher encoding throughput is to disable HTML escaping. | ||
| 26 | It allows the string encoding to use a much more efficient code path which | ||
| 27 | does not require parsing UTF-8 runes most of the time. | ||
| 28 | |||
| 29 | ## Performance Improvements | ||
| 30 | |||
| 31 | The internal implementation uses a fair amount of unsafe operations (untyped | ||
| 32 | code, pointer arithmetic, etc...) to avoid using reflection as much as possible, | ||
| 33 | which is often the reason why serialization code has a large CPU and memory | ||
| 34 | footprint. | ||
| 35 | |||
| 36 | The package aims for zero unnecessary dynamic memory allocations and hot code | ||
| 37 | paths that are mostly free from calls into the reflect package. | ||
| 38 | |||
| 39 | ## Compatibility with encoding/json | ||
| 40 | |||
| 41 | This package aims to be a drop-in replacement, therefore it is tested to behave | ||
| 42 | exactly like the standard library's package. However, there are still a few | ||
| 43 | missing features that have not been ported yet: | ||
| 44 | |||
| 45 | - Streaming decoder, currently the `Decoder` implementation offered by the | ||
| 46 | package does not support progressively reading values from a JSON array (unlike | ||
| 47 | the standard library). In our experience this is a very rare use-case, if you | ||
| 48 | need it you're better off sticking to the standard library, or spend a bit of | ||
| 49 | time implementing it in here ;) | ||
| 50 | |||
| 51 | Note that none of those features should result in performance degradations if | ||
| 52 | they were implemented in the package, and we welcome contributions! | ||
| 53 | |||
| 54 | ## Trade-offs | ||
| 55 | |||
| 56 | As one would expect, we had to make a couple of trade-offs to achieve greater | ||
| 57 | performance than the standard library, but there were also features that we | ||
| 58 | did not want to give away. | ||
| 59 | |||
| 60 | Other open-source packages offering a reduced CPU and memory footprint usually | ||
| 61 | do so by designing a different API, or require code generation (therefore adding | ||
| 62 | complexity to the build process). These were not acceptable conditions for us, | ||
| 63 | as we were not willing to trade off developer productivity for better runtime | ||
| 64 | performance. To achieve this, we chose to exactly replicate the standard | ||
| 65 | library interfaces and behavior, which meant the package implementation was the | ||
| 66 | only area that we were able to work with. The internals of this package make | ||
| 67 | heavy use of unsafe pointer arithmetics and other performance optimizations, | ||
| 68 | and therefore are not as approachable as typical Go programs. Basically, we put | ||
| 69 | a bigger burden on maintainers to achieve better runtime cost without | ||
| 70 | sacrificing developer productivity. | ||
| 71 | |||
| 72 | For these reasons, we also don't believe that this code should be ported upstream | ||
| 73 | to the standard `encoding/json` package. The standard library has to remain | ||
| 74 | readable and approachable to maximize stability and maintainability, and make | ||
| 75 | projects like this one possible because a high quality reference implementation | ||
| 76 | already exists. | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/ascii.go b/vendor/github.com/neilotoole/jsoncolor/ascii.go new file mode 100644 index 0000000..6c66eb5 --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/ascii.go | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | package jsoncolor | ||
| 2 | |||
| 3 | import "unsafe" | ||
| 4 | |||
| 5 | // asciiValid returns true if b contains only ASCII characters. | ||
| 6 | // | ||
| 7 | // From https://github.com/segmentio/encoding/blob/v0.1.14/ascii/valid.go#L28 | ||
| 8 | // | ||
| 9 | //go:nosplit | ||
| 10 | func asciiValid(b []byte) bool { | ||
| 11 | s, n := unsafe.Pointer(&b), uintptr(len(b)) | ||
| 12 | |||
| 13 | i := uintptr(0) | ||
| 14 | p := *(*unsafe.Pointer)(s) | ||
| 15 | |||
| 16 | for n >= 8 { | ||
| 17 | if ((*(*uint64)(unsafe.Pointer(uintptr(p) + i))) & 0x8080808080808080) != 0 { | ||
| 18 | return false | ||
| 19 | } | ||
| 20 | i += 8 | ||
| 21 | n -= 8 | ||
| 22 | } | ||
| 23 | |||
| 24 | if n >= 4 { | ||
| 25 | if ((*(*uint32)(unsafe.Pointer(uintptr(p) + i))) & 0x80808080) != 0 { | ||
| 26 | return false | ||
| 27 | } | ||
| 28 | i += 4 | ||
| 29 | n -= 4 | ||
| 30 | } | ||
| 31 | |||
| 32 | var x uint32 | ||
| 33 | switch n { | ||
| 34 | case 3: | ||
| 35 | x = uint32(*(*uint8)(unsafe.Pointer(uintptr(p) + i))) | uint32(*(*uint16)(unsafe.Pointer(uintptr(p) + i + 1)))<<8 | ||
| 36 | case 2: | ||
| 37 | x = uint32(*(*uint16)(unsafe.Pointer(uintptr(p) + i))) | ||
| 38 | case 1: | ||
| 39 | x = uint32(*(*uint8)(unsafe.Pointer(uintptr(p) + i))) | ||
| 40 | default: | ||
| 41 | return true | ||
| 42 | } | ||
| 43 | return (x & 0x80808080) == 0 | ||
| 44 | } | ||
| 45 | |||
| 46 | // asciiValidPrint returns true if b contains only printable ASCII characters. | ||
| 47 | // | ||
| 48 | // From https://github.com/segmentio/encoding/blob/v0.1.14/ascii/valid.go#L83 | ||
| 49 | // | ||
| 50 | //go:nosplit | ||
| 51 | func asciiValidPrint(b []byte) bool { | ||
| 52 | s, n := unsafe.Pointer(&b), uintptr(len(b)) | ||
| 53 | |||
| 54 | if n == 0 { | ||
| 55 | return true | ||
| 56 | } | ||
| 57 | |||
| 58 | i := uintptr(0) | ||
| 59 | p := *(*unsafe.Pointer)(s) | ||
| 60 | |||
| 61 | for (n - i) >= 8 { | ||
| 62 | x := *(*uint64)(unsafe.Pointer(uintptr(p) + i)) | ||
| 63 | if hasLess64(x, 0x20) || hasMore64(x, 0x7e) { | ||
| 64 | return false | ||
| 65 | } | ||
| 66 | i += 8 | ||
| 67 | } | ||
| 68 | |||
| 69 | if (n - i) >= 4 { | ||
| 70 | x := *(*uint32)(unsafe.Pointer(uintptr(p) + i)) | ||
| 71 | if hasLess32(x, 0x20) || hasMore32(x, 0x7e) { | ||
| 72 | return false | ||
| 73 | } | ||
| 74 | i += 4 | ||
| 75 | } | ||
| 76 | |||
| 77 | var x uint32 | ||
| 78 | switch n - i { | ||
| 79 | case 3: | ||
| 80 | x = 0x20000000 | uint32(*(*uint8)(unsafe.Pointer(uintptr(p) + i))) | uint32(*(*uint16)(unsafe.Pointer(uintptr(p) + i + 1)))<<8 | ||
| 81 | case 2: | ||
| 82 | x = 0x20200000 | uint32(*(*uint16)(unsafe.Pointer(uintptr(p) + i))) | ||
| 83 | case 1: | ||
| 84 | x = 0x20202000 | uint32(*(*uint8)(unsafe.Pointer(uintptr(p) + i))) | ||
| 85 | default: | ||
| 86 | return true | ||
| 87 | } | ||
| 88 | return !(hasLess32(x, 0x20) || hasMore32(x, 0x7e)) | ||
| 89 | } | ||
| 90 | |||
| 91 | // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord | ||
| 92 | const ( | ||
| 93 | hasLessConstL64 = (^uint64(0)) / 255 | ||
| 94 | hasLessConstR64 = hasLessConstL64 * 128 | ||
| 95 | |||
| 96 | hasLessConstL32 = (^uint32(0)) / 255 | ||
| 97 | hasLessConstR32 = hasLessConstL32 * 128 | ||
| 98 | |||
| 99 | hasMoreConstL64 = (^uint64(0)) / 255 | ||
| 100 | hasMoreConstR64 = hasMoreConstL64 * 128 | ||
| 101 | |||
| 102 | hasMoreConstL32 = (^uint32(0)) / 255 | ||
| 103 | hasMoreConstR32 = hasMoreConstL32 * 128 | ||
| 104 | ) | ||
| 105 | |||
| 106 | //go:nosplit | ||
| 107 | func hasLess64(x, n uint64) bool { | ||
| 108 | return ((x - (hasLessConstL64 * n)) & ^x & hasLessConstR64) != 0 | ||
| 109 | } | ||
| 110 | |||
| 111 | //go:nosplit | ||
| 112 | func hasLess32(x, n uint32) bool { | ||
| 113 | return ((x - (hasLessConstL32 * n)) & ^x & hasLessConstR32) != 0 | ||
| 114 | } | ||
| 115 | |||
| 116 | //go:nosplit | ||
| 117 | func hasMore64(x, n uint64) bool { | ||
| 118 | return (((x + (hasMoreConstL64 * (127 - n))) | x) & hasMoreConstR64) != 0 | ||
| 119 | } | ||
| 120 | |||
| 121 | //go:nosplit | ||
| 122 | func hasMore32(x, n uint32) bool { | ||
| 123 | return (((x + (hasMoreConstL32 * (127 - n))) | x) & hasMoreConstR32) != 0 | ||
| 124 | } | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/codec.go b/vendor/github.com/neilotoole/jsoncolor/codec.go new file mode 100644 index 0000000..b3b42ef --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/codec.go | |||
| @@ -0,0 +1,1183 @@ | |||
| 1 | package jsoncolor | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "encoding" | ||
| 5 | "encoding/json" | ||
| 6 | "fmt" | ||
| 7 | "reflect" | ||
| 8 | "sort" | ||
| 9 | "strconv" | ||
| 10 | "strings" | ||
| 11 | "sync/atomic" | ||
| 12 | "time" | ||
| 13 | "unicode" | ||
| 14 | "unsafe" | ||
| 15 | ) | ||
| 16 | |||
| 17 | type codec struct { | ||
| 18 | encode encodeFunc | ||
| 19 | decode decodeFunc | ||
| 20 | } | ||
| 21 | |||
| 22 | type encoder struct { | ||
| 23 | flags AppendFlags | ||
| 24 | clrs *Colors | ||
| 25 | indentr *indenter | ||
| 26 | } | ||
| 27 | type decoder struct{ flags ParseFlags } | ||
| 28 | |||
| 29 | type encodeFunc func(encoder, []byte, unsafe.Pointer) ([]byte, error) | ||
| 30 | type decodeFunc func(decoder, []byte, unsafe.Pointer) ([]byte, error) | ||
| 31 | |||
| 32 | type emptyFunc func(unsafe.Pointer) bool | ||
| 33 | type sortFunc func([]reflect.Value) | ||
| 34 | |||
| 35 | var ( | ||
| 36 | // Eventually consistent cache mapping go types to dynamically generated | ||
| 37 | // codecs. | ||
| 38 | // | ||
| 39 | // Note: using a uintptr as key instead of reflect.Type shaved ~15ns off of | ||
| 40 | // the ~30ns Marhsal/Unmarshal functions which were dominated by the map | ||
| 41 | // lookup time for simple types like bool, int, etc.. | ||
| 42 | cache unsafe.Pointer // map[unsafe.Pointer]codec | ||
| 43 | ) | ||
| 44 | |||
| 45 | func cacheLoad() map[unsafe.Pointer]codec { | ||
| 46 | p := atomic.LoadPointer(&cache) | ||
| 47 | return *(*map[unsafe.Pointer]codec)(unsafe.Pointer(&p)) | ||
| 48 | } | ||
| 49 | |||
| 50 | func cacheStore(typ reflect.Type, cod codec, oldCodecs map[unsafe.Pointer]codec) { | ||
| 51 | newCodecs := make(map[unsafe.Pointer]codec, len(oldCodecs)+1) | ||
| 52 | newCodecs[typeid(typ)] = cod | ||
| 53 | |||
| 54 | for t, c := range oldCodecs { | ||
| 55 | newCodecs[t] = c | ||
| 56 | } | ||
| 57 | |||
| 58 | atomic.StorePointer(&cache, *(*unsafe.Pointer)(unsafe.Pointer(&newCodecs))) | ||
| 59 | } | ||
| 60 | |||
| 61 | func typeid(t reflect.Type) unsafe.Pointer { | ||
| 62 | return (*iface)(unsafe.Pointer(&t)).ptr | ||
| 63 | } | ||
| 64 | |||
| 65 | func constructCachedCodec(t reflect.Type, cache map[unsafe.Pointer]codec) codec { | ||
| 66 | c := constructCodec(t, map[reflect.Type]*structType{}, t.Kind() == reflect.Ptr) | ||
| 67 | |||
| 68 | if inlined(t) { | ||
| 69 | c.encode = constructInlineValueEncodeFunc(c.encode) | ||
| 70 | } | ||
| 71 | |||
| 72 | cacheStore(t, c, cache) | ||
| 73 | return c | ||
| 74 | } | ||
| 75 | |||
| 76 | func constructCodec(t reflect.Type, seen map[reflect.Type]*structType, canAddr bool) (c codec) { | ||
| 77 | switch t { | ||
| 78 | case nullType, nil: | ||
| 79 | c = codec{encode: encoder.encodeNull, decode: decoder.decodeNull} | ||
| 80 | |||
| 81 | case numberType: | ||
| 82 | c = codec{encode: encoder.encodeNumber, decode: decoder.decodeNumber} | ||
| 83 | |||
| 84 | case bytesType: | ||
| 85 | c = codec{encode: encoder.encodeBytes, decode: decoder.decodeBytes} | ||
| 86 | |||
| 87 | case durationType: | ||
| 88 | c = codec{encode: encoder.encodeDuration, decode: decoder.decodeDuration} | ||
| 89 | |||
| 90 | case timeType: | ||
| 91 | c = codec{encode: encoder.encodeTime, decode: decoder.decodeTime} | ||
| 92 | |||
| 93 | case interfaceType: | ||
| 94 | c = codec{encode: encoder.encodeInterface, decode: decoder.decodeInterface} | ||
| 95 | |||
| 96 | case rawMessageType: | ||
| 97 | c = codec{encode: encoder.encodeRawMessage, decode: decoder.decodeRawMessage} | ||
| 98 | |||
| 99 | case numberPtrType: | ||
| 100 | c = constructPointerCodec(numberPtrType, nil) | ||
| 101 | |||
| 102 | case durationPtrType: | ||
| 103 | c = constructPointerCodec(durationPtrType, nil) | ||
| 104 | |||
| 105 | case timePtrType: | ||
| 106 | c = constructPointerCodec(timePtrType, nil) | ||
| 107 | |||
| 108 | case rawMessagePtrType: | ||
| 109 | c = constructPointerCodec(rawMessagePtrType, nil) | ||
| 110 | } | ||
| 111 | |||
| 112 | if c.encode != nil { | ||
| 113 | return | ||
| 114 | } | ||
| 115 | |||
| 116 | switch t.Kind() { | ||
| 117 | case reflect.Bool: | ||
| 118 | c = codec{encode: encoder.encodeBool, decode: decoder.decodeBool} | ||
| 119 | |||
| 120 | case reflect.Int: | ||
| 121 | c = codec{encode: encoder.encodeInt, decode: decoder.decodeInt} | ||
| 122 | |||
| 123 | case reflect.Int8: | ||
| 124 | c = codec{encode: encoder.encodeInt8, decode: decoder.decodeInt8} | ||
| 125 | |||
| 126 | case reflect.Int16: | ||
| 127 | c = codec{encode: encoder.encodeInt16, decode: decoder.decodeInt16} | ||
| 128 | |||
| 129 | case reflect.Int32: | ||
| 130 | c = codec{encode: encoder.encodeInt32, decode: decoder.decodeInt32} | ||
| 131 | |||
| 132 | case reflect.Int64: | ||
| 133 | c = codec{encode: encoder.encodeInt64, decode: decoder.decodeInt64} | ||
| 134 | |||
| 135 | case reflect.Uint: | ||
| 136 | c = codec{encode: encoder.encodeUint, decode: decoder.decodeUint} | ||
| 137 | |||
| 138 | case reflect.Uintptr: | ||
| 139 | c = codec{encode: encoder.encodeUintptr, decode: decoder.decodeUintptr} | ||
| 140 | |||
| 141 | case reflect.Uint8: | ||
| 142 | c = codec{encode: encoder.encodeUint8, decode: decoder.decodeUint8} | ||
| 143 | |||
| 144 | case reflect.Uint16: | ||
| 145 | c = codec{encode: encoder.encodeUint16, decode: decoder.decodeUint16} | ||
| 146 | |||
| 147 | case reflect.Uint32: | ||
| 148 | c = codec{encode: encoder.encodeUint32, decode: decoder.decodeUint32} | ||
| 149 | |||
| 150 | case reflect.Uint64: | ||
| 151 | c = codec{encode: encoder.encodeUint64, decode: decoder.decodeUint64} | ||
| 152 | |||
| 153 | case reflect.Float32: | ||
| 154 | c = codec{encode: encoder.encodeFloat32, decode: decoder.decodeFloat32} | ||
| 155 | |||
| 156 | case reflect.Float64: | ||
| 157 | c = codec{encode: encoder.encodeFloat64, decode: decoder.decodeFloat64} | ||
| 158 | |||
| 159 | case reflect.String: | ||
| 160 | c = codec{encode: encoder.encodeString, decode: decoder.decodeString} | ||
| 161 | |||
| 162 | case reflect.Interface: | ||
| 163 | c = constructInterfaceCodec(t) | ||
| 164 | |||
| 165 | case reflect.Array: | ||
| 166 | c = constructArrayCodec(t, seen, canAddr) | ||
| 167 | |||
| 168 | case reflect.Slice: | ||
| 169 | c = constructSliceCodec(t, seen) | ||
| 170 | |||
| 171 | case reflect.Map: | ||
| 172 | c = constructMapCodec(t, seen) | ||
| 173 | |||
| 174 | case reflect.Struct: | ||
| 175 | c = constructStructCodec(t, seen, canAddr) | ||
| 176 | |||
| 177 | case reflect.Ptr: | ||
| 178 | c = constructPointerCodec(t, seen) | ||
| 179 | |||
| 180 | default: | ||
| 181 | c = constructUnsupportedTypeCodec(t) | ||
| 182 | } | ||
| 183 | |||
| 184 | p := reflect.PtrTo(t) | ||
| 185 | |||
| 186 | if canAddr { | ||
| 187 | switch { | ||
| 188 | case p.Implements(jsonMarshalerType): | ||
| 189 | c.encode = constructJSONMarshalerEncodeFunc(t, true) | ||
| 190 | case p.Implements(textMarshalerType): | ||
| 191 | c.encode = constructTextMarshalerEncodeFunc(t, true) | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | switch { | ||
| 196 | case t.Implements(jsonMarshalerType): | ||
| 197 | c.encode = constructJSONMarshalerEncodeFunc(t, false) | ||
| 198 | case t.Implements(textMarshalerType): | ||
| 199 | c.encode = constructTextMarshalerEncodeFunc(t, false) | ||
| 200 | } | ||
| 201 | |||
| 202 | switch { | ||
| 203 | case p.Implements(jsonUnmarshalerType): | ||
| 204 | c.decode = constructJSONUnmarshalerDecodeFunc(t, true) | ||
| 205 | case p.Implements(textUnmarshalerType): | ||
| 206 | c.decode = constructTextUnmarshalerDecodeFunc(t, true) | ||
| 207 | } | ||
| 208 | |||
| 209 | return | ||
| 210 | } | ||
| 211 | |||
| 212 | func constructStringCodec(t reflect.Type, seen map[reflect.Type]*structType, canAddr bool) codec { | ||
| 213 | c := constructCodec(t, seen, canAddr) | ||
| 214 | return codec{ | ||
| 215 | encode: constructStringEncodeFunc(c.encode), | ||
| 216 | decode: constructStringDecodeFunc(c.decode), | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | func constructStringEncodeFunc(encode encodeFunc) encodeFunc { | ||
| 221 | return func(e encoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 222 | return e.encodeToString(b, p, encode) | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | func constructStringDecodeFunc(decode decodeFunc) decodeFunc { | ||
| 227 | return func(d decoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 228 | return d.decodeFromString(b, p, decode) | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | func constructStringToIntDecodeFunc(t reflect.Type, decode decodeFunc) decodeFunc { | ||
| 233 | return func(d decoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 234 | return d.decodeFromStringToInt(b, p, t, decode) | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | func constructArrayCodec(t reflect.Type, seen map[reflect.Type]*structType, canAddr bool) codec { | ||
| 239 | e := t.Elem() | ||
| 240 | c := constructCodec(e, seen, canAddr) | ||
| 241 | s := alignedSize(e) | ||
| 242 | return codec{ | ||
| 243 | encode: constructArrayEncodeFunc(s, t, c.encode), | ||
| 244 | decode: constructArrayDecodeFunc(s, t, c.decode), | ||
| 245 | } | ||
| 246 | } | ||
| 247 | |||
| 248 | func constructArrayEncodeFunc(size uintptr, t reflect.Type, encode encodeFunc) encodeFunc { | ||
| 249 | n := t.Len() | ||
| 250 | return func(e encoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 251 | return e.encodeArray(b, p, n, size, t, encode) | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | func constructArrayDecodeFunc(size uintptr, t reflect.Type, decode decodeFunc) decodeFunc { | ||
| 256 | n := t.Len() | ||
| 257 | return func(d decoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 258 | return d.decodeArray(b, p, n, size, t, decode) | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | func constructSliceCodec(t reflect.Type, seen map[reflect.Type]*structType) codec { | ||
| 263 | e := t.Elem() | ||
| 264 | s := alignedSize(e) | ||
| 265 | |||
| 266 | if e.Kind() == reflect.Uint8 { | ||
| 267 | // Go 1.7+ behavior: slices of byte types (and aliases) may override the | ||
| 268 | // default encoding and decoding behaviors by implementing marshaler and | ||
| 269 | // unmarshaler interfaces. | ||
| 270 | p := reflect.PtrTo(e) | ||
| 271 | c := codec{} | ||
| 272 | |||
| 273 | switch { | ||
| 274 | case e.Implements(jsonMarshalerType): | ||
| 275 | c.encode = constructJSONMarshalerEncodeFunc(e, false) | ||
| 276 | case e.Implements(textMarshalerType): | ||
| 277 | c.encode = constructTextMarshalerEncodeFunc(e, false) | ||
| 278 | case p.Implements(jsonMarshalerType): | ||
| 279 | c.encode = constructJSONMarshalerEncodeFunc(e, true) | ||
| 280 | case p.Implements(textMarshalerType): | ||
| 281 | c.encode = constructTextMarshalerEncodeFunc(e, true) | ||
| 282 | } | ||
| 283 | |||
| 284 | switch { | ||
| 285 | case e.Implements(jsonUnmarshalerType): | ||
| 286 | c.decode = constructJSONUnmarshalerDecodeFunc(e, false) | ||
| 287 | case e.Implements(textUnmarshalerType): | ||
| 288 | c.decode = constructTextUnmarshalerDecodeFunc(e, false) | ||
| 289 | case p.Implements(jsonUnmarshalerType): | ||
| 290 | c.decode = constructJSONUnmarshalerDecodeFunc(e, true) | ||
| 291 | case p.Implements(textUnmarshalerType): | ||
| 292 | c.decode = constructTextUnmarshalerDecodeFunc(e, true) | ||
| 293 | } | ||
| 294 | |||
| 295 | if c.encode != nil { | ||
| 296 | c.encode = constructSliceEncodeFunc(s, t, c.encode) | ||
| 297 | } else { | ||
| 298 | c.encode = encoder.encodeBytes | ||
| 299 | } | ||
| 300 | |||
| 301 | if c.decode != nil { | ||
| 302 | c.decode = constructSliceDecodeFunc(s, t, c.decode) | ||
| 303 | } else { | ||
| 304 | c.decode = decoder.decodeBytes | ||
| 305 | } | ||
| 306 | |||
| 307 | return c | ||
| 308 | } | ||
| 309 | |||
| 310 | c := constructCodec(e, seen, true) | ||
| 311 | return codec{ | ||
| 312 | encode: constructSliceEncodeFunc(s, t, c.encode), | ||
| 313 | decode: constructSliceDecodeFunc(s, t, c.decode), | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 317 | func constructSliceEncodeFunc(size uintptr, t reflect.Type, encode encodeFunc) encodeFunc { | ||
| 318 | return func(e encoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 319 | return e.encodeSlice(b, p, size, t, encode) | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | func constructSliceDecodeFunc(size uintptr, t reflect.Type, decode decodeFunc) decodeFunc { | ||
| 324 | return func(d decoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 325 | return d.decodeSlice(b, p, size, t, decode) | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | func constructMapCodec(t reflect.Type, seen map[reflect.Type]*structType) codec { | ||
| 330 | var sortKeys sortFunc | ||
| 331 | k := t.Key() | ||
| 332 | v := t.Elem() | ||
| 333 | |||
| 334 | // Faster implementations for some common cases. | ||
| 335 | switch { | ||
| 336 | case k == stringType && v == interfaceType: | ||
| 337 | return codec{ | ||
| 338 | encode: encoder.encodeMapStringInterface, | ||
| 339 | decode: decoder.decodeMapStringInterface, | ||
| 340 | } | ||
| 341 | |||
| 342 | case k == stringType && v == rawMessageType: | ||
| 343 | return codec{ | ||
| 344 | encode: encoder.encodeMapStringRawMessage, | ||
| 345 | decode: decoder.decodeMapStringRawMessage, | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | kc := codec{} | ||
| 350 | vc := constructCodec(v, seen, false) | ||
| 351 | |||
| 352 | if k.Implements(textMarshalerType) || reflect.PtrTo(k).Implements(textUnmarshalerType) { | ||
| 353 | kc.encode = constructTextMarshalerEncodeFunc(k, false) | ||
| 354 | kc.decode = constructTextUnmarshalerDecodeFunc(k, true) | ||
| 355 | |||
| 356 | sortKeys = func(keys []reflect.Value) { | ||
| 357 | sort.Slice(keys, func(i, j int) bool { | ||
| 358 | // This is a performance abomination but the use case is rare | ||
| 359 | // enough that it shouldn't be a problem in practice. | ||
| 360 | k1, _ := keys[i].Interface().(encoding.TextMarshaler).MarshalText() | ||
| 361 | k2, _ := keys[j].Interface().(encoding.TextMarshaler).MarshalText() | ||
| 362 | return string(k1) < string(k2) | ||
| 363 | }) | ||
| 364 | } | ||
| 365 | } else { | ||
| 366 | switch k.Kind() { | ||
| 367 | case reflect.String: | ||
| 368 | kc.encode = encoder.encodeKey | ||
| 369 | kc.decode = decoder.decodeString | ||
| 370 | |||
| 371 | sortKeys = func(keys []reflect.Value) { | ||
| 372 | sort.Slice(keys, func(i, j int) bool { return keys[i].String() < keys[j].String() }) | ||
| 373 | } | ||
| 374 | |||
| 375 | case reflect.Int, | ||
| 376 | reflect.Int8, | ||
| 377 | reflect.Int16, | ||
| 378 | reflect.Int32, | ||
| 379 | reflect.Int64: | ||
| 380 | kc = constructStringCodec(k, seen, false) | ||
| 381 | |||
| 382 | sortKeys = func(keys []reflect.Value) { | ||
| 383 | sort.Slice(keys, func(i, j int) bool { return intStringsAreSorted(keys[i].Int(), keys[j].Int()) }) | ||
| 384 | } | ||
| 385 | |||
| 386 | case reflect.Uint, | ||
| 387 | reflect.Uintptr, | ||
| 388 | reflect.Uint8, | ||
| 389 | reflect.Uint16, | ||
| 390 | reflect.Uint32, | ||
| 391 | reflect.Uint64: | ||
| 392 | kc = constructStringCodec(k, seen, false) | ||
| 393 | |||
| 394 | sortKeys = func(keys []reflect.Value) { | ||
| 395 | sort.Slice(keys, func(i, j int) bool { return uintStringsAreSorted(keys[i].Uint(), keys[j].Uint()) }) | ||
| 396 | } | ||
| 397 | |||
| 398 | default: | ||
| 399 | return constructUnsupportedTypeCodec(t) | ||
| 400 | } | ||
| 401 | } | ||
| 402 | |||
| 403 | if inlined(v) { | ||
| 404 | vc.encode = constructInlineValueEncodeFunc(vc.encode) | ||
| 405 | } | ||
| 406 | |||
| 407 | return codec{ | ||
| 408 | encode: constructMapEncodeFunc(t, kc.encode, vc.encode, sortKeys), | ||
| 409 | decode: constructMapDecodeFunc(t, kc.decode, vc.decode), | ||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 413 | func constructMapEncodeFunc(t reflect.Type, encodeKey, encodeValue encodeFunc, sortKeys sortFunc) encodeFunc { | ||
| 414 | return func(e encoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 415 | return e.encodeMap(b, p, t, encodeKey, encodeValue, sortKeys) | ||
| 416 | } | ||
| 417 | } | ||
| 418 | |||
| 419 | func constructMapDecodeFunc(t reflect.Type, decodeKey, decodeValue decodeFunc) decodeFunc { | ||
| 420 | kt := t.Key() | ||
| 421 | vt := t.Elem() | ||
| 422 | kz := reflect.Zero(kt) | ||
| 423 | vz := reflect.Zero(vt) | ||
| 424 | return func(d decoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 425 | return d.decodeMap(b, p, t, kt, vt, kz, vz, decodeKey, decodeValue) | ||
| 426 | } | ||
| 427 | } | ||
| 428 | |||
| 429 | func constructStructCodec(t reflect.Type, seen map[reflect.Type]*structType, canAddr bool) codec { | ||
| 430 | st := constructStructType(t, seen, canAddr) | ||
| 431 | return codec{ | ||
| 432 | encode: constructStructEncodeFunc(st), | ||
| 433 | decode: constructStructDecodeFunc(st), | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 | func constructStructType(t reflect.Type, seen map[reflect.Type]*structType, canAddr bool) *structType { | ||
| 438 | // Used for preventing infinite recursion on types that have pointers to | ||
| 439 | // themselves. | ||
| 440 | st := seen[t] | ||
| 441 | |||
| 442 | if st == nil { | ||
| 443 | st = &structType{ | ||
| 444 | fields: make([]structField, 0, t.NumField()), | ||
| 445 | fieldsIndex: make(map[string]*structField), | ||
| 446 | ficaseIndex: make(map[string]*structField), | ||
| 447 | typ: t, | ||
| 448 | } | ||
| 449 | |||
| 450 | seen[t] = st | ||
| 451 | st.fields = appendStructFields(st.fields, t, 0, seen, canAddr) | ||
| 452 | |||
| 453 | for i := range st.fields { | ||
| 454 | f := &st.fields[i] | ||
| 455 | s := strings.ToLower(f.name) | ||
| 456 | st.fieldsIndex[f.name] = f | ||
| 457 | // When there is ambiguity because multiple fields have the same | ||
| 458 | // case-insensitive representation, the first field must win. | ||
| 459 | if _, exists := st.ficaseIndex[s]; !exists { | ||
| 460 | st.ficaseIndex[s] = f | ||
| 461 | } | ||
| 462 | } | ||
| 463 | } | ||
| 464 | |||
| 465 | return st | ||
| 466 | } | ||
| 467 | |||
| 468 | func constructStructEncodeFunc(st *structType) encodeFunc { | ||
| 469 | return func(e encoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 470 | return e.encodeStruct(b, p, st) | ||
| 471 | } | ||
| 472 | } | ||
| 473 | |||
| 474 | func constructStructDecodeFunc(st *structType) decodeFunc { | ||
| 475 | return func(d decoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 476 | return d.decodeStruct(b, p, st) | ||
| 477 | } | ||
| 478 | } | ||
| 479 | |||
| 480 | func constructEmbeddedStructPointerCodec(t reflect.Type, unexported bool, offset uintptr, field codec) codec { | ||
| 481 | return codec{ | ||
| 482 | encode: constructEmbeddedStructPointerEncodeFunc(t, unexported, offset, field.encode), | ||
| 483 | decode: constructEmbeddedStructPointerDecodeFunc(t, unexported, offset, field.decode), | ||
| 484 | } | ||
| 485 | } | ||
| 486 | |||
| 487 | func constructEmbeddedStructPointerEncodeFunc(t reflect.Type, unexported bool, offset uintptr, encode encodeFunc) encodeFunc { | ||
| 488 | return func(e encoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 489 | return e.encodeEmbeddedStructPointer(b, p, t, unexported, offset, encode) | ||
| 490 | } | ||
| 491 | } | ||
| 492 | |||
| 493 | func constructEmbeddedStructPointerDecodeFunc(t reflect.Type, unexported bool, offset uintptr, decode decodeFunc) decodeFunc { | ||
| 494 | return func(d decoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 495 | return d.decodeEmbeddedStructPointer(b, p, t, unexported, offset, decode) | ||
| 496 | } | ||
| 497 | } | ||
| 498 | |||
| 499 | func appendStructFields(fields []structField, t reflect.Type, offset uintptr, seen map[reflect.Type]*structType, canAddr bool) []structField { | ||
| 500 | type embeddedField struct { | ||
| 501 | index int | ||
| 502 | offset uintptr | ||
| 503 | pointer bool | ||
| 504 | unexported bool | ||
| 505 | subtype *structType | ||
| 506 | subfield *structField | ||
| 507 | } | ||
| 508 | |||
| 509 | names := make(map[string]struct{}) | ||
| 510 | embedded := make([]embeddedField, 0, 10) | ||
| 511 | |||
| 512 | for i, n := 0, t.NumField(); i < n; i++ { | ||
| 513 | f := t.Field(i) | ||
| 514 | |||
| 515 | var ( | ||
| 516 | name = f.Name | ||
| 517 | anonymous = f.Anonymous | ||
| 518 | tag = false | ||
| 519 | omitempty = false | ||
| 520 | stringify = false | ||
| 521 | unexported = len(f.PkgPath) != 0 | ||
| 522 | ) | ||
| 523 | |||
| 524 | if unexported && !anonymous { // unexported | ||
| 525 | continue | ||
| 526 | } | ||
| 527 | |||
| 528 | if parts := strings.Split(f.Tag.Get("json"), ","); len(parts) != 0 { | ||
| 529 | if len(parts[0]) != 0 { | ||
| 530 | name, tag = parts[0], true | ||
| 531 | } | ||
| 532 | |||
| 533 | if name == "-" && len(parts) == 1 { // ignored | ||
| 534 | continue | ||
| 535 | } | ||
| 536 | |||
| 537 | if !isValidTag(name) { | ||
| 538 | name = f.Name | ||
| 539 | } | ||
| 540 | |||
| 541 | for _, tag := range parts[1:] { | ||
| 542 | switch tag { | ||
| 543 | case "omitempty": | ||
| 544 | omitempty = true | ||
| 545 | case "string": | ||
| 546 | stringify = true | ||
| 547 | } | ||
| 548 | } | ||
| 549 | } | ||
| 550 | |||
| 551 | if anonymous && !tag { // embedded | ||
| 552 | typ := f.Type | ||
| 553 | ptr := f.Type.Kind() == reflect.Ptr | ||
| 554 | |||
| 555 | if ptr { | ||
| 556 | typ = f.Type.Elem() | ||
| 557 | } | ||
| 558 | |||
| 559 | if typ.Kind() == reflect.Struct { | ||
| 560 | // When the embedded fields is inlined the fields can be looked | ||
| 561 | // up by offset from the address of the wrapping object, so we | ||
| 562 | // simply add the embedded struct fields to the list of fields | ||
| 563 | // of the current struct type. | ||
| 564 | subtype := constructStructType(typ, seen, canAddr) | ||
| 565 | |||
| 566 | for j := range subtype.fields { | ||
| 567 | embedded = append(embedded, embeddedField{ | ||
| 568 | index: i<<32 | j, | ||
| 569 | offset: offset + f.Offset, | ||
| 570 | pointer: ptr, | ||
| 571 | unexported: unexported, | ||
| 572 | subtype: subtype, | ||
| 573 | subfield: &subtype.fields[j], | ||
| 574 | }) | ||
| 575 | } | ||
| 576 | |||
| 577 | continue | ||
| 578 | } | ||
| 579 | |||
| 580 | if unexported { // ignore unexported non-struct types | ||
| 581 | continue | ||
| 582 | } | ||
| 583 | } | ||
| 584 | |||
| 585 | codec := constructCodec(f.Type, seen, canAddr) | ||
| 586 | |||
| 587 | if stringify { | ||
| 588 | // https://golang.org/pkg/encoding/json/#Marshal | ||
| 589 | // | ||
| 590 | // The "string" option signals that a field is stored as JSON inside | ||
| 591 | // a JSON-encoded string. It applies only to fields of string, | ||
| 592 | // floating point, integer, or boolean types. This extra level of | ||
| 593 | // encoding is sometimes used when communicating with JavaScript | ||
| 594 | // programs: | ||
| 595 | typ := f.Type | ||
| 596 | |||
| 597 | if typ.Kind() == reflect.Ptr { | ||
| 598 | typ = typ.Elem() | ||
| 599 | } | ||
| 600 | |||
| 601 | switch typ.Kind() { | ||
| 602 | case reflect.Int, | ||
| 603 | reflect.Int8, | ||
| 604 | reflect.Int16, | ||
| 605 | reflect.Int32, | ||
| 606 | reflect.Int64, | ||
| 607 | reflect.Uint, | ||
| 608 | reflect.Uintptr, | ||
| 609 | reflect.Uint8, | ||
| 610 | reflect.Uint16, | ||
| 611 | reflect.Uint32, | ||
| 612 | reflect.Uint64: | ||
| 613 | codec.encode = constructStringEncodeFunc(codec.encode) | ||
| 614 | codec.decode = constructStringToIntDecodeFunc(typ, codec.decode) | ||
| 615 | case reflect.Bool, | ||
| 616 | reflect.Float32, | ||
| 617 | reflect.Float64, | ||
| 618 | reflect.String: | ||
| 619 | codec.encode = constructStringEncodeFunc(codec.encode) | ||
| 620 | codec.decode = constructStringDecodeFunc(codec.decode) | ||
| 621 | } | ||
| 622 | } | ||
| 623 | |||
| 624 | fields = append(fields, structField{ | ||
| 625 | codec: codec, | ||
| 626 | offset: offset + f.Offset, | ||
| 627 | empty: emptyFuncOf(f.Type), | ||
| 628 | tag: tag, | ||
| 629 | omitempty: omitempty, | ||
| 630 | name: name, | ||
| 631 | index: i << 32, | ||
| 632 | typ: f.Type, | ||
| 633 | zero: reflect.Zero(f.Type), | ||
| 634 | }) | ||
| 635 | |||
| 636 | names[name] = struct{}{} | ||
| 637 | } | ||
| 638 | |||
| 639 | // Only unambiguous embedded fields must be serialized. | ||
| 640 | ambiguousNames := make(map[string]int) | ||
| 641 | ambiguousTags := make(map[string]int) | ||
| 642 | |||
| 643 | // Embedded types can never override a field that was already present at | ||
| 644 | // the top-level. | ||
| 645 | for name := range names { | ||
| 646 | ambiguousNames[name]++ | ||
| 647 | ambiguousTags[name]++ | ||
| 648 | } | ||
| 649 | |||
| 650 | for _, embfield := range embedded { | ||
| 651 | ambiguousNames[embfield.subfield.name]++ | ||
| 652 | if embfield.subfield.tag { | ||
| 653 | ambiguousTags[embfield.subfield.name]++ | ||
| 654 | } | ||
| 655 | } | ||
| 656 | |||
| 657 | for _, embfield := range embedded { | ||
| 658 | subfield := *embfield.subfield | ||
| 659 | |||
| 660 | if ambiguousNames[subfield.name] > 1 && !(subfield.tag && ambiguousTags[subfield.name] == 1) { | ||
| 661 | continue // ambiguous embedded field | ||
| 662 | } | ||
| 663 | |||
| 664 | if embfield.pointer { | ||
| 665 | subfield.codec = constructEmbeddedStructPointerCodec(embfield.subtype.typ, embfield.unexported, subfield.offset, subfield.codec) | ||
| 666 | subfield.offset = embfield.offset | ||
| 667 | } else { | ||
| 668 | subfield.offset += embfield.offset | ||
| 669 | } | ||
| 670 | |||
| 671 | // To prevent dominant flags more than one level below the embedded one. | ||
| 672 | subfield.tag = false | ||
| 673 | |||
| 674 | // To ensure the order of the fields in the output is the same is in the | ||
| 675 | // struct type. | ||
| 676 | subfield.index = embfield.index | ||
| 677 | |||
| 678 | fields = append(fields, subfield) | ||
| 679 | } | ||
| 680 | |||
| 681 | for i := range fields { | ||
| 682 | fields[i].json = encodeString(fields[i].name, 0) | ||
| 683 | fields[i].html = encodeString(fields[i].name, EscapeHTML) | ||
| 684 | } | ||
| 685 | |||
| 686 | sort.Slice(fields, func(i, j int) bool { return fields[i].index < fields[j].index }) | ||
| 687 | return fields | ||
| 688 | } | ||
| 689 | |||
| 690 | func encodeString(s string, flags AppendFlags) string { | ||
| 691 | b := make([]byte, 0, len(s)+2) | ||
| 692 | e := encoder{flags: flags} | ||
| 693 | b, _ = e.doEncodeString(b, unsafe.Pointer(&s)) | ||
| 694 | return *(*string)(unsafe.Pointer(&b)) | ||
| 695 | } | ||
| 696 | |||
| 697 | func constructPointerCodec(t reflect.Type, seen map[reflect.Type]*structType) codec { | ||
| 698 | e := t.Elem() | ||
| 699 | c := constructCodec(e, seen, true) | ||
| 700 | return codec{ | ||
| 701 | encode: constructPointerEncodeFunc(e, c.encode), | ||
| 702 | decode: constructPointerDecodeFunc(e, c.decode), | ||
| 703 | } | ||
| 704 | } | ||
| 705 | |||
| 706 | func constructPointerEncodeFunc(t reflect.Type, encode encodeFunc) encodeFunc { | ||
| 707 | return func(e encoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 708 | return e.encodePointer(b, p, t, encode) | ||
| 709 | } | ||
| 710 | } | ||
| 711 | |||
| 712 | func constructPointerDecodeFunc(t reflect.Type, decode decodeFunc) decodeFunc { | ||
| 713 | return func(d decoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 714 | return d.decodePointer(b, p, t, decode) | ||
| 715 | } | ||
| 716 | } | ||
| 717 | |||
| 718 | func constructInterfaceCodec(t reflect.Type) codec { | ||
| 719 | return codec{ | ||
| 720 | encode: constructMaybeEmptyInterfaceEncoderFunc(t), | ||
| 721 | decode: constructMaybeEmptyInterfaceDecoderFunc(t), | ||
| 722 | } | ||
| 723 | } | ||
| 724 | |||
| 725 | func constructMaybeEmptyInterfaceEncoderFunc(t reflect.Type) encodeFunc { | ||
| 726 | return func(e encoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 727 | return e.encodeMaybeEmptyInterface(b, p, t) | ||
| 728 | } | ||
| 729 | } | ||
| 730 | |||
| 731 | func constructMaybeEmptyInterfaceDecoderFunc(t reflect.Type) decodeFunc { | ||
| 732 | return func(d decoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 733 | return d.decodeMaybeEmptyInterface(b, p, t) | ||
| 734 | } | ||
| 735 | } | ||
| 736 | |||
| 737 | func constructUnsupportedTypeCodec(t reflect.Type) codec { | ||
| 738 | return codec{ | ||
| 739 | encode: constructUnsupportedTypeEncodeFunc(t), | ||
| 740 | decode: constructUnsupportedTypeDecodeFunc(t), | ||
| 741 | } | ||
| 742 | } | ||
| 743 | |||
| 744 | func constructUnsupportedTypeEncodeFunc(t reflect.Type) encodeFunc { | ||
| 745 | return func(e encoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 746 | return e.encodeUnsupportedTypeError(b, p, t) | ||
| 747 | } | ||
| 748 | } | ||
| 749 | |||
| 750 | func constructUnsupportedTypeDecodeFunc(t reflect.Type) decodeFunc { | ||
| 751 | return func(d decoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 752 | return d.decodeUnmarshalTypeError(b, p, t) | ||
| 753 | } | ||
| 754 | } | ||
| 755 | |||
| 756 | func constructJSONMarshalerEncodeFunc(t reflect.Type, pointer bool) encodeFunc { | ||
| 757 | return func(e encoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 758 | return e.encodeJSONMarshaler(b, p, t, pointer) | ||
| 759 | } | ||
| 760 | } | ||
| 761 | |||
| 762 | func constructJSONUnmarshalerDecodeFunc(t reflect.Type, pointer bool) decodeFunc { | ||
| 763 | return func(d decoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 764 | return d.decodeJSONUnmarshaler(b, p, t, pointer) | ||
| 765 | } | ||
| 766 | } | ||
| 767 | |||
| 768 | func constructTextMarshalerEncodeFunc(t reflect.Type, pointer bool) encodeFunc { | ||
| 769 | return func(e encoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 770 | return e.encodeTextMarshaler(b, p, t, pointer) | ||
| 771 | } | ||
| 772 | } | ||
| 773 | |||
| 774 | func constructTextUnmarshalerDecodeFunc(t reflect.Type, pointer bool) decodeFunc { | ||
| 775 | return func(d decoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 776 | return d.decodeTextUnmarshaler(b, p, t, pointer) | ||
| 777 | } | ||
| 778 | } | ||
| 779 | |||
| 780 | func constructInlineValueEncodeFunc(encode encodeFunc) encodeFunc { | ||
| 781 | return func(e encoder, b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 782 | return encode(e, b, noescape(unsafe.Pointer(&p))) | ||
| 783 | } | ||
| 784 | } | ||
| 785 | |||
| 786 | // noescape hides a pointer from escape analysis. noescape is | ||
| 787 | // the identity function but escape analysis doesn't think the | ||
| 788 | // output depends on the input. noescape is inlined and currently | ||
| 789 | // compiles down to zero instructions. | ||
| 790 | // USE CAREFULLY! | ||
| 791 | // This was copied from the runtime; see issues 23382 and 7921. | ||
| 792 | //go:nosplit | ||
| 793 | func noescape(p unsafe.Pointer) unsafe.Pointer { | ||
| 794 | x := uintptr(p) | ||
| 795 | return unsafe.Pointer(x ^ 0) | ||
| 796 | } | ||
| 797 | |||
| 798 | func alignedSize(t reflect.Type) uintptr { | ||
| 799 | a := t.Align() | ||
| 800 | s := t.Size() | ||
| 801 | return align(uintptr(a), uintptr(s)) | ||
| 802 | } | ||
| 803 | |||
| 804 | func align(align, size uintptr) uintptr { | ||
| 805 | if align != 0 && (size%align) != 0 { | ||
| 806 | size = ((size / align) + 1) * align | ||
| 807 | } | ||
| 808 | return size | ||
| 809 | } | ||
| 810 | |||
| 811 | func inlined(t reflect.Type) bool { | ||
| 812 | switch t.Kind() { | ||
| 813 | case reflect.Ptr: | ||
| 814 | return true | ||
| 815 | case reflect.Map: | ||
| 816 | return true | ||
| 817 | case reflect.Struct: | ||
| 818 | return t.NumField() == 1 && inlined(t.Field(0).Type) | ||
| 819 | default: | ||
| 820 | return false | ||
| 821 | } | ||
| 822 | } | ||
| 823 | |||
| 824 | func isValidTag(s string) bool { | ||
| 825 | if s == "" { | ||
| 826 | return false | ||
| 827 | } | ||
| 828 | for _, c := range s { | ||
| 829 | switch { | ||
| 830 | case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): | ||
| 831 | // Backslash and quote chars are reserved, but | ||
| 832 | // otherwise any punctuation chars are allowed | ||
| 833 | // in a tag name. | ||
| 834 | default: | ||
| 835 | if !unicode.IsLetter(c) && !unicode.IsDigit(c) { | ||
| 836 | return false | ||
| 837 | } | ||
| 838 | } | ||
| 839 | } | ||
| 840 | return true | ||
| 841 | } | ||
| 842 | |||
| 843 | func emptyFuncOf(t reflect.Type) emptyFunc { | ||
| 844 | switch t { | ||
| 845 | case bytesType, rawMessageType: | ||
| 846 | return func(p unsafe.Pointer) bool { return (*slice)(p).len == 0 } | ||
| 847 | } | ||
| 848 | |||
| 849 | switch t.Kind() { | ||
| 850 | case reflect.Array: | ||
| 851 | if t.Len() == 0 { | ||
| 852 | return func(unsafe.Pointer) bool { return true } | ||
| 853 | } | ||
| 854 | |||
| 855 | case reflect.Map: | ||
| 856 | return func(p unsafe.Pointer) bool { return reflect.NewAt(t, p).Elem().Len() == 0 } | ||
| 857 | |||
| 858 | case reflect.Slice: | ||
| 859 | return func(p unsafe.Pointer) bool { return (*slice)(p).len == 0 } | ||
| 860 | |||
| 861 | case reflect.String: | ||
| 862 | return func(p unsafe.Pointer) bool { return len(*(*string)(p)) == 0 } | ||
| 863 | |||
| 864 | case reflect.Bool: | ||
| 865 | return func(p unsafe.Pointer) bool { return !*(*bool)(p) } | ||
| 866 | |||
| 867 | case reflect.Int, reflect.Uint: | ||
| 868 | return func(p unsafe.Pointer) bool { return *(*uint)(p) == 0 } | ||
| 869 | |||
| 870 | case reflect.Uintptr: | ||
| 871 | return func(p unsafe.Pointer) bool { return *(*uintptr)(p) == 0 } | ||
| 872 | |||
| 873 | case reflect.Int8, reflect.Uint8: | ||
| 874 | return func(p unsafe.Pointer) bool { return *(*uint8)(p) == 0 } | ||
| 875 | |||
| 876 | case reflect.Int16, reflect.Uint16: | ||
| 877 | return func(p unsafe.Pointer) bool { return *(*uint16)(p) == 0 } | ||
| 878 | |||
| 879 | case reflect.Int32, reflect.Uint32: | ||
| 880 | return func(p unsafe.Pointer) bool { return *(*uint32)(p) == 0 } | ||
| 881 | |||
| 882 | case reflect.Int64, reflect.Uint64: | ||
| 883 | return func(p unsafe.Pointer) bool { return *(*uint64)(p) == 0 } | ||
| 884 | |||
| 885 | case reflect.Float32: | ||
| 886 | return func(p unsafe.Pointer) bool { return *(*float32)(p) == 0 } | ||
| 887 | |||
| 888 | case reflect.Float64: | ||
| 889 | return func(p unsafe.Pointer) bool { return *(*float64)(p) == 0 } | ||
| 890 | |||
| 891 | case reflect.Ptr: | ||
| 892 | return func(p unsafe.Pointer) bool { return *(*unsafe.Pointer)(p) == nil } | ||
| 893 | |||
| 894 | case reflect.Interface: | ||
| 895 | return func(p unsafe.Pointer) bool { return (*iface)(p).ptr == nil } | ||
| 896 | } | ||
| 897 | |||
| 898 | return func(unsafe.Pointer) bool { return false } | ||
| 899 | } | ||
| 900 | |||
| 901 | type iface struct { | ||
| 902 | typ unsafe.Pointer | ||
| 903 | ptr unsafe.Pointer | ||
| 904 | } | ||
| 905 | |||
| 906 | type slice struct { | ||
| 907 | data unsafe.Pointer | ||
| 908 | len int | ||
| 909 | cap int | ||
| 910 | } | ||
| 911 | |||
| 912 | type structType struct { | ||
| 913 | fields []structField | ||
| 914 | fieldsIndex map[string]*structField | ||
| 915 | ficaseIndex map[string]*structField | ||
| 916 | typ reflect.Type | ||
| 917 | inlined bool | ||
| 918 | } | ||
| 919 | |||
| 920 | type structField struct { | ||
| 921 | codec codec | ||
| 922 | offset uintptr | ||
| 923 | empty emptyFunc | ||
| 924 | tag bool | ||
| 925 | omitempty bool | ||
| 926 | json string | ||
| 927 | html string | ||
| 928 | name string | ||
| 929 | typ reflect.Type | ||
| 930 | zero reflect.Value | ||
| 931 | index int | ||
| 932 | } | ||
| 933 | |||
| 934 | func unmarshalTypeError(b []byte, t reflect.Type) error { | ||
| 935 | return &UnmarshalTypeError{Value: strconv.Quote(prefix(b)), Type: t} | ||
| 936 | } | ||
| 937 | |||
| 938 | func unmarshalOverflow(b []byte, t reflect.Type) error { | ||
| 939 | return &UnmarshalTypeError{Value: "number " + prefix(b) + " overflows", Type: t} | ||
| 940 | } | ||
| 941 | |||
| 942 | func unexpectedEOF(b []byte) error { | ||
| 943 | return syntaxError(b, "unexpected end of JSON input") | ||
| 944 | } | ||
| 945 | |||
| 946 | var syntaxErrorMsgOffset = ^uintptr(0) | ||
| 947 | |||
| 948 | func init() { | ||
| 949 | t := reflect.TypeOf(SyntaxError{}) | ||
| 950 | for i, n := 0, t.NumField(); i < n; i++ { | ||
| 951 | if f := t.Field(i); f.Type.Kind() == reflect.String { | ||
| 952 | syntaxErrorMsgOffset = f.Offset | ||
| 953 | } | ||
| 954 | } | ||
| 955 | } | ||
| 956 | |||
| 957 | func syntaxError(b []byte, msg string, args ...interface{}) error { | ||
| 958 | e := new(SyntaxError) | ||
| 959 | i := syntaxErrorMsgOffset | ||
| 960 | if i != ^uintptr(0) { | ||
| 961 | s := "json: " + fmt.Sprintf(msg, args...) + ": " + prefix(b) | ||
| 962 | p := unsafe.Pointer(e) | ||
| 963 | // Hack to set the unexported `msg` field. | ||
| 964 | *(*string)(unsafe.Pointer(uintptr(p) + i)) = s | ||
| 965 | } | ||
| 966 | return e | ||
| 967 | } | ||
| 968 | |||
| 969 | func inputError(b []byte, t reflect.Type) ([]byte, error) { | ||
| 970 | if len(b) == 0 { | ||
| 971 | return nil, unexpectedEOF(b) | ||
| 972 | } | ||
| 973 | _, r, err := parseValue(b) | ||
| 974 | if err != nil { | ||
| 975 | return r, err | ||
| 976 | } | ||
| 977 | return skipSpaces(r), unmarshalTypeError(b, t) | ||
| 978 | } | ||
| 979 | |||
| 980 | func objectKeyError(b []byte, err error) ([]byte, error) { | ||
| 981 | if len(b) == 0 { | ||
| 982 | return nil, unexpectedEOF(b) | ||
| 983 | } | ||
| 984 | switch err.(type) { | ||
| 985 | case *UnmarshalTypeError: | ||
| 986 | err = syntaxError(b, "invalid character '%c' looking for beginning of object key", b[0]) | ||
| 987 | } | ||
| 988 | return b, err | ||
| 989 | } | ||
| 990 | |||
| 991 | func prefix(b []byte) string { | ||
| 992 | if len(b) < 32 { | ||
| 993 | return string(b) | ||
| 994 | } | ||
| 995 | return string(b[:32]) + "..." | ||
| 996 | } | ||
| 997 | |||
| 998 | func intStringsAreSorted(i0, i1 int64) bool { | ||
| 999 | var b0, b1 [32]byte | ||
| 1000 | return string(strconv.AppendInt(b0[:0], i0, 10)) < string(strconv.AppendInt(b1[:0], i1, 10)) | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | func uintStringsAreSorted(u0, u1 uint64) bool { | ||
| 1004 | var b0, b1 [32]byte | ||
| 1005 | return string(strconv.AppendUint(b0[:0], u0, 10)) < string(strconv.AppendUint(b1[:0], u1, 10)) | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | //go:nosplit | ||
| 1009 | func stringToBytes(s string) []byte { | ||
| 1010 | return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ // nolint:govet // from segment's code | ||
| 1011 | Data: ((*reflect.StringHeader)(unsafe.Pointer(&s))).Data, | ||
| 1012 | Len: len(s), | ||
| 1013 | Cap: len(s), | ||
| 1014 | })) | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | var ( | ||
| 1018 | nullType = reflect.TypeOf(nil) | ||
| 1019 | boolType = reflect.TypeOf(false) | ||
| 1020 | |||
| 1021 | intType = reflect.TypeOf(int(0)) | ||
| 1022 | int8Type = reflect.TypeOf(int8(0)) | ||
| 1023 | int16Type = reflect.TypeOf(int16(0)) | ||
| 1024 | int32Type = reflect.TypeOf(int32(0)) | ||
| 1025 | int64Type = reflect.TypeOf(int64(0)) | ||
| 1026 | |||
| 1027 | uintType = reflect.TypeOf(uint(0)) | ||
| 1028 | uint8Type = reflect.TypeOf(uint8(0)) | ||
| 1029 | uint16Type = reflect.TypeOf(uint16(0)) | ||
| 1030 | uint32Type = reflect.TypeOf(uint32(0)) | ||
| 1031 | uint64Type = reflect.TypeOf(uint64(0)) | ||
| 1032 | uintptrType = reflect.TypeOf(uintptr(0)) | ||
| 1033 | |||
| 1034 | float32Type = reflect.TypeOf(float32(0)) | ||
| 1035 | float64Type = reflect.TypeOf(float64(0)) | ||
| 1036 | |||
| 1037 | numberType = reflect.TypeOf(json.Number("")) | ||
| 1038 | stringType = reflect.TypeOf("") | ||
| 1039 | bytesType = reflect.TypeOf(([]byte)(nil)) | ||
| 1040 | durationType = reflect.TypeOf(time.Duration(0)) | ||
| 1041 | timeType = reflect.TypeOf(time.Time{}) | ||
| 1042 | rawMessageType = reflect.TypeOf(RawMessage(nil)) | ||
| 1043 | |||
| 1044 | numberPtrType = reflect.PtrTo(numberType) | ||
| 1045 | durationPtrType = reflect.PtrTo(durationType) | ||
| 1046 | timePtrType = reflect.PtrTo(timeType) | ||
| 1047 | rawMessagePtrType = reflect.PtrTo(rawMessageType) | ||
| 1048 | |||
| 1049 | sliceInterfaceType = reflect.TypeOf(([]interface{})(nil)) | ||
| 1050 | mapStringInterfaceType = reflect.TypeOf((map[string]interface{})(nil)) | ||
| 1051 | mapStringRawMessageType = reflect.TypeOf((map[string]RawMessage)(nil)) | ||
| 1052 | |||
| 1053 | interfaceType = reflect.TypeOf((*interface{})(nil)).Elem() | ||
| 1054 | jsonMarshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() | ||
| 1055 | jsonUnmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() | ||
| 1056 | textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() | ||
| 1057 | textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() | ||
| 1058 | ) | ||
| 1059 | |||
| 1060 | // ============================================================================= | ||
| 1061 | // Copyright 2009 The Go Authors. All rights reserved. | ||
| 1062 | // Use of this source code is governed by a BSD-style | ||
| 1063 | // license that can be found in the LICENSE file. | ||
| 1064 | |||
| 1065 | // appendDuration appends a human-readable representation of d to b. | ||
| 1066 | // | ||
| 1067 | // The function copies the implementation of time.Duration.String but prevents | ||
| 1068 | // Go from making a dynamic memory allocation on the returned value. | ||
| 1069 | func appendDuration(b []byte, d time.Duration) []byte { | ||
| 1070 | // Largest time is 2540400h10m10.000000000s | ||
| 1071 | var buf [32]byte | ||
| 1072 | w := len(buf) | ||
| 1073 | |||
| 1074 | u := uint64(d) | ||
| 1075 | neg := d < 0 | ||
| 1076 | if neg { | ||
| 1077 | u = -u | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | if u < uint64(time.Second) { | ||
| 1081 | // Special case: if duration is smaller than a second, | ||
| 1082 | // use smaller units, like 1.2ms | ||
| 1083 | var prec int | ||
| 1084 | w-- | ||
| 1085 | buf[w] = 's' | ||
| 1086 | w-- | ||
| 1087 | switch { | ||
| 1088 | case u == 0: | ||
| 1089 | return append(b, '0', 's') | ||
| 1090 | case u < uint64(time.Microsecond): | ||
| 1091 | // print nanoseconds | ||
| 1092 | prec = 0 | ||
| 1093 | buf[w] = 'n' | ||
| 1094 | case u < uint64(time.Millisecond): | ||
| 1095 | // print microseconds | ||
| 1096 | prec = 3 | ||
| 1097 | // U+00B5 'µ' micro sign == 0xC2 0xB5 | ||
| 1098 | w-- // Need room for two bytes. | ||
| 1099 | copy(buf[w:], "µ") | ||
| 1100 | default: | ||
| 1101 | // print milliseconds | ||
| 1102 | prec = 6 | ||
| 1103 | buf[w] = 'm' | ||
| 1104 | } | ||
| 1105 | w, u = fmtFrac(buf[:w], u, prec) | ||
| 1106 | w = fmtInt(buf[:w], u) | ||
| 1107 | } else { | ||
| 1108 | w-- | ||
| 1109 | buf[w] = 's' | ||
| 1110 | |||
| 1111 | w, u = fmtFrac(buf[:w], u, 9) | ||
| 1112 | |||
| 1113 | // u is now integer seconds | ||
| 1114 | w = fmtInt(buf[:w], u%60) | ||
| 1115 | u /= 60 | ||
| 1116 | |||
| 1117 | // u is now integer minutes | ||
| 1118 | if u > 0 { | ||
| 1119 | w-- | ||
| 1120 | buf[w] = 'm' | ||
| 1121 | w = fmtInt(buf[:w], u%60) | ||
| 1122 | u /= 60 | ||
| 1123 | |||
| 1124 | // u is now integer hours | ||
| 1125 | // Stop at hours because days can be different lengths. | ||
| 1126 | if u > 0 { | ||
| 1127 | w-- | ||
| 1128 | buf[w] = 'h' | ||
| 1129 | w = fmtInt(buf[:w], u) | ||
| 1130 | } | ||
| 1131 | } | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | if neg { | ||
| 1135 | w-- | ||
| 1136 | buf[w] = '-' | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | return append(b, buf[w:]...) | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | // fmtFrac formats the fraction of v/10**prec (e.g., ".12345") into the | ||
| 1143 | // tail of buf, omitting trailing zeros. it omits the decimal | ||
| 1144 | // point too when the fraction is 0. It returns the index where the | ||
| 1145 | // output bytes begin and the value v/10**prec. | ||
| 1146 | func fmtFrac(buf []byte, v uint64, prec int) (nw int, nv uint64) { | ||
| 1147 | // Omit trailing zeros up to and including decimal point. | ||
| 1148 | w := len(buf) | ||
| 1149 | print := false | ||
| 1150 | for i := 0; i < prec; i++ { | ||
| 1151 | digit := v % 10 | ||
| 1152 | print = print || digit != 0 | ||
| 1153 | if print { | ||
| 1154 | w-- | ||
| 1155 | buf[w] = byte(digit) + '0' | ||
| 1156 | } | ||
| 1157 | v /= 10 | ||
| 1158 | } | ||
| 1159 | if print { | ||
| 1160 | w-- | ||
| 1161 | buf[w] = '.' | ||
| 1162 | } | ||
| 1163 | return w, v | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | // fmtInt formats v into the tail of buf. | ||
| 1167 | // It returns the index where the output begins. | ||
| 1168 | func fmtInt(buf []byte, v uint64) int { | ||
| 1169 | w := len(buf) | ||
| 1170 | if v == 0 { | ||
| 1171 | w-- | ||
| 1172 | buf[w] = '0' | ||
| 1173 | } else { | ||
| 1174 | for v > 0 { | ||
| 1175 | w-- | ||
| 1176 | buf[w] = byte(v%10) + '0' | ||
| 1177 | v /= 10 | ||
| 1178 | } | ||
| 1179 | } | ||
| 1180 | return w | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | // ============================================================================= | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/decode.go b/vendor/github.com/neilotoole/jsoncolor/decode.go new file mode 100644 index 0000000..b30a38f --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/decode.go | |||
| @@ -0,0 +1,1195 @@ | |||
| 1 | package jsoncolor | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "bytes" | ||
| 5 | "encoding" | ||
| 6 | "encoding/base64" | ||
| 7 | "encoding/json" | ||
| 8 | "fmt" | ||
| 9 | "math" | ||
| 10 | "reflect" | ||
| 11 | "strconv" | ||
| 12 | "time" | ||
| 13 | "unsafe" | ||
| 14 | ) | ||
| 15 | |||
| 16 | func (d decoder) decodeNull(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 17 | if hasNullPrefix(b) { | ||
| 18 | return b[4:], nil | ||
| 19 | } | ||
| 20 | return inputError(b, nullType) | ||
| 21 | } | ||
| 22 | |||
| 23 | func (d decoder) decodeBool(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 24 | switch { | ||
| 25 | case hasTruePrefix(b): | ||
| 26 | *(*bool)(p) = true | ||
| 27 | return b[4:], nil | ||
| 28 | |||
| 29 | case hasFalsePrefix(b): | ||
| 30 | *(*bool)(p) = false | ||
| 31 | return b[5:], nil | ||
| 32 | |||
| 33 | case hasNullPrefix(b): | ||
| 34 | return b[4:], nil | ||
| 35 | |||
| 36 | default: | ||
| 37 | return inputError(b, boolType) | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | func (d decoder) decodeInt(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 42 | if hasNullPrefix(b) { | ||
| 43 | return b[4:], nil | ||
| 44 | } | ||
| 45 | |||
| 46 | v, r, err := parseInt(b, intType) | ||
| 47 | if err != nil { | ||
| 48 | return r, err | ||
| 49 | } | ||
| 50 | |||
| 51 | *(*int)(p) = int(v) | ||
| 52 | return r, nil | ||
| 53 | } | ||
| 54 | |||
| 55 | func (d decoder) decodeInt8(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 56 | if hasNullPrefix(b) { | ||
| 57 | return b[4:], nil | ||
| 58 | } | ||
| 59 | |||
| 60 | v, r, err := parseInt(b, int8Type) | ||
| 61 | if err != nil { | ||
| 62 | return r, err | ||
| 63 | } | ||
| 64 | |||
| 65 | if v < math.MinInt8 || v > math.MaxInt8 { | ||
| 66 | return r, unmarshalOverflow(b[:len(b)-len(r)], int8Type) | ||
| 67 | } | ||
| 68 | |||
| 69 | *(*int8)(p) = int8(v) | ||
| 70 | return r, nil | ||
| 71 | } | ||
| 72 | |||
| 73 | func (d decoder) decodeInt16(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 74 | if hasNullPrefix(b) { | ||
| 75 | return b[4:], nil | ||
| 76 | } | ||
| 77 | |||
| 78 | v, r, err := parseInt(b, int16Type) | ||
| 79 | if err != nil { | ||
| 80 | return r, err | ||
| 81 | } | ||
| 82 | |||
| 83 | if v < math.MinInt16 || v > math.MaxInt16 { | ||
| 84 | return r, unmarshalOverflow(b[:len(b)-len(r)], int16Type) | ||
| 85 | } | ||
| 86 | |||
| 87 | *(*int16)(p) = int16(v) | ||
| 88 | return r, nil | ||
| 89 | } | ||
| 90 | |||
| 91 | func (d decoder) decodeInt32(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 92 | if hasNullPrefix(b) { | ||
| 93 | return b[4:], nil | ||
| 94 | } | ||
| 95 | |||
| 96 | v, r, err := parseInt(b, int32Type) | ||
| 97 | if err != nil { | ||
| 98 | return r, err | ||
| 99 | } | ||
| 100 | |||
| 101 | if v < math.MinInt32 || v > math.MaxInt32 { | ||
| 102 | return r, unmarshalOverflow(b[:len(b)-len(r)], int32Type) | ||
| 103 | } | ||
| 104 | |||
| 105 | *(*int32)(p) = int32(v) | ||
| 106 | return r, nil | ||
| 107 | } | ||
| 108 | |||
| 109 | func (d decoder) decodeInt64(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 110 | if hasNullPrefix(b) { | ||
| 111 | return b[4:], nil | ||
| 112 | } | ||
| 113 | |||
| 114 | v, r, err := parseInt(b, int64Type) | ||
| 115 | if err != nil { | ||
| 116 | return r, err | ||
| 117 | } | ||
| 118 | |||
| 119 | *(*int64)(p) = v | ||
| 120 | return r, nil | ||
| 121 | } | ||
| 122 | |||
| 123 | func (d decoder) decodeUint(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 124 | if hasNullPrefix(b) { | ||
| 125 | return b[4:], nil | ||
| 126 | } | ||
| 127 | |||
| 128 | v, r, err := parseUint(b, uintType) | ||
| 129 | if err != nil { | ||
| 130 | return r, err | ||
| 131 | } | ||
| 132 | |||
| 133 | *(*uint)(p) = uint(v) | ||
| 134 | return r, nil | ||
| 135 | } | ||
| 136 | |||
| 137 | func (d decoder) decodeUintptr(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 138 | if hasNullPrefix(b) { | ||
| 139 | return b[4:], nil | ||
| 140 | } | ||
| 141 | |||
| 142 | v, r, err := parseUint(b, uintptrType) | ||
| 143 | if err != nil { | ||
| 144 | return r, err | ||
| 145 | } | ||
| 146 | |||
| 147 | *(*uintptr)(p) = uintptr(v) | ||
| 148 | return r, nil | ||
| 149 | } | ||
| 150 | |||
| 151 | func (d decoder) decodeUint8(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 152 | if hasNullPrefix(b) { | ||
| 153 | return b[4:], nil | ||
| 154 | } | ||
| 155 | |||
| 156 | v, r, err := parseUint(b, uint8Type) | ||
| 157 | if err != nil { | ||
| 158 | return r, err | ||
| 159 | } | ||
| 160 | |||
| 161 | if v > math.MaxUint8 { | ||
| 162 | return r, unmarshalOverflow(b[:len(b)-len(r)], uint8Type) | ||
| 163 | } | ||
| 164 | |||
| 165 | *(*uint8)(p) = uint8(v) | ||
| 166 | return r, nil | ||
| 167 | } | ||
| 168 | |||
| 169 | func (d decoder) decodeUint16(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 170 | if hasNullPrefix(b) { | ||
| 171 | return b[4:], nil | ||
| 172 | } | ||
| 173 | |||
| 174 | v, r, err := parseUint(b, uint16Type) | ||
| 175 | if err != nil { | ||
| 176 | return r, err | ||
| 177 | } | ||
| 178 | |||
| 179 | if v > math.MaxUint16 { | ||
| 180 | return r, unmarshalOverflow(b[:len(b)-len(r)], uint16Type) | ||
| 181 | } | ||
| 182 | |||
| 183 | *(*uint16)(p) = uint16(v) | ||
| 184 | return r, nil | ||
| 185 | } | ||
| 186 | |||
| 187 | func (d decoder) decodeUint32(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 188 | if hasNullPrefix(b) { | ||
| 189 | return b[4:], nil | ||
| 190 | } | ||
| 191 | |||
| 192 | v, r, err := parseUint(b, uint32Type) | ||
| 193 | if err != nil { | ||
| 194 | return r, err | ||
| 195 | } | ||
| 196 | |||
| 197 | if v > math.MaxUint32 { | ||
| 198 | return r, unmarshalOverflow(b[:len(b)-len(r)], uint32Type) | ||
| 199 | } | ||
| 200 | |||
| 201 | *(*uint32)(p) = uint32(v) | ||
| 202 | return r, nil | ||
| 203 | } | ||
| 204 | |||
| 205 | func (d decoder) decodeUint64(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 206 | if hasNullPrefix(b) { | ||
| 207 | return b[4:], nil | ||
| 208 | } | ||
| 209 | |||
| 210 | v, r, err := parseUint(b, uint64Type) | ||
| 211 | if err != nil { | ||
| 212 | return r, err | ||
| 213 | } | ||
| 214 | |||
| 215 | *(*uint64)(p) = v | ||
| 216 | return r, nil | ||
| 217 | } | ||
| 218 | |||
| 219 | func (d decoder) decodeFloat32(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 220 | if hasNullPrefix(b) { | ||
| 221 | return b[4:], nil | ||
| 222 | } | ||
| 223 | |||
| 224 | v, r, err := parseNumber(b) | ||
| 225 | if err != nil { | ||
| 226 | return inputError(b, float32Type) | ||
| 227 | } | ||
| 228 | |||
| 229 | f, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&v)), 32) | ||
| 230 | if err != nil { | ||
| 231 | return inputError(b, float32Type) | ||
| 232 | } | ||
| 233 | |||
| 234 | *(*float32)(p) = float32(f) | ||
| 235 | return r, nil | ||
| 236 | } | ||
| 237 | |||
| 238 | func (d decoder) decodeFloat64(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 239 | if hasNullPrefix(b) { | ||
| 240 | return b[4:], nil | ||
| 241 | } | ||
| 242 | |||
| 243 | v, r, err := parseNumber(b) | ||
| 244 | if err != nil { | ||
| 245 | return inputError(b, float64Type) | ||
| 246 | } | ||
| 247 | |||
| 248 | f, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&v)), 64) | ||
| 249 | if err != nil { | ||
| 250 | return inputError(b, float64Type) | ||
| 251 | } | ||
| 252 | |||
| 253 | *(*float64)(p) = f | ||
| 254 | return r, nil | ||
| 255 | } | ||
| 256 | |||
| 257 | func (d decoder) decodeNumber(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 258 | if hasNullPrefix(b) { | ||
| 259 | return b[4:], nil | ||
| 260 | } | ||
| 261 | |||
| 262 | v, r, err := parseNumber(b) | ||
| 263 | if err != nil { | ||
| 264 | return inputError(b, numberType) | ||
| 265 | } | ||
| 266 | |||
| 267 | if (d.flags & DontCopyNumber) != 0 { | ||
| 268 | *(*Number)(p) = *(*Number)(unsafe.Pointer(&v)) | ||
| 269 | } else { | ||
| 270 | *(*Number)(p) = Number(v) | ||
| 271 | } | ||
| 272 | |||
| 273 | return r, nil | ||
| 274 | } | ||
| 275 | |||
| 276 | func (d decoder) decodeString(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 277 | if hasNullPrefix(b) { | ||
| 278 | return b[4:], nil | ||
| 279 | } | ||
| 280 | |||
| 281 | s, r, new, err := parseStringUnquote(b, nil) | ||
| 282 | if err != nil { | ||
| 283 | if len(b) == 0 || b[0] != '"' { | ||
| 284 | return inputError(b, stringType) | ||
| 285 | } | ||
| 286 | return r, err | ||
| 287 | } | ||
| 288 | |||
| 289 | if new || (d.flags&DontCopyString) != 0 { | ||
| 290 | *(*string)(p) = *(*string)(unsafe.Pointer(&s)) | ||
| 291 | } else { | ||
| 292 | *(*string)(p) = string(s) | ||
| 293 | } | ||
| 294 | |||
| 295 | return r, nil | ||
| 296 | } | ||
| 297 | |||
| 298 | func (d decoder) decodeFromString(b []byte, p unsafe.Pointer, decode decodeFunc) ([]byte, error) { | ||
| 299 | if hasNullPrefix(b) { | ||
| 300 | return decode(d, b, p) | ||
| 301 | } | ||
| 302 | |||
| 303 | v, b, _, err := parseStringUnquote(b, nil) | ||
| 304 | if err != nil { | ||
| 305 | return inputError(v, stringType) | ||
| 306 | } | ||
| 307 | |||
| 308 | if v, err = decode(d, v, p); err != nil { | ||
| 309 | return b, err | ||
| 310 | } | ||
| 311 | |||
| 312 | if v = skipSpaces(v); len(v) != 0 { | ||
| 313 | return b, syntaxError(v, "unexpected trailing tokens after string value") | ||
| 314 | } | ||
| 315 | |||
| 316 | return b, nil | ||
| 317 | } | ||
| 318 | |||
| 319 | func (d decoder) decodeFromStringToInt(b []byte, p unsafe.Pointer, t reflect.Type, decode decodeFunc) ([]byte, error) { | ||
| 320 | if hasPrefix(b, "null") { | ||
| 321 | return decode(d, b, p) | ||
| 322 | } | ||
| 323 | |||
| 324 | if len(b) > 0 && b[0] != '"' { | ||
| 325 | v, r, err := parseNumber(b) | ||
| 326 | if err == nil { | ||
| 327 | // The encoding/json package will return a *json.UnmarshalTypeError if | ||
| 328 | // the input was a floating point number representation, even tho a | ||
| 329 | // string is expected here. | ||
| 330 | isFloat := true | ||
| 331 | switch { | ||
| 332 | case bytes.IndexByte(v, '.') >= 0: | ||
| 333 | case bytes.IndexByte(v, 'e') >= 0: | ||
| 334 | case bytes.IndexByte(v, 'E') >= 0: | ||
| 335 | default: | ||
| 336 | isFloat = false | ||
| 337 | } | ||
| 338 | if isFloat { | ||
| 339 | _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&v)), 64) | ||
| 340 | if err != nil { | ||
| 341 | return r, unmarshalTypeError(v, t) | ||
| 342 | } | ||
| 343 | } | ||
| 344 | } | ||
| 345 | return r, fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into int") | ||
| 346 | } | ||
| 347 | |||
| 348 | if len(b) > 1 && b[0] == '"' && b[1] == '"' { | ||
| 349 | return b, fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal \"\" into int") | ||
| 350 | } | ||
| 351 | |||
| 352 | v, b, _, err := parseStringUnquote(b, nil) | ||
| 353 | if err != nil { | ||
| 354 | return inputError(v, t) | ||
| 355 | } | ||
| 356 | |||
| 357 | if hasLeadingZeroes(v) { | ||
| 358 | // In this context the encoding/json package accepts leading zeroes because | ||
| 359 | // it is not constrained by the JSON syntax, remove them so the parsing | ||
| 360 | // functions don't return syntax errors. | ||
| 361 | u := make([]byte, 0, len(v)) | ||
| 362 | i := 0 | ||
| 363 | |||
| 364 | if i < len(v) && v[i] == '-' || v[i] == '+' { | ||
| 365 | u = append(u, v[i]) | ||
| 366 | i++ | ||
| 367 | } | ||
| 368 | |||
| 369 | for (i+1) < len(v) && v[i] == '0' && '0' <= v[i+1] && v[i+1] <= '9' { | ||
| 370 | i++ | ||
| 371 | } | ||
| 372 | |||
| 373 | v = append(u, v[i:]...) | ||
| 374 | } | ||
| 375 | |||
| 376 | if r, err := decode(d, v, p); err != nil { | ||
| 377 | if _, isSyntaxError := err.(*SyntaxError); isSyntaxError { | ||
| 378 | if hasPrefix(v, "-") { | ||
| 379 | // The standard library interprets sequences of '-' characters | ||
| 380 | // as numbers but still returns type errors in this case... | ||
| 381 | return b, unmarshalTypeError(v, t) | ||
| 382 | } | ||
| 383 | return b, fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into int", prefix(v)) | ||
| 384 | } | ||
| 385 | // When the input value was a valid number representation we retain the | ||
| 386 | // error returned by the decoder. | ||
| 387 | if _, _, err := parseNumber(v); err != nil { | ||
| 388 | // When the input value valid JSON we mirror the behavior of the | ||
| 389 | // encoding/json package and return a generic error. | ||
| 390 | if _, _, err := parseValue(v); err == nil { | ||
| 391 | return b, fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into int", prefix(v)) | ||
| 392 | } | ||
| 393 | } | ||
| 394 | return b, err | ||
| 395 | } else if len(r) != 0 { | ||
| 396 | return r, unmarshalTypeError(v, t) | ||
| 397 | } | ||
| 398 | |||
| 399 | return b, nil | ||
| 400 | } | ||
| 401 | |||
| 402 | func (d decoder) decodeBytes(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 403 | if hasNullPrefix(b) { | ||
| 404 | *(*[]byte)(p) = nil | ||
| 405 | return b[4:], nil | ||
| 406 | } | ||
| 407 | |||
| 408 | if len(b) < 2 { | ||
| 409 | return inputError(b, bytesType) | ||
| 410 | } | ||
| 411 | |||
| 412 | if b[0] != '"' { | ||
| 413 | // Go 1.7- behavior: bytes slices may be decoded from array of integers. | ||
| 414 | if len(b) > 0 && b[0] == '[' { | ||
| 415 | return d.decodeSlice(b, p, 1, bytesType, decoder.decodeUint8) | ||
| 416 | } | ||
| 417 | return inputError(b, bytesType) | ||
| 418 | } | ||
| 419 | |||
| 420 | // The input string contains escaped sequences, we need to parse it before | ||
| 421 | // decoding it to match the encoding/json package behvaior. | ||
| 422 | src, r, _, err := parseStringUnquote(b, nil) | ||
| 423 | if err != nil { | ||
| 424 | return inputError(b, bytesType) | ||
| 425 | } | ||
| 426 | |||
| 427 | dst := make([]byte, base64.StdEncoding.DecodedLen(len(src))) | ||
| 428 | |||
| 429 | n, err := base64.StdEncoding.Decode(dst, src) | ||
| 430 | if err != nil { | ||
| 431 | return r, err | ||
| 432 | } | ||
| 433 | |||
| 434 | *(*[]byte)(p) = dst[:n] | ||
| 435 | return r, nil | ||
| 436 | } | ||
| 437 | |||
| 438 | func (d decoder) decodeDuration(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 439 | if hasNullPrefix(b) { | ||
| 440 | return b[4:], nil | ||
| 441 | } | ||
| 442 | |||
| 443 | // in order to inter-operate with the stdlib, we must be able to interpret | ||
| 444 | // durations passed as integer values. there's some discussion about being | ||
| 445 | // flexible on how durations are formatted, but for the time being, it's | ||
| 446 | // been punted to go2 at the earliest: https://github.com/golang/go/issues/4712 | ||
| 447 | if len(b) > 0 && b[0] != '"' { | ||
| 448 | v, r, err := parseInt(b, durationType) | ||
| 449 | if err != nil { | ||
| 450 | return inputError(b, int32Type) | ||
| 451 | } | ||
| 452 | |||
| 453 | if v < math.MinInt64 || v > math.MaxInt64 { | ||
| 454 | return r, unmarshalOverflow(b[:len(b)-len(r)], int32Type) | ||
| 455 | } | ||
| 456 | |||
| 457 | *(*time.Duration)(p) = time.Duration(v) | ||
| 458 | return r, nil | ||
| 459 | } | ||
| 460 | |||
| 461 | if len(b) < 2 || b[0] != '"' { | ||
| 462 | return inputError(b, durationType) | ||
| 463 | } | ||
| 464 | |||
| 465 | i := bytes.IndexByte(b[1:], '"') + 1 | ||
| 466 | if i <= 0 { | ||
| 467 | return inputError(b, durationType) | ||
| 468 | } | ||
| 469 | |||
| 470 | s := b[1:i] // trim quotes | ||
| 471 | |||
| 472 | v, err := time.ParseDuration(*(*string)(unsafe.Pointer(&s))) | ||
| 473 | if err != nil { | ||
| 474 | return inputError(b, durationType) | ||
| 475 | } | ||
| 476 | |||
| 477 | *(*time.Duration)(p) = v | ||
| 478 | return b[i+1:], nil | ||
| 479 | } | ||
| 480 | |||
| 481 | func (d decoder) decodeTime(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 482 | if hasNullPrefix(b) { | ||
| 483 | return b[4:], nil | ||
| 484 | } | ||
| 485 | |||
| 486 | if len(b) < 2 || b[0] != '"' { | ||
| 487 | return inputError(b, timeType) | ||
| 488 | } | ||
| 489 | |||
| 490 | i := bytes.IndexByte(b[1:], '"') + 1 | ||
| 491 | if i <= 0 { | ||
| 492 | return inputError(b, timeType) | ||
| 493 | } | ||
| 494 | |||
| 495 | s := b[1:i] // trim quotes | ||
| 496 | |||
| 497 | v, err := time.Parse(time.RFC3339Nano, *(*string)(unsafe.Pointer(&s))) | ||
| 498 | if err != nil { | ||
| 499 | return inputError(b, timeType) | ||
| 500 | } | ||
| 501 | |||
| 502 | *(*time.Time)(p) = v | ||
| 503 | return b[i+1:], nil | ||
| 504 | } | ||
| 505 | |||
| 506 | func (d decoder) decodeArray(b []byte, p unsafe.Pointer, n int, size uintptr, t reflect.Type, decode decodeFunc) ([]byte, error) { | ||
| 507 | if hasNullPrefix(b) { | ||
| 508 | return b[4:], nil | ||
| 509 | } | ||
| 510 | |||
| 511 | if len(b) < 2 || b[0] != '[' { | ||
| 512 | return inputError(b, t) | ||
| 513 | } | ||
| 514 | b = b[1:] | ||
| 515 | |||
| 516 | var err error | ||
| 517 | for i := 0; i < n; i++ { | ||
| 518 | b = skipSpaces(b) | ||
| 519 | |||
| 520 | if i != 0 { | ||
| 521 | if len(b) == 0 { | ||
| 522 | return b, syntaxError(b, "unexpected EOF after array element") | ||
| 523 | } | ||
| 524 | switch b[0] { | ||
| 525 | case ',': | ||
| 526 | b = skipSpaces(b[1:]) | ||
| 527 | case ']': | ||
| 528 | return b[1:], nil | ||
| 529 | default: | ||
| 530 | return b, syntaxError(b, "expected ',' after array element but found '%c'", b[0]) | ||
| 531 | } | ||
| 532 | } | ||
| 533 | |||
| 534 | b, err = decode(d, b, unsafe.Pointer(uintptr(p)+(uintptr(i)*size))) | ||
| 535 | if err != nil { | ||
| 536 | if e, ok := err.(*UnmarshalTypeError); ok { | ||
| 537 | e.Struct = t.String() + e.Struct | ||
| 538 | e.Field = strconv.Itoa(i) + "." + e.Field | ||
| 539 | } | ||
| 540 | return b, err | ||
| 541 | } | ||
| 542 | } | ||
| 543 | |||
| 544 | // The encoding/json package ignores extra elements found when decoding into | ||
| 545 | // array types (which have a fixed size). | ||
| 546 | for { | ||
| 547 | b = skipSpaces(b) | ||
| 548 | |||
| 549 | if len(b) == 0 { | ||
| 550 | return b, syntaxError(b, "missing closing ']' in array value") | ||
| 551 | } | ||
| 552 | |||
| 553 | switch b[0] { | ||
| 554 | case ',': | ||
| 555 | b = skipSpaces(b[1:]) | ||
| 556 | case ']': | ||
| 557 | return b[1:], nil | ||
| 558 | } | ||
| 559 | |||
| 560 | _, b, err = parseValue(b) | ||
| 561 | if err != nil { | ||
| 562 | return b, err | ||
| 563 | } | ||
| 564 | } | ||
| 565 | } | ||
| 566 | |||
| 567 | var ( | ||
| 568 | // This is a placeholder used to consturct non-nil empty slices. | ||
| 569 | empty struct{} | ||
| 570 | ) | ||
| 571 | |||
| 572 | func (d decoder) decodeSlice(b []byte, p unsafe.Pointer, size uintptr, t reflect.Type, decode decodeFunc) ([]byte, error) { | ||
| 573 | if hasNullPrefix(b) { | ||
| 574 | *(*slice)(p) = slice{} | ||
| 575 | return b[4:], nil | ||
| 576 | } | ||
| 577 | |||
| 578 | if len(b) < 2 { | ||
| 579 | return inputError(b, t) | ||
| 580 | } | ||
| 581 | |||
| 582 | if b[0] != '[' { | ||
| 583 | // Go 1.7- behavior: fallback to decoding as a []byte if the element | ||
| 584 | // type is byte; allow conversions from JSON strings even tho the | ||
| 585 | // underlying type implemented unmarshaler interfaces. | ||
| 586 | if t.Elem().Kind() == reflect.Uint8 { | ||
| 587 | return d.decodeBytes(b, p) | ||
| 588 | } | ||
| 589 | return inputError(b, t) | ||
| 590 | } | ||
| 591 | |||
| 592 | input := b | ||
| 593 | b = b[1:] | ||
| 594 | |||
| 595 | s := (*slice)(p) | ||
| 596 | s.len = 0 | ||
| 597 | |||
| 598 | var err error | ||
| 599 | for { | ||
| 600 | b = skipSpaces(b) | ||
| 601 | |||
| 602 | if len(b) != 0 && b[0] == ']' { | ||
| 603 | if s.data == nil { | ||
| 604 | s.data = unsafe.Pointer(&empty) | ||
| 605 | } | ||
| 606 | return b[1:], nil | ||
| 607 | } | ||
| 608 | |||
| 609 | if s.len != 0 { | ||
| 610 | if len(b) == 0 { | ||
| 611 | return b, syntaxError(b, "unexpected EOF after array element") | ||
| 612 | } | ||
| 613 | if b[0] != ',' { | ||
| 614 | return b, syntaxError(b, "expected ',' after array element but found '%c'", b[0]) | ||
| 615 | } | ||
| 616 | b = skipSpaces(b[1:]) | ||
| 617 | } | ||
| 618 | |||
| 619 | if s.len == s.cap { | ||
| 620 | c := s.cap | ||
| 621 | |||
| 622 | if c == 0 { | ||
| 623 | c = 10 | ||
| 624 | } else { | ||
| 625 | c *= 2 | ||
| 626 | } | ||
| 627 | |||
| 628 | *s = extendSlice(t, s, c) | ||
| 629 | } | ||
| 630 | |||
| 631 | b, err = decode(d, b, unsafe.Pointer(uintptr(s.data)+(uintptr(s.len)*size))) | ||
| 632 | if err != nil { | ||
| 633 | if _, r, err := parseValue(input); err != nil { | ||
| 634 | return r, err | ||
| 635 | } else { | ||
| 636 | b = r | ||
| 637 | } | ||
| 638 | if e, ok := err.(*UnmarshalTypeError); ok { | ||
| 639 | e.Struct = t.String() + e.Struct | ||
| 640 | e.Field = strconv.Itoa(s.len) + "." + e.Field | ||
| 641 | } | ||
| 642 | return b, err | ||
| 643 | } | ||
| 644 | |||
| 645 | s.len++ | ||
| 646 | } | ||
| 647 | } | ||
| 648 | |||
| 649 | func (d decoder) decodeMap(b []byte, p unsafe.Pointer, t, kt, vt reflect.Type, kz, vz reflect.Value, decodeKey, decodeValue decodeFunc) ([]byte, error) { | ||
| 650 | if hasNullPrefix(b) { | ||
| 651 | *(*unsafe.Pointer)(p) = nil | ||
| 652 | return b[4:], nil | ||
| 653 | } | ||
| 654 | |||
| 655 | if len(b) < 2 || b[0] != '{' { | ||
| 656 | return inputError(b, t) | ||
| 657 | } | ||
| 658 | i := 0 | ||
| 659 | m := reflect.NewAt(t, p).Elem() | ||
| 660 | |||
| 661 | k := reflect.New(kt).Elem() | ||
| 662 | v := reflect.New(vt).Elem() | ||
| 663 | |||
| 664 | kptr := (*iface)(unsafe.Pointer(&k)).ptr | ||
| 665 | vptr := (*iface)(unsafe.Pointer(&v)).ptr | ||
| 666 | input := b | ||
| 667 | |||
| 668 | if m.IsNil() { | ||
| 669 | m = reflect.MakeMap(t) | ||
| 670 | } | ||
| 671 | |||
| 672 | var err error | ||
| 673 | b = b[1:] | ||
| 674 | for { | ||
| 675 | k.Set(kz) | ||
| 676 | v.Set(vz) | ||
| 677 | b = skipSpaces(b) | ||
| 678 | |||
| 679 | if len(b) != 0 && b[0] == '}' { | ||
| 680 | *(*unsafe.Pointer)(p) = unsafe.Pointer(m.Pointer()) | ||
| 681 | return b[1:], nil | ||
| 682 | } | ||
| 683 | |||
| 684 | if i != 0 { | ||
| 685 | if len(b) == 0 { | ||
| 686 | return b, syntaxError(b, "unexpected end of JONS input after object field value") | ||
| 687 | } | ||
| 688 | if b[0] != ',' { | ||
| 689 | return b, syntaxError(b, "expected ',' after object field value but found '%c'", b[0]) | ||
| 690 | } | ||
| 691 | b = skipSpaces(b[1:]) | ||
| 692 | } | ||
| 693 | |||
| 694 | if hasPrefix(b, "null") { | ||
| 695 | return b, syntaxError(b, "cannot decode object key string from 'null' value") | ||
| 696 | } | ||
| 697 | |||
| 698 | if b, err = decodeKey(d, b, kptr); err != nil { | ||
| 699 | return objectKeyError(b, err) | ||
| 700 | } | ||
| 701 | b = skipSpaces(b) | ||
| 702 | |||
| 703 | if len(b) == 0 { | ||
| 704 | return b, syntaxError(b, "unexpected end of JSON input after object field key") | ||
| 705 | } | ||
| 706 | if b[0] != ':' { | ||
| 707 | return b, syntaxError(b, "expected ':' after object field key but found '%c'", b[0]) | ||
| 708 | } | ||
| 709 | b = skipSpaces(b[1:]) | ||
| 710 | |||
| 711 | if b, err = decodeValue(d, b, vptr); err != nil { | ||
| 712 | if _, r, err := parseValue(input); err != nil { | ||
| 713 | return r, err | ||
| 714 | } else { | ||
| 715 | b = r | ||
| 716 | } | ||
| 717 | if e, ok := err.(*UnmarshalTypeError); ok { | ||
| 718 | e.Struct = "map[" + kt.String() + "]" + vt.String() + "{" + e.Struct + "}" | ||
| 719 | e.Field = fmt.Sprint(k.Interface()) + "." + e.Field | ||
| 720 | } | ||
| 721 | return b, err | ||
| 722 | } | ||
| 723 | |||
| 724 | m.SetMapIndex(k, v) | ||
| 725 | i++ | ||
| 726 | } | ||
| 727 | } | ||
| 728 | |||
| 729 | func (d decoder) decodeMapStringInterface(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 730 | if hasNullPrefix(b) { | ||
| 731 | *(*unsafe.Pointer)(p) = nil | ||
| 732 | return b[4:], nil | ||
| 733 | } | ||
| 734 | |||
| 735 | if len(b) < 2 || b[0] != '{' { | ||
| 736 | return inputError(b, mapStringInterfaceType) | ||
| 737 | } | ||
| 738 | |||
| 739 | i := 0 | ||
| 740 | m := *(*map[string]interface{})(p) | ||
| 741 | |||
| 742 | if m == nil { | ||
| 743 | m = make(map[string]interface{}, 64) | ||
| 744 | } | ||
| 745 | |||
| 746 | var err error | ||
| 747 | var key string | ||
| 748 | var val interface{} | ||
| 749 | var input = b | ||
| 750 | |||
| 751 | b = b[1:] | ||
| 752 | for { | ||
| 753 | key = "" | ||
| 754 | val = nil | ||
| 755 | |||
| 756 | b = skipSpaces(b) | ||
| 757 | |||
| 758 | if len(b) != 0 && b[0] == '}' { | ||
| 759 | *(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(unsafe.Pointer(&m)) | ||
| 760 | return b[1:], nil | ||
| 761 | } | ||
| 762 | |||
| 763 | if i != 0 { | ||
| 764 | if len(b) == 0 { | ||
| 765 | return b, syntaxError(b, "unexpected end of JSON input after object field value") | ||
| 766 | } | ||
| 767 | if b[0] != ',' { | ||
| 768 | return b, syntaxError(b, "expected ',' after object field value but found '%c'", b[0]) | ||
| 769 | } | ||
| 770 | b = skipSpaces(b[1:]) | ||
| 771 | } | ||
| 772 | |||
| 773 | if hasPrefix(b, "null") { | ||
| 774 | return b, syntaxError(b, "cannot decode object key string from 'null' value") | ||
| 775 | } | ||
| 776 | |||
| 777 | b, err = d.decodeString(b, unsafe.Pointer(&key)) | ||
| 778 | if err != nil { | ||
| 779 | return objectKeyError(b, err) | ||
| 780 | } | ||
| 781 | b = skipSpaces(b) | ||
| 782 | |||
| 783 | if len(b) == 0 { | ||
| 784 | return b, syntaxError(b, "unexpected end of JSON input after object field key") | ||
| 785 | } | ||
| 786 | if b[0] != ':' { | ||
| 787 | return b, syntaxError(b, "expected ':' after object field key but found '%c'", b[0]) | ||
| 788 | } | ||
| 789 | b = skipSpaces(b[1:]) | ||
| 790 | |||
| 791 | b, err = d.decodeInterface(b, unsafe.Pointer(&val)) | ||
| 792 | if err != nil { | ||
| 793 | if _, r, err := parseValue(input); err != nil { | ||
| 794 | return r, err | ||
| 795 | } else { | ||
| 796 | b = r | ||
| 797 | } | ||
| 798 | if e, ok := err.(*UnmarshalTypeError); ok { | ||
| 799 | e.Struct = mapStringInterfaceType.String() + e.Struct | ||
| 800 | e.Field = key + "." + e.Field | ||
| 801 | } | ||
| 802 | return b, err | ||
| 803 | } | ||
| 804 | |||
| 805 | m[key] = val | ||
| 806 | i++ | ||
| 807 | } | ||
| 808 | } | ||
| 809 | |||
| 810 | func (d decoder) decodeMapStringRawMessage(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 811 | if hasNullPrefix(b) { | ||
| 812 | *(*unsafe.Pointer)(p) = nil | ||
| 813 | return b[4:], nil | ||
| 814 | } | ||
| 815 | |||
| 816 | if len(b) < 2 || b[0] != '{' { | ||
| 817 | return inputError(b, mapStringRawMessageType) | ||
| 818 | } | ||
| 819 | |||
| 820 | i := 0 | ||
| 821 | m := *(*map[string]RawMessage)(p) | ||
| 822 | |||
| 823 | if m == nil { | ||
| 824 | m = make(map[string]RawMessage, 64) | ||
| 825 | } | ||
| 826 | |||
| 827 | var err error | ||
| 828 | var key string | ||
| 829 | var val RawMessage | ||
| 830 | var input = b | ||
| 831 | |||
| 832 | b = b[1:] | ||
| 833 | for { | ||
| 834 | key = "" | ||
| 835 | val = nil | ||
| 836 | |||
| 837 | b = skipSpaces(b) | ||
| 838 | |||
| 839 | if len(b) != 0 && b[0] == '}' { | ||
| 840 | *(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(unsafe.Pointer(&m)) | ||
| 841 | return b[1:], nil | ||
| 842 | } | ||
| 843 | |||
| 844 | if i != 0 { | ||
| 845 | if len(b) == 0 { | ||
| 846 | return b, syntaxError(b, "unexpected end of JSON input after object field value") | ||
| 847 | } | ||
| 848 | if b[0] != ',' { | ||
| 849 | return b, syntaxError(b, "expected ',' after object field value but found '%c'", b[0]) | ||
| 850 | } | ||
| 851 | b = skipSpaces(b[1:]) | ||
| 852 | } | ||
| 853 | |||
| 854 | if hasPrefix(b, "null") { | ||
| 855 | return b, syntaxError(b, "cannot decode object key string from 'null' value") | ||
| 856 | } | ||
| 857 | |||
| 858 | b, err = d.decodeString(b, unsafe.Pointer(&key)) | ||
| 859 | if err != nil { | ||
| 860 | return objectKeyError(b, err) | ||
| 861 | } | ||
| 862 | b = skipSpaces(b) | ||
| 863 | |||
| 864 | if len(b) == 0 { | ||
| 865 | return b, syntaxError(b, "unexpected end of JSON input after object field key") | ||
| 866 | } | ||
| 867 | if b[0] != ':' { | ||
| 868 | return b, syntaxError(b, "expected ':' after object field key but found '%c'", b[0]) | ||
| 869 | } | ||
| 870 | b = skipSpaces(b[1:]) | ||
| 871 | |||
| 872 | b, err = d.decodeRawMessage(b, unsafe.Pointer(&val)) | ||
| 873 | if err != nil { | ||
| 874 | if _, r, err := parseValue(input); err != nil { | ||
| 875 | return r, err | ||
| 876 | } else { | ||
| 877 | b = r | ||
| 878 | } | ||
| 879 | if e, ok := err.(*UnmarshalTypeError); ok { | ||
| 880 | e.Struct = mapStringRawMessageType.String() + e.Struct | ||
| 881 | e.Field = key + "." + e.Field | ||
| 882 | } | ||
| 883 | return b, err | ||
| 884 | } | ||
| 885 | |||
| 886 | m[key] = val | ||
| 887 | i++ | ||
| 888 | } | ||
| 889 | } | ||
| 890 | |||
| 891 | func (d decoder) decodeStruct(b []byte, p unsafe.Pointer, st *structType) ([]byte, error) { | ||
| 892 | if hasNullPrefix(b) { | ||
| 893 | return b[4:], nil | ||
| 894 | } | ||
| 895 | |||
| 896 | if len(b) < 2 || b[0] != '{' { | ||
| 897 | return inputError(b, st.typ) | ||
| 898 | } | ||
| 899 | |||
| 900 | var err error | ||
| 901 | var k []byte | ||
| 902 | var i int | ||
| 903 | |||
| 904 | // memory buffer used to convert short field names to lowercase | ||
| 905 | var buf [64]byte | ||
| 906 | var key []byte | ||
| 907 | var input = b | ||
| 908 | |||
| 909 | b = b[1:] | ||
| 910 | for { | ||
| 911 | b = skipSpaces(b) | ||
| 912 | |||
| 913 | if len(b) != 0 && b[0] == '}' { | ||
| 914 | return b[1:], nil | ||
| 915 | } | ||
| 916 | |||
| 917 | if i != 0 { | ||
| 918 | if len(b) == 0 { | ||
| 919 | return b, syntaxError(b, "unexpected end of JSON input after object field value") | ||
| 920 | } | ||
| 921 | if b[0] != ',' { | ||
| 922 | return b, syntaxError(b, "expected ',' after object field value but found '%c'", b[0]) | ||
| 923 | } | ||
| 924 | b = skipSpaces(b[1:]) | ||
| 925 | } | ||
| 926 | i++ | ||
| 927 | |||
| 928 | if hasPrefix(b, "null") { | ||
| 929 | return b, syntaxError(b, "cannot decode object key string from 'null' value") | ||
| 930 | } | ||
| 931 | |||
| 932 | k, b, _, err = parseStringUnquote(b, nil) | ||
| 933 | if err != nil { | ||
| 934 | return objectKeyError(b, err) | ||
| 935 | } | ||
| 936 | b = skipSpaces(b) | ||
| 937 | |||
| 938 | if len(b) == 0 { | ||
| 939 | return b, syntaxError(b, "unexpected end of JSON input after object field key") | ||
| 940 | } | ||
| 941 | if b[0] != ':' { | ||
| 942 | return b, syntaxError(b, "expected ':' after object field key but found '%c'", b[0]) | ||
| 943 | } | ||
| 944 | b = skipSpaces(b[1:]) | ||
| 945 | |||
| 946 | f := st.fieldsIndex[string(k)] | ||
| 947 | |||
| 948 | if f == nil && (d.flags&DontMatchCaseInsensitiveStructFields) == 0 { | ||
| 949 | key = appendToLower(buf[:0], k) | ||
| 950 | f = st.ficaseIndex[string(key)] | ||
| 951 | } | ||
| 952 | |||
| 953 | if f == nil { | ||
| 954 | if (d.flags & DisallowUnknownFields) != 0 { | ||
| 955 | return b, fmt.Errorf("json: unknown field %q", k) | ||
| 956 | } | ||
| 957 | if _, b, err = parseValue(b); err != nil { | ||
| 958 | return b, err | ||
| 959 | } | ||
| 960 | continue | ||
| 961 | } | ||
| 962 | |||
| 963 | if b, err = f.codec.decode(d, b, unsafe.Pointer(uintptr(p)+f.offset)); err != nil { | ||
| 964 | if _, r, err := parseValue(input); err != nil { | ||
| 965 | return r, err | ||
| 966 | } else { | ||
| 967 | b = r | ||
| 968 | } | ||
| 969 | if e, ok := err.(*UnmarshalTypeError); ok { | ||
| 970 | e.Struct = st.typ.String() + e.Struct | ||
| 971 | e.Field = string(k) + "." + e.Field | ||
| 972 | } | ||
| 973 | return b, err | ||
| 974 | } | ||
| 975 | } | ||
| 976 | } | ||
| 977 | |||
| 978 | func (d decoder) decodeEmbeddedStructPointer(b []byte, p unsafe.Pointer, t reflect.Type, unexported bool, offset uintptr, decode decodeFunc) ([]byte, error) { | ||
| 979 | v := *(*unsafe.Pointer)(p) | ||
| 980 | |||
| 981 | if v == nil { | ||
| 982 | if unexported { | ||
| 983 | return nil, fmt.Errorf("json: cannot set embedded pointer to unexported struct: %s", t) | ||
| 984 | } | ||
| 985 | v = unsafe.Pointer(reflect.New(t).Pointer()) | ||
| 986 | *(*unsafe.Pointer)(p) = v | ||
| 987 | } | ||
| 988 | |||
| 989 | return decode(d, b, unsafe.Pointer(uintptr(v)+offset)) | ||
| 990 | } | ||
| 991 | |||
| 992 | func (d decoder) decodePointer(b []byte, p unsafe.Pointer, t reflect.Type, decode decodeFunc) ([]byte, error) { | ||
| 993 | if hasNullPrefix(b) { | ||
| 994 | pp := *(*unsafe.Pointer)(p) | ||
| 995 | if pp != nil && t.Kind() == reflect.Ptr { | ||
| 996 | return decode(d, b, pp) | ||
| 997 | } | ||
| 998 | *(*unsafe.Pointer)(p) = nil | ||
| 999 | return b[4:], nil | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | v := *(*unsafe.Pointer)(p) | ||
| 1003 | if v == nil { | ||
| 1004 | v = unsafe.Pointer(reflect.New(t).Pointer()) | ||
| 1005 | *(*unsafe.Pointer)(p) = v | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | return decode(d, b, v) | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | func (d decoder) decodeInterface(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 1012 | val := *(*interface{})(p) | ||
| 1013 | *(*interface{})(p) = nil | ||
| 1014 | |||
| 1015 | if t := reflect.TypeOf(val); t != nil && t.Kind() == reflect.Ptr { | ||
| 1016 | if v := reflect.ValueOf(val); v.IsNil() || t.Elem().Kind() != reflect.Ptr { | ||
| 1017 | // If the destination is nil the only value that is OK to decode is | ||
| 1018 | // `null`, and the encoding/json package always nils the destination | ||
| 1019 | // interface value in this case. | ||
| 1020 | if hasNullPrefix(b) { | ||
| 1021 | *(*interface{})(p) = nil | ||
| 1022 | return b[4:], nil | ||
| 1023 | } | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | b, err := Parse(b, val, d.flags) | ||
| 1027 | if err == nil { | ||
| 1028 | *(*interface{})(p) = val | ||
| 1029 | } | ||
| 1030 | return b, err | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | v, b, err := parseValue(b) | ||
| 1034 | if err != nil { | ||
| 1035 | return b, err | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | switch v[0] { | ||
| 1039 | case '{': | ||
| 1040 | m := make(map[string]interface{}) | ||
| 1041 | v, err = d.decodeMapStringInterface(v, unsafe.Pointer(&m)) | ||
| 1042 | val = m | ||
| 1043 | |||
| 1044 | case '[': | ||
| 1045 | a := make([]interface{}, 0, 10) | ||
| 1046 | v, err = d.decodeSlice(v, unsafe.Pointer(&a), unsafe.Sizeof(a[0]), sliceInterfaceType, decoder.decodeInterface) | ||
| 1047 | val = a | ||
| 1048 | |||
| 1049 | case '"': | ||
| 1050 | s := "" | ||
| 1051 | v, err = d.decodeString(v, unsafe.Pointer(&s)) | ||
| 1052 | val = s | ||
| 1053 | |||
| 1054 | case 'n': | ||
| 1055 | v, err = d.decodeNull(v, nil) | ||
| 1056 | val = nil | ||
| 1057 | |||
| 1058 | case 't', 'f': | ||
| 1059 | x := false | ||
| 1060 | v, err = d.decodeBool(v, unsafe.Pointer(&x)) | ||
| 1061 | val = x | ||
| 1062 | |||
| 1063 | case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': | ||
| 1064 | if (d.flags & UseNumber) != 0 { | ||
| 1065 | n := Number("") | ||
| 1066 | v, err = d.decodeNumber(v, unsafe.Pointer(&n)) | ||
| 1067 | val = n | ||
| 1068 | } else { | ||
| 1069 | f := 0.0 | ||
| 1070 | v, err = d.decodeFloat64(v, unsafe.Pointer(&f)) | ||
| 1071 | val = f | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | default: | ||
| 1075 | return b, syntaxError(v, "expected token but found '%c'", v[0]) | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | if err != nil { | ||
| 1079 | return b, err | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | if v = skipSpaces(v); len(v) != 0 { | ||
| 1083 | return b, syntaxError(v, "unexpected trailing trailing tokens after json value") | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | *(*interface{})(p) = val | ||
| 1087 | return b, nil | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | func (d decoder) decodeMaybeEmptyInterface(b []byte, p unsafe.Pointer, t reflect.Type) ([]byte, error) { | ||
| 1091 | if hasNullPrefix(b) { | ||
| 1092 | *(*interface{})(p) = nil | ||
| 1093 | return b[4:], nil | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | if x := reflect.NewAt(t, p).Elem(); !x.IsNil() { | ||
| 1097 | if e := x.Elem(); e.Kind() == reflect.Ptr { | ||
| 1098 | return Parse(b, e.Interface(), d.flags) | ||
| 1099 | } | ||
| 1100 | } else if t.NumMethod() == 0 { // empty interface | ||
| 1101 | return Parse(b, (*interface{})(p), d.flags) | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | return d.decodeUnmarshalTypeError(b, p, t) | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | func (d decoder) decodeUnmarshalTypeError(b []byte, p unsafe.Pointer, t reflect.Type) ([]byte, error) { | ||
| 1108 | v, b, err := parseValue(b) | ||
| 1109 | if err != nil { | ||
| 1110 | return b, err | ||
| 1111 | } | ||
| 1112 | return b, &UnmarshalTypeError{ | ||
| 1113 | Value: string(v), | ||
| 1114 | Type: t, | ||
| 1115 | } | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | func (d decoder) decodeRawMessage(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 1119 | v, r, err := parseValue(b) | ||
| 1120 | if err != nil { | ||
| 1121 | return inputError(b, rawMessageType) | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | if (d.flags & DontCopyRawMessage) == 0 { | ||
| 1125 | v = append(make([]byte, 0, len(v)), v...) | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | *(*RawMessage)(p) = json.RawMessage(v) | ||
| 1129 | return r, err | ||
| 1130 | } | ||
| 1131 | |||
| 1132 | func (d decoder) decodeJSONUnmarshaler(b []byte, p unsafe.Pointer, t reflect.Type, pointer bool) ([]byte, error) { | ||
| 1133 | v, b, err := parseValue(b) | ||
| 1134 | if err != nil { | ||
| 1135 | return b, err | ||
| 1136 | } | ||
| 1137 | |||
| 1138 | if len(v) != 0 && v[0] == 'n' { // null | ||
| 1139 | return b, nil | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | u := reflect.NewAt(t, p) | ||
| 1143 | if !pointer { | ||
| 1144 | u = u.Elem() | ||
| 1145 | t = t.Elem() | ||
| 1146 | } | ||
| 1147 | if u.IsNil() { | ||
| 1148 | u.Set(reflect.New(t)) | ||
| 1149 | } | ||
| 1150 | return b, u.Interface().(Unmarshaler).UnmarshalJSON(v) | ||
| 1151 | } | ||
| 1152 | |||
| 1153 | func (d decoder) decodeTextUnmarshaler(b []byte, p unsafe.Pointer, t reflect.Type, pointer bool) ([]byte, error) { | ||
| 1154 | var value string | ||
| 1155 | |||
| 1156 | v, b, err := parseValue(b) | ||
| 1157 | if err != nil { | ||
| 1158 | return b, err | ||
| 1159 | } | ||
| 1160 | if len(v) == 0 { | ||
| 1161 | return inputError(v, t) | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | switch v[0] { | ||
| 1165 | case 'n': | ||
| 1166 | _, _, err := parseNull(v) | ||
| 1167 | return b, err | ||
| 1168 | case '"': | ||
| 1169 | s, _, _, err := parseStringUnquote(v, nil) | ||
| 1170 | if err != nil { | ||
| 1171 | return b, err | ||
| 1172 | } | ||
| 1173 | u := reflect.NewAt(t, p) | ||
| 1174 | if !pointer { | ||
| 1175 | u = u.Elem() | ||
| 1176 | t = t.Elem() | ||
| 1177 | } | ||
| 1178 | if u.IsNil() { | ||
| 1179 | u.Set(reflect.New(t)) | ||
| 1180 | } | ||
| 1181 | return b, u.Interface().(encoding.TextUnmarshaler).UnmarshalText(s) | ||
| 1182 | case '{': | ||
| 1183 | value = "object" | ||
| 1184 | case '[': | ||
| 1185 | value = "array" | ||
| 1186 | case 't': | ||
| 1187 | value = "true" | ||
| 1188 | case 'f': | ||
| 1189 | value = "false" | ||
| 1190 | case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': | ||
| 1191 | value = "number" | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | return b, &UnmarshalTypeError{Value: value, Type: reflect.PtrTo(t)} | ||
| 1195 | } | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/encode.go b/vendor/github.com/neilotoole/jsoncolor/encode.go new file mode 100644 index 0000000..4259352 --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/encode.go | |||
| @@ -0,0 +1,1054 @@ | |||
| 1 | package jsoncolor | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "bytes" | ||
| 5 | "encoding" | ||
| 6 | "encoding/base64" | ||
| 7 | "math" | ||
| 8 | "reflect" | ||
| 9 | "sort" | ||
| 10 | "strconv" | ||
| 11 | "sync" | ||
| 12 | "time" | ||
| 13 | "unicode/utf8" | ||
| 14 | "unsafe" | ||
| 15 | ) | ||
| 16 | |||
| 17 | const hex = "0123456789abcdef" | ||
| 18 | |||
| 19 | func (e encoder) encodeNull(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 20 | return e.clrs.appendNull(b), nil | ||
| 21 | } | ||
| 22 | |||
| 23 | func (e encoder) encodeBool(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 24 | return e.clrs.appendBool(b, *(*bool)(p)), nil | ||
| 25 | } | ||
| 26 | |||
| 27 | func (e encoder) encodeInt(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 28 | return e.clrs.appendInt64(b, int64(*(*int)(p))), nil | ||
| 29 | } | ||
| 30 | |||
| 31 | func (e encoder) encodeInt8(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 32 | return e.clrs.appendInt64(b, int64(*(*int8)(p))), nil | ||
| 33 | } | ||
| 34 | |||
| 35 | func (e encoder) encodeInt16(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 36 | return e.clrs.appendInt64(b, int64(*(*int16)(p))), nil | ||
| 37 | } | ||
| 38 | |||
| 39 | func (e encoder) encodeInt32(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 40 | return e.clrs.appendInt64(b, int64(*(*int32)(p))), nil | ||
| 41 | } | ||
| 42 | |||
| 43 | func (e encoder) encodeInt64(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 44 | return e.clrs.appendInt64(b, *(*int64)(p)), nil | ||
| 45 | } | ||
| 46 | |||
| 47 | func (e encoder) encodeUint(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 48 | return e.clrs.appendUint64(b, uint64(*(*uint)(p))), nil | ||
| 49 | } | ||
| 50 | |||
| 51 | func (e encoder) encodeUintptr(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 52 | return e.clrs.appendUint64(b, uint64(*(*uintptr)(p))), nil | ||
| 53 | } | ||
| 54 | |||
| 55 | func (e encoder) encodeUint8(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 56 | return e.clrs.appendUint64(b, uint64(*(*uint8)(p))), nil | ||
| 57 | } | ||
| 58 | |||
| 59 | func (e encoder) encodeUint16(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 60 | return e.clrs.appendUint64(b, uint64(*(*uint16)(p))), nil | ||
| 61 | } | ||
| 62 | |||
| 63 | func (e encoder) encodeUint32(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 64 | return e.clrs.appendUint64(b, uint64(*(*uint32)(p))), nil | ||
| 65 | } | ||
| 66 | |||
| 67 | func (e encoder) encodeUint64(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 68 | return e.clrs.appendUint64(b, *(*uint64)(p)), nil | ||
| 69 | } | ||
| 70 | |||
| 71 | func (e encoder) encodeFloat32(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 72 | if e.clrs == nil { | ||
| 73 | return e.encodeFloat(b, float64(*(*float32)(p)), 32) | ||
| 74 | } | ||
| 75 | |||
| 76 | b = append(b, e.clrs.Number...) | ||
| 77 | var err error | ||
| 78 | b, err = e.encodeFloat(b, float64(*(*float32)(p)), 32) | ||
| 79 | b = append(b, ansiReset...) | ||
| 80 | return b, err | ||
| 81 | } | ||
| 82 | |||
| 83 | func (e encoder) encodeFloat64(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 84 | if e.clrs == nil { | ||
| 85 | return e.encodeFloat(b, *(*float64)(p), 64) | ||
| 86 | } | ||
| 87 | |||
| 88 | b = append(b, e.clrs.Number...) | ||
| 89 | var err error | ||
| 90 | b, err = e.encodeFloat(b, *(*float64)(p), 64) | ||
| 91 | b = append(b, ansiReset...) | ||
| 92 | return b, err | ||
| 93 | } | ||
| 94 | |||
| 95 | func (e encoder) encodeFloat(b []byte, f float64, bits int) ([]byte, error) { | ||
| 96 | switch { | ||
| 97 | case math.IsNaN(f): | ||
| 98 | return b, &UnsupportedValueError{Value: reflect.ValueOf(f), Str: "NaN"} | ||
| 99 | case math.IsInf(f, 0): | ||
| 100 | return b, &UnsupportedValueError{Value: reflect.ValueOf(f), Str: "inf"} | ||
| 101 | } | ||
| 102 | |||
| 103 | // Convert as if by ES6 number to string conversion. | ||
| 104 | // This matches most other JSON generators. | ||
| 105 | // See golang.org/issue/6384 and golang.org/issue/14135. | ||
| 106 | // Like fmt %g, but the exponent cutoffs are different | ||
| 107 | // and exponents themselves are not padded to two digits. | ||
| 108 | abs := math.Abs(f) | ||
| 109 | fmt := byte('f') | ||
| 110 | // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. | ||
| 111 | if abs != 0 { | ||
| 112 | if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { | ||
| 113 | fmt = 'e' | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | b = strconv.AppendFloat(b, f, fmt, -1, int(bits)) | ||
| 118 | |||
| 119 | if fmt == 'e' { | ||
| 120 | // clean up e-09 to e-9 | ||
| 121 | n := len(b) | ||
| 122 | if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' { | ||
| 123 | b[n-2] = b[n-1] | ||
| 124 | b = b[:n-1] | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | return b, nil | ||
| 129 | } | ||
| 130 | |||
| 131 | func (e encoder) encodeNumber(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 132 | n := *(*Number)(p) | ||
| 133 | if n == "" { | ||
| 134 | n = "0" | ||
| 135 | } | ||
| 136 | |||
| 137 | _, _, err := parseNumber(stringToBytes(string(n))) | ||
| 138 | if err != nil { | ||
| 139 | return b, err | ||
| 140 | } | ||
| 141 | |||
| 142 | if e.clrs == nil { | ||
| 143 | return append(b, n...), nil | ||
| 144 | } | ||
| 145 | |||
| 146 | b = append(b, e.clrs.Number...) | ||
| 147 | b = append(b, n...) | ||
| 148 | b = append(b, ansiReset...) | ||
| 149 | return b, nil | ||
| 150 | } | ||
| 151 | |||
| 152 | func (e encoder) encodeKey(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 153 | if e.clrs == nil { | ||
| 154 | return e.doEncodeString(b, p) | ||
| 155 | } | ||
| 156 | |||
| 157 | b = append(b, e.clrs.Key...) | ||
| 158 | var err error | ||
| 159 | b, err = e.doEncodeString(b, p) | ||
| 160 | b = append(b, ansiReset...) | ||
| 161 | return b, err | ||
| 162 | } | ||
| 163 | |||
| 164 | func (e encoder) encodeString(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 165 | if e.clrs == nil { | ||
| 166 | return e.doEncodeString(b, p) | ||
| 167 | } | ||
| 168 | |||
| 169 | b = append(b, e.clrs.String...) | ||
| 170 | var err error | ||
| 171 | b, err = e.doEncodeString(b, p) | ||
| 172 | b = append(b, ansiReset...) | ||
| 173 | return b, err | ||
| 174 | } | ||
| 175 | |||
| 176 | func (e encoder) doEncodeString(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 177 | s := *(*string)(p) | ||
| 178 | i := 0 | ||
| 179 | j := 0 | ||
| 180 | escapeHTML := (e.flags & EscapeHTML) != 0 | ||
| 181 | |||
| 182 | b = append(b, '"') | ||
| 183 | |||
| 184 | for j < len(s) { | ||
| 185 | c := s[j] | ||
| 186 | |||
| 187 | if c >= 0x20 && c <= 0x7f && c != '\\' && c != '"' && (!escapeHTML || (c != '<' && c != '>' && c != '&')) { | ||
| 188 | // fast path: most of the time, printable ascii characters are used | ||
| 189 | j++ | ||
| 190 | continue | ||
| 191 | } | ||
| 192 | |||
| 193 | switch c { | ||
| 194 | case '\\', '"': | ||
| 195 | b = append(b, s[i:j]...) | ||
| 196 | b = append(b, '\\', c) | ||
| 197 | i = j + 1 | ||
| 198 | j = j + 1 | ||
| 199 | continue | ||
| 200 | |||
| 201 | case '\n': | ||
| 202 | b = append(b, s[i:j]...) | ||
| 203 | b = append(b, '\\', 'n') | ||
| 204 | i = j + 1 | ||
| 205 | j = j + 1 | ||
| 206 | continue | ||
| 207 | |||
| 208 | case '\r': | ||
| 209 | b = append(b, s[i:j]...) | ||
| 210 | b = append(b, '\\', 'r') | ||
| 211 | i = j + 1 | ||
| 212 | j = j + 1 | ||
| 213 | continue | ||
| 214 | |||
| 215 | case '\t': | ||
| 216 | b = append(b, s[i:j]...) | ||
| 217 | b = append(b, '\\', 't') | ||
| 218 | i = j + 1 | ||
| 219 | j = j + 1 | ||
| 220 | continue | ||
| 221 | |||
| 222 | case '<', '>', '&': | ||
| 223 | b = append(b, s[i:j]...) | ||
| 224 | b = append(b, `\u00`...) | ||
| 225 | b = append(b, hex[c>>4], hex[c&0xF]) | ||
| 226 | i = j + 1 | ||
| 227 | j = j + 1 | ||
| 228 | continue | ||
| 229 | } | ||
| 230 | |||
| 231 | // This encodes bytes < 0x20 except for \t, \n and \r. | ||
| 232 | if c < 0x20 { | ||
| 233 | b = append(b, s[i:j]...) | ||
| 234 | b = append(b, `\u00`...) | ||
| 235 | b = append(b, hex[c>>4], hex[c&0xF]) | ||
| 236 | i = j + 1 | ||
| 237 | j = j + 1 | ||
| 238 | continue | ||
| 239 | } | ||
| 240 | |||
| 241 | r, size := utf8.DecodeRuneInString(s[j:]) | ||
| 242 | |||
| 243 | if r == utf8.RuneError && size == 1 { | ||
| 244 | b = append(b, s[i:j]...) | ||
| 245 | b = append(b, `\ufffd`...) | ||
| 246 | i = j + size | ||
| 247 | j = j + size | ||
| 248 | continue | ||
| 249 | } | ||
| 250 | |||
| 251 | switch r { | ||
| 252 | case '\u2028', '\u2029': | ||
| 253 | // U+2028 is LINE SEPARATOR. | ||
| 254 | // U+2029 is PARAGRAPH SEPARATOR. | ||
| 255 | // They are both technically valid characters in JSON strings, | ||
| 256 | // but don't work in JSONP, which has to be evaluated as JavaScript, | ||
| 257 | // and can lead to security holes there. It is valid JSON to | ||
| 258 | // escape them, so we do so unconditionally. | ||
| 259 | // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. | ||
| 260 | b = append(b, s[i:j]...) | ||
| 261 | b = append(b, `\u202`...) | ||
| 262 | b = append(b, hex[r&0xF]) | ||
| 263 | i = j + size | ||
| 264 | j = j + size | ||
| 265 | continue | ||
| 266 | } | ||
| 267 | |||
| 268 | j += size | ||
| 269 | } | ||
| 270 | |||
| 271 | b = append(b, s[i:]...) | ||
| 272 | b = append(b, '"') | ||
| 273 | return b, nil | ||
| 274 | } | ||
| 275 | |||
| 276 | func (e encoder) encodeToString(b []byte, p unsafe.Pointer, encode encodeFunc) ([]byte, error) { | ||
| 277 | i := len(b) | ||
| 278 | |||
| 279 | b, err := encode(e, b, p) | ||
| 280 | if err != nil { | ||
| 281 | return b, err | ||
| 282 | } | ||
| 283 | |||
| 284 | j := len(b) | ||
| 285 | s := b[i:] | ||
| 286 | |||
| 287 | if b, err = e.doEncodeString(b, unsafe.Pointer(&s)); err != nil { | ||
| 288 | return b, err | ||
| 289 | } | ||
| 290 | |||
| 291 | n := copy(b[i:], b[j:]) | ||
| 292 | return b[:i+n], nil | ||
| 293 | } | ||
| 294 | |||
| 295 | func (e encoder) encodeBytes(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 296 | if e.clrs == nil { | ||
| 297 | return e.doEncodeBytes(b, p) | ||
| 298 | } | ||
| 299 | |||
| 300 | b = append(b, e.clrs.Bytes...) | ||
| 301 | var err error | ||
| 302 | b, err = e.doEncodeBytes(b, p) | ||
| 303 | return append(b, ansiReset...), err | ||
| 304 | } | ||
| 305 | |||
| 306 | func (e encoder) doEncodeBytes(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 307 | v := *(*[]byte)(p) | ||
| 308 | if v == nil { | ||
| 309 | return e.clrs.appendNull(b), nil | ||
| 310 | } | ||
| 311 | |||
| 312 | n := base64.StdEncoding.EncodedLen(len(v)) + 2 | ||
| 313 | |||
| 314 | if avail := cap(b) - len(b); avail < n { | ||
| 315 | newB := make([]byte, cap(b)+(n-avail)) | ||
| 316 | copy(newB, b) | ||
| 317 | b = newB[:len(b)] | ||
| 318 | } | ||
| 319 | |||
| 320 | i := len(b) | ||
| 321 | j := len(b) + n | ||
| 322 | |||
| 323 | b = b[:j] | ||
| 324 | b[i] = '"' | ||
| 325 | base64.StdEncoding.Encode(b[i+1:j-1], v) | ||
| 326 | b[j-1] = '"' | ||
| 327 | return b, nil | ||
| 328 | } | ||
| 329 | |||
| 330 | func (e encoder) encodeDuration(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 331 | // NOTE: The segmentj encoder does special handling for time.Duration (converts to string). | ||
| 332 | // The stdlib encoder does not. It just outputs the int64 value. | ||
| 333 | // We choose to follow the stdlib pattern, for fuller compatibility. | ||
| 334 | |||
| 335 | b = e.clrs.appendInt64(b, int64(*(*time.Duration)(p))) | ||
| 336 | return b, nil | ||
| 337 | |||
| 338 | // NOTE: if we were to follow the segmentj pattern, we'd execute the code below. | ||
| 339 | //if e.clrs == nil { | ||
| 340 | // b = append(b, '"') | ||
| 341 | // | ||
| 342 | // b = appendDuration(b, *(*time.Duration)(p)) | ||
| 343 | // b = append(b, '"') | ||
| 344 | // return b, nil | ||
| 345 | //} | ||
| 346 | // | ||
| 347 | //b = append(b, e.clrs.Time...) | ||
| 348 | //b = append(b, '"') | ||
| 349 | //b = appendDuration(b, *(*time.Duration)(p)) | ||
| 350 | //b = append(b, '"') | ||
| 351 | //b = append(b, ansiReset...) | ||
| 352 | //return b, nil | ||
| 353 | } | ||
| 354 | |||
| 355 | func (e encoder) encodeTime(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 356 | if e.clrs == nil { | ||
| 357 | t := *(*time.Time)(p) | ||
| 358 | b = append(b, '"') | ||
| 359 | b = t.AppendFormat(b, time.RFC3339Nano) | ||
| 360 | b = append(b, '"') | ||
| 361 | return b, nil | ||
| 362 | } | ||
| 363 | |||
| 364 | t := *(*time.Time)(p) | ||
| 365 | b = append(b, e.clrs.Time...) | ||
| 366 | b = append(b, '"') | ||
| 367 | b = t.AppendFormat(b, time.RFC3339Nano) | ||
| 368 | b = append(b, '"') | ||
| 369 | b = append(b, ansiReset...) | ||
| 370 | return b, nil | ||
| 371 | } | ||
| 372 | |||
| 373 | func (e encoder) encodeArray(b []byte, p unsafe.Pointer, n int, size uintptr, t reflect.Type, encode encodeFunc) ([]byte, error) { | ||
| 374 | var start = len(b) | ||
| 375 | var err error | ||
| 376 | |||
| 377 | b = e.clrs.appendPunc(b, '[') | ||
| 378 | |||
| 379 | if n > 0 { | ||
| 380 | e.indentr.push() | ||
| 381 | for i := 0; i < n; i++ { | ||
| 382 | if i != 0 { | ||
| 383 | b = e.clrs.appendPunc(b, ',') | ||
| 384 | } | ||
| 385 | |||
| 386 | b = e.indentr.appendByte(b, '\n') | ||
| 387 | b = e.indentr.appendIndent(b) | ||
| 388 | |||
| 389 | if b, err = encode(e, b, unsafe.Pointer(uintptr(p)+(uintptr(i)*size))); err != nil { | ||
| 390 | return b[:start], err | ||
| 391 | } | ||
| 392 | } | ||
| 393 | e.indentr.pop() | ||
| 394 | b = e.indentr.appendByte(b, '\n') | ||
| 395 | b = e.indentr.appendIndent(b) | ||
| 396 | } | ||
| 397 | |||
| 398 | b = e.clrs.appendPunc(b, ']') | ||
| 399 | |||
| 400 | return b, nil | ||
| 401 | } | ||
| 402 | |||
| 403 | func (e encoder) encodeSlice(b []byte, p unsafe.Pointer, size uintptr, t reflect.Type, encode encodeFunc) ([]byte, error) { | ||
| 404 | s := (*slice)(p) | ||
| 405 | |||
| 406 | if s.data == nil && s.len == 0 && s.cap == 0 { | ||
| 407 | return e.clrs.appendNull(b), nil | ||
| 408 | } | ||
| 409 | |||
| 410 | return e.encodeArray(b, s.data, s.len, size, t, encode) | ||
| 411 | } | ||
| 412 | |||
| 413 | func (e encoder) encodeMap(b []byte, p unsafe.Pointer, t reflect.Type, encodeKey, encodeValue encodeFunc, sortKeys sortFunc) ([]byte, error) { | ||
| 414 | m := reflect.NewAt(t, p).Elem() | ||
| 415 | if m.IsNil() { | ||
| 416 | return e.clrs.appendNull(b), nil | ||
| 417 | } | ||
| 418 | |||
| 419 | keys := m.MapKeys() | ||
| 420 | if sortKeys != nil && (e.flags&SortMapKeys) != 0 { | ||
| 421 | sortKeys(keys) | ||
| 422 | } | ||
| 423 | |||
| 424 | var start = len(b) | ||
| 425 | var err error | ||
| 426 | b = e.clrs.appendPunc(b, '{') | ||
| 427 | |||
| 428 | if len(keys) != 0 { | ||
| 429 | b = e.indentr.appendByte(b, '\n') | ||
| 430 | |||
| 431 | e.indentr.push() | ||
| 432 | for i, k := range keys { | ||
| 433 | v := m.MapIndex(k) | ||
| 434 | |||
| 435 | if i != 0 { | ||
| 436 | b = e.clrs.appendPunc(b, ',') | ||
| 437 | b = e.indentr.appendByte(b, '\n') | ||
| 438 | } | ||
| 439 | |||
| 440 | b = e.indentr.appendIndent(b) | ||
| 441 | if b, err = encodeKey(e, b, (*iface)(unsafe.Pointer(&k)).ptr); err != nil { | ||
| 442 | return b[:start], err | ||
| 443 | } | ||
| 444 | |||
| 445 | b = e.clrs.appendPunc(b, ':') | ||
| 446 | b = e.indentr.appendByte(b, ' ') | ||
| 447 | |||
| 448 | if b, err = encodeValue(e, b, (*iface)(unsafe.Pointer(&v)).ptr); err != nil { | ||
| 449 | return b[:start], err | ||
| 450 | } | ||
| 451 | } | ||
| 452 | b = e.indentr.appendByte(b, '\n') | ||
| 453 | e.indentr.pop() | ||
| 454 | b = e.indentr.appendIndent(b) | ||
| 455 | } | ||
| 456 | |||
| 457 | b = e.clrs.appendPunc(b, '}') | ||
| 458 | return b, nil | ||
| 459 | } | ||
| 460 | |||
| 461 | type element struct { | ||
| 462 | key string | ||
| 463 | val interface{} | ||
| 464 | raw RawMessage | ||
| 465 | } | ||
| 466 | |||
| 467 | type mapslice struct { | ||
| 468 | elements []element | ||
| 469 | } | ||
| 470 | |||
| 471 | func (m *mapslice) Len() int { return len(m.elements) } | ||
| 472 | func (m *mapslice) Less(i, j int) bool { return m.elements[i].key < m.elements[j].key } | ||
| 473 | func (m *mapslice) Swap(i, j int) { m.elements[i], m.elements[j] = m.elements[j], m.elements[i] } | ||
| 474 | |||
| 475 | var mapslicePool = sync.Pool{ | ||
| 476 | New: func() interface{} { return new(mapslice) }, | ||
| 477 | } | ||
| 478 | |||
| 479 | func (e encoder) encodeMapStringInterface(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 480 | m := *(*map[string]interface{})(p) | ||
| 481 | if m == nil { | ||
| 482 | return e.clrs.appendNull(b), nil | ||
| 483 | } | ||
| 484 | |||
| 485 | if (e.flags & SortMapKeys) == 0 { | ||
| 486 | // Optimized code path when the program does not need the map keys to be | ||
| 487 | // sorted. | ||
| 488 | b = e.clrs.appendPunc(b, '{') | ||
| 489 | |||
| 490 | if len(m) != 0 { | ||
| 491 | b = e.indentr.appendByte(b, '\n') | ||
| 492 | |||
| 493 | var err error | ||
| 494 | var i = 0 | ||
| 495 | |||
| 496 | e.indentr.push() | ||
| 497 | for k, v := range m { | ||
| 498 | if i != 0 { | ||
| 499 | b = e.clrs.appendPunc(b, ',') | ||
| 500 | b = e.indentr.appendByte(b, '\n') | ||
| 501 | } | ||
| 502 | |||
| 503 | b = e.indentr.appendIndent(b) | ||
| 504 | |||
| 505 | b, err = e.encodeKey(b, unsafe.Pointer(&k)) | ||
| 506 | if err != nil { | ||
| 507 | return b, err | ||
| 508 | } | ||
| 509 | |||
| 510 | b = e.clrs.appendPunc(b, ':') | ||
| 511 | b = e.indentr.appendByte(b, ' ') | ||
| 512 | |||
| 513 | b, err = Append(b, v, e.flags, e.clrs, e.indentr) | ||
| 514 | if err != nil { | ||
| 515 | return b, err | ||
| 516 | } | ||
| 517 | |||
| 518 | i++ | ||
| 519 | } | ||
| 520 | b = e.indentr.appendByte(b, '\n') | ||
| 521 | e.indentr.pop() | ||
| 522 | b = e.indentr.appendIndent(b) | ||
| 523 | } | ||
| 524 | |||
| 525 | b = e.clrs.appendPunc(b, '}') | ||
| 526 | return b, nil | ||
| 527 | } | ||
| 528 | |||
| 529 | s := mapslicePool.Get().(*mapslice) | ||
| 530 | if cap(s.elements) < len(m) { | ||
| 531 | s.elements = make([]element, 0, align(10, uintptr(len(m)))) | ||
| 532 | } | ||
| 533 | for key, val := range m { | ||
| 534 | s.elements = append(s.elements, element{key: key, val: val}) | ||
| 535 | } | ||
| 536 | sort.Sort(s) | ||
| 537 | |||
| 538 | var start = len(b) | ||
| 539 | var err error | ||
| 540 | b = e.clrs.appendPunc(b, '{') | ||
| 541 | |||
| 542 | if len(s.elements) > 0 { | ||
| 543 | b = e.indentr.appendByte(b, '\n') | ||
| 544 | |||
| 545 | e.indentr.push() | ||
| 546 | for i, elem := range s.elements { | ||
| 547 | if i != 0 { | ||
| 548 | b = e.clrs.appendPunc(b, ',') | ||
| 549 | b = e.indentr.appendByte(b, '\n') | ||
| 550 | } | ||
| 551 | |||
| 552 | b = e.indentr.appendIndent(b) | ||
| 553 | |||
| 554 | b, _ = e.encodeKey(b, unsafe.Pointer(&elem.key)) | ||
| 555 | b = e.clrs.appendPunc(b, ':') | ||
| 556 | b = e.indentr.appendByte(b, ' ') | ||
| 557 | |||
| 558 | b, err = Append(b, elem.val, e.flags, e.clrs, e.indentr) | ||
| 559 | if err != nil { | ||
| 560 | break | ||
| 561 | } | ||
| 562 | } | ||
| 563 | b = e.indentr.appendByte(b, '\n') | ||
| 564 | e.indentr.pop() | ||
| 565 | b = e.indentr.appendIndent(b) | ||
| 566 | } | ||
| 567 | |||
| 568 | for i := range s.elements { | ||
| 569 | s.elements[i] = element{} | ||
| 570 | } | ||
| 571 | |||
| 572 | s.elements = s.elements[:0] | ||
| 573 | mapslicePool.Put(s) | ||
| 574 | |||
| 575 | if err != nil { | ||
| 576 | return b[:start], err | ||
| 577 | } | ||
| 578 | |||
| 579 | b = e.clrs.appendPunc(b, '}') | ||
| 580 | return b, nil | ||
| 581 | } | ||
| 582 | |||
| 583 | func (e encoder) encodeMapStringRawMessage(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 584 | m := *(*map[string]RawMessage)(p) | ||
| 585 | if m == nil { | ||
| 586 | return e.clrs.appendNull(b), nil | ||
| 587 | } | ||
| 588 | |||
| 589 | if (e.flags & SortMapKeys) == 0 { | ||
| 590 | // Optimized code path when the program does not need the map keys to be | ||
| 591 | // sorted. | ||
| 592 | b = e.clrs.appendPunc(b, '{') | ||
| 593 | |||
| 594 | if len(m) != 0 { | ||
| 595 | b = e.indentr.appendByte(b, '\n') | ||
| 596 | |||
| 597 | var err error | ||
| 598 | var i = 0 | ||
| 599 | |||
| 600 | e.indentr.push() | ||
| 601 | for k, v := range m { | ||
| 602 | if i != 0 { | ||
| 603 | b = e.clrs.appendPunc(b, ',') | ||
| 604 | b = e.indentr.appendByte(b, '\n') | ||
| 605 | } | ||
| 606 | |||
| 607 | b = e.indentr.appendIndent(b) | ||
| 608 | |||
| 609 | b, _ = e.encodeKey(b, unsafe.Pointer(&k)) | ||
| 610 | |||
| 611 | b = e.clrs.appendPunc(b, ':') | ||
| 612 | b = e.indentr.appendByte(b, ' ') | ||
| 613 | |||
| 614 | b, err = e.encodeRawMessage(b, unsafe.Pointer(&v)) | ||
| 615 | if err != nil { | ||
| 616 | break | ||
| 617 | } | ||
| 618 | |||
| 619 | i++ | ||
| 620 | } | ||
| 621 | b = e.indentr.appendByte(b, '\n') | ||
| 622 | e.indentr.pop() | ||
| 623 | b = e.indentr.appendIndent(b) | ||
| 624 | } | ||
| 625 | |||
| 626 | b = e.clrs.appendPunc(b, '}') | ||
| 627 | return b, nil | ||
| 628 | } | ||
| 629 | |||
| 630 | s := mapslicePool.Get().(*mapslice) | ||
| 631 | if cap(s.elements) < len(m) { | ||
| 632 | s.elements = make([]element, 0, align(10, uintptr(len(m)))) | ||
| 633 | } | ||
| 634 | for key, raw := range m { | ||
| 635 | s.elements = append(s.elements, element{key: key, raw: raw}) | ||
| 636 | } | ||
| 637 | sort.Sort(s) | ||
| 638 | |||
| 639 | var start = len(b) | ||
| 640 | var err error | ||
| 641 | b = e.clrs.appendPunc(b, '{') | ||
| 642 | |||
| 643 | if len(s.elements) > 0 { | ||
| 644 | b = e.indentr.appendByte(b, '\n') | ||
| 645 | |||
| 646 | e.indentr.push() | ||
| 647 | |||
| 648 | for i, elem := range s.elements { | ||
| 649 | if i != 0 { | ||
| 650 | b = e.clrs.appendPunc(b, ',') | ||
| 651 | b = e.indentr.appendByte(b, '\n') | ||
| 652 | } | ||
| 653 | |||
| 654 | b = e.indentr.appendIndent(b) | ||
| 655 | |||
| 656 | b, _ = e.encodeKey(b, unsafe.Pointer(&elem.key)) | ||
| 657 | b = e.clrs.appendPunc(b, ':') | ||
| 658 | b = e.indentr.appendByte(b, ' ') | ||
| 659 | |||
| 660 | b, err = e.encodeRawMessage(b, unsafe.Pointer(&elem.raw)) | ||
| 661 | if err != nil { | ||
| 662 | break | ||
| 663 | } | ||
| 664 | } | ||
| 665 | b = e.indentr.appendByte(b, '\n') | ||
| 666 | e.indentr.pop() | ||
| 667 | b = e.indentr.appendIndent(b) | ||
| 668 | } | ||
| 669 | |||
| 670 | for i := range s.elements { | ||
| 671 | s.elements[i] = element{} | ||
| 672 | } | ||
| 673 | |||
| 674 | s.elements = s.elements[:0] | ||
| 675 | mapslicePool.Put(s) | ||
| 676 | |||
| 677 | if err != nil { | ||
| 678 | return b[:start], err | ||
| 679 | } | ||
| 680 | |||
| 681 | b = e.clrs.appendPunc(b, '}') | ||
| 682 | return b, nil | ||
| 683 | } | ||
| 684 | |||
| 685 | func (e encoder) encodeStruct(b []byte, p unsafe.Pointer, st *structType) ([]byte, error) { | ||
| 686 | var start = len(b) | ||
| 687 | var err error | ||
| 688 | var k string | ||
| 689 | var n int | ||
| 690 | |||
| 691 | b = e.clrs.appendPunc(b, '{') | ||
| 692 | |||
| 693 | if len(st.fields) > 0 { | ||
| 694 | b = e.indentr.appendByte(b, '\n') | ||
| 695 | } | ||
| 696 | |||
| 697 | e.indentr.push() | ||
| 698 | |||
| 699 | for i := range st.fields { | ||
| 700 | f := &st.fields[i] | ||
| 701 | v := unsafe.Pointer(uintptr(p) + f.offset) | ||
| 702 | |||
| 703 | if f.omitempty && f.empty(v) { | ||
| 704 | continue | ||
| 705 | } | ||
| 706 | |||
| 707 | if n != 0 { | ||
| 708 | b = e.clrs.appendPunc(b, ',') | ||
| 709 | b = e.indentr.appendByte(b, '\n') | ||
| 710 | } | ||
| 711 | |||
| 712 | if (e.flags & EscapeHTML) != 0 { | ||
| 713 | k = f.html | ||
| 714 | } else { | ||
| 715 | k = f.json | ||
| 716 | } | ||
| 717 | |||
| 718 | lengthBeforeKey := len(b) | ||
| 719 | b = e.indentr.appendIndent(b) | ||
| 720 | |||
| 721 | if e.clrs == nil { | ||
| 722 | b = append(b, k...) | ||
| 723 | } else { | ||
| 724 | b = append(b, e.clrs.Key...) | ||
| 725 | b = append(b, k...) | ||
| 726 | b = append(b, ansiReset...) | ||
| 727 | } | ||
| 728 | |||
| 729 | b = e.clrs.appendPunc(b, ':') | ||
| 730 | |||
| 731 | b = e.indentr.appendByte(b, ' ') | ||
| 732 | |||
| 733 | if b, err = f.codec.encode(e, b, v); err != nil { | ||
| 734 | if err == (rollback{}) { | ||
| 735 | b = b[:lengthBeforeKey] | ||
| 736 | continue | ||
| 737 | } | ||
| 738 | return b[:start], err | ||
| 739 | } | ||
| 740 | |||
| 741 | n++ | ||
| 742 | } | ||
| 743 | |||
| 744 | if n > 0 { | ||
| 745 | b = e.indentr.appendByte(b, '\n') | ||
| 746 | } | ||
| 747 | |||
| 748 | e.indentr.pop() | ||
| 749 | b = e.indentr.appendIndent(b) | ||
| 750 | |||
| 751 | b = e.clrs.appendPunc(b, '}') | ||
| 752 | return b, nil | ||
| 753 | } | ||
| 754 | |||
| 755 | type rollback struct{} | ||
| 756 | |||
| 757 | func (rollback) Error() string { return "rollback" } | ||
| 758 | |||
| 759 | func (e encoder) encodeEmbeddedStructPointer(b []byte, p unsafe.Pointer, t reflect.Type, unexported bool, offset uintptr, encode encodeFunc) ([]byte, error) { | ||
| 760 | p = *(*unsafe.Pointer)(p) | ||
| 761 | if p == nil { | ||
| 762 | return b, rollback{} | ||
| 763 | } | ||
| 764 | return encode(e, b, unsafe.Pointer(uintptr(p)+offset)) | ||
| 765 | } | ||
| 766 | |||
| 767 | func (e encoder) encodePointer(b []byte, p unsafe.Pointer, t reflect.Type, encode encodeFunc) ([]byte, error) { | ||
| 768 | if p = *(*unsafe.Pointer)(p); p != nil { | ||
| 769 | return encode(e, b, p) | ||
| 770 | } | ||
| 771 | return e.encodeNull(b, nil) | ||
| 772 | } | ||
| 773 | |||
| 774 | func (e encoder) encodeInterface(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 775 | return Append(b, *(*interface{})(p), e.flags, e.clrs, e.indentr) | ||
| 776 | } | ||
| 777 | |||
| 778 | func (e encoder) encodeMaybeEmptyInterface(b []byte, p unsafe.Pointer, t reflect.Type) ([]byte, error) { | ||
| 779 | return Append(b, reflect.NewAt(t, p).Elem().Interface(), e.flags, e.clrs, e.indentr) | ||
| 780 | } | ||
| 781 | |||
| 782 | func (e encoder) encodeUnsupportedTypeError(b []byte, p unsafe.Pointer, t reflect.Type) ([]byte, error) { | ||
| 783 | return b, &UnsupportedTypeError{Type: t} | ||
| 784 | } | ||
| 785 | |||
| 786 | // encodeRawMessage encodes a RawMessage to bytes. Unfortunately, this | ||
| 787 | // implementation has a deficiency: it uses Unmarshal to build an | ||
| 788 | // object from the RawMessage, which in the case of a struct, results | ||
| 789 | // in a map being constructed, and thus the order of the keys is not | ||
| 790 | // guaranteed to be maintained. A superior implementation would decode and | ||
| 791 | // then re-encode (with color/indentation) the basic JSON tokens on the fly. | ||
| 792 | // Note also that if TrustRawMessage is set, and the RawMessage is | ||
| 793 | // invalid JSON (cannot be parsed by Unmarshal), then this function | ||
| 794 | // falls back to encodeRawMessageNoParseTrusted, which seems to exhibit the | ||
| 795 | // correct behavior. It's a bit of a mess, but seems to do the trick. | ||
| 796 | func (e encoder) encodeRawMessage(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 797 | v := *(*RawMessage)(p) | ||
| 798 | |||
| 799 | if v == nil { | ||
| 800 | return e.clrs.appendNull(b), nil | ||
| 801 | } | ||
| 802 | |||
| 803 | var s []byte | ||
| 804 | |||
| 805 | if (e.flags & TrustRawMessage) != 0 { | ||
| 806 | s = v | ||
| 807 | } else { | ||
| 808 | var err error | ||
| 809 | s, _, err = parseValue(v) | ||
| 810 | if err != nil { | ||
| 811 | return b, &UnsupportedValueError{Value: reflect.ValueOf(v), Str: err.Error()} | ||
| 812 | } | ||
| 813 | } | ||
| 814 | |||
| 815 | var x interface{} | ||
| 816 | if err := Unmarshal(s, &x); err != nil { | ||
| 817 | return e.encodeRawMessageNoParseTrusted(b, p) | ||
| 818 | } | ||
| 819 | |||
| 820 | return Append(b, x, e.flags, e.clrs, e.indentr) | ||
| 821 | } | ||
| 822 | |||
| 823 | // encodeRawMessageNoParseTrusted is a fallback method that is | ||
| 824 | // used by encodeRawMessage if it fails to parse a trusted RawMessage. | ||
| 825 | // The (invalid) JSON produced by this method is not colorized. | ||
| 826 | // This method may have wonky logic or even bugs in it; little effort | ||
| 827 | // has been expended on it because it's a rarely visited edge case. | ||
| 828 | func (e encoder) encodeRawMessageNoParseTrusted(b []byte, p unsafe.Pointer) ([]byte, error) { | ||
| 829 | v := *(*RawMessage)(p) | ||
| 830 | |||
| 831 | if v == nil { | ||
| 832 | return e.clrs.appendNull(b), nil | ||
| 833 | } | ||
| 834 | |||
| 835 | var s []byte | ||
| 836 | |||
| 837 | if (e.flags & TrustRawMessage) != 0 { | ||
| 838 | s = v | ||
| 839 | } else { | ||
| 840 | var err error | ||
| 841 | s, _, err = parseValue(v) | ||
| 842 | if err != nil { | ||
| 843 | return b, &UnsupportedValueError{Value: reflect.ValueOf(v), Str: err.Error()} | ||
| 844 | } | ||
| 845 | } | ||
| 846 | |||
| 847 | if e.indentr == nil { | ||
| 848 | if (e.flags & EscapeHTML) != 0 { | ||
| 849 | return appendCompactEscapeHTML(b, s), nil | ||
| 850 | } | ||
| 851 | |||
| 852 | return append(b, s...), nil | ||
| 853 | } | ||
| 854 | |||
| 855 | // In order to get the tests inherited from the original segmentio | ||
| 856 | // encoder to work, we need to support indentation. | ||
| 857 | |||
| 858 | // This below is sloppy, but seems to work. | ||
| 859 | if (e.flags & EscapeHTML) != 0 { | ||
| 860 | s = appendCompactEscapeHTML(nil, s) | ||
| 861 | } | ||
| 862 | |||
| 863 | // The "prefix" arg to Indent is the current indentation. | ||
| 864 | pre := e.indentr.appendIndent(nil) | ||
| 865 | |||
| 866 | buf := &bytes.Buffer{} | ||
| 867 | // And now we just make use of the existing Indent function. | ||
| 868 | err := Indent(buf, s, string(pre), e.indentr.indent) | ||
| 869 | if err != nil { | ||
| 870 | return b, err | ||
| 871 | } | ||
| 872 | |||
| 873 | s = buf.Bytes() | ||
| 874 | |||
| 875 | return append(b, s...), nil | ||
| 876 | } | ||
| 877 | |||
| 878 | |||
| 879 | // encodeJSONMarshaler suffers from the same defect as encodeRawMessage; it | ||
| 880 | // can result in keys being reordered. | ||
| 881 | func (e encoder) encodeJSONMarshaler(b []byte, p unsafe.Pointer, t reflect.Type, pointer bool) ([]byte, error) { | ||
| 882 | v := reflect.NewAt(t, p) | ||
| 883 | |||
| 884 | if !pointer { | ||
| 885 | v = v.Elem() | ||
| 886 | } | ||
| 887 | |||
| 888 | switch v.Kind() { | ||
| 889 | case reflect.Ptr, reflect.Interface: | ||
| 890 | if v.IsNil() { | ||
| 891 | return e.clrs.appendNull(b), nil | ||
| 892 | } | ||
| 893 | } | ||
| 894 | |||
| 895 | j, err := v.Interface().(Marshaler).MarshalJSON() | ||
| 896 | if err != nil { | ||
| 897 | return b, err | ||
| 898 | } | ||
| 899 | |||
| 900 | // We effectively delegate to the encodeRawMessage method. | ||
| 901 | return Append(b, RawMessage(j), e.flags, e.clrs, e.indentr) | ||
| 902 | } | ||
| 903 | |||
| 904 | func (e encoder) encodeTextMarshaler(b []byte, p unsafe.Pointer, t reflect.Type, pointer bool) ([]byte, error) { | ||
| 905 | v := reflect.NewAt(t, p) | ||
| 906 | |||
| 907 | if !pointer { | ||
| 908 | v = v.Elem() | ||
| 909 | } | ||
| 910 | |||
| 911 | switch v.Kind() { | ||
| 912 | case reflect.Ptr, reflect.Interface: | ||
| 913 | if v.IsNil() { | ||
| 914 | return e.clrs.appendNull(b), nil | ||
| 915 | } | ||
| 916 | } | ||
| 917 | |||
| 918 | s, err := v.Interface().(encoding.TextMarshaler).MarshalText() | ||
| 919 | if err != nil { | ||
| 920 | return b, err | ||
| 921 | } | ||
| 922 | |||
| 923 | if e.clrs == nil { | ||
| 924 | return e.doEncodeString(b, unsafe.Pointer(&s)) | ||
| 925 | } | ||
| 926 | |||
| 927 | b = append(b, e.clrs.TextMarshaler...) | ||
| 928 | b, err = e.doEncodeString(b, unsafe.Pointer(&s)) | ||
| 929 | b = append(b, ansiReset...) | ||
| 930 | return b, err | ||
| 931 | } | ||
| 932 | |||
| 933 | func appendCompactEscapeHTML(dst []byte, src []byte) []byte { | ||
| 934 | start := 0 | ||
| 935 | escape := false | ||
| 936 | inString := false | ||
| 937 | |||
| 938 | for i, c := range src { | ||
| 939 | if !inString { | ||
| 940 | switch c { | ||
| 941 | case '"': // enter string | ||
| 942 | inString = true | ||
| 943 | case ' ', '\n', '\r', '\t': // skip space | ||
| 944 | if start < i { | ||
| 945 | dst = append(dst, src[start:i]...) | ||
| 946 | } | ||
| 947 | start = i + 1 | ||
| 948 | } | ||
| 949 | continue | ||
| 950 | } | ||
| 951 | |||
| 952 | if escape { | ||
| 953 | escape = false | ||
| 954 | continue | ||
| 955 | } | ||
| 956 | |||
| 957 | if c == '\\' { | ||
| 958 | escape = true | ||
| 959 | continue | ||
| 960 | } | ||
| 961 | |||
| 962 | if c == '"' { | ||
| 963 | inString = false | ||
| 964 | continue | ||
| 965 | } | ||
| 966 | |||
| 967 | if c == '<' || c == '>' || c == '&' { | ||
| 968 | if start < i { | ||
| 969 | dst = append(dst, src[start:i]...) | ||
| 970 | } | ||
| 971 | dst = append(dst, `\u00`...) | ||
| 972 | dst = append(dst, hex[c>>4], hex[c&0xF]) | ||
| 973 | start = i + 1 | ||
| 974 | continue | ||
| 975 | } | ||
| 976 | |||
| 977 | // Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9). | ||
| 978 | if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 { | ||
| 979 | if start < i { | ||
| 980 | dst = append(dst, src[start:i]...) | ||
| 981 | } | ||
| 982 | dst = append(dst, `\u202`...) | ||
| 983 | dst = append(dst, hex[src[i+2]&0xF]) | ||
| 984 | start = i + 3 | ||
| 985 | continue | ||
| 986 | } | ||
| 987 | } | ||
| 988 | |||
| 989 | if start < len(src) { | ||
| 990 | dst = append(dst, src[start:]...) | ||
| 991 | } | ||
| 992 | |||
| 993 | return dst | ||
| 994 | } | ||
| 995 | |||
| 996 | // indenter is used to indent JSON. The push and pop methods | ||
| 997 | // change indentation level. The appendIndent method appends the | ||
| 998 | // computed indentation. The appendByte method appends a byte. All | ||
| 999 | // methods are safe to use with a nil receiver. | ||
| 1000 | type indenter struct { | ||
| 1001 | disabled bool | ||
| 1002 | prefix string | ||
| 1003 | indent string | ||
| 1004 | depth int | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | // newIndenter returns a new indenter instance. If prefix and | ||
| 1008 | // indent are both empty, the indenter is effectively disabled, | ||
| 1009 | // and the appendIndent and appendByte methods are no-op. | ||
| 1010 | func newIndenter(prefix, indent string) *indenter { | ||
| 1011 | return &indenter{ | ||
| 1012 | disabled: prefix == "" && indent == "", | ||
| 1013 | prefix: prefix, | ||
| 1014 | indent: indent, | ||
| 1015 | } | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | // push increases the indentation level. | ||
| 1019 | func (in *indenter) push() { | ||
| 1020 | if in != nil { | ||
| 1021 | in.depth++ | ||
| 1022 | } | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | // pop decreases the indentation level. | ||
| 1026 | func (in *indenter) pop() { | ||
| 1027 | if in != nil { | ||
| 1028 | in.depth-- | ||
| 1029 | } | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | // appendByte appends a to b if the indenter is non-nil and enabled. | ||
| 1033 | // Otherwise b is returned unmodified. | ||
| 1034 | func (in *indenter) appendByte(b []byte, a byte) []byte { | ||
| 1035 | if in == nil || in.disabled { | ||
| 1036 | return b | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | return append(b, a) | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | // appendIndent writes indentation to b, returning the resulting slice. | ||
| 1043 | // If the indenter is nil or disabled b is returned unchanged. | ||
| 1044 | func (in *indenter) appendIndent(b []byte) []byte { | ||
| 1045 | if in == nil || in.disabled { | ||
| 1046 | return b | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | b = append(b, in.prefix...) | ||
| 1050 | for i := 0; i < in.depth; i++ { | ||
| 1051 | b = append(b, in.indent...) | ||
| 1052 | } | ||
| 1053 | return b | ||
| 1054 | } | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/json.go b/vendor/github.com/neilotoole/jsoncolor/json.go new file mode 100644 index 0000000..3dc5b46 --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/json.go | |||
| @@ -0,0 +1,459 @@ | |||
| 1 | package jsoncolor | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "bytes" | ||
| 5 | "encoding/json" | ||
| 6 | "io" | ||
| 7 | "reflect" | ||
| 8 | "runtime" | ||
| 9 | "sync" | ||
| 10 | "unsafe" | ||
| 11 | ) | ||
| 12 | |||
| 13 | // Delim is documented at https://golang.org/pkg/encoding/json/#Delim | ||
| 14 | type Delim = json.Delim | ||
| 15 | |||
| 16 | // InvalidUTF8Error is documented at https://golang.org/pkg/encoding/json/#InvalidUTF8Error | ||
| 17 | type InvalidUTF8Error = json.InvalidUTF8Error | ||
| 18 | |||
| 19 | // InvalidUnmarshalError is documented at https://golang.org/pkg/encoding/json/#InvalidUnmarshalError | ||
| 20 | type InvalidUnmarshalError = json.InvalidUnmarshalError | ||
| 21 | |||
| 22 | // Marshaler is documented at https://golang.org/pkg/encoding/json/#Marshaler | ||
| 23 | type Marshaler = json.Marshaler | ||
| 24 | |||
| 25 | // MarshalerError is documented at https://golang.org/pkg/encoding/json/#MarshalerError | ||
| 26 | type MarshalerError = json.MarshalerError | ||
| 27 | |||
| 28 | // Number is documented at https://golang.org/pkg/encoding/json/#Number | ||
| 29 | type Number = json.Number | ||
| 30 | |||
| 31 | // RawMessage is documented at https://golang.org/pkg/encoding/json/#RawMessage | ||
| 32 | type RawMessage = json.RawMessage | ||
| 33 | |||
| 34 | // A SyntaxError is a description of a JSON syntax error. | ||
| 35 | type SyntaxError = json.SyntaxError | ||
| 36 | |||
| 37 | // Token is documented at https://golang.org/pkg/encoding/json/#Token | ||
| 38 | type Token = json.Token | ||
| 39 | |||
| 40 | // UnmarshalFieldError is documented at https://golang.org/pkg/encoding/json/#UnmarshalFieldError | ||
| 41 | type UnmarshalFieldError = json.UnmarshalFieldError | ||
| 42 | |||
| 43 | // UnmarshalTypeError is documented at https://golang.org/pkg/encoding/json/#UnmarshalTypeError | ||
| 44 | type UnmarshalTypeError = json.UnmarshalTypeError | ||
| 45 | |||
| 46 | // Unmarshaler is documented at https://golang.org/pkg/encoding/json/#Unmarshaler | ||
| 47 | type Unmarshaler = json.Unmarshaler | ||
| 48 | |||
| 49 | // UnsupportedTypeError is documented at https://golang.org/pkg/encoding/json/#UnsupportedTypeError | ||
| 50 | type UnsupportedTypeError = json.UnsupportedTypeError | ||
| 51 | |||
| 52 | // UnsupportedValueError is documented at https://golang.org/pkg/encoding/json/#UnsupportedValueError | ||
| 53 | type UnsupportedValueError = json.UnsupportedValueError | ||
| 54 | |||
| 55 | // AppendFlags is a type used to represent configuration options that can be | ||
| 56 | // applied when formatting json output. | ||
| 57 | type AppendFlags int | ||
| 58 | |||
| 59 | const ( | ||
| 60 | // EscapeHTML is a formatting flag used to to escape HTML in json strings. | ||
| 61 | EscapeHTML AppendFlags = 1 << iota | ||
| 62 | |||
| 63 | // SortMapKeys is formatting flag used to enable sorting of map keys when | ||
| 64 | // encoding JSON (this matches the behavior of the standard encoding/json | ||
| 65 | // package). | ||
| 66 | SortMapKeys | ||
| 67 | |||
| 68 | // TrustRawMessage is a performance optimization flag to skip value | ||
| 69 | // checking of raw messages. It should only be used if the values are | ||
| 70 | // known to be valid json (e.g., they were created by json.Unmarshal). | ||
| 71 | TrustRawMessage | ||
| 72 | ) | ||
| 73 | |||
| 74 | // ParseFlags is a type used to represent configuration options that can be | ||
| 75 | // applied when parsing json input. | ||
| 76 | type ParseFlags int | ||
| 77 | |||
| 78 | const ( | ||
| 79 | // DisallowUnknownFields is a parsing flag used to prevent decoding of | ||
| 80 | // objects to Go struct values when a field of the input does not match | ||
| 81 | // with any of the struct fields. | ||
| 82 | DisallowUnknownFields ParseFlags = 1 << iota | ||
| 83 | |||
| 84 | // UseNumber is a parsing flag used to load numeric values as Number | ||
| 85 | // instead of float64. | ||
| 86 | UseNumber | ||
| 87 | |||
| 88 | // DontCopyString is a parsing flag used to provide zero-copy support when | ||
| 89 | // loading string values from a json payload. It is not always possible to | ||
| 90 | // avoid dynamic memory allocations, for example when a string is escaped in | ||
| 91 | // the json data a new buffer has to be allocated, but when the `wire` value | ||
| 92 | // can be used as content of a Go value the decoder will simply point into | ||
| 93 | // the input buffer. | ||
| 94 | DontCopyString | ||
| 95 | |||
| 96 | // DontCopyNumber is a parsing flag used to provide zero-copy support when | ||
| 97 | // loading Number values (see DontCopyString and DontCopyRawMessage). | ||
| 98 | DontCopyNumber | ||
| 99 | |||
| 100 | // DontCopyRawMessage is a parsing flag used to provide zero-copy support | ||
| 101 | // when loading RawMessage values from a json payload. When used, the | ||
| 102 | // RawMessage values will not be allocated into new memory buffers and | ||
| 103 | // will instead point directly to the area of the input buffer where the | ||
| 104 | // value was found. | ||
| 105 | DontCopyRawMessage | ||
| 106 | |||
| 107 | // DontMatchCaseInsensitiveStructFields is a parsing flag used to prevent | ||
| 108 | // matching fields in a case-insensitive way. This can prevent degrading | ||
| 109 | // performance on case conversions, and can also act as a stricter decoding | ||
| 110 | // mode. | ||
| 111 | DontMatchCaseInsensitiveStructFields | ||
| 112 | |||
| 113 | // ZeroCopy is a parsing flag that combines all the copy optimizations | ||
| 114 | // available in the package. | ||
| 115 | // | ||
| 116 | // The zero-copy optimizations are better used in request-handler style | ||
| 117 | // code where none of the values are retained after the handler returns. | ||
| 118 | ZeroCopy = DontCopyString | DontCopyNumber | DontCopyRawMessage | ||
| 119 | ) | ||
| 120 | |||
| 121 | // Append acts like Marshal but appends the json representation to b instead of | ||
| 122 | // always reallocating a new slice. | ||
| 123 | func Append(b []byte, x interface{}, flags AppendFlags, clrs *Colors, indentr *indenter) ([]byte, error) { | ||
| 124 | if x == nil { | ||
| 125 | // Special case for nil values because it makes the rest of the code | ||
| 126 | // simpler to assume that it won't be seeing nil pointers. | ||
| 127 | return clrs.appendNull(b), nil | ||
| 128 | } | ||
| 129 | |||
| 130 | t := reflect.TypeOf(x) | ||
| 131 | p := (*iface)(unsafe.Pointer(&x)).ptr | ||
| 132 | |||
| 133 | cache := cacheLoad() | ||
| 134 | c, found := cache[typeid(t)] | ||
| 135 | |||
| 136 | if !found { | ||
| 137 | c = constructCachedCodec(t, cache) | ||
| 138 | } | ||
| 139 | |||
| 140 | b, err := c.encode(encoder{flags: flags, clrs: clrs, indentr: indentr}, b, p) | ||
| 141 | runtime.KeepAlive(x) | ||
| 142 | return b, err | ||
| 143 | } | ||
| 144 | |||
| 145 | // Compact is documented at https://golang.org/pkg/encoding/json/#Compact | ||
| 146 | func Compact(dst *bytes.Buffer, src []byte) error { | ||
| 147 | return json.Compact(dst, src) | ||
| 148 | } | ||
| 149 | |||
| 150 | // HTMLEscape is documented at https://golang.org/pkg/encoding/json/#HTMLEscape | ||
| 151 | func HTMLEscape(dst *bytes.Buffer, src []byte) { | ||
| 152 | json.HTMLEscape(dst, src) | ||
| 153 | } | ||
| 154 | |||
| 155 | // Indent is documented at https://golang.org/pkg/encoding/json/#Indent | ||
| 156 | func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error { | ||
| 157 | return json.Indent(dst, src, prefix, indent) | ||
| 158 | } | ||
| 159 | |||
| 160 | // Marshal is documented at https://golang.org/pkg/encoding/json/#Marshal | ||
| 161 | func Marshal(x interface{}) ([]byte, error) { | ||
| 162 | var err error | ||
| 163 | var buf = encoderBufferPool.Get().(*encoderBuffer) | ||
| 164 | |||
| 165 | if buf.data, err = Append(buf.data[:0], x, EscapeHTML|SortMapKeys, nil, nil); err != nil { | ||
| 166 | return nil, err | ||
| 167 | } | ||
| 168 | |||
| 169 | b := make([]byte, len(buf.data)) | ||
| 170 | copy(b, buf.data) | ||
| 171 | encoderBufferPool.Put(buf) | ||
| 172 | return b, nil | ||
| 173 | } | ||
| 174 | |||
| 175 | // MarshalIndent is documented at https://golang.org/pkg/encoding/json/#MarshalIndent | ||
| 176 | func MarshalIndent(x interface{}, prefix, indent string) ([]byte, error) { | ||
| 177 | b, err := Marshal(x) | ||
| 178 | |||
| 179 | if err == nil { | ||
| 180 | tmp := &bytes.Buffer{} | ||
| 181 | tmp.Grow(2 * len(b)) | ||
| 182 | |||
| 183 | if err = Indent(tmp, b, prefix, indent); err != nil { | ||
| 184 | return b, err | ||
| 185 | } | ||
| 186 | |||
| 187 | b = tmp.Bytes() | ||
| 188 | } | ||
| 189 | |||
| 190 | return b, err | ||
| 191 | } | ||
| 192 | |||
| 193 | // Unmarshal is documented at https://golang.org/pkg/encoding/json/#Unmarshal | ||
| 194 | func Unmarshal(b []byte, x interface{}) error { | ||
| 195 | r, err := Parse(b, x, 0) | ||
| 196 | if len(r) != 0 { | ||
| 197 | if _, ok := err.(*SyntaxError); !ok { | ||
| 198 | // The encoding/json package prioritizes reporting errors caused by | ||
| 199 | // unexpected trailing bytes over other issues; here we emulate this | ||
| 200 | // behavior by overriding the error. | ||
| 201 | err = syntaxError(r, "invalid character '%c' after top-level value", r[0]) | ||
| 202 | } | ||
| 203 | } | ||
| 204 | return err | ||
| 205 | } | ||
| 206 | |||
| 207 | // Parse behaves like Unmarshal but the caller can pass a set of flags to | ||
| 208 | // configure the parsing behavior. | ||
| 209 | func Parse(b []byte, x interface{}, flags ParseFlags) ([]byte, error) { | ||
| 210 | t := reflect.TypeOf(x) | ||
| 211 | p := (*iface)(unsafe.Pointer(&x)).ptr | ||
| 212 | |||
| 213 | if t == nil || p == nil || t.Kind() != reflect.Ptr { | ||
| 214 | _, r, err := parseValue(skipSpaces(b)) | ||
| 215 | r = skipSpaces(r) | ||
| 216 | if err != nil { | ||
| 217 | return r, err | ||
| 218 | } | ||
| 219 | return r, &InvalidUnmarshalError{Type: t} | ||
| 220 | } | ||
| 221 | t = t.Elem() | ||
| 222 | |||
| 223 | cache := cacheLoad() | ||
| 224 | c, found := cache[typeid(t)] | ||
| 225 | |||
| 226 | if !found { | ||
| 227 | c = constructCachedCodec(t, cache) | ||
| 228 | } | ||
| 229 | |||
| 230 | r, err := c.decode(decoder{flags: flags}, skipSpaces(b), p) | ||
| 231 | return skipSpaces(r), err | ||
| 232 | } | ||
| 233 | |||
| 234 | // Valid is documented at https://golang.org/pkg/encoding/json/#Valid | ||
| 235 | func Valid(data []byte) bool { | ||
| 236 | _, data, err := parseValue(skipSpaces(data)) | ||
| 237 | if err != nil { | ||
| 238 | return false | ||
| 239 | } | ||
| 240 | return len(skipSpaces(data)) == 0 | ||
| 241 | } | ||
| 242 | |||
| 243 | // Decoder is documented at https://golang.org/pkg/encoding/json/#Decoder | ||
| 244 | type Decoder struct { | ||
| 245 | reader io.Reader | ||
| 246 | buffer []byte | ||
| 247 | remain []byte | ||
| 248 | inputOffset int64 | ||
| 249 | err error | ||
| 250 | flags ParseFlags | ||
| 251 | } | ||
| 252 | |||
| 253 | // NewDecoder is documented at https://golang.org/pkg/encoding/json/#NewDecoder | ||
| 254 | func NewDecoder(r io.Reader) *Decoder { return &Decoder{reader: r} } | ||
| 255 | |||
| 256 | // Buffered is documented at https://golang.org/pkg/encoding/json/#Decoder.Buffered | ||
| 257 | func (dec *Decoder) Buffered() io.Reader { | ||
| 258 | return bytes.NewReader(dec.remain) | ||
| 259 | } | ||
| 260 | |||
| 261 | // Decode is documented at https://golang.org/pkg/encoding/json/#Decoder.Decode | ||
| 262 | func (dec *Decoder) Decode(v interface{}) error { | ||
| 263 | raw, err := dec.readValue() | ||
| 264 | if err != nil { | ||
| 265 | return err | ||
| 266 | } | ||
| 267 | _, err = Parse(raw, v, dec.flags) | ||
| 268 | return err | ||
| 269 | } | ||
| 270 | |||
| 271 | const ( | ||
| 272 | minBufferSize = 32768 | ||
| 273 | minReadSize = 4096 | ||
| 274 | ) | ||
| 275 | |||
| 276 | // readValue reads one JSON value from the buffer and returns its raw bytes. It | ||
| 277 | // is optimized for the "one JSON value per line" case. | ||
| 278 | func (dec *Decoder) readValue() (v []byte, err error) { | ||
| 279 | var n int | ||
| 280 | var r []byte | ||
| 281 | |||
| 282 | for { | ||
| 283 | if len(dec.remain) != 0 { | ||
| 284 | v, r, err = parseValue(dec.remain) | ||
| 285 | if err == nil { | ||
| 286 | dec.remain, n = skipSpacesN(r) | ||
| 287 | dec.inputOffset += int64(len(v) + n) | ||
| 288 | return | ||
| 289 | } | ||
| 290 | if len(r) != 0 { | ||
| 291 | // Parsing of the next JSON value stopped at a position other | ||
| 292 | // than the end of the input buffer, which indicaates that a | ||
| 293 | // syntax error was encountered. | ||
| 294 | return | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | if err = dec.err; err != nil { | ||
| 299 | if len(dec.remain) != 0 && err == io.EOF { | ||
| 300 | err = io.ErrUnexpectedEOF | ||
| 301 | } | ||
| 302 | return | ||
| 303 | } | ||
| 304 | |||
| 305 | if dec.buffer == nil { | ||
| 306 | dec.buffer = make([]byte, 0, minBufferSize) | ||
| 307 | } else { | ||
| 308 | dec.buffer = dec.buffer[:copy(dec.buffer[:cap(dec.buffer)], dec.remain)] | ||
| 309 | dec.remain = nil | ||
| 310 | } | ||
| 311 | |||
| 312 | if (cap(dec.buffer) - len(dec.buffer)) < minReadSize { | ||
| 313 | buf := make([]byte, len(dec.buffer), 2*cap(dec.buffer)) | ||
| 314 | copy(buf, dec.buffer) | ||
| 315 | dec.buffer = buf | ||
| 316 | } | ||
| 317 | |||
| 318 | n, err = io.ReadFull(dec.reader, dec.buffer[len(dec.buffer):cap(dec.buffer)]) | ||
| 319 | if n > 0 { | ||
| 320 | dec.buffer = dec.buffer[:len(dec.buffer)+n] | ||
| 321 | if err != nil { | ||
| 322 | err = nil | ||
| 323 | } | ||
| 324 | } else if err == io.ErrUnexpectedEOF { | ||
| 325 | err = io.EOF | ||
| 326 | } | ||
| 327 | dec.remain, n = skipSpacesN(dec.buffer) | ||
| 328 | dec.inputOffset += int64(n) | ||
| 329 | dec.err = err | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | // DisallowUnknownFields is documented at https://golang.org/pkg/encoding/json/#Decoder.DisallowUnknownFields | ||
| 334 | func (dec *Decoder) DisallowUnknownFields() { dec.flags |= DisallowUnknownFields } | ||
| 335 | |||
| 336 | // UseNumber is documented at https://golang.org/pkg/encoding/json/#Decoder.UseNumber | ||
| 337 | func (dec *Decoder) UseNumber() { dec.flags |= UseNumber } | ||
| 338 | |||
| 339 | // DontCopyString is an extension to the standard encoding/json package | ||
| 340 | // which instructs the decoder to not copy strings loaded from the json | ||
| 341 | // payloads when possible. | ||
| 342 | func (dec *Decoder) DontCopyString() { dec.flags |= DontCopyString } | ||
| 343 | |||
| 344 | // DontCopyNumber is an extension to the standard encoding/json package | ||
| 345 | // which instructs the decoder to not copy numbers loaded from the json | ||
| 346 | // payloads. | ||
| 347 | func (dec *Decoder) DontCopyNumber() { dec.flags |= DontCopyNumber } | ||
| 348 | |||
| 349 | // DontCopyRawMessage is an extension to the standard encoding/json package | ||
| 350 | // which instructs the decoder to not allocate RawMessage values in separate | ||
| 351 | // memory buffers (see the documentation of the DontcopyRawMessage flag for | ||
| 352 | // more detais). | ||
| 353 | func (dec *Decoder) DontCopyRawMessage() { dec.flags |= DontCopyRawMessage } | ||
| 354 | |||
| 355 | // DontMatchCaseInsensitiveStructFields is an extension to the standard | ||
| 356 | // encoding/json package which instructs the decoder to not match object fields | ||
| 357 | // against struct fields in a case-insensitive way, the field names have to | ||
| 358 | // match exactly to be decoded into the struct field values. | ||
| 359 | func (dec *Decoder) DontMatchCaseInsensitiveStructFields() { | ||
| 360 | dec.flags |= DontMatchCaseInsensitiveStructFields | ||
| 361 | } | ||
| 362 | |||
| 363 | // ZeroCopy is an extension to the standard encoding/json package which enables | ||
| 364 | // all the copy optimizations of the decoder. | ||
| 365 | func (dec *Decoder) ZeroCopy() { dec.flags |= ZeroCopy } | ||
| 366 | |||
| 367 | // InputOffset returns the input stream byte offset of the current decoder position. | ||
| 368 | // The offset gives the location of the end of the most recently returned token | ||
| 369 | // and the beginning of the next token. | ||
| 370 | func (dec *Decoder) InputOffset() int64 { | ||
| 371 | return dec.inputOffset | ||
| 372 | } | ||
| 373 | |||
| 374 | // Encoder is documented at https://golang.org/pkg/encoding/json/#Encoder | ||
| 375 | type Encoder struct { | ||
| 376 | writer io.Writer | ||
| 377 | buffer *bytes.Buffer | ||
| 378 | err error | ||
| 379 | flags AppendFlags | ||
| 380 | clrs *Colors | ||
| 381 | indentr *indenter | ||
| 382 | } | ||
| 383 | |||
| 384 | // NewEncoder is documented at https://golang.org/pkg/encoding/json/#NewEncoder | ||
| 385 | func NewEncoder(w io.Writer) *Encoder { return &Encoder{writer: w, flags: EscapeHTML | SortMapKeys} } | ||
| 386 | |||
| 387 | // SetColors sets the colors for the encoder to use. | ||
| 388 | func (enc *Encoder) SetColors(c *Colors) { | ||
| 389 | enc.clrs = c | ||
| 390 | } | ||
| 391 | |||
| 392 | // Encode is documented at https://golang.org/pkg/encoding/json/#Encoder.Encode | ||
| 393 | func (enc *Encoder) Encode(v interface{}) error { | ||
| 394 | if enc.err != nil { | ||
| 395 | return enc.err | ||
| 396 | } | ||
| 397 | |||
| 398 | var err error | ||
| 399 | var buf = encoderBufferPool.Get().(*encoderBuffer) | ||
| 400 | |||
| 401 | // Note: unlike the original segmentio encoder, indentation is | ||
| 402 | // performed via the Append function. | ||
| 403 | buf.data, err = Append(buf.data[:0], v, enc.flags, enc.clrs, enc.indentr) | ||
| 404 | if err != nil { | ||
| 405 | encoderBufferPool.Put(buf) | ||
| 406 | return err | ||
| 407 | } | ||
| 408 | |||
| 409 | buf.data = append(buf.data, '\n') | ||
| 410 | b := buf.data | ||
| 411 | |||
| 412 | if _, err := enc.writer.Write(b); err != nil { | ||
| 413 | enc.err = err | ||
| 414 | } | ||
| 415 | |||
| 416 | encoderBufferPool.Put(buf) | ||
| 417 | return err | ||
| 418 | } | ||
| 419 | |||
| 420 | // SetEscapeHTML is documented at https://golang.org/pkg/encoding/json/#Encoder.SetEscapeHTML | ||
| 421 | func (enc *Encoder) SetEscapeHTML(on bool) { | ||
| 422 | if on { | ||
| 423 | enc.flags |= EscapeHTML | ||
| 424 | } else { | ||
| 425 | enc.flags &= ^EscapeHTML | ||
| 426 | } | ||
| 427 | } | ||
| 428 | |||
| 429 | // SetIndent is documented at https://golang.org/pkg/encoding/json/#Encoder.SetIndent | ||
| 430 | func (enc *Encoder) SetIndent(prefix, indent string) { | ||
| 431 | enc.indentr = newIndenter(prefix, indent) | ||
| 432 | } | ||
| 433 | |||
| 434 | // SetSortMapKeys is an extension to the standard encoding/json package which | ||
| 435 | // allows the program to toggle sorting of map keys on and off. | ||
| 436 | func (enc *Encoder) SetSortMapKeys(on bool) { | ||
| 437 | if on { | ||
| 438 | enc.flags |= SortMapKeys | ||
| 439 | } else { | ||
| 440 | enc.flags &= ^SortMapKeys | ||
| 441 | } | ||
| 442 | } | ||
| 443 | |||
| 444 | // SetTrustRawMessage skips value checking when encoding a raw json message. It should only | ||
| 445 | // be used if the values are known to be valid json, e.g. because they were originally created | ||
| 446 | // by json.Unmarshal. | ||
| 447 | func (enc *Encoder) SetTrustRawMessage(on bool) { | ||
| 448 | if on { | ||
| 449 | enc.flags |= TrustRawMessage | ||
| 450 | } else { | ||
| 451 | enc.flags &= ^TrustRawMessage | ||
| 452 | } | ||
| 453 | } | ||
| 454 | |||
| 455 | var encoderBufferPool = sync.Pool{ | ||
| 456 | New: func() interface{} { return &encoderBuffer{data: make([]byte, 0, 4096)} }, | ||
| 457 | } | ||
| 458 | |||
| 459 | type encoderBuffer struct{ data []byte } | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/jsoncolor.go b/vendor/github.com/neilotoole/jsoncolor/jsoncolor.go new file mode 100644 index 0000000..4c8835c --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/jsoncolor.go | |||
| @@ -0,0 +1,141 @@ | |||
| 1 | package jsoncolor | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "strconv" | ||
| 5 | ) | ||
| 6 | |||
| 7 | // Colors specifies colorization of JSON output. Each field | ||
| 8 | // is a Color, which is simply the bytes of the terminal color code. | ||
| 9 | type Colors struct { | ||
| 10 | // Null is the color for JSON nil. | ||
| 11 | Null Color | ||
| 12 | |||
| 13 | // Bool is the color for boolean values. | ||
| 14 | Bool Color | ||
| 15 | |||
| 16 | // Number is the color for number values. | ||
| 17 | Number Color | ||
| 18 | |||
| 19 | // String is the color for string values. | ||
| 20 | String Color | ||
| 21 | |||
| 22 | // Key is the color for JSON keys. | ||
| 23 | Key Color | ||
| 24 | |||
| 25 | // Bytes is the color for byte data. | ||
| 26 | Bytes Color | ||
| 27 | |||
| 28 | // Time is the color for datetime values. | ||
| 29 | Time Color | ||
| 30 | |||
| 31 | // Punc is the color for JSON punctuation: []{},: etc. | ||
| 32 | Punc Color | ||
| 33 | |||
| 34 | // TextMarshaler is the color for values implementing encoding.TextMarshaler. | ||
| 35 | TextMarshaler Color | ||
| 36 | } | ||
| 37 | |||
| 38 | // appendNull appends a colorized "null" to b. | ||
| 39 | func (c *Colors) appendNull(b []byte) []byte { | ||
| 40 | if c == nil { | ||
| 41 | return append(b, "null"...) | ||
| 42 | } | ||
| 43 | |||
| 44 | b = append(b, c.Null...) | ||
| 45 | b = append(b, "null"...) | ||
| 46 | return append(b, ansiReset...) | ||
| 47 | } | ||
| 48 | |||
| 49 | // appendBool appends the colorized bool v to b. | ||
| 50 | func (c *Colors) appendBool(b []byte, v bool) []byte { | ||
| 51 | if c == nil { | ||
| 52 | if v { | ||
| 53 | return append(b, "true"...) | ||
| 54 | } | ||
| 55 | |||
| 56 | return append(b, "false"...) | ||
| 57 | } | ||
| 58 | |||
| 59 | b = append(b, c.Bool...) | ||
| 60 | if v { | ||
| 61 | b = append(b, "true"...) | ||
| 62 | } else { | ||
| 63 | b = append(b, "false"...) | ||
| 64 | } | ||
| 65 | |||
| 66 | return append(b, ansiReset...) | ||
| 67 | } | ||
| 68 | |||
| 69 | // appendKey appends the colorized key v to b. | ||
| 70 | func (c *Colors) appendKey(b []byte, v []byte) []byte { | ||
| 71 | if c == nil { | ||
| 72 | return append(b, v...) | ||
| 73 | } | ||
| 74 | |||
| 75 | b = append(b, c.Key...) | ||
| 76 | b = append(b, v...) | ||
| 77 | return append(b, ansiReset...) | ||
| 78 | } | ||
| 79 | |||
| 80 | // appendInt64 appends the colorized int64 v to b. | ||
| 81 | func (c *Colors) appendInt64(b []byte, v int64) []byte { | ||
| 82 | if c == nil { | ||
| 83 | return strconv.AppendInt(b, v, 10) | ||
| 84 | } | ||
| 85 | |||
| 86 | b = append(b, c.Number...) | ||
| 87 | b = strconv.AppendInt(b, v, 10) | ||
| 88 | return append(b, ansiReset...) | ||
| 89 | } | ||
| 90 | |||
| 91 | // appendUint64 appends the colorized uint64 v to b. | ||
| 92 | func (c *Colors) appendUint64(b []byte, v uint64) []byte { | ||
| 93 | if c == nil { | ||
| 94 | return strconv.AppendUint(b, v, 10) | ||
| 95 | } | ||
| 96 | |||
| 97 | b = append(b, c.Number...) | ||
| 98 | b = strconv.AppendUint(b, v, 10) | ||
| 99 | return append(b, ansiReset...) | ||
| 100 | } | ||
| 101 | |||
| 102 | // appendPunc appends the colorized punctuation mark v to b. | ||
| 103 | func (c *Colors) appendPunc(b []byte, v byte) []byte { | ||
| 104 | if c == nil { | ||
| 105 | return append(b, v) | ||
| 106 | } | ||
| 107 | |||
| 108 | b = append(b, c.Punc...) | ||
| 109 | b = append(b, v) | ||
| 110 | return append(b, ansiReset...) | ||
| 111 | } | ||
| 112 | |||
| 113 | // Color is used to render terminal colors. In effect, Color is | ||
| 114 | // the bytes of the ANSI prefix code. The zero value is valid (results in | ||
| 115 | // no colorization). When Color is non-zero, the encoder writes the prefix, | ||
| 116 | // then the actual value, then the ANSI reset code. | ||
| 117 | // | ||
| 118 | // Example value: | ||
| 119 | // | ||
| 120 | // number := Color("\x1b[36m") | ||
| 121 | type Color []byte | ||
| 122 | |||
| 123 | // ansiReset is the ANSI ansiReset escape code. | ||
| 124 | const ansiReset = "\x1b[0m" | ||
| 125 | |||
| 126 | // DefaultColors returns the default Colors configuration. | ||
| 127 | // These colors largely follow jq's default colorization, | ||
| 128 | // with some deviation. | ||
| 129 | func DefaultColors() *Colors { | ||
| 130 | return &Colors{ | ||
| 131 | Null: Color("\x1b[2m"), | ||
| 132 | Bool: Color("\x1b[1m"), | ||
| 133 | Number: Color("\x1b[36m"), | ||
| 134 | String: Color("\x1b[32m"), | ||
| 135 | Key: Color("\x1b[34;1m"), | ||
| 136 | Bytes: Color("\x1b[2m"), | ||
| 137 | Time: Color("\x1b[32;2m"), | ||
| 138 | Punc: Color{}, // No colorization | ||
| 139 | TextMarshaler: Color("\x1b[32m"), // Same as String | ||
| 140 | } | ||
| 141 | } | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/parse.go b/vendor/github.com/neilotoole/jsoncolor/parse.go new file mode 100644 index 0000000..0f43b4c --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/parse.go | |||
| @@ -0,0 +1,735 @@ | |||
| 1 | package jsoncolor | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "bytes" | ||
| 5 | "math" | ||
| 6 | "reflect" | ||
| 7 | "unicode" | ||
| 8 | "unicode/utf16" | ||
| 9 | "unicode/utf8" | ||
| 10 | ) | ||
| 11 | |||
| 12 | // All spaces characters defined in the json specification. | ||
| 13 | const ( | ||
| 14 | sp = ' ' | ||
| 15 | ht = '\t' | ||
| 16 | nl = '\n' | ||
| 17 | cr = '\r' | ||
| 18 | ) | ||
| 19 | |||
| 20 | const ( | ||
| 21 | escape = '\\' | ||
| 22 | quote = '"' //nolint:varcheck // from original code | ||
| 23 | ) | ||
| 24 | |||
| 25 | func skipSpaces(b []byte) []byte { | ||
| 26 | b, _ = skipSpacesN(b) | ||
| 27 | return b | ||
| 28 | } | ||
| 29 | |||
| 30 | func skipSpacesN(b []byte) ([]byte, int) { | ||
| 31 | for i := range b { | ||
| 32 | switch b[i] { | ||
| 33 | case sp, ht, nl, cr: | ||
| 34 | default: | ||
| 35 | return b[i:], i | ||
| 36 | } | ||
| 37 | } | ||
| 38 | return nil, 0 | ||
| 39 | } | ||
| 40 | |||
| 41 | // parseInt parses a decimanl representation of an int64 from b. | ||
| 42 | // | ||
| 43 | // The function is equivalent to calling strconv.ParseInt(string(b), 10, 64) but | ||
| 44 | // it prevents Go from making a memory allocation for converting a byte slice to | ||
| 45 | // a string (escape analysis fails due to the error returned by strconv.ParseInt). | ||
| 46 | // | ||
| 47 | // Because it only works with base 10 the function is also significantly faster | ||
| 48 | // than strconv.ParseInt. | ||
| 49 | func parseInt(b []byte, t reflect.Type) (int64, []byte, error) { | ||
| 50 | var value int64 | ||
| 51 | var count int | ||
| 52 | |||
| 53 | if len(b) == 0 { | ||
| 54 | return 0, b, syntaxError(b, "cannot decode integer from an empty input") | ||
| 55 | } | ||
| 56 | |||
| 57 | if b[0] == '-' { | ||
| 58 | const max = math.MinInt64 | ||
| 59 | const lim = max / 10 | ||
| 60 | |||
| 61 | if len(b) == 1 { | ||
| 62 | return 0, b, syntaxError(b, "cannot decode integer from '-'") | ||
| 63 | } | ||
| 64 | |||
| 65 | if len(b) > 2 && b[1] == '0' && '0' <= b[2] && b[2] <= '9' { | ||
| 66 | return 0, b, syntaxError(b, "invalid leading character '0' in integer") | ||
| 67 | } | ||
| 68 | |||
| 69 | for _, d := range b[1:] { | ||
| 70 | if !(d >= '0' && d <= '9') { | ||
| 71 | if count == 0 { | ||
| 72 | b, err := inputError(b, t) | ||
| 73 | return 0, b, err | ||
| 74 | } | ||
| 75 | break | ||
| 76 | } | ||
| 77 | |||
| 78 | if value < lim { | ||
| 79 | return 0, b, unmarshalOverflow(b, t) | ||
| 80 | } | ||
| 81 | |||
| 82 | value *= 10 | ||
| 83 | x := int64(d - '0') | ||
| 84 | |||
| 85 | if value < (max + x) { | ||
| 86 | return 0, b, unmarshalOverflow(b, t) | ||
| 87 | } | ||
| 88 | |||
| 89 | value -= x | ||
| 90 | count++ | ||
| 91 | } | ||
| 92 | |||
| 93 | count++ | ||
| 94 | } else { | ||
| 95 | const max = math.MaxInt64 | ||
| 96 | const lim = max / 10 | ||
| 97 | |||
| 98 | if len(b) > 1 && b[0] == '0' && '0' <= b[1] && b[1] <= '9' { | ||
| 99 | return 0, b, syntaxError(b, "invalid leading character '0' in integer") | ||
| 100 | } | ||
| 101 | |||
| 102 | for _, d := range b { | ||
| 103 | if !(d >= '0' && d <= '9') { | ||
| 104 | if count == 0 { | ||
| 105 | b, err := inputError(b, t) | ||
| 106 | return 0, b, err | ||
| 107 | } | ||
| 108 | break | ||
| 109 | } | ||
| 110 | x := int64(d - '0') | ||
| 111 | |||
| 112 | if value > lim { | ||
| 113 | return 0, b, unmarshalOverflow(b, t) | ||
| 114 | } | ||
| 115 | |||
| 116 | if value *= 10; value > (max - x) { | ||
| 117 | return 0, b, unmarshalOverflow(b, t) | ||
| 118 | } | ||
| 119 | |||
| 120 | value += x | ||
| 121 | count++ | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | if count < len(b) { | ||
| 126 | switch b[count] { | ||
| 127 | case '.', 'e', 'E': // was this actually a float? | ||
| 128 | v, r, err := parseNumber(b) | ||
| 129 | if err != nil { | ||
| 130 | v, r = b[:count+1], b[count+1:] | ||
| 131 | } | ||
| 132 | return 0, r, unmarshalTypeError(v, t) | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | return value, b[count:], nil | ||
| 137 | } | ||
| 138 | |||
| 139 | // parseUint is like parseInt but for unsigned integers. | ||
| 140 | func parseUint(b []byte, t reflect.Type) (uint64, []byte, error) { | ||
| 141 | const max = math.MaxUint64 | ||
| 142 | const lim = max / 10 | ||
| 143 | |||
| 144 | var value uint64 | ||
| 145 | var count int | ||
| 146 | |||
| 147 | if len(b) == 0 { | ||
| 148 | return 0, b, syntaxError(b, "cannot decode integer value from an empty input") | ||
| 149 | } | ||
| 150 | |||
| 151 | if len(b) > 1 && b[0] == '0' && '0' <= b[1] && b[1] <= '9' { | ||
| 152 | return 0, b, syntaxError(b, "invalid leading character '0' in integer") | ||
| 153 | } | ||
| 154 | |||
| 155 | for _, d := range b { | ||
| 156 | if !(d >= '0' && d <= '9') { | ||
| 157 | if count == 0 { | ||
| 158 | b, err := inputError(b, t) | ||
| 159 | return 0, b, err | ||
| 160 | } | ||
| 161 | break | ||
| 162 | } | ||
| 163 | x := uint64(d - '0') | ||
| 164 | |||
| 165 | if value > lim { | ||
| 166 | return 0, b, unmarshalOverflow(b, t) | ||
| 167 | } | ||
| 168 | |||
| 169 | if value *= 10; value > (max - x) { | ||
| 170 | return 0, b, unmarshalOverflow(b, t) | ||
| 171 | } | ||
| 172 | |||
| 173 | value += x | ||
| 174 | count++ | ||
| 175 | } | ||
| 176 | |||
| 177 | if count < len(b) { | ||
| 178 | switch b[count] { | ||
| 179 | case '.', 'e', 'E': // was this actually a float? | ||
| 180 | v, r, err := parseNumber(b) | ||
| 181 | if err != nil { | ||
| 182 | v, r = b[:count+1], b[count+1:] | ||
| 183 | } | ||
| 184 | return 0, r, unmarshalTypeError(v, t) | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | return value, b[count:], nil | ||
| 189 | } | ||
| 190 | |||
| 191 | // parseUintHex parses a hexadecimanl representation of a uint64 from b. | ||
| 192 | // | ||
| 193 | // The function is equivalent to calling strconv.ParseUint(string(b), 16, 64) but | ||
| 194 | // it prevents Go from making a memory allocation for converting a byte slice to | ||
| 195 | // a string (escape analysis fails due to the error returned by strconv.ParseUint). | ||
| 196 | // | ||
| 197 | // Because it only works with base 16 the function is also significantly faster | ||
| 198 | // than strconv.ParseUint. | ||
| 199 | func parseUintHex(b []byte) (uint64, []byte, error) { | ||
| 200 | const max = math.MaxUint64 | ||
| 201 | const lim = max / 0x10 | ||
| 202 | |||
| 203 | var value uint64 | ||
| 204 | var count int | ||
| 205 | |||
| 206 | if len(b) == 0 { | ||
| 207 | return 0, b, syntaxError(b, "cannot decode hexadecimal value from an empty input") | ||
| 208 | } | ||
| 209 | |||
| 210 | parseLoop: | ||
| 211 | for i, d := range b { | ||
| 212 | var x uint64 | ||
| 213 | |||
| 214 | switch { | ||
| 215 | case d >= '0' && d <= '9': | ||
| 216 | x = uint64(d - '0') | ||
| 217 | |||
| 218 | case d >= 'A' && d <= 'F': | ||
| 219 | x = uint64(d-'A') + 0xA | ||
| 220 | |||
| 221 | case d >= 'a' && d <= 'f': | ||
| 222 | x = uint64(d-'a') + 0xA | ||
| 223 | |||
| 224 | default: | ||
| 225 | if i == 0 { | ||
| 226 | return 0, b, syntaxError(b, "expected hexadecimal digit but found '%c'", d) | ||
| 227 | } | ||
| 228 | break parseLoop | ||
| 229 | } | ||
| 230 | |||
| 231 | if value > lim { | ||
| 232 | return 0, b, syntaxError(b, "hexadecimal value out of range") | ||
| 233 | } | ||
| 234 | |||
| 235 | if value *= 0x10; value > (max - x) { | ||
| 236 | return 0, b, syntaxError(b, "hexadecimal value out of range") | ||
| 237 | } | ||
| 238 | |||
| 239 | value += x | ||
| 240 | count++ | ||
| 241 | } | ||
| 242 | |||
| 243 | return value, b[count:], nil | ||
| 244 | } | ||
| 245 | |||
| 246 | func parseNull(b []byte) ([]byte, []byte, error) { | ||
| 247 | if hasNullPrefix(b) { | ||
| 248 | return b[:4], b[4:], nil | ||
| 249 | } | ||
| 250 | if len(b) < 4 { | ||
| 251 | return nil, b[len(b):], unexpectedEOF(b) | ||
| 252 | } | ||
| 253 | return nil, b, syntaxError(b, "expected 'null' but found invalid token") | ||
| 254 | } | ||
| 255 | |||
| 256 | func parseTrue(b []byte) ([]byte, []byte, error) { | ||
| 257 | if hasTruePrefix(b) { | ||
| 258 | return b[:4], b[4:], nil | ||
| 259 | } | ||
| 260 | if len(b) < 4 { | ||
| 261 | return nil, b[len(b):], unexpectedEOF(b) | ||
| 262 | } | ||
| 263 | return nil, b, syntaxError(b, "expected 'true' but found invalid token") | ||
| 264 | } | ||
| 265 | |||
| 266 | func parseFalse(b []byte) ([]byte, []byte, error) { | ||
| 267 | if hasFalsePrefix(b) { | ||
| 268 | return b[:5], b[5:], nil | ||
| 269 | } | ||
| 270 | if len(b) < 5 { | ||
| 271 | return nil, b[len(b):], unexpectedEOF(b) | ||
| 272 | } | ||
| 273 | return nil, b, syntaxError(b, "expected 'false' but found invalid token") | ||
| 274 | } | ||
| 275 | |||
| 276 | func parseNumber(b []byte) (v, r []byte, err error) { | ||
| 277 | if len(b) == 0 { | ||
| 278 | r, err = b, unexpectedEOF(b) | ||
| 279 | return | ||
| 280 | } | ||
| 281 | |||
| 282 | i := 0 | ||
| 283 | // sign | ||
| 284 | if b[i] == '-' { | ||
| 285 | i++ | ||
| 286 | } | ||
| 287 | |||
| 288 | if i == len(b) { | ||
| 289 | r, err = b[i:], syntaxError(b, "missing number value after sign") | ||
| 290 | return | ||
| 291 | } | ||
| 292 | |||
| 293 | if b[i] < '0' || b[i] > '9' { | ||
| 294 | r, err = b[i:], syntaxError(b, "expected digit but got '%c'", b[i]) | ||
| 295 | return | ||
| 296 | } | ||
| 297 | |||
| 298 | // integer part | ||
| 299 | if b[i] == '0' { | ||
| 300 | i++ | ||
| 301 | if i == len(b) || (b[i] != '.' && b[i] != 'e' && b[i] != 'E') { | ||
| 302 | v, r = b[:i], b[i:] | ||
| 303 | return | ||
| 304 | } | ||
| 305 | if '0' <= b[i] && b[i] <= '9' { | ||
| 306 | r, err = b[i:], syntaxError(b, "cannot decode number with leading '0' character") | ||
| 307 | return | ||
| 308 | } | ||
| 309 | } | ||
| 310 | |||
| 311 | for i < len(b) && '0' <= b[i] && b[i] <= '9' { | ||
| 312 | i++ | ||
| 313 | } | ||
| 314 | |||
| 315 | // decimal part | ||
| 316 | if i < len(b) && b[i] == '.' { | ||
| 317 | i++ | ||
| 318 | decimalStart := i | ||
| 319 | |||
| 320 | for i < len(b) { | ||
| 321 | if c := b[i]; !('0' <= c && c <= '9') { | ||
| 322 | if i == decimalStart { | ||
| 323 | r, err = b[i:], syntaxError(b, "expected digit but found '%c'", c) | ||
| 324 | return | ||
| 325 | } | ||
| 326 | break | ||
| 327 | } | ||
| 328 | i++ | ||
| 329 | } | ||
| 330 | |||
| 331 | if i == decimalStart { | ||
| 332 | r, err = b[i:], syntaxError(b, "expected decimal part after '.'") | ||
| 333 | return | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | // exponent part | ||
| 338 | if i < len(b) && (b[i] == 'e' || b[i] == 'E') { | ||
| 339 | i++ | ||
| 340 | |||
| 341 | if i < len(b) { | ||
| 342 | if c := b[i]; c == '+' || c == '-' { | ||
| 343 | i++ | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | if i == len(b) { | ||
| 348 | r, err = b[i:], syntaxError(b, "missing exponent in number") | ||
| 349 | return | ||
| 350 | } | ||
| 351 | |||
| 352 | exponentStart := i | ||
| 353 | |||
| 354 | for i < len(b) { | ||
| 355 | if c := b[i]; !('0' <= c && c <= '9') { | ||
| 356 | if i == exponentStart { | ||
| 357 | err = syntaxError(b, "expected digit but found '%c'", c) | ||
| 358 | return | ||
| 359 | } | ||
| 360 | break | ||
| 361 | } | ||
| 362 | i++ | ||
| 363 | } | ||
| 364 | } | ||
| 365 | |||
| 366 | v, r = b[:i], b[i:] | ||
| 367 | return | ||
| 368 | } | ||
| 369 | |||
| 370 | func parseUnicode(b []byte) (rune, int, error) { | ||
| 371 | if len(b) < 4 { | ||
| 372 | return 0, 0, syntaxError(b, "unicode code point must have at least 4 characters") | ||
| 373 | } | ||
| 374 | |||
| 375 | u, r, err := parseUintHex(b[:4]) | ||
| 376 | if err != nil { | ||
| 377 | return 0, 0, syntaxError(b, "parsing unicode code point: %s", err) | ||
| 378 | } | ||
| 379 | |||
| 380 | if len(r) != 0 { | ||
| 381 | return 0, 0, syntaxError(b, "invalid unicode code point") | ||
| 382 | } | ||
| 383 | |||
| 384 | return rune(u), 4, nil | ||
| 385 | } | ||
| 386 | |||
| 387 | func parseStringFast(b []byte) ([]byte, []byte, bool, error) { | ||
| 388 | if len(b) < 2 { | ||
| 389 | return nil, b[len(b):], false, unexpectedEOF(b) | ||
| 390 | } | ||
| 391 | if b[0] != '"' { | ||
| 392 | return nil, b, false, syntaxError(b, "expected '\"' at the beginning of a string value") | ||
| 393 | } | ||
| 394 | |||
| 395 | n := bytes.IndexByte(b[1:], '"') + 2 | ||
| 396 | if n <= 1 { | ||
| 397 | return nil, b[len(b):], false, syntaxError(b, "missing '\"' at the end of a string value") | ||
| 398 | } | ||
| 399 | if bytes.IndexByte(b[1:n], '\\') < 0 && asciiValidPrint(b[1:n]) { | ||
| 400 | return b[:n], b[n:], false, nil | ||
| 401 | } | ||
| 402 | |||
| 403 | for i := 1; i < len(b); i++ { | ||
| 404 | switch b[i] { | ||
| 405 | case '\\': | ||
| 406 | if i++; i < len(b) { | ||
| 407 | switch b[i] { | ||
| 408 | case '"', '\\', '/', 'n', 'r', 't', 'f', 'b': | ||
| 409 | case 'u': | ||
| 410 | _, n, err := parseUnicode(b[i+1:]) | ||
| 411 | if err != nil { | ||
| 412 | return nil, b, false, err | ||
| 413 | } | ||
| 414 | i += n | ||
| 415 | default: | ||
| 416 | return nil, b, false, syntaxError(b, "invalid character '%c' in string escape code", b[i]) | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 420 | case '"': | ||
| 421 | return b[:i+1], b[i+1:], true, nil | ||
| 422 | |||
| 423 | default: | ||
| 424 | if b[i] < 0x20 { | ||
| 425 | return nil, b, false, syntaxError(b, "invalid character '%c' in string escape code", b[i]) | ||
| 426 | } | ||
| 427 | } | ||
| 428 | } | ||
| 429 | |||
| 430 | return nil, b[len(b):], false, syntaxError(b, "missing '\"' at the end of a string value") | ||
| 431 | } | ||
| 432 | |||
| 433 | func parseString(b []byte) ([]byte, []byte, error) { | ||
| 434 | s, b, _, err := parseStringFast(b) | ||
| 435 | return s, b, err | ||
| 436 | } | ||
| 437 | |||
| 438 | func parseStringUnquote(b []byte, r []byte) ([]byte, []byte, bool, error) { | ||
| 439 | s, b, escaped, err := parseStringFast(b) | ||
| 440 | if err != nil { | ||
| 441 | return s, b, false, err | ||
| 442 | } | ||
| 443 | |||
| 444 | s = s[1 : len(s)-1] // trim the quotes | ||
| 445 | |||
| 446 | if !escaped { | ||
| 447 | return s, b, false, nil | ||
| 448 | } | ||
| 449 | |||
| 450 | if r == nil { | ||
| 451 | r = make([]byte, 0, len(s)) | ||
| 452 | } | ||
| 453 | |||
| 454 | for len(s) != 0 { | ||
| 455 | i := bytes.IndexByte(s, '\\') | ||
| 456 | |||
| 457 | if i < 0 { | ||
| 458 | r = appendCoerceInvalidUTF8(r, s) | ||
| 459 | break | ||
| 460 | } | ||
| 461 | |||
| 462 | r = appendCoerceInvalidUTF8(r, s[:i]) | ||
| 463 | s = s[i+1:] | ||
| 464 | |||
| 465 | c := s[0] | ||
| 466 | switch c { | ||
| 467 | case '"', '\\', '/': | ||
| 468 | // simple escaped character | ||
| 469 | case 'n': | ||
| 470 | c = '\n' | ||
| 471 | |||
| 472 | case 'r': | ||
| 473 | c = '\r' | ||
| 474 | |||
| 475 | case 't': | ||
| 476 | c = '\t' | ||
| 477 | |||
| 478 | case 'b': | ||
| 479 | c = '\b' | ||
| 480 | |||
| 481 | case 'f': | ||
| 482 | c = '\f' | ||
| 483 | |||
| 484 | case 'u': | ||
| 485 | s = s[1:] | ||
| 486 | |||
| 487 | r1, n1, err := parseUnicode(s) | ||
| 488 | if err != nil { | ||
| 489 | return r, b, true, err | ||
| 490 | } | ||
| 491 | s = s[n1:] | ||
| 492 | |||
| 493 | if utf16.IsSurrogate(r1) { | ||
| 494 | if !hasPrefix(s, `\u`) { | ||
| 495 | r1 = unicode.ReplacementChar | ||
| 496 | } else { | ||
| 497 | r2, n2, err := parseUnicode(s[2:]) | ||
| 498 | if err != nil { | ||
| 499 | return r, b, true, err | ||
| 500 | } | ||
| 501 | if r1 = utf16.DecodeRune(r1, r2); r1 != unicode.ReplacementChar { | ||
| 502 | s = s[2+n2:] | ||
| 503 | } | ||
| 504 | } | ||
| 505 | } | ||
| 506 | |||
| 507 | r = appendRune(r, r1) | ||
| 508 | continue | ||
| 509 | |||
| 510 | default: // not sure what this escape sequence is | ||
| 511 | return r, b, false, syntaxError(s, "invalid character '%c' in string escape code", c) | ||
| 512 | } | ||
| 513 | |||
| 514 | r = append(r, c) | ||
| 515 | s = s[1:] | ||
| 516 | } | ||
| 517 | |||
| 518 | return r, b, true, nil | ||
| 519 | } | ||
| 520 | |||
| 521 | func appendRune(b []byte, r rune) []byte { | ||
| 522 | n := len(b) | ||
| 523 | b = append(b, 0, 0, 0, 0) | ||
| 524 | return b[:n+utf8.EncodeRune(b[n:], r)] | ||
| 525 | } | ||
| 526 | |||
| 527 | func appendCoerceInvalidUTF8(b []byte, s []byte) []byte { | ||
| 528 | c := [4]byte{} | ||
| 529 | |||
| 530 | for _, r := range string(s) { | ||
| 531 | b = append(b, c[:utf8.EncodeRune(c[:], r)]...) | ||
| 532 | } | ||
| 533 | |||
| 534 | return b | ||
| 535 | } | ||
| 536 | |||
| 537 | func parseObject(b []byte) ([]byte, []byte, error) { | ||
| 538 | if len(b) < 2 { | ||
| 539 | return nil, b[len(b):], unexpectedEOF(b) | ||
| 540 | } | ||
| 541 | |||
| 542 | if b[0] != '{' { | ||
| 543 | return nil, b, syntaxError(b, "expected '{' at the beginning of an object value") | ||
| 544 | } | ||
| 545 | |||
| 546 | var err error | ||
| 547 | var a = b | ||
| 548 | var n = len(b) | ||
| 549 | var i = 0 | ||
| 550 | |||
| 551 | b = b[1:] | ||
| 552 | for { | ||
| 553 | b = skipSpaces(b) | ||
| 554 | |||
| 555 | if len(b) == 0 { | ||
| 556 | return nil, b, syntaxError(b, "cannot decode object from empty input") | ||
| 557 | } | ||
| 558 | |||
| 559 | if b[0] == '}' { | ||
| 560 | j := (n - len(b)) + 1 | ||
| 561 | return a[:j], a[j:], nil | ||
| 562 | } | ||
| 563 | |||
| 564 | if i != 0 { | ||
| 565 | if len(b) == 0 { | ||
| 566 | return nil, b, syntaxError(b, "unexpected EOF after object field value") | ||
| 567 | } | ||
| 568 | if b[0] != ',' { | ||
| 569 | return nil, b, syntaxError(b, "expected ',' after object field value but found '%c'", b[0]) | ||
| 570 | } | ||
| 571 | b = skipSpaces(b[1:]) | ||
| 572 | if len(b) == 0 { | ||
| 573 | return nil, b, unexpectedEOF(b) | ||
| 574 | } | ||
| 575 | if b[0] == '}' { | ||
| 576 | return nil, b, syntaxError(b, "unexpected trailing comma after object field") | ||
| 577 | } | ||
| 578 | } | ||
| 579 | |||
| 580 | _, b, err = parseString(b) | ||
| 581 | if err != nil { | ||
| 582 | return nil, b, err | ||
| 583 | } | ||
| 584 | b = skipSpaces(b) | ||
| 585 | |||
| 586 | if len(b) == 0 { | ||
| 587 | return nil, b, syntaxError(b, "unexpected EOF after object field key") | ||
| 588 | } | ||
| 589 | if b[0] != ':' { | ||
| 590 | return nil, b, syntaxError(b, "expected ':' after object field key but found '%c'", b[0]) | ||
| 591 | } | ||
| 592 | b = skipSpaces(b[1:]) | ||
| 593 | |||
| 594 | _, b, err = parseValue(b) | ||
| 595 | if err != nil { | ||
| 596 | return nil, b, err | ||
| 597 | } | ||
| 598 | |||
| 599 | i++ | ||
| 600 | } | ||
| 601 | } | ||
| 602 | |||
| 603 | func parseArray(b []byte) ([]byte, []byte, error) { | ||
| 604 | if len(b) < 2 { | ||
| 605 | return nil, b[len(b):], unexpectedEOF(b) | ||
| 606 | } | ||
| 607 | |||
| 608 | if b[0] != '[' { | ||
| 609 | return nil, b, syntaxError(b, "expected '[' at the beginning of array value") | ||
| 610 | } | ||
| 611 | |||
| 612 | var err error | ||
| 613 | var a = b | ||
| 614 | var n = len(b) | ||
| 615 | var i = 0 | ||
| 616 | |||
| 617 | b = b[1:] | ||
| 618 | for { | ||
| 619 | b = skipSpaces(b) | ||
| 620 | |||
| 621 | if len(b) == 0 { | ||
| 622 | return nil, b, syntaxError(b, "missing closing ']' after array value") | ||
| 623 | } | ||
| 624 | |||
| 625 | if b[0] == ']' { | ||
| 626 | j := (n - len(b)) + 1 | ||
| 627 | return a[:j], a[j:], nil | ||
| 628 | } | ||
| 629 | |||
| 630 | if i != 0 { | ||
| 631 | if len(b) == 0 { | ||
| 632 | return nil, b, syntaxError(b, "unexpected EOF after array element") | ||
| 633 | } | ||
| 634 | if b[0] != ',' { | ||
| 635 | return nil, b, syntaxError(b, "expected ',' after array element but found '%c'", b[0]) | ||
| 636 | } | ||
| 637 | b = skipSpaces(b[1:]) | ||
| 638 | if len(b) == 0 { | ||
| 639 | return nil, b, unexpectedEOF(b) | ||
| 640 | } | ||
| 641 | if b[0] == ']' { | ||
| 642 | return nil, b, syntaxError(b, "unexpected trailing comma after object field") | ||
| 643 | } | ||
| 644 | } | ||
| 645 | |||
| 646 | _, b, err = parseValue(b) | ||
| 647 | if err != nil { | ||
| 648 | return nil, b, err | ||
| 649 | } | ||
| 650 | |||
| 651 | i++ | ||
| 652 | } | ||
| 653 | } | ||
| 654 | |||
| 655 | func parseValue(b []byte) ([]byte, []byte, error) { | ||
| 656 | if len(b) != 0 { | ||
| 657 | switch b[0] { | ||
| 658 | case '{': | ||
| 659 | return parseObject(b) | ||
| 660 | case '[': | ||
| 661 | return parseArray(b) | ||
| 662 | case '"': | ||
| 663 | return parseString(b) | ||
| 664 | case 'n': | ||
| 665 | return parseNull(b) | ||
| 666 | case 't': | ||
| 667 | return parseTrue(b) | ||
| 668 | case 'f': | ||
| 669 | return parseFalse(b) | ||
| 670 | case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': | ||
| 671 | return parseNumber(b) | ||
| 672 | default: | ||
| 673 | return nil, b, syntaxError(b, "invalid character '%c' looking for beginning of value", b[0]) | ||
| 674 | } | ||
| 675 | } | ||
| 676 | return nil, b, syntaxError(b, "unexpected end of JSON input") | ||
| 677 | } | ||
| 678 | |||
| 679 | func hasNullPrefix(b []byte) bool { | ||
| 680 | return len(b) >= 4 && string(b[:4]) == "null" | ||
| 681 | } | ||
| 682 | |||
| 683 | func hasTruePrefix(b []byte) bool { | ||
| 684 | return len(b) >= 4 && string(b[:4]) == "true" | ||
| 685 | } | ||
| 686 | |||
| 687 | func hasFalsePrefix(b []byte) bool { | ||
| 688 | return len(b) >= 5 && string(b[:5]) == "false" | ||
| 689 | } | ||
| 690 | |||
| 691 | func hasPrefix(b []byte, s string) bool { | ||
| 692 | return len(b) >= len(s) && s == string(b[:len(s)]) | ||
| 693 | } | ||
| 694 | |||
| 695 | func hasLeadingSign(b []byte) bool { | ||
| 696 | return len(b) > 0 && (b[0] == '+' || b[0] == '-') | ||
| 697 | } | ||
| 698 | |||
| 699 | func hasLeadingZeroes(b []byte) bool { | ||
| 700 | if hasLeadingSign(b) { | ||
| 701 | b = b[1:] | ||
| 702 | } | ||
| 703 | return len(b) > 1 && b[0] == '0' && '0' <= b[1] && b[1] <= '9' | ||
| 704 | } | ||
| 705 | |||
| 706 | func appendToLower(b, s []byte) []byte { | ||
| 707 | if asciiValid(s) { // fast path for ascii strings | ||
| 708 | i := 0 | ||
| 709 | |||
| 710 | for j := range s { | ||
| 711 | c := s[j] | ||
| 712 | |||
| 713 | if 'A' <= c && c <= 'Z' { | ||
| 714 | b = append(b, s[i:j]...) | ||
| 715 | b = append(b, c+('a'-'A')) | ||
| 716 | i = j + 1 | ||
| 717 | } | ||
| 718 | } | ||
| 719 | |||
| 720 | return append(b, s[i:]...) | ||
| 721 | } | ||
| 722 | |||
| 723 | for _, r := range string(s) { | ||
| 724 | b = appendRune(b, foldRune(r)) | ||
| 725 | } | ||
| 726 | |||
| 727 | return b | ||
| 728 | } | ||
| 729 | |||
| 730 | func foldRune(r rune) rune { | ||
| 731 | if r = unicode.SimpleFold(r); 'A' <= r && r <= 'Z' { | ||
| 732 | r = r + ('a' - 'A') | ||
| 733 | } | ||
| 734 | return r | ||
| 735 | } | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/reflect.go b/vendor/github.com/neilotoole/jsoncolor/reflect.go new file mode 100644 index 0000000..0dcf174 --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/reflect.go | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | //go:build go1.15 | ||
| 2 | // +build go1.15 | ||
| 3 | |||
| 4 | package jsoncolor | ||
| 5 | |||
| 6 | import ( | ||
| 7 | "reflect" | ||
| 8 | "unsafe" | ||
| 9 | ) | ||
| 10 | |||
| 11 | func extendSlice(t reflect.Type, s *slice, n int) slice { | ||
| 12 | arrayType := reflect.ArrayOf(n, t.Elem()) | ||
| 13 | arrayData := reflect.New(arrayType) | ||
| 14 | reflect.Copy(arrayData.Elem(), reflect.NewAt(t, unsafe.Pointer(s)).Elem()) | ||
| 15 | return slice{ | ||
| 16 | data: unsafe.Pointer(arrayData.Pointer()), | ||
| 17 | len: s.len, | ||
| 18 | cap: n, | ||
| 19 | } | ||
| 20 | } | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/reflect_optimize.go b/vendor/github.com/neilotoole/jsoncolor/reflect_optimize.go new file mode 100644 index 0000000..03fc849 --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/reflect_optimize.go | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | //go:build !go1.15 | ||
| 2 | // +build !go1.15 | ||
| 3 | |||
| 4 | package jsoncolor | ||
| 5 | |||
| 6 | import ( | ||
| 7 | "reflect" | ||
| 8 | "unsafe" | ||
| 9 | ) | ||
| 10 | |||
| 11 | //go:linkname unsafe_NewArray reflect.unsafe_NewArray | ||
| 12 | func unsafe_NewArray(rtype unsafe.Pointer, length int) unsafe.Pointer | ||
| 13 | |||
| 14 | //go:linkname typedslicecopy reflect.typedslicecopy | ||
| 15 | //go:noescape | ||
| 16 | func typedslicecopy(elemType unsafe.Pointer, dst, src slice) int | ||
| 17 | |||
| 18 | func extendSlice(t reflect.Type, s *slice, n int) slice { | ||
| 19 | elemTypeRef := t.Elem() | ||
| 20 | elemTypePtr := ((*iface)(unsafe.Pointer(&elemTypeRef))).ptr | ||
| 21 | |||
| 22 | d := slice{ | ||
| 23 | data: unsafe_NewArray(elemTypePtr, n), | ||
| 24 | len: s.len, | ||
| 25 | cap: n, | ||
| 26 | } | ||
| 27 | |||
| 28 | typedslicecopy(elemTypePtr, d, *s) | ||
| 29 | return d | ||
| 30 | } | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/splash.png b/vendor/github.com/neilotoole/jsoncolor/splash.png new file mode 100644 index 0000000..f962327 --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/splash.png | |||
| Binary files differ | |||
diff --git a/vendor/github.com/neilotoole/jsoncolor/terminal.go b/vendor/github.com/neilotoole/jsoncolor/terminal.go new file mode 100644 index 0000000..e9398f9 --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/terminal.go | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | //go:build !windows | ||
| 2 | |||
| 3 | package jsoncolor | ||
| 4 | |||
| 5 | import ( | ||
| 6 | "io" | ||
| 7 | "os" | ||
| 8 | |||
| 9 | "golang.org/x/term" | ||
| 10 | ) | ||
| 11 | |||
| 12 | // IsColorTerminal returns true if w is a colorable terminal. | ||
| 13 | // It respects [NO_COLOR], [FORCE_COLOR] and TERM=dumb environment variables. | ||
| 14 | // | ||
| 15 | // [NO_COLOR]: https://no-color.org/ | ||
| 16 | // [FORCE_COLOR]: https://force-color.org/ | ||
| 17 | func IsColorTerminal(w io.Writer) bool { | ||
| 18 | if os.Getenv("NO_COLOR") != "" { | ||
| 19 | return false | ||
| 20 | } | ||
| 21 | if os.Getenv("FORCE_COLOR") != "" { | ||
| 22 | return true | ||
| 23 | } | ||
| 24 | if os.Getenv("TERM") == "dumb" { | ||
| 25 | return false | ||
| 26 | } | ||
| 27 | |||
| 28 | if w == nil { | ||
| 29 | return false | ||
| 30 | } | ||
| 31 | |||
| 32 | f, ok := w.(*os.File) | ||
| 33 | if !ok { | ||
| 34 | return false | ||
| 35 | } | ||
| 36 | |||
| 37 | if !term.IsTerminal(int(f.Fd())) { | ||
| 38 | return false | ||
| 39 | } | ||
| 40 | |||
| 41 | return true | ||
| 42 | } | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/terminal_windows.go b/vendor/github.com/neilotoole/jsoncolor/terminal_windows.go new file mode 100644 index 0000000..38259dc --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/terminal_windows.go | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | package jsoncolor | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "io" | ||
| 5 | "os" | ||
| 6 | |||
| 7 | "golang.org/x/sys/windows" | ||
| 8 | ) | ||
| 9 | |||
| 10 | // IsColorTerminal returns true if w is a colorable terminal. | ||
| 11 | // It respects [NO_COLOR], [FORCE_COLOR] and TERM=dumb environment variables. | ||
| 12 | // | ||
| 13 | // [NO_COLOR]: https://no-color.org/ | ||
| 14 | // [FORCE_COLOR]: https://force-color.org/ | ||
| 15 | func IsColorTerminal(w io.Writer) bool { | ||
| 16 | if os.Getenv("NO_COLOR") != "" { | ||
| 17 | return false | ||
| 18 | } | ||
| 19 | if os.Getenv("FORCE_COLOR") != "" { | ||
| 20 | return true | ||
| 21 | } | ||
| 22 | if os.Getenv("TERM") == "dumb" { | ||
| 23 | return false | ||
| 24 | } | ||
| 25 | |||
| 26 | if w == nil { | ||
| 27 | return false | ||
| 28 | } | ||
| 29 | |||
| 30 | f, ok := w.(*os.File) | ||
| 31 | if !ok { | ||
| 32 | return false | ||
| 33 | } | ||
| 34 | fd := f.Fd() | ||
| 35 | |||
| 36 | console := windows.Handle(fd) | ||
| 37 | var mode uint32 | ||
| 38 | if err := windows.GetConsoleMode(console, &mode); err != nil { | ||
| 39 | return false | ||
| 40 | } | ||
| 41 | |||
| 42 | var want uint32 = windows.ENABLE_PROCESSED_OUTPUT | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING | ||
| 43 | if (mode & want) == want { | ||
| 44 | return true | ||
| 45 | } | ||
| 46 | |||
| 47 | mode |= want | ||
| 48 | if err := windows.SetConsoleMode(console, mode); err != nil { | ||
| 49 | return false | ||
| 50 | } | ||
| 51 | |||
| 52 | return true | ||
| 53 | } | ||
diff --git a/vendor/github.com/neilotoole/jsoncolor/token.go b/vendor/github.com/neilotoole/jsoncolor/token.go new file mode 100644 index 0000000..ba3277e --- /dev/null +++ b/vendor/github.com/neilotoole/jsoncolor/token.go | |||
| @@ -0,0 +1,286 @@ | |||
| 1 | package jsoncolor | ||
| 2 | |||
| 3 | // Tokenizer is an iterator-style type which can be used to progressively parse | ||
| 4 | // through a json input. | ||
| 5 | // | ||
| 6 | // Tokenizing json is useful to build highly efficient parsing operations, for | ||
| 7 | // example when doing tranformations on-the-fly where as the program reads the | ||
| 8 | // input and produces the transformed json to an output buffer. | ||
| 9 | // | ||
| 10 | // Here is a common pattern to use a tokenizer: | ||
| 11 | // | ||
| 12 | // for t := json.NewTokenizer(b); t.Next(); { | ||
| 13 | // switch t.Delim { | ||
| 14 | // case '{': | ||
| 15 | // ... | ||
| 16 | // case '}': | ||
| 17 | // ... | ||
| 18 | // case '[': | ||
| 19 | // ... | ||
| 20 | // case ']': | ||
| 21 | // ... | ||
| 22 | // case ':': | ||
| 23 | // ... | ||
| 24 | // case ',': | ||
| 25 | // ... | ||
| 26 | // } | ||
| 27 | // | ||
| 28 | // switch { | ||
| 29 | // case t.Value.String(): | ||
| 30 | // ... | ||
| 31 | // case t.Value.Null(): | ||
| 32 | // ... | ||
| 33 | // case t.Value.True(): | ||
| 34 | // ... | ||
| 35 | // case t.Value.False(): | ||
| 36 | // ... | ||
| 37 | // case t.Value.Number(): | ||
| 38 | // ... | ||
| 39 | // } | ||
| 40 | // } | ||
| 41 | // | ||
| 42 | type Tokenizer struct { | ||
| 43 | // When the tokenizer is positioned on a json delimiter this field is not | ||
| 44 | // zero. In this case the possible values are '{', '}', '[', ']', ':', and | ||
| 45 | // ','. | ||
| 46 | Delim Delim | ||
| 47 | |||
| 48 | // This field contains the raw json token that the tokenizer is pointing at. | ||
| 49 | // When Delim is not zero, this field is a single-element byte slice | ||
| 50 | // continaing the delimiter value. Otherwise, this field holds values like | ||
| 51 | // null, true, false, numbers, or quoted strings. | ||
| 52 | Value RawValue | ||
| 53 | |||
| 54 | // When the tokenizer has encountered invalid content this field is not nil. | ||
| 55 | Err error | ||
| 56 | |||
| 57 | // When the value is in an array or an object, this field contains the depth | ||
| 58 | // at which it was found. | ||
| 59 | Depth int | ||
| 60 | |||
| 61 | // When the value is in an array or an object, this field contains the | ||
| 62 | // position at which it was found. | ||
| 63 | Index int | ||
| 64 | |||
| 65 | // This field is true when the value is the key of an object. | ||
| 66 | IsKey bool | ||
| 67 | |||
| 68 | // Tells whether the next value read from the tokenizer is a key. | ||
| 69 | isKey bool | ||
| 70 | |||
| 71 | // json input for the tokenizer, pointing at data right after the last token | ||
| 72 | // that was parsed. | ||
| 73 | json []byte | ||
| 74 | |||
| 75 | // Stack used to track entering and leaving arrays, objects, and keys. The | ||
| 76 | // buffer is used as a AppendPre-allocated space to | ||
| 77 | stack []state | ||
| 78 | buffer [8]state | ||
| 79 | } | ||
| 80 | |||
| 81 | type state struct { | ||
| 82 | typ scope | ||
| 83 | len int | ||
| 84 | } | ||
| 85 | |||
| 86 | type scope int | ||
| 87 | |||
| 88 | const ( | ||
| 89 | inArray scope = iota | ||
| 90 | inObject | ||
| 91 | ) | ||
| 92 | |||
| 93 | // NewTokenizer constructs a new Tokenizer which reads its json input from b. | ||
| 94 | func NewTokenizer(b []byte) *Tokenizer { return &Tokenizer{json: b} } | ||
| 95 | |||
| 96 | // Reset erases the state of t and re-initializes it with the json input from b. | ||
| 97 | func (t *Tokenizer) Reset(b []byte) { | ||
| 98 | // This code is similar to: | ||
| 99 | // | ||
| 100 | // *t = Tokenizer{json: b} | ||
| 101 | // | ||
| 102 | // However, it does not compile down to an invocation of duff-copy, which | ||
| 103 | // ends up being slower and prevents the code from being inlined. | ||
| 104 | t.Delim = 0 | ||
| 105 | t.Value = nil | ||
| 106 | t.Err = nil | ||
| 107 | t.Depth = 0 | ||
| 108 | t.Index = 0 | ||
| 109 | t.IsKey = false | ||
| 110 | t.isKey = false | ||
| 111 | t.json = b | ||
| 112 | t.stack = nil | ||
| 113 | } | ||
| 114 | |||
| 115 | // Next returns a new tokenizer pointing at the next token, or the zero-value of | ||
| 116 | // Tokenizer if the end of the json input has been reached. | ||
| 117 | // | ||
| 118 | // If the tokenizer encounters malformed json while reading the input the method | ||
| 119 | // sets t.Err to an error describing the issue, and returns false. Once an error | ||
| 120 | // has been encountered, the tokenizer will always fail until its input is | ||
| 121 | // cleared by a call to its Reset method. | ||
| 122 | func (t *Tokenizer) Next() bool { | ||
| 123 | if t.Err != nil { | ||
| 124 | return false | ||
| 125 | } | ||
| 126 | |||
| 127 | // Inlined code of the skipSpaces function, this give a ~15% speed boost. | ||
| 128 | i := 0 | ||
| 129 | skipLoop: | ||
| 130 | for _, c := range t.json { | ||
| 131 | switch c { | ||
| 132 | case sp, ht, nl, cr: | ||
| 133 | i++ | ||
| 134 | default: | ||
| 135 | break skipLoop | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | if t.json = t.json[i:]; len(t.json) == 0 { | ||
| 140 | t.Reset(nil) | ||
| 141 | return false | ||
| 142 | } | ||
| 143 | |||
| 144 | var d Delim | ||
| 145 | var v []byte | ||
| 146 | var b []byte | ||
| 147 | var err error | ||
| 148 | |||
| 149 | switch t.json[0] { | ||
| 150 | case '"': | ||
| 151 | v, b, err = parseString(t.json) | ||
| 152 | case 'n': | ||
| 153 | v, b, err = parseNull(t.json) | ||
| 154 | case 't': | ||
| 155 | v, b, err = parseTrue(t.json) | ||
| 156 | case 'f': | ||
| 157 | v, b, err = parseFalse(t.json) | ||
| 158 | case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': | ||
| 159 | v, b, err = parseNumber(t.json) | ||
| 160 | case '{', '}', '[', ']', ':', ',': | ||
| 161 | d, v, b = Delim(t.json[0]), t.json[:1], t.json[1:] | ||
| 162 | default: | ||
| 163 | v, b, err = t.json[:1], t.json[1:], syntaxError(t.json, "expected token but found '%c'", t.json[0]) | ||
| 164 | } | ||
| 165 | |||
| 166 | t.Delim = d | ||
| 167 | t.Value = RawValue(v) | ||
| 168 | t.Err = err | ||
| 169 | t.Depth = t.depth() | ||
| 170 | t.Index = t.index() | ||
| 171 | t.IsKey = d == 0 && t.isKey | ||
| 172 | t.json = b | ||
| 173 | |||
| 174 | if d != 0 { | ||
| 175 | switch d { | ||
| 176 | case '{': | ||
| 177 | t.isKey = true | ||
| 178 | t.push(inObject) | ||
| 179 | case '[': | ||
| 180 | t.push(inArray) | ||
| 181 | case '}': | ||
| 182 | err = t.pop(inObject) | ||
| 183 | t.Depth-- | ||
| 184 | t.Index = t.index() | ||
| 185 | case ']': | ||
| 186 | err = t.pop(inArray) | ||
| 187 | t.Depth-- | ||
| 188 | t.Index = t.index() | ||
| 189 | case ':': | ||
| 190 | t.isKey = false | ||
| 191 | case ',': | ||
| 192 | if t.is(inObject) { | ||
| 193 | t.isKey = true | ||
| 194 | } | ||
| 195 | t.stack[len(t.stack)-1].len++ | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | return (d != 0 || len(v) != 0) && err == nil | ||
| 200 | } | ||
| 201 | |||
| 202 | func (t *Tokenizer) push(typ scope) { | ||
| 203 | if t.stack == nil { | ||
| 204 | t.stack = t.buffer[:0] | ||
| 205 | } | ||
| 206 | t.stack = append(t.stack, state{typ: typ, len: 1}) | ||
| 207 | } | ||
| 208 | |||
| 209 | func (t *Tokenizer) pop(expect scope) error { | ||
| 210 | i := len(t.stack) - 1 | ||
| 211 | |||
| 212 | if i < 0 { | ||
| 213 | return syntaxError(t.json, "found unexpected character while tokenizing json input") | ||
| 214 | } | ||
| 215 | |||
| 216 | if found := t.stack[i]; expect != found.typ { | ||
| 217 | return syntaxError(t.json, "found unexpected character while tokenizing json input") | ||
| 218 | } | ||
| 219 | |||
| 220 | t.stack = t.stack[:i] | ||
| 221 | return nil | ||
| 222 | } | ||
| 223 | |||
| 224 | func (t *Tokenizer) is(typ scope) bool { | ||
| 225 | return len(t.stack) != 0 && t.stack[len(t.stack)-1].typ == typ | ||
| 226 | } | ||
| 227 | |||
| 228 | func (t *Tokenizer) depth() int { | ||
| 229 | return len(t.stack) | ||
| 230 | } | ||
| 231 | |||
| 232 | func (t *Tokenizer) index() int { | ||
| 233 | if len(t.stack) == 0 { | ||
| 234 | return 0 | ||
| 235 | } | ||
| 236 | return t.stack[len(t.stack)-1].len - 1 | ||
| 237 | } | ||
| 238 | |||
| 239 | // RawValue represents a raw json value, it is intended to carry null, true, | ||
| 240 | // false, number, and string values only. | ||
| 241 | type RawValue []byte | ||
| 242 | |||
| 243 | // String returns true if v contains a string value. | ||
| 244 | func (v RawValue) String() bool { return len(v) != 0 && v[0] == '"' } | ||
| 245 | |||
| 246 | // Null returns true if v contains a null value. | ||
| 247 | func (v RawValue) Null() bool { return len(v) != 0 && v[0] == 'n' } | ||
| 248 | |||
| 249 | // True returns true if v contains a true value. | ||
| 250 | func (v RawValue) True() bool { return len(v) != 0 && v[0] == 't' } | ||
| 251 | |||
| 252 | // False returns true if v contains a false value. | ||
| 253 | func (v RawValue) False() bool { return len(v) != 0 && v[0] == 'f' } | ||
| 254 | |||
| 255 | // Number returns true if v contains a number value. | ||
| 256 | func (v RawValue) Number() bool { | ||
| 257 | if len(v) != 0 { | ||
| 258 | switch v[0] { | ||
| 259 | case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': | ||
| 260 | return true | ||
| 261 | } | ||
| 262 | } | ||
| 263 | return false | ||
| 264 | } | ||
| 265 | |||
| 266 | // AppendUnquote writes the unquoted version of the string value in v into b. | ||
| 267 | func (v RawValue) AppendUnquote(b []byte) []byte { | ||
| 268 | s, r, new, err := parseStringUnquote([]byte(v), b) | ||
| 269 | if err != nil { | ||
| 270 | panic(err) | ||
| 271 | } | ||
| 272 | if len(r) != 0 { | ||
| 273 | panic(syntaxError(r, "unexpected trailing tokens after json value")) | ||
| 274 | } | ||
| 275 | if new { | ||
| 276 | b = s | ||
| 277 | } else { | ||
| 278 | b = append(b, s...) | ||
| 279 | } | ||
| 280 | return b | ||
| 281 | } | ||
| 282 | |||
| 283 | // Unquote returns the unquoted version of the string value in v. | ||
| 284 | func (v RawValue) Unquote() []byte { | ||
| 285 | return v.AppendUnquote(nil) | ||
| 286 | } | ||
