├── .buildkite
├── hooks
│ └── post-checkout
├── pipeline.yml
├── pull-requests.json
└── scripts
│ └── test.sh
├── .github
├── CODEOWNERS
└── workflows
│ └── catalog-info.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── array.go
├── basetype_string.go
├── bench
├── bench_json_decode_test.go
├── encoder.go
└── files
│ ├── filebeat_events.json
│ ├── metricbeat_events.json
│ └── packetbeat_events.json
├── catalog-info.yaml
├── cborl
├── cborl_test.go
├── decode.go
├── defs.go
├── error.go
├── parse.go
├── stack.go
└── visitor.go
├── go.mod
├── go.sum
├── gotype
├── 0gen.go
├── defs.go
├── error.go
├── fold.go
├── fold_arr.go
├── fold_inline.go
├── fold_map.go
├── fold_map_inline.generated.go
├── fold_map_inline.yml
├── fold_opts.go
├── fold_primitives.go
├── fold_refl_sel.generated.go
├── fold_refl_sel.yml
├── fold_reflect.go
├── fold_test.go
├── fold_user.go
├── gotypes_test.go
├── stacks.generated.go
├── stacks.yml
├── symbols.go
├── tags.go
├── types.yml
├── unfold.go
├── unfold_arr.generated.go
├── unfold_arr.yml
├── unfold_err.generated.go
├── unfold_err.yml
├── unfold_ignore.generated.go
├── unfold_ignore.yml
├── unfold_lookup.go
├── unfold_lookup_go.generated.go
├── unfold_lookup_go.yml
├── unfold_map.generated.go
├── unfold_map.yml
├── unfold_opts.go
├── unfold_primitive.generated.go
├── unfold_primitive.yml
├── unfold_refl.generated.go
├── unfold_refl.go
├── unfold_refl.yml
├── unfold_struct.go
├── unfold_templates.yml
├── unfold_test.go
├── unfold_user.go
├── unfold_user_primitive.generated.go
├── unfold_user_primitive.yml
├── unfold_user_processing.generated.go
└── unfold_user_processing.yml
├── internal
└── unsafe
│ └── unsafe.go
├── json
├── decode.go
├── defs.go
├── json.go
├── json_test.go
├── parse.go
├── state_string.go
└── visitor.go
├── map.go
├── sftest
├── cases.go
├── sftest.go
├── sftest_test.go
└── util.go
├── string.go
├── ubjson
├── decode.go
├── defs.go
├── parse.go
├── stack.go
├── statestep_string.go
├── statetype_string.go
├── ubjson_test.go
└── visitor.go
├── visitor.go
└── visitors
├── expect_obj.go
├── nilVisitor.go
└── stringer.go
/.buildkite/hooks/post-checkout:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euo pipefail
4 |
5 | checkout_merge() {
6 | local target_branch=$1
7 | local pr_commit=$2
8 | local merge_branch=$3
9 |
10 | if [[ -z "${target_branch}" ]]; then
11 | echo "No pull request target branch"
12 | exit 1
13 | fi
14 |
15 | git fetch -v origin "${target_branch}"
16 | git checkout FETCH_HEAD
17 | echo "Current branch: $(git rev-parse --abbrev-ref HEAD)"
18 |
19 | # create temporal branch to merge the PR with the target branch
20 | git checkout -b ${merge_branch}
21 | echo "New branch created: $(git rev-parse --abbrev-ref HEAD)"
22 |
23 | # set author identity so it can be run git merge
24 | git config user.name "github-merged-pr-post-checkout"
25 | git config user.email "auto-merge@buildkite"
26 |
27 | git merge --no-edit "${BUILDKITE_COMMIT}" || {
28 | local merge_result=$?
29 | echo "Merge failed: ${merge_result}"
30 | git merge --abort
31 | exit ${merge_result}
32 | }
33 | }
34 |
35 | pull_request="${BUILDKITE_PULL_REQUEST:-false}"
36 |
37 | if [[ "${pull_request}" == "false" ]]; then
38 | echo "Not a pull request, skipping"
39 | exit 0
40 | fi
41 |
42 | TARGET_BRANCH="${BUILDKITE_PULL_REQUEST_BASE_BRANCH:-master}"
43 | PR_COMMIT="${BUILDKITE_COMMIT}"
44 | PR_ID=${BUILDKITE_PULL_REQUEST}
45 | MERGE_BRANCH="pr_merge_${PR_ID}"
46 |
47 | checkout_merge "${TARGET_BRANCH}" "${PR_COMMIT}" "${MERGE_BRANCH}"
48 |
49 | echo "Commit information"
50 | git --no-pager log --format=%B -n 1
51 |
52 | # Ensure buildkite groups are rendered
53 | echo ""
54 |
--------------------------------------------------------------------------------
/.buildkite/pipeline.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/buildkite/pipeline-schema/main/schema.json
2 |
3 | steps:
4 | - group: "Test matrix. Linux"
5 | steps:
6 | - label: ":linux: Test matrix. Go {{matrix.go_version}}"
7 | key: test-matrix-lin
8 | matrix:
9 | setup:
10 | go_version:
11 | - "1.15.6"
12 | - "1.16.2"
13 | command:
14 | - ".buildkite/scripts/test.sh"
15 | env:
16 | GO_VERSION: "{{matrix.go_version}}"
17 | agents:
18 | image: golang:{{matrix.go_version}}
19 | cpu: "8"
20 | memory: "4G"
21 | artifact_paths:
22 | - "build/junit-*.xml"
23 |
24 | - label: ":junit: Junit annotate"
25 | plugins:
26 | - junit-annotate#v2.4.1:
27 | artifacts: "*.xml"
28 | fail-build-on-error: true
29 | agents:
30 | provider: "gcp"
31 | depends_on:
32 | - step: "test-matrix-lin"
33 | allow_failure: true
34 |
--------------------------------------------------------------------------------
/.buildkite/pull-requests.json:
--------------------------------------------------------------------------------
1 | {
2 | "jobs": [
3 | {
4 | "enabled": true,
5 | "pipelineSlug": "go-structform",
6 | "allow_org_users": true,
7 | "allowed_repo_permissions": ["admin", "write"],
8 | "allowed_list": [ ],
9 | "set_commit_status": true,
10 | "build_on_commit": true,
11 | "build_on_comment": true,
12 | "trigger_comment_regex": "^(?:(?:buildkite\\W+)?(?:build|test)\\W+(?:this|it))|^/test$",
13 | "always_trigger_comment_regex": "^(?:(?:buildkite\\W+)?(?:build|test)\\W+(?:this|it))|^/test$",
14 | "skip_ci_labels": [ ],
15 | "skip_target_branches": [ ],
16 | "skip_ci_on_only_changed": [ ],
17 | "always_require_ci_on_changed": [ ]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/.buildkite/scripts/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euxo pipefail
3 |
4 | echo "--- go get for ${GO_VERSION}"
5 | go get -v -t ./...
6 |
7 | echo "--- go test for ${GO_VERSION}"
8 | set +e
9 | export OUT_FILE="build/test-report.out"
10 | mkdir -p build
11 | go test -v -race ./... 2>&1 | tee ${OUT_FILE}
12 | status=$?
13 |
14 | go get -v -u github.com/jstemmer/go-junit-report
15 | go-junit-report > "build/junit-${GO_VERSION}.xml" < ${OUT_FILE}
16 |
17 | exit ${status}
18 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # GitHub CODEOWNERS definition
2 | # See: https://help.github.com/articles/about-codeowners/
3 | * @elastic/elastic-agent-data-plane
--------------------------------------------------------------------------------
/.github/workflows/catalog-info.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: catalog-info
3 |
4 | on:
5 | pull_request:
6 | branches:
7 | - main
8 | paths:
9 | - 'catalog-info.yaml'
10 |
11 | jobs:
12 | validate:
13 | runs-on: ubuntu-latest
14 | permissions:
15 | contents: read
16 | packages: read
17 | steps:
18 | - uses: actions/checkout@v4
19 |
20 | - uses: elastic/oblt-actions/elastic/validate-catalog@v1
21 |
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.dll
4 | *.so
5 | *.dylib
6 |
7 | # Test binary, build with `go test -c`
8 | *.test
9 |
10 | # Output of the go coverage tool, specifically when used with LiteIDE
11 | *.out
12 |
13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
14 | .glide/
15 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 | This project adheres to [Semantic Versioning](http://semver.org/).
4 |
5 | ## [Unreleased]
6 |
7 | ### Added
8 |
9 | ### Changed
10 |
11 | ### Deprecated
12 |
13 | ### Removed
14 |
15 | ### Fixed
16 |
17 | ## [0.0.10]
18 |
19 | ### Changed
20 | - Remove duplicate fields to avoid unnecessary struct grows. (PR #38)
21 | - Reorder elements in structs to reduce memory. (PR #37)
22 |
23 | ### Fixed
24 | - Fix to break out of endless loop. (PR #36)
25 |
26 | ## [0.0.9]
27 |
28 | ### Added
29 | - Added `IsZeroer` interface to allow custom types to report that they are not initialized. A structs field is not serialized if the `omitempty` struct tag is set and `IsZero()` returns true. #32
30 |
31 | ### Fixed
32 | - Ensure `Fold` can be called when a value is given by value, but the `Folder` interface is implemented on the pointer type. #32
33 |
34 | ## [0.0.8]
35 |
36 | ### Added
37 |
38 | - Add optional support to JSON encoder to encode a NaN or Inf floating point value to null. (PR #28)
39 |
40 | ## [0.0.7]
41 |
42 | ### Fixed
43 |
44 | - Fix potential use after free in string and []byte conversions. (PR #21)
45 |
46 | ## [0.0.6]
47 |
48 | ### Added
49 | - Regenerate code with new stringer. (PR #9)
50 | - Add support for custom unfolders when generating gotype.Unfolder. (PR #14, PR #15, PR #17)
51 | - Add go.mod file
52 |
53 | ## [0.0.5]
54 |
55 | ### Added
56 | - Add Reset to gotype.Unfolder. (PR #7)
57 |
58 | ## [0.0.4]
59 |
60 | ### Added
61 | - Add SetEscapeHTML to json visitor. (PR #4)
62 |
63 | ## [0.0.3]
64 |
65 | ### Added
66 | - Add `visitors.NilVisitor`. (Commit ab1cb2d)
67 |
68 | ### Changed
69 | - Replace code generator with mktmlp (github.com/urso/mktmpl). (Commit 0356386)
70 | - Introduce custom number parser. (Commit 41308dd)
71 |
72 | ### Fixed
73 | - Fix gc failures by removing region allocator for temporary objects in decoder. Decoding into `map[string]X` with `X` being a custom go struct will require an extra alloc by now. (Commit 9b12176)
74 | - Fix invalid cast on pointer math. (Commit ea18344)
75 |
76 | ## [0.0.2]
77 |
78 | ### Added
79 | - Add struct tag option ",omitempty".
80 | - Add StringConvVisitor converting all primitive values to strings.
81 | - Move and export object visitor into visitors package
82 |
83 | ### Fixed
84 | - Fix invalid pointer indirections in struct to array/map.
85 |
86 | [Unreleased]: https://github.com/elastic/go-structform/compare/v0.0.10...HEAD
87 | [0.0.10]: https://github.com/elastic/go-structform/compare/v0.0.9...v0.0.10
88 | [0.0.9]: https://github.com/elastic/go-structform/compare/v0.0.8...v0.0.9
89 | [0.0.8]: https://github.com/elastic/go-structform/compare/v0.0.7...v0.0.8
90 | [0.0.7]: https://github.com/elastic/go-structform/compare/v0.0.6...v0.0.7
91 | [0.0.6]: https://github.com/elastic/go-structform/compare/v0.0.5...v0.0.6
92 | [0.0.5]: https://github.com/elastic/go-structform/compare/v0.0.4...v0.0.5
93 | [0.0.4]: https://github.com/elastic/go-structform/compare/v0.0.3...v0.0.4
94 | [0.0.3]: https://github.com/elastic/go-structform/compare/v0.0.2...v0.0.3
95 | [0.0.2]: https://github.com/elastic/go-structform/compare/v0.0.1...v0.0.2
96 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://beats-ci.elastic.co/job/Library/job/go-structform-mbp/job/master/)
2 | # Go-Structform - Structured Formatters
3 |
4 | go-structform provides capabilities for serializing, desirializing, and
5 | transcoding structured data efficiently and generically.
6 |
7 | The top-level package provides the common layer by which serializers and
8 | deserializers interact with each other. Serializers convert the input into a
9 | stream of events by calling methods on the
10 | [Visitor](https://pkg.go.dev/github.com/elastic/go-structform?tab=doc#Visitor)
11 | interfaces. The Deserializers implement the Visitor interface to convert the
12 | stream of events into the target structure.
13 |
14 | A type implementing the `Visitor` interface, but forwards calls to another
15 | visitor is called a Transformer or Filter. Transformers/Filters can manipulate
16 | the data stream or create/collect errors if some wanted validation fails.
17 |
18 | ## Examples
19 |
20 | Transcode a stream of JSON objects into a stream of CBOR objects:
21 |
22 | ```
23 | func TranscodeJSON2CBOR(out io.Writer, in io.Reader) (int64, error) {
24 | bytesCount, err := json.ParseReader(in, cborl.NewVisitor(out))
25 | return bytesCount, err
26 | }
27 | ```
28 |
29 | Parse a stream of JSON objects:
30 |
31 | ```
32 | var in io.Reader = ...
33 | visitor, _ := gotype.NewUnfolder(nil)
34 | dec := json.NewDecoder(in, 2048, visitor)
35 | for {
36 | var to interface{}
37 | visitor.SetTarget(&to)
38 | if err := dec.Next(); err != nil {
39 | return err
40 | }
41 |
42 | // process `to`
43 | }
44 | ```
45 |
46 | Encode a channel of go `map[string]interface{}` to a stream of cbor objects:
47 |
48 | ```
49 | var out io.Writer = ...
50 | var objects chan map[string]interface{} = ...
51 |
52 | visitor := cborl.NewVisitor(out)
53 | it, _ := gotype.NewIterator(visitor)
54 | for _, obj := range objects {
55 | if err := it.Fold(obj); err != nil {
56 | return err
57 | }
58 | }
59 |
60 | return nil
61 | ```
62 |
63 | Convert between go types:
64 |
65 | ```
66 | var to map[string]int
67 | visitor, _ := gotype.NewUnfolder(&to)
68 | it, _ := gotype.NewIterator(visitor)
69 |
70 | st := struct {
71 | A int `struct:"a"`
72 | B string `struct:",omit"`
73 | }{A: 1, B: "hello"}
74 | if err := it.Fold(st); err != nil {
75 | return err
76 | }
77 |
78 | // to == map[string]int{"a": 1}
79 | ```
80 |
81 | Use custom folder and unfolder for existing go types:
82 |
83 | ```
84 | type durationUnfolder struct {
85 | gotype.BaseUnfoldState // Use BaseUnfoldState to create errors for methods not implemented
86 | to *time.Duration
87 | }
88 |
89 | func foldDuration(in *time.Duration, v structform.ExtVisitor) error {
90 | return v.OnString(in.String())
91 | }
92 |
93 | func unfoldDuration(to *time.Duration) gotype.UnfoldState {
94 | return &durationUnfolder{to: to}
95 | }
96 |
97 | type durationUnfolder struct {
98 | gotype.BaseUnfoldState // Use BaseUnfoldState to create errors for methods not implemented
99 | to *time.Duration
100 | }
101 |
102 | func (u *durationUnfolder) OnString(_ gotype.UnfoldCtx, str string) error {
103 | d, err := time.ParseDuration(str)
104 | if err == nil {
105 | *u.to = d
106 | }
107 | return err
108 | }
109 |
110 |
111 | ...
112 |
113 |
114 | visitor, _ := gotype.NewUnfolder(nil, gotype.Unfolders(
115 | unfoldDuration,
116 | ))
117 | it, _ := gotype.NewIterator(visitor, gotype.Folders(
118 | foldDuration,
119 | ))
120 |
121 | // store duration in temporary value
122 | var tmp interface{}
123 | visitor.SetTarget(&tmp)
124 | it.Fold(5 * time.Minute)
125 |
126 | // restore duration from temporary value
127 | var dur time.Duration
128 | visitor.SetTarget(&dur)
129 | it.Fold(tmp)
130 |
131 | // dur == 5 * time.Minute
132 | ```
133 |
134 | ## Data Model
135 |
136 | The data model describes by which data types Serializers and Deserializers
137 | interact. In this sense the data model provides a simplified type system, that supports a subset of
138 | serializable go types (for example channels or function pointers can not be serialized).
139 |
140 | Go-structform provides a simplified, common data model via the [Visitor](https://pkg.go.dev/github.com/elastic/go-structform?tab=doc#Visitor) interface.
141 |
142 | ### Types
143 |
144 | - **primitives** (See [ValueVisitor](https://pkg.go.dev/github.com/elastic/go-structform?tab=doc#ValueVisitor) interface): `Bool`, `Byte`, `String`, `Int`, `Int8/16/32/64`, `Uint`, `Uint8/16/32/64`, `Float32`, `Float64`, untyped `Nil`
145 | - **compound**: objects ([ObjectVisitor](https://pkg.go.dev/github.com/elastic/go-structform?tab=doc#ObjectVisitor)), arrays ([ArrayVisitor](https://pkg.go.dev/github.com/elastic/go-structform?tab=doc#ArrayVisitor))
146 |
147 | ## Extended Data Model
148 |
149 | The extended data model provides support for similar types to the `Visitor`
150 | interface, but provides a number of optimizations, allowing users to pass a set
151 | of common go values directly without having to serialize and deserialize those
152 | values.
153 |
154 | The extended data model is provided by the
155 | [`ExtVisitor`](https://pkg.go.dev/github.com/elastic/go-structform?tab=doc#ExtVisitor)
156 | interface.
157 |
158 | All features in the Extended Data Model can be seamlessly converted to the Data
159 | Model provided by the `Visitor interface.
160 |
161 | Deserializers supporting the Extended Data Model must always implement the
162 | common Data Model as is required by the `Visitor` interface.
163 |
164 | Serializers wanting to interact with the Extended Data Model should still
165 | accept the `Visitor` interface only and use `EnsureExtVisitor` in order to create an `ExtVisitor`.
166 | `EnsureExtVisitor` wraps the `Visitor` if necessarry, allowing the `Visitor` to
167 | implement only a subset of features in the Extended Data Model.
168 |
169 | - **extended primitives**: The Visitor adds support for `[]byte` values as
170 | strings. The value must be consumed immediately or copied, as the buffer is
171 | not guaranteed to be stable.
172 | - **slices**: The visitor adds support for slice types, for each supported
173 | primitive type. For example `[]int8/16/32/64` can be passed as is.
174 | - **map**: The visitor adds support for `map[string]T` types, for each
175 | supported primitive type. For example `map[string]int8/16/32/64`.
176 |
177 |
178 | ## Data Formats
179 |
180 | - JSON: the `json` package provides a JSON parser and JSON serializer. The serializer implements a subset of `ExtVisitor`.
181 | - UBJSON: the `ubjson` packages provides a parser and serializer for Universal Binary JSON.
182 | - CBOR: the `cborl` package supports a compatible subset of CBOR (for example object keys must be strings).
183 | - Go Types: the `gotype` package provides a `Folder` to convert go values into
184 | a stream of events and an `Unfolder` to apply a stream of events to go
185 | values.
186 |
--------------------------------------------------------------------------------
/array.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package structform
19 |
20 | type extArrVisitor struct {
21 | Visitor
22 | }
23 |
24 | func (ev extArrVisitor) OnStringArray(a []string) error {
25 | if err := ev.OnArrayStart(len(a), StringType); err != nil {
26 | return err
27 | }
28 | for _, v := range a {
29 | if err := ev.OnString(v); err != nil {
30 | return err
31 | }
32 | }
33 | return ev.OnArrayFinished()
34 | }
35 |
36 | func (ev extArrVisitor) OnBoolArray(a []bool) error {
37 | if err := ev.OnArrayStart(len(a), BoolType); err != nil {
38 | return err
39 | }
40 | for _, v := range a {
41 | if err := ev.OnBool(v); err != nil {
42 | return err
43 | }
44 | }
45 | return ev.OnArrayFinished()
46 | }
47 |
48 | func (ev extArrVisitor) OnInt8Array(a []int8) error {
49 | if err := ev.OnArrayStart(len(a), Int8Type); err != nil {
50 | return err
51 | }
52 | for _, v := range a {
53 | if err := ev.OnInt8(v); err != nil {
54 | return err
55 | }
56 | }
57 | return ev.OnArrayFinished()
58 | }
59 |
60 | func (ev extArrVisitor) OnInt16Array(a []int16) error {
61 | if err := ev.OnArrayStart(len(a), Int16Type); err != nil {
62 | return err
63 | }
64 | for _, v := range a {
65 | if err := ev.OnInt16(v); err != nil {
66 | return err
67 | }
68 | }
69 | return ev.OnArrayFinished()
70 | }
71 |
72 | func (ev extArrVisitor) OnInt32Array(a []int32) error {
73 | if err := ev.OnArrayStart(len(a), Int32Type); err != nil {
74 | return err
75 | }
76 | for _, v := range a {
77 | if err := ev.OnInt32(v); err != nil {
78 | return err
79 | }
80 | }
81 | return ev.OnArrayFinished()
82 | }
83 |
84 | func (ev extArrVisitor) OnInt64Array(a []int64) error {
85 | if err := ev.OnArrayStart(len(a), Int64Type); err != nil {
86 | return err
87 | }
88 | for _, v := range a {
89 | if err := ev.OnInt64(v); err != nil {
90 | return err
91 | }
92 | }
93 | return ev.OnArrayFinished()
94 | }
95 |
96 | func (ev extArrVisitor) OnIntArray(a []int) error {
97 | if err := ev.OnArrayStart(len(a), IntType); err != nil {
98 | return err
99 | }
100 | for _, v := range a {
101 | if err := ev.OnInt(v); err != nil {
102 | return err
103 | }
104 | }
105 | return ev.OnArrayFinished()
106 | }
107 |
108 | func (ev extArrVisitor) OnBytes(b []byte) error {
109 | if err := ev.OnArrayStart(len(b), ByteType); err != nil {
110 | return err
111 | }
112 | for _, v := range b {
113 | if err := ev.OnByte(v); err != nil {
114 | return err
115 | }
116 | }
117 | return ev.OnArrayFinished()
118 | }
119 |
120 | func (ev extArrVisitor) OnUint8Array(a []uint8) error {
121 | if err := ev.OnArrayStart(len(a), Uint8Type); err != nil {
122 | return err
123 | }
124 | for _, v := range a {
125 | if err := ev.OnUint8(v); err != nil {
126 | return err
127 | }
128 | }
129 | return ev.OnArrayFinished()
130 | }
131 |
132 | func (ev extArrVisitor) OnUint16Array(a []uint16) error {
133 | if err := ev.OnArrayStart(len(a), Uint16Type); err != nil {
134 | return err
135 | }
136 | for _, v := range a {
137 | if err := ev.OnUint16(v); err != nil {
138 | return err
139 | }
140 | }
141 | return ev.OnArrayFinished()
142 | }
143 |
144 | func (ev extArrVisitor) OnUint32Array(a []uint32) error {
145 | if err := ev.OnArrayStart(len(a), Uint32Type); err != nil {
146 | return err
147 | }
148 | for _, v := range a {
149 | if err := ev.OnUint32(v); err != nil {
150 | return err
151 | }
152 | }
153 | return ev.OnArrayFinished()
154 | }
155 |
156 | func (ev extArrVisitor) OnUint64Array(a []uint64) error {
157 | if err := ev.OnArrayStart(len(a), Uint64Type); err != nil {
158 | return err
159 | }
160 | for _, v := range a {
161 | if err := ev.OnUint64(v); err != nil {
162 | return err
163 | }
164 | }
165 | return ev.OnArrayFinished()
166 | }
167 |
168 | func (ev extArrVisitor) OnUintArray(a []uint) error {
169 | if err := ev.OnArrayStart(len(a), UintType); err != nil {
170 | return err
171 | }
172 | for _, v := range a {
173 | if err := ev.OnUint(v); err != nil {
174 | return err
175 | }
176 | }
177 | return ev.OnArrayFinished()
178 | }
179 |
180 | func (ev extArrVisitor) OnFloat32Array(a []float32) error {
181 | if err := ev.OnArrayStart(len(a), Float32Type); err != nil {
182 | return err
183 | }
184 | for _, v := range a {
185 | if err := ev.OnFloat32(v); err != nil {
186 | return err
187 | }
188 | }
189 | return ev.OnArrayFinished()
190 | }
191 |
192 | func (ev extArrVisitor) OnFloat64Array(a []float64) error {
193 | if err := ev.OnArrayStart(len(a), Float64Type); err != nil {
194 | return err
195 | }
196 | for _, v := range a {
197 | if err := ev.OnFloat64(v); err != nil {
198 | return err
199 | }
200 | }
201 | return ev.OnArrayFinished()
202 | }
203 |
--------------------------------------------------------------------------------
/basetype_string.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | // Code generated by "stringer -type=BaseType"; DO NOT EDIT.
19 |
20 | package structform
21 |
22 | import "strconv"
23 |
24 | const _BaseType_name = "AnyTypeByteTypeStringTypeBoolTypeZeroTypeIntTypeInt8TypeInt16TypeInt32TypeInt64TypeUintTypeUint8TypeUint16TypeUint32TypeUint64TypeFloat32TypeFloat64Type"
25 |
26 | var _BaseType_index = [...]uint8{0, 7, 15, 25, 33, 41, 48, 56, 65, 74, 83, 91, 100, 110, 120, 130, 141, 152}
27 |
28 | func (i BaseType) String() string {
29 | if i >= BaseType(len(_BaseType_index)-1) {
30 | return "BaseType(" + strconv.FormatInt(int64(i), 10) + ")"
31 | }
32 | return _BaseType_name[_BaseType_index[i]:_BaseType_index[i+1]]
33 | }
34 |
--------------------------------------------------------------------------------
/bench/encoder.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | //+build compare
19 |
20 | package bench
21 |
22 | import (
23 | "bytes"
24 | stdjson "encoding/json"
25 | "io"
26 |
27 | jsoniter "github.com/json-iterator/go"
28 | "github.com/ugorji/go/codec"
29 |
30 | "github.com/elastic/go-structform/cborl"
31 | "github.com/elastic/go-structform/gotype"
32 | "github.com/elastic/go-structform/json"
33 | "github.com/elastic/go-structform/ubjson"
34 | )
35 |
36 | type encoderFactory func(io.Writer) func(interface{}) error
37 | type decoderFactory func([]byte) func(interface{}) error
38 | type transcodeFactory func(io.Writer) func([]byte) error
39 |
40 | func stdJSONEncoder(w io.Writer) func(interface{}) error {
41 | enc := stdjson.NewEncoder(w)
42 | return enc.Encode
43 | }
44 |
45 | func stdJSONDecoder(r io.Reader) func(interface{}) error {
46 | dec := stdjson.NewDecoder(r)
47 | return dec.Decode
48 | }
49 |
50 | func stdJSONBufDecoder(b []byte) func(interface{}) error {
51 | return stdJSONDecoder(bytes.NewReader(b))
52 | }
53 |
54 | func gocodecJSONDecoder(r io.Reader) func(interface{}) error {
55 | h := &codec.JsonHandle{}
56 | dec := codec.NewDecoder(r, h)
57 | return dec.Decode
58 | }
59 |
60 | func jsoniterDecoder(r io.Reader) func(interface{}) error {
61 | dec := jsoniter.ConfigCompatibleWithStandardLibrary.NewDecoder(r)
62 | return func(v interface{}) error {
63 | if !dec.More() {
64 | return io.EOF
65 | }
66 | return dec.Decode(v)
67 | }
68 | }
69 |
70 | func jsoniterBufDecoder(b []byte) func(interface{}) error {
71 | return jsoniterDecoder(bytes.NewReader(b))
72 | }
73 |
74 | func structformJSONEncoder(w io.Writer) func(interface{}) error {
75 | vs := json.NewVisitor(w)
76 | folder, _ := gotype.NewIterator(vs)
77 | return folder.Fold
78 | }
79 |
80 | func structformUBJSONEncoder(w io.Writer) func(interface{}) error {
81 | vs := ubjson.NewVisitor(w)
82 | folder, _ := gotype.NewIterator(vs)
83 | return folder.Fold
84 | }
85 |
86 | func structformCBORLEncoder(w io.Writer) func(interface{}) error {
87 | vs := cborl.NewVisitor(w)
88 | folder, _ := gotype.NewIterator(vs)
89 | return folder.Fold
90 | }
91 |
92 | func structformJSONBufDecoder(keyCache int) func([]byte) func(interface{}) error {
93 | return func(b []byte) func(interface{}) error {
94 | u, _ := gotype.NewUnfolder(nil)
95 | dec := json.NewBytesDecoder(b, u)
96 | return makeStructformDecoder(u, dec.Next, keyCache)
97 | }
98 | }
99 |
100 | func structformUBJSONBufDecoder(keyCache int) func([]byte) func(interface{}) error {
101 | return func(b []byte) func(interface{}) error {
102 | u, _ := gotype.NewUnfolder(nil)
103 | dec := ubjson.NewBytesDecoder(b, u)
104 | return makeStructformDecoder(u, dec.Next, keyCache)
105 | }
106 | }
107 |
108 | func structformCBORLBufDecoder(keyCache int) func([]byte) func(interface{}) error {
109 | return func(b []byte) func(interface{}) error {
110 | u, _ := gotype.NewUnfolder(nil)
111 | dec := cborl.NewBytesDecoder(b, u)
112 | return makeStructformDecoder(u, dec.Next, keyCache)
113 | }
114 | }
115 |
116 | func makeStructformDecoder(
117 | u *gotype.Unfolder,
118 | next func() error,
119 | keyCache int,
120 | ) func(interface{}) error {
121 | if keyCache > 0 {
122 | u.EnableKeyCache(keyCache)
123 | }
124 | return func(v interface{}) error {
125 | if err := u.SetTarget(v); err != nil {
126 | return err
127 | }
128 | return next()
129 | }
130 | }
131 |
132 | func makeCBORL2JSONTranscoder(w io.Writer) func([]byte) error {
133 | j := json.NewVisitor(w)
134 | p := cborl.NewParser(j)
135 | return p.Parse
136 | }
137 |
138 | func makeUBJSON2JSONTranscoder(w io.Writer) func([]byte) error {
139 | j := json.NewVisitor(w)
140 | p := ubjson.NewParser(j)
141 | return p.Parse
142 | }
143 |
--------------------------------------------------------------------------------
/catalog-info.yaml:
--------------------------------------------------------------------------------
1 | # Declare a Backstage Component that represents your application.
2 | ---
3 | # yaml-language-server: $schema=https://json.schemastore.org/catalog-info.json
4 | apiVersion: backstage.io/v1alpha1
5 | kind: Component
6 | metadata:
7 | name: go-structform
8 |
9 | spec:
10 | type: library
11 | owner: group:ingest-fp
12 | system: platform-ingest
13 | lifecycle: production
14 |
15 | ---
16 | # yaml-language-server: $schema=https://gist.githubusercontent.com/elasticmachine/988b80dae436cafea07d9a4a460a011d/raw/rre.schema.json
17 | apiVersion: backstage.io/v1alpha1
18 | kind: Resource
19 | metadata:
20 | name: buildkite-pipeline-go-structform
21 | description: Buildkite pipeline for the go-structform project
22 | links:
23 | - title: Pipeline
24 | url: https://buildkite.com/elastic/go-structform
25 |
26 | spec:
27 | type: buildkite-pipeline
28 | owner: group:ingest-fp
29 | system: platform-ingest
30 | implementation:
31 | apiVersion: buildkite.elastic.dev/v1
32 | kind: Pipeline
33 | metadata:
34 | name: go-structform
35 | description: Buildkite pipeline for the go-structform project
36 | spec:
37 | repository: elastic/go-structform
38 | pipeline_file: ".buildkite/pipeline.yml"
39 | maximum_timeout_in_minutes: 60
40 | provider_settings:
41 | build_pull_request_forks: false
42 | build_pull_requests: true # requires filter_enabled and filter_condition settings as below when used with buildkite-pr-bot
43 | build_tags: true
44 | filter_enabled: true
45 | filter_condition: >-
46 | build.pull_request.id == null || (build.creator.name == 'elasticmachine' && build.pull_request.id != null)
47 | cancel_intermediate_builds: true
48 | cancel_intermediate_builds_branch_filter: '!main'
49 | skip_intermediate_builds: true
50 | skip_intermediate_builds_branch_filter: '!main'
51 | env:
52 | ELASTIC_PR_COMMENTS_ENABLED: 'true'
53 | teams:
54 | ingest-fp:
55 | access_level: MANAGE_BUILD_AND_READ
56 | ingest-eng-prod:
57 | access_level: MANAGE_BUILD_AND_READ
58 | everyone:
59 | access_level: READ_ONLY
60 |
--------------------------------------------------------------------------------
/cborl/cborl_test.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package cborl
19 |
20 | import (
21 | "bytes"
22 | "testing"
23 |
24 | structform "github.com/elastic/go-structform"
25 | "github.com/elastic/go-structform/sftest"
26 | )
27 |
28 | func TestEncParseConsistent(t *testing.T) {
29 | testEncParseConsistent(t, Parse)
30 | }
31 |
32 | func TestEncDecoderConsistent(t *testing.T) {
33 | testEncParseConsistent(t, func(content []byte, to structform.Visitor) error {
34 | dec := NewBytesDecoder(content, to)
35 | return dec.Next()
36 | })
37 | }
38 |
39 | func TestEncParseBytesConsistent(t *testing.T) {
40 | testEncParseConsistent(t, func(content []byte, to structform.Visitor) error {
41 | p := NewParser(to)
42 | for _, b := range content {
43 | err := p.feed([]byte{b})
44 | if err != nil {
45 | return err
46 | }
47 | }
48 | return nil
49 | })
50 | }
51 |
52 | func testEncParseConsistent(
53 | t *testing.T,
54 | parse func([]byte, structform.Visitor) error,
55 | ) {
56 | sftest.TestEncodeParseConsistent(t, sftest.Samples,
57 | func() (structform.Visitor, func(structform.Visitor) error) {
58 | buf := bytes.NewBuffer(nil)
59 | vs := NewVisitor(buf)
60 |
61 | return vs, func(to structform.Visitor) error {
62 | return parse(buf.Bytes(), to)
63 | }
64 | })
65 | }
66 |
--------------------------------------------------------------------------------
/cborl/decode.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package cborl
19 |
20 | import (
21 | "io"
22 |
23 | structform "github.com/elastic/go-structform"
24 | )
25 |
26 | type Decoder struct {
27 | in io.Reader
28 | buffer []byte
29 | buffer0 []byte
30 |
31 | p Parser
32 | }
33 |
34 | func NewDecoder(in io.Reader, buffer int, vs structform.Visitor) *Decoder {
35 | dec := &Decoder{
36 | buffer0: make([]byte, buffer),
37 | in: in,
38 | }
39 | dec.p.init(vs)
40 | return dec
41 | }
42 |
43 | func NewBytesDecoder(b []byte, vs structform.Visitor) *Decoder {
44 | dec := &Decoder{
45 | buffer: b,
46 | buffer0: b[:0],
47 | in: nil,
48 | }
49 | dec.p.init(vs)
50 | return dec
51 | }
52 |
53 | func (dec *Decoder) Next() error {
54 | var (
55 | n int
56 | err error
57 | reported bool
58 | )
59 |
60 | for !reported {
61 | if len(dec.buffer) == 0 {
62 | if dec.in == nil {
63 | return io.EOF
64 | }
65 |
66 | n, err := dec.in.Read(dec.buffer0)
67 | dec.buffer = dec.buffer0[:n]
68 | if err != nil {
69 | return err
70 | }
71 | }
72 |
73 | n, reported, err = dec.p.feedUntil(dec.buffer)
74 | if err != nil {
75 | return err
76 | }
77 |
78 | dec.buffer = dec.buffer[n:]
79 | if reported {
80 | return nil
81 | }
82 | }
83 |
84 | return nil
85 | }
86 |
--------------------------------------------------------------------------------
/cborl/defs.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package cborl
19 |
20 | import "github.com/elastic/go-structform/internal/unsafe"
21 |
22 | const (
23 | majorUint uint8 = 0x00
24 | majorNeg uint8 = 1 << 5
25 | majorBytes uint8 = 2 << 5
26 | majorText uint8 = 3 << 5
27 | majorArr uint8 = 4 << 5
28 | majorMap uint8 = 5 << 5
29 | majorTag uint8 = 6 << 5
30 | majorOther uint8 = 7 << 5
31 |
32 | majorMask uint8 = 7 << 5
33 | minorMask uint8 = ^majorMask
34 | )
35 |
36 | const (
37 | lenSmall uint8 = 0
38 | len8b uint8 = 24
39 | len16b uint8 = 25
40 | len32b uint8 = 26
41 | len64b uint8 = 27
42 | lenIndef uint8 = 31
43 | )
44 |
45 | const (
46 | codeFalse uint8 = 20 | majorOther
47 | codeTrue uint8 = 21 | majorOther
48 | codeNull uint8 = 22 | majorOther
49 | codeUndef uint8 = 23 | majorOther
50 |
51 | codeHalfFloat uint8 = 25 | majorOther
52 | codeSingleFloat uint8 = 26 | majorOther
53 | codeDoubleFloat uint8 = 27 | majorOther
54 | codeBreak uint8 = lenIndef | majorOther
55 | )
56 |
57 | func str2Bytes(s string) []byte {
58 | return unsafe.Str2Bytes(s)
59 | }
60 |
61 | func bytes2Str(b []byte) string {
62 | return unsafe.Bytes2Str(b)
63 | }
64 |
--------------------------------------------------------------------------------
/cborl/error.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package cborl
19 |
20 | import "errors"
21 |
22 | func errTODO() error {
23 | err := errors.New("TODO")
24 | panic(err)
25 | }
26 |
27 | var errInvalidCode = errors.New("invalid type code")
28 | var errTextKeyRequired = errors.New("only text keys supported")
29 | var errIndefByteSeq = errors.New("text/bytes of indefinite length not supported")
30 | var errEmptyKey = errors.New("object keys must not be empty")
31 |
--------------------------------------------------------------------------------
/cborl/stack.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package cborl
19 |
20 | type stateStack struct {
21 | stack []state // state stack for nested arrays/objects
22 | stack0 [64]state
23 | current state
24 | }
25 |
26 | type lengthStack struct {
27 | stack []int64
28 | stack0 [32]int64
29 | current int64
30 | }
31 |
32 | func (s *stateStack) init(s0 state) {
33 | s.current = s0
34 | s.stack = s.stack0[:0]
35 | }
36 |
37 | func (s *stateStack) push(next state) {
38 | if s.current.major != stFail {
39 | s.stack = append(s.stack, s.current)
40 | }
41 | s.current = next
42 | }
43 |
44 | func (s *stateStack) pop() {
45 | if len(s.stack) == 0 {
46 | s.current = state{stFail, stStart}
47 | } else {
48 | last := len(s.stack) - 1
49 | s.current = s.stack[last]
50 | s.stack = s.stack[:last]
51 | }
52 | }
53 |
54 | func (s *lengthStack) init() {
55 | s.stack = s.stack0[:0]
56 | }
57 |
58 | func (s *lengthStack) push(l int64) {
59 | s.stack = append(s.stack, s.current)
60 | s.current = l
61 | }
62 |
63 | func (s *lengthStack) pop() int64 {
64 | if len(s.stack) == 0 {
65 | s.current = -1
66 | return -1
67 | } else {
68 | last := len(s.stack) - 1
69 | old := s.current
70 | s.current = s.stack[last]
71 | s.stack = s.stack[:last]
72 | return old
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/elastic/go-structform
2 |
3 | go 1.12
4 |
5 | require github.com/stretchr/testify v1.7.0
6 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
6 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
7 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
9 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
10 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
11 |
--------------------------------------------------------------------------------
/gotype/0gen.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | //go:generate mktmpl -f -o fold_map_inline.generated.go fold_map_inline.yml
21 | //go:generate mktmpl -f -o fold_refl_sel.generated.go fold_refl_sel.yml
22 | //go:generate mktmpl -f -o stacks.generated.go stacks.yml
23 | //go:generate mktmpl -f -o unfold_primitive.generated.go unfold_primitive.yml
24 | //go:generate mktmpl -f -o unfold_lookup_go.generated.go unfold_lookup_go.yml
25 | //go:generate mktmpl -f -o unfold_err.generated.go unfold_err.yml
26 | //go:generate mktmpl -f -o unfold_arr.generated.go unfold_arr.yml
27 | //go:generate mktmpl -f -o unfold_map.generated.go unfold_map.yml
28 | //go:generate mktmpl -f -o unfold_refl.generated.go unfold_refl.yml
29 | //go:generate mktmpl -f -o unfold_ignore.generated.go unfold_ignore.yml
30 | //go:generate mktmpl -f -o unfold_user_primitive.generated.go unfold_user_primitive.yml
31 | //go:generate mktmpl -f -o unfold_user_processing.generated.go unfold_user_processing.yml
32 |
33 | // go:generate mktmpl -f -o unfold_sel_generated.go unfold_sel.yml
34 |
--------------------------------------------------------------------------------
/gotype/defs.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | import (
21 | "reflect"
22 |
23 | structform "github.com/elastic/go-structform"
24 | "github.com/elastic/go-structform/internal/unsafe"
25 | )
26 |
27 | type options struct {
28 | tag string
29 | }
30 |
31 | var (
32 | tInterface = reflect.TypeOf((*interface{})(nil)).Elem()
33 | tString = reflect.TypeOf("")
34 | tBool = reflect.TypeOf(true)
35 | tInt = reflect.TypeOf(int(0))
36 | tInt8 = reflect.TypeOf(int8(0))
37 | tInt16 = reflect.TypeOf(int16(0))
38 | tInt32 = reflect.TypeOf(int32(0))
39 | tInt64 = reflect.TypeOf(int64(0))
40 | tUint = reflect.TypeOf(uint(0))
41 | tByte = reflect.TypeOf(byte(0))
42 | tUint8 = reflect.TypeOf(uint8(0))
43 | tUint16 = reflect.TypeOf(uint16(0))
44 | tUint32 = reflect.TypeOf(uint32(0))
45 | tUint64 = reflect.TypeOf(uint64(0))
46 | tFloat32 = reflect.TypeOf(float32(0))
47 | tFloat64 = reflect.TypeOf(float64(0))
48 |
49 | tError = reflect.TypeOf((*error)(nil)).Elem()
50 |
51 | tExtVisitor = reflect.TypeOf((*structform.ExtVisitor)(nil)).Elem()
52 | tFolder = reflect.TypeOf((*Folder)(nil)).Elem()
53 | tExpander = reflect.TypeOf((*Expander)(nil)).Elem()
54 | tUnfoldState = reflect.TypeOf((*UnfoldState)(nil)).Elem()
55 | tIsZeroer = reflect.TypeOf((*IsZeroer)(nil)).Elem()
56 | )
57 |
58 | func bytes2Str(b []byte) string {
59 | return unsafe.Bytes2Str(b)
60 | }
61 |
62 | func implementsFolder(t reflect.Type) bool { return t.Implements(tFolder) }
63 | func implementsPtrFolder(t reflect.Type) bool { return implementsFolder(reflect.PtrTo(t)) }
64 |
65 | func implementsIsZeroer(t reflect.Type) bool { return t.Implements(tIsZeroer) }
66 | func implementsPtrIsZeroer(t reflect.Type) bool { return implementsIsZeroer(reflect.PtrTo(t)) }
67 |
--------------------------------------------------------------------------------
/gotype/error.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | import "errors"
21 |
22 | var (
23 | errNotInitialized = errors.New("Unfolder is not initialized")
24 | errInvalidState = errors.New("invalid state")
25 | errUnsupported = errors.New("unsupported")
26 | errMapRequiresStringKey = errors.New("map requires string key")
27 | errSquashNeedObject = errors.New("require map or struct when using squash/inline")
28 | errNilInput = errors.New("nil input")
29 | errRequiresPointer = errors.New("requires pointer")
30 | errKeyIntoNonStruct = errors.New("key for non-structure target")
31 | errUnexpectedObjectKey = errors.New("unexpected object key")
32 | errRequiresPrimitive = errors.New("requires primitive target to set a boolean value")
33 | errRequiresBoolReceiver = errors.New("requires bool receiver")
34 | errIncompatibleTypes = errors.New("can not assign to incompatible go type")
35 | errStartArrayWaitingForKey = errors.New("start array while waiting for object field name")
36 | errStartObjectWaitingForKey = errors.New("start object while waiting for object field name")
37 | errExpectedArrayNotObject = errors.New("expected array but received object")
38 | errExpectedObjectNotArray = errors.New("expected object but received array")
39 | errUnexpectedArrayStart = errors.New("unexpected array start")
40 | errUnexpectedObjectStart = errors.New("unexpected object start")
41 | errExpectedObjectKey = errors.New("waiting for object key or object end marker")
42 | errExpectedArray = errors.New("expected array")
43 | errExpectedObject = errors.New("expected object")
44 | errExpectedObjectValue = errors.New("expected object value")
45 | errExpectedObjectClose = errors.New("missing object close")
46 | errInlineAndOmitEmpty = errors.New("inline and omitempty must not be set at the same time")
47 |
48 | errUnexpectedNil = errors.New("unexpected nil value received")
49 | errUnexpectedBool = errors.New("unexpected bool value received")
50 | errUnexpectedNum = errors.New("unexpected numeric value received")
51 | errUnexpectedString = errors.New("unexpected string value received")
52 | errUnexpectedArrayEnd = errors.New("array closed early")
53 | errUnexpectedObjectEnd = errors.New("unexpected object close")
54 | )
55 |
56 | func errTODO() error {
57 | panic(errors.New("TODO"))
58 | }
59 |
60 | func visitErrTODO(V visitor, v interface{}) error {
61 | return errTODO()
62 | }
63 |
--------------------------------------------------------------------------------
/gotype/fold.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | import (
21 | "reflect"
22 |
23 | structform "github.com/elastic/go-structform"
24 | )
25 |
26 | type foldFn func(c *foldContext, v interface{}) error
27 |
28 | type reFoldFn func(c *foldContext, v reflect.Value) error
29 |
30 | type visitor interface {
31 | structform.ExtVisitor
32 | }
33 |
34 | type Iterator struct {
35 | ctx foldContext
36 | }
37 |
38 | type Folder interface {
39 | Fold(structform.ExtVisitor) error
40 | }
41 |
42 | // IsZeroer interface allows custom types to be reported as empty.
43 | // If the `omitempty` struct tag option is set and the custom type implements
44 | // IsZero(), which returns true, then the field will not be reported.
45 | type IsZeroer interface {
46 | IsZero() bool
47 | }
48 |
49 | type foldContext struct {
50 | visitor
51 | userReg map[reflect.Type]reFoldFn
52 | reg *typeFoldRegistry
53 | opts options
54 | }
55 |
56 | func Fold(v interface{}, vs structform.Visitor, opts ...FoldOption) error {
57 | if it, err := NewIterator(vs, opts...); err == nil {
58 | return it.Fold(v)
59 | }
60 | return nil
61 | }
62 |
63 | func NewIterator(vs structform.Visitor, opts ...FoldOption) (*Iterator, error) {
64 | reg := newTypeFoldRegistry()
65 | O, err := applyFoldOpts(opts)
66 | if err != nil {
67 | return nil, err
68 | }
69 |
70 | var userReg map[reflect.Type]reFoldFn
71 | if O.foldFns != nil {
72 | userReg = map[reflect.Type]reFoldFn{}
73 | for typ, folder := range O.foldFns {
74 | reg.set(typ, folder)
75 | userReg[typ] = folder
76 | }
77 | }
78 |
79 | it := &Iterator{
80 | ctx: foldContext{
81 | visitor: structform.EnsureExtVisitor(vs).(visitor),
82 | userReg: userReg,
83 | reg: reg,
84 | opts: options{
85 | tag: "struct",
86 | },
87 | },
88 | }
89 |
90 | return it, nil
91 | }
92 |
93 | func (i *Iterator) Fold(v interface{}) error {
94 | return foldInterfaceValue(&i.ctx, v)
95 | }
96 |
97 | func foldInterfaceValue(C *foldContext, v interface{}) error {
98 | if C.userReg != nil {
99 | t := reflect.TypeOf(v)
100 | if f := C.userReg[t]; f != nil {
101 | return f(C, reflect.ValueOf(v))
102 | }
103 | }
104 |
105 | if f := getFoldGoTypes(v); f != nil {
106 | return f(C, v)
107 | }
108 |
109 | if f, ok := v.(Folder); ok {
110 | return f.Fold(C.visitor)
111 | }
112 |
113 | if tmp, f := getFoldConvert(v); f != nil {
114 | return f(C, tmp)
115 | }
116 |
117 | return foldAnyReflect(C, reflect.ValueOf(v))
118 | }
119 |
120 | func getFoldConvert(v interface{}) (interface{}, foldFn) {
121 | t := reflect.TypeOf(v)
122 | cast := false
123 |
124 | switch t.Kind() {
125 | case reflect.Map:
126 | if cast = t.Name() != ""; cast {
127 | mt := reflect.MapOf(t.Key(), t.Elem())
128 | v = reflect.ValueOf(v).Convert(mt).Interface()
129 | }
130 | case reflect.Slice:
131 | if cast = t.Name() != ""; cast {
132 | mt := reflect.SliceOf(t.Elem())
133 | v = reflect.ValueOf(v).Convert(mt).Interface()
134 | }
135 | case reflect.Array:
136 | if cast = t.Name() != ""; cast {
137 | mt := reflect.ArrayOf(t.Len(), t.Elem())
138 | v = reflect.ValueOf(v).Convert(mt).Interface()
139 | }
140 | }
141 |
142 | return v, getFoldGoTypes(v)
143 | }
144 |
145 | func getFoldGoTypes(v interface{}) foldFn {
146 | switch v.(type) {
147 | case nil:
148 | return foldNil
149 |
150 | case bool:
151 | return foldBool
152 | case []bool:
153 | return foldArrBool
154 | case map[string]bool:
155 | return foldMapBool
156 |
157 | case int8:
158 | return foldInt8
159 | case int16:
160 | return foldInt16
161 | case int32:
162 | return foldInt32
163 | case int64:
164 | return foldInt64
165 | case int:
166 | return foldInt
167 |
168 | case []int8:
169 | return foldArrInt8
170 | case []int16:
171 | return foldArrInt16
172 | case []int32:
173 | return foldArrInt32
174 | case []int64:
175 | return foldArrInt64
176 | case []int:
177 | return foldArrInt
178 |
179 | case map[string]int8:
180 | return foldMapInt8
181 | case map[string]int16:
182 | return foldMapInt16
183 | case map[string]int32:
184 | return foldMapInt32
185 | case map[string]int64:
186 | return foldMapInt64
187 | case map[string]int:
188 | return foldMapInt
189 |
190 | /*
191 | case byte:
192 | return visitByte
193 | */
194 | case uint8:
195 | return foldUint8
196 | case uint16:
197 | return foldUint16
198 | case uint32:
199 | return foldUint32
200 | case uint64:
201 | return foldUint64
202 | case uint:
203 | return foldUint
204 |
205 | case []byte:
206 | return foldBytes
207 | /*
208 | case []uint8:
209 | return visitArrUint8
210 | */
211 | case []uint16:
212 | return foldArrUint16
213 | case []uint32:
214 | return foldArrUint32
215 | case []uint64:
216 | return foldArrUint64
217 | case []uint:
218 | return foldArrUint
219 |
220 | case map[string]uint8:
221 | return foldMapUint8
222 | case map[string]uint16:
223 | return foldMapUint16
224 | case map[string]uint32:
225 | return foldMapUint32
226 | case map[string]uint64:
227 | return foldMapUint64
228 | case map[string]uint:
229 | return foldMapUint
230 |
231 | case float32:
232 | return foldFloat32
233 | case float64:
234 | return foldFloat64
235 |
236 | case []float32:
237 | return foldArrFloat32
238 | case []float64:
239 | return foldArrFloat64
240 |
241 | case map[string]float32:
242 | return foldMapFloat32
243 | case map[string]float64:
244 | return foldMapFloat64
245 |
246 | case string:
247 | return foldString
248 | case []string:
249 | return foldArrString
250 | case map[string]string:
251 | return foldMapString
252 |
253 | case []interface{}:
254 | return foldArrInterface
255 | case map[string]interface{}:
256 | return foldMapInterface
257 | }
258 |
259 | return nil
260 | }
261 |
--------------------------------------------------------------------------------
/gotype/fold_arr.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | import (
21 | "reflect"
22 |
23 | structform "github.com/elastic/go-structform"
24 | )
25 |
26 | var (
27 | reFoldArrBool = liftFold([]bool(nil), foldArrBool)
28 | reFoldArrInt = liftFold([]int(nil), foldArrInt)
29 | reFoldArrInt8 = liftFold([]int8(nil), foldArrInt8)
30 | reFoldArrInt16 = liftFold([]int16(nil), foldArrInt16)
31 | reFoldArrInt32 = liftFold([]int32(nil), foldArrInt32)
32 | reFoldArrInt64 = liftFold([]int64(nil), foldArrInt64)
33 | reFoldArrUint = liftFold([]uint(nil), foldArrUint)
34 | reFoldArrUint8 = liftFold([]uint8(nil), foldArrUint8)
35 | reFoldArrUint16 = liftFold([]uint16(nil), foldArrUint16)
36 | reFoldArrUint32 = liftFold([]uint32(nil), foldArrUint32)
37 | reFoldArrUint64 = liftFold([]uint64(nil), foldArrUint64)
38 | reFoldArrFloat32 = liftFold([]float32(nil), foldArrFloat32)
39 | reFoldArrFloat64 = liftFold([]float64(nil), foldArrFloat64)
40 | reFoldArrString = liftFold([]string(nil), foldArrString)
41 | )
42 |
43 | var tArrayAny = reflect.TypeOf([]interface{}(nil))
44 |
45 | func foldArrInterface(C *foldContext, v interface{}) error {
46 | a := v.([]interface{})
47 | if err := C.OnArrayStart(len(a), structform.AnyType); err != nil {
48 | return err
49 | }
50 |
51 | for _, v := range a {
52 | if err := foldInterfaceValue(C, v); err != nil {
53 | return err
54 | }
55 | }
56 | return C.OnArrayFinished()
57 | }
58 |
59 | func foldArrBool(C *foldContext, v interface{}) error { return C.visitor.OnBoolArray(v.([]bool)) }
60 | func foldArrString(C *foldContext, v interface{}) error { return C.visitor.OnStringArray(v.([]string)) }
61 | func foldArrInt8(C *foldContext, v interface{}) error { return C.visitor.OnInt8Array(v.([]int8)) }
62 | func foldArrInt16(C *foldContext, v interface{}) error { return C.visitor.OnInt16Array(v.([]int16)) }
63 | func foldArrInt32(C *foldContext, v interface{}) error { return C.visitor.OnInt32Array(v.([]int32)) }
64 | func foldArrInt64(C *foldContext, v interface{}) error { return C.visitor.OnInt64Array(v.([]int64)) }
65 | func foldArrInt(C *foldContext, v interface{}) error { return C.visitor.OnIntArray(v.([]int)) }
66 | func foldBytes(C *foldContext, v interface{}) error { return C.visitor.OnBytes(v.([]byte)) }
67 | func foldArrUint8(C *foldContext, v interface{}) error { return C.visitor.OnUint8Array(v.([]uint8)) }
68 | func foldArrUint16(C *foldContext, v interface{}) error { return C.visitor.OnUint16Array(v.([]uint16)) }
69 | func foldArrUint32(C *foldContext, v interface{}) error { return C.visitor.OnUint32Array(v.([]uint32)) }
70 | func foldArrUint64(C *foldContext, v interface{}) error { return C.visitor.OnUint64Array(v.([]uint64)) }
71 | func foldArrUint(C *foldContext, v interface{}) error { return C.visitor.OnUintArray(v.([]uint)) }
72 | func foldArrFloat32(C *foldContext, v interface{}) error {
73 | return C.visitor.OnFloat32Array(v.([]float32))
74 | }
75 | func foldArrFloat64(C *foldContext, v interface{}) error {
76 | return C.visitor.OnFloat64Array(v.([]float64))
77 | }
78 |
--------------------------------------------------------------------------------
/gotype/fold_inline.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | import (
21 | "reflect"
22 |
23 | structform "github.com/elastic/go-structform"
24 | "github.com/elastic/go-structform/visitors"
25 | )
26 |
27 | // getReflectFoldMapKeys implements inline fold of a map[string]X type,
28 | // not reporting object start/end events
29 | func getReflectFoldMapKeys(c *foldContext, t reflect.Type) (reFoldFn, error) {
30 | if t.Key().Kind() != reflect.String {
31 | return nil, errMapRequiresStringKey
32 | }
33 |
34 | f := getMapInlineByPrimitiveElem(t.Elem())
35 | if f != nil {
36 | return f, nil
37 | }
38 |
39 | elemVisitor, err := getReflectFold(c, t.Elem())
40 | if err != nil {
41 | return nil, err
42 | }
43 |
44 | return makeMapKeysFold(elemVisitor), nil
45 | }
46 |
47 | func makeMapKeysFold(elemVisitor reFoldFn) reFoldFn {
48 | return func(C *foldContext, rv reflect.Value) error {
49 | if rv.IsNil() || !rv.IsValid() {
50 | return nil
51 | }
52 |
53 | for _, k := range rv.MapKeys() {
54 | if err := C.OnKey(k.String()); err != nil {
55 | return err
56 | }
57 | if err := elemVisitor(C, rv.MapIndex(k)); err != nil {
58 | return err
59 | }
60 | }
61 | return nil
62 | }
63 | }
64 |
65 | // getReflectFoldInlineInterface create an inline folder for an yet unknown type.
66 | // The actual types folder must open/close an object
67 | func getReflectFoldInlineInterface(C *foldContext, t reflect.Type) (reFoldFn, error) {
68 | var (
69 | // cache last used folder
70 | lastType reflect.Type
71 | lastVisitor reFoldFn
72 | )
73 |
74 | return embeddObjReFold(C, func(C *foldContext, rv reflect.Value) error {
75 | if rv.Type() != lastType {
76 | elemVisitor, err := getReflectFold(C, rv.Type())
77 | if err != nil {
78 | return err
79 | }
80 |
81 | lastVisitor = elemVisitor
82 | lastType = rv.Type()
83 | }
84 | return lastVisitor(C, rv)
85 | }), nil
86 | }
87 |
88 | func embeddObjReFold(C *foldContext, objFold reFoldFn) reFoldFn {
89 | var (
90 | ctx = *C
91 | vs = visitors.NewExpectObjVisitor(nil)
92 | )
93 |
94 | ctx.visitor = structform.EnsureExtVisitor(vs).(visitor)
95 | return func(C *foldContext, rv reflect.Value) error {
96 | // don't inline missing/empty object
97 | if rv.IsNil() || !rv.IsValid() {
98 | return nil
99 | }
100 |
101 | vs.SetActive(C.visitor)
102 | err := objFold(&ctx, rv)
103 | if err == nil && !vs.Done() {
104 | err = errExpectedObjectClose
105 | }
106 |
107 | vs.SetActive(nil)
108 | return err
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/gotype/fold_map.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | import (
21 | "reflect"
22 |
23 | structform "github.com/elastic/go-structform"
24 | )
25 |
26 | var (
27 | reFoldMapBool = liftFold(map[string]bool(nil), foldMapBool)
28 | reFoldMapInt = liftFold(map[string]int(nil), foldMapInt)
29 | reFoldMapInt8 = liftFold(map[string]int8(nil), foldMapInt8)
30 | reFoldMapInt16 = liftFold(map[string]int16(nil), foldMapInt16)
31 | reFoldMapInt32 = liftFold(map[string]int32(nil), foldMapInt32)
32 | reFoldMapInt64 = liftFold(map[string]int64(nil), foldMapInt64)
33 | reFoldMapUint = liftFold(map[string]uint(nil), foldMapUint)
34 | reFoldMapUint8 = liftFold(map[string]uint8(nil), foldMapUint8)
35 | reFoldMapUint16 = liftFold(map[string]uint16(nil), foldMapUint16)
36 | reFoldMapUint32 = liftFold(map[string]uint32(nil), foldMapUint32)
37 | reFoldMapUint64 = liftFold(map[string]uint64(nil), foldMapUint64)
38 | reFoldMapFloat32 = liftFold(map[string]float32(nil), foldMapFloat32)
39 | reFoldMapFloat64 = liftFold(map[string]float64(nil), foldMapFloat64)
40 | reFoldMapString = liftFold(map[string]string(nil), foldMapString)
41 | )
42 |
43 | var tMapAny = reflect.TypeOf(map[string]interface{}(nil))
44 |
45 | func foldMapInterface(C *foldContext, v interface{}) error {
46 | m := v.(map[string]interface{})
47 | if err := C.OnObjectStart(len(m), structform.AnyType); err != nil {
48 | return err
49 | }
50 |
51 | for k, v := range m {
52 | if err := C.OnKey(k); err != nil {
53 | return err
54 | }
55 | if err := foldInterfaceValue(C, v); err != nil {
56 | return err
57 | }
58 | }
59 | return C.OnObjectFinished()
60 | }
61 |
62 | func foldMapBool(C *foldContext, v interface{}) error {
63 | return C.visitor.OnBoolObject(v.(map[string]bool))
64 | }
65 |
66 | func foldMapString(C *foldContext, v interface{}) error {
67 | return C.visitor.OnStringObject(v.(map[string]string))
68 | }
69 |
70 | func foldMapInt8(C *foldContext, v interface{}) error {
71 | return C.visitor.OnInt8Object(v.(map[string]int8))
72 | }
73 |
74 | func foldMapInt16(C *foldContext, v interface{}) error {
75 | return C.visitor.OnInt16Object(v.(map[string]int16))
76 | }
77 |
78 | func foldMapInt32(C *foldContext, v interface{}) error {
79 | return C.visitor.OnInt32Object(v.(map[string]int32))
80 | }
81 |
82 | func foldMapInt64(C *foldContext, v interface{}) error {
83 | return C.visitor.OnInt64Object(v.(map[string]int64))
84 | }
85 |
86 | func foldMapInt(C *foldContext, v interface{}) error {
87 | return C.visitor.OnIntObject(v.(map[string]int))
88 | }
89 |
90 | func foldMapUint8(C *foldContext, v interface{}) error {
91 | return C.visitor.OnUint8Object(v.(map[string]uint8))
92 | }
93 |
94 | func foldMapUint16(C *foldContext, v interface{}) error {
95 | return C.visitor.OnUint16Object(v.(map[string]uint16))
96 | }
97 |
98 | func foldMapUint32(C *foldContext, v interface{}) error {
99 | return C.visitor.OnUint32Object(v.(map[string]uint32))
100 | }
101 |
102 | func foldMapUint64(C *foldContext, v interface{}) error {
103 | return C.visitor.OnUint64Object(v.(map[string]uint64))
104 | }
105 |
106 | func foldMapUint(C *foldContext, v interface{}) error {
107 | return C.visitor.OnUintObject(v.(map[string]uint))
108 | }
109 |
110 | func foldMapFloat32(C *foldContext, v interface{}) error {
111 | return C.visitor.OnFloat32Object(v.(map[string]float32))
112 | }
113 |
114 | func foldMapFloat64(C *foldContext, v interface{}) error {
115 | return C.visitor.OnFloat64Object(v.(map[string]float64))
116 | }
117 |
--------------------------------------------------------------------------------
/gotype/fold_map_inline.yml:
--------------------------------------------------------------------------------
1 | # Licensed to Elasticsearch B.V. under one or more contributor
2 | # license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright
4 | # ownership. Elasticsearch B.V. licenses this file to you under
5 | # the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | import:
19 | - types.yml
20 |
21 | main: |
22 | package gotype
23 |
24 | import (
25 | "reflect"
26 |
27 | stunsafe "github.com/urso/go-structform/internal/unsafe"
28 | )
29 |
30 | var _mapInlineMapping = map[reflect.Type]reFoldFn{
31 | {{ range data.primitiveTypes }}
32 | {{- $t := capitalize . -}}
33 | t{{ $t }}: foldMapInline{{ $t }},
34 | {{ end }}
35 | }
36 |
37 | func getMapInlineByPrimitiveElem(t reflect.Type) reFoldFn {
38 | if t == tInterface {
39 | return foldMapInlineInterface
40 | }
41 | return _mapInlineMapping[t]
42 | }
43 |
44 | func foldMapInlineInterface(C *foldContext, v reflect.Value) (err error) {
45 | ptr := unsafe.Pointer(v.Pointer())
46 | if ptr == nil {
47 | return nil
48 | }
49 |
50 | m := *((*map[string]interface{})(unsafe.Pointer(&ptr)))
51 | for k, v := range m {
52 | if err = C.OnKey(k); err != nil {
53 | return err
54 | }
55 | if err = foldInterfaceValue(C, v); err != nil {
56 | return err
57 | }
58 | }
59 | return
60 | }
61 |
62 | {{ range data.primitiveTypes }}
63 | {{ $t := capitalize . }}
64 | func foldMapInline{{ $t }}(C *foldContext, v reflect.Value) (err error) {
65 | ptr := unsafe.Pointer(v.Pointer())
66 | if ptr == nil {
67 | return nil
68 | }
69 |
70 | m := *((*map[string]{{ . }})(unsafe.Pointer(&ptr)))
71 | for k, v := range m {
72 | if err = C.OnKey(k); err != nil {
73 | return err
74 | }
75 | if err = C.On{{ $t }}(v); err != nil {
76 | return err
77 | }
78 | }
79 | return
80 | }
81 | {{ end }}
82 |
--------------------------------------------------------------------------------
/gotype/fold_opts.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | import "reflect"
21 |
22 | type initFoldOptions struct {
23 | foldFns map[reflect.Type]reFoldFn
24 | }
25 |
26 | type FoldOption func(*initFoldOptions) error
27 |
28 | func applyFoldOpts(opts []FoldOption) (i initFoldOptions, err error) {
29 | for _, o := range opts {
30 | if err = o(&i); err != nil {
31 | break
32 | }
33 | }
34 | return i, err
35 | }
36 |
37 | func Folders(in ...interface{}) FoldOption {
38 | folders, err := makeUserFoldFns(in)
39 | if err != nil {
40 | return func(_ *initFoldOptions) error { return err }
41 | }
42 |
43 | if len(folders) == 0 {
44 | return func(*initFoldOptions) error { return nil }
45 | }
46 |
47 | return func(o *initFoldOptions) error {
48 | if o.foldFns == nil {
49 | o.foldFns = map[reflect.Type]reFoldFn{}
50 | }
51 |
52 | for k, v := range folders {
53 | o.foldFns[k] = v
54 | }
55 | return nil
56 | }
57 | }
58 |
59 | func makeUserFoldFns(in []interface{}) (map[reflect.Type]reFoldFn, error) {
60 | M := map[reflect.Type]reFoldFn{}
61 |
62 | for _, v := range in {
63 | fn := reflect.ValueOf(v)
64 | fptr, err := makeUserFoldFn(fn)
65 | if err != nil {
66 | return nil, err
67 | }
68 |
69 | ta0 := fn.Type().In(0)
70 | M[ta0] = liftUserPtrFn(fptr)
71 | M[ta0.Elem()] = liftUserValueFn(fptr)
72 | }
73 |
74 | return M, nil
75 | }
76 |
--------------------------------------------------------------------------------
/gotype/fold_primitives.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | import "reflect"
21 |
22 | func foldNil(C *foldContext, v interface{}) error { return C.OnNil() }
23 | func foldBool(C *foldContext, v interface{}) error { return C.OnBool(v.(bool)) }
24 | func foldInt8(C *foldContext, v interface{}) error { return C.OnInt8(v.(int8)) }
25 | func foldInt16(C *foldContext, v interface{}) error { return C.OnInt16(v.(int16)) }
26 | func foldInt32(C *foldContext, v interface{}) error { return C.OnInt32(v.(int32)) }
27 | func foldInt64(C *foldContext, v interface{}) error { return C.OnInt64(v.(int64)) }
28 | func foldInt(C *foldContext, v interface{}) error { return C.OnInt64(int64(v.(int))) }
29 | func foldByte(C *foldContext, v interface{}) error { return C.OnByte(v.(byte)) }
30 | func foldUint8(C *foldContext, v interface{}) error { return C.OnUint8(v.(uint8)) }
31 | func foldUint16(C *foldContext, v interface{}) error { return C.OnUint16(v.(uint16)) }
32 | func foldUint32(C *foldContext, v interface{}) error { return C.OnUint32(v.(uint32)) }
33 | func foldUint64(C *foldContext, v interface{}) error { return C.OnUint64(v.(uint64)) }
34 | func foldUint(C *foldContext, v interface{}) error { return C.OnUint(v.(uint)) }
35 | func foldFloat32(C *foldContext, v interface{}) error { return C.OnFloat32(v.(float32)) }
36 | func foldFloat64(C *foldContext, v interface{}) error { return C.OnFloat64(v.(float64)) }
37 | func foldString(C *foldContext, v interface{}) error { return C.OnString(v.(string)) }
38 |
39 | func reFoldNil(C *foldContext, v reflect.Value) error { return C.OnNil() }
40 | func reFoldBool(C *foldContext, v reflect.Value) error { return C.OnBool(v.Bool()) }
41 | func reFoldInt8(C *foldContext, v reflect.Value) error { return C.OnInt8(int8(v.Int())) }
42 | func reFoldInt16(C *foldContext, v reflect.Value) error { return C.OnInt16(int16(v.Int())) }
43 | func reFoldInt32(C *foldContext, v reflect.Value) error { return C.OnInt32(int32(v.Int())) }
44 | func reFoldInt64(C *foldContext, v reflect.Value) error { return C.OnInt64(v.Int()) }
45 | func reFoldInt(C *foldContext, v reflect.Value) error { return C.OnInt64(int64(int(v.Int()))) }
46 | func reFoldUint8(C *foldContext, v reflect.Value) error { return C.OnUint8(uint8(v.Uint())) }
47 | func reFoldUint16(C *foldContext, v reflect.Value) error { return C.OnUint16(uint16(v.Uint())) }
48 | func reFoldUint32(C *foldContext, v reflect.Value) error { return C.OnUint32(uint32(v.Uint())) }
49 | func reFoldUint64(C *foldContext, v reflect.Value) error { return C.OnUint64(v.Uint()) }
50 | func reFoldUint(C *foldContext, v reflect.Value) error { return C.OnUint(uint(v.Uint())) }
51 | func reFoldFloat32(C *foldContext, v reflect.Value) error {
52 | return C.OnFloat32(float32(v.Float()))
53 | }
54 | func reFoldFloat64(C *foldContext, v reflect.Value) error { return C.OnFloat64(v.Float()) }
55 | func reFoldString(C *foldContext, v reflect.Value) error { return C.OnString(v.String()) }
56 |
57 | func reFoldFolderIfc(C *foldContext, v reflect.Value) error {
58 | if implementsFolder(v.Type()) {
59 | return v.Interface().(Folder).Fold(C.visitor)
60 | }
61 |
62 | if v.CanAddr() {
63 | return reFoldFolderIfc(C, v.Addr())
64 | }
65 |
66 | tmp := reflect.New(v.Type())
67 | tmp.Elem().Set(v)
68 | return reFoldFolderIfc(C, tmp)
69 | }
70 |
--------------------------------------------------------------------------------
/gotype/fold_refl_sel.generated.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | // This file has been generated from 'fold_refl_sel.yml', do not edit
19 | package gotype
20 |
21 | import "reflect"
22 |
23 | var _reflPrimitivesMapping = map[reflect.Type]reFoldFn{
24 |
25 | tBool: reFoldBool,
26 | reflect.SliceOf(tBool): reFoldArrBool,
27 | reflect.MapOf(tString, tBool): reFoldMapBool,
28 |
29 | tString: reFoldString,
30 | reflect.SliceOf(tString): reFoldArrString,
31 | reflect.MapOf(tString, tString): reFoldMapString,
32 |
33 | tUint: reFoldUint,
34 | reflect.SliceOf(tUint): reFoldArrUint,
35 | reflect.MapOf(tString, tUint): reFoldMapUint,
36 |
37 | tUint8: reFoldUint8,
38 | reflect.SliceOf(tUint8): reFoldArrUint8,
39 | reflect.MapOf(tString, tUint8): reFoldMapUint8,
40 |
41 | tUint16: reFoldUint16,
42 | reflect.SliceOf(tUint16): reFoldArrUint16,
43 | reflect.MapOf(tString, tUint16): reFoldMapUint16,
44 |
45 | tUint32: reFoldUint32,
46 | reflect.SliceOf(tUint32): reFoldArrUint32,
47 | reflect.MapOf(tString, tUint32): reFoldMapUint32,
48 |
49 | tUint64: reFoldUint64,
50 | reflect.SliceOf(tUint64): reFoldArrUint64,
51 | reflect.MapOf(tString, tUint64): reFoldMapUint64,
52 |
53 | tInt: reFoldInt,
54 | reflect.SliceOf(tInt): reFoldArrInt,
55 | reflect.MapOf(tString, tInt): reFoldMapInt,
56 |
57 | tInt8: reFoldInt8,
58 | reflect.SliceOf(tInt8): reFoldArrInt8,
59 | reflect.MapOf(tString, tInt8): reFoldMapInt8,
60 |
61 | tInt16: reFoldInt16,
62 | reflect.SliceOf(tInt16): reFoldArrInt16,
63 | reflect.MapOf(tString, tInt16): reFoldMapInt16,
64 |
65 | tInt32: reFoldInt32,
66 | reflect.SliceOf(tInt32): reFoldArrInt32,
67 | reflect.MapOf(tString, tInt32): reFoldMapInt32,
68 |
69 | tInt64: reFoldInt64,
70 | reflect.SliceOf(tInt64): reFoldArrInt64,
71 | reflect.MapOf(tString, tInt64): reFoldMapInt64,
72 |
73 | tFloat32: reFoldFloat32,
74 | reflect.SliceOf(tFloat32): reFoldArrFloat32,
75 | reflect.MapOf(tString, tFloat32): reFoldMapFloat32,
76 |
77 | tFloat64: reFoldFloat64,
78 | reflect.SliceOf(tFloat64): reFoldArrFloat64,
79 | reflect.MapOf(tString, tFloat64): reFoldMapFloat64,
80 | }
81 |
82 | func getReflectFoldPrimitive(t reflect.Type) reFoldFn {
83 | return _reflPrimitivesMapping[t]
84 | }
85 |
86 | func getReflectFoldPrimitiveKind(t reflect.Type) (reFoldFn, error) {
87 | switch t.Kind() {
88 |
89 | case reflect.Bool:
90 | return reFoldBool, nil
91 |
92 | case reflect.String:
93 | return reFoldString, nil
94 |
95 | case reflect.Uint:
96 | return reFoldUint, nil
97 |
98 | case reflect.Uint8:
99 | return reFoldUint8, nil
100 |
101 | case reflect.Uint16:
102 | return reFoldUint16, nil
103 |
104 | case reflect.Uint32:
105 | return reFoldUint32, nil
106 |
107 | case reflect.Uint64:
108 | return reFoldUint64, nil
109 |
110 | case reflect.Int:
111 | return reFoldInt, nil
112 |
113 | case reflect.Int8:
114 | return reFoldInt8, nil
115 |
116 | case reflect.Int16:
117 | return reFoldInt16, nil
118 |
119 | case reflect.Int32:
120 | return reFoldInt32, nil
121 |
122 | case reflect.Int64:
123 | return reFoldInt64, nil
124 |
125 | case reflect.Float32:
126 | return reFoldFloat32, nil
127 |
128 | case reflect.Float64:
129 | return reFoldFloat64, nil
130 |
131 | default:
132 | return nil, errUnsupported
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/gotype/fold_refl_sel.yml:
--------------------------------------------------------------------------------
1 | # Licensed to Elasticsearch B.V. under one or more contributor
2 | # license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright
4 | # ownership. Elasticsearch B.V. licenses this file to you under
5 | # the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | import:
19 | - types.yml
20 |
21 | main: |
22 | package gotype
23 |
24 | var _reflPrimitivesMapping = map[reflect.Type]reFoldFn{
25 | {{ range data.primitiveTypes }}
26 | {{ $t := capitalize . }}
27 | t{{ $t }}: reFold{{ $t }},
28 | reflect.SliceOf(t{{ $t }}): reFoldArr{{ $t }},
29 | reflect.MapOf(tString, t{{ $t }}): reFoldMap{{ $t }},
30 | {{ end }}
31 | }
32 |
33 | func getReflectFoldPrimitive(t reflect.Type) reFoldFn {
34 | return _reflPrimitivesMapping[t]
35 | }
36 |
37 | func getReflectFoldPrimitiveKind(t reflect.Type) (reFoldFn, error) {
38 | switch t.Kind() {
39 | {{ range data.primitiveTypes }}
40 | {{ $t := capitalize . }}
41 | case reflect.{{ $t }}:
42 | return reFold{{ $t }}, nil
43 | {{ end }}
44 | default:
45 | return nil, errUnsupported
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/gotype/fold_user.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | import (
21 | "errors"
22 | "fmt"
23 | "reflect"
24 | "unsafe"
25 |
26 | structform "github.com/elastic/go-structform"
27 | stunsafe "github.com/elastic/go-structform/internal/unsafe"
28 | )
29 |
30 | type userFoldFn func(unsafe.Pointer, structform.ExtVisitor) error
31 |
32 | func makeUserFoldFn(fn reflect.Value) (userFoldFn, error) {
33 | t := fn.Type()
34 |
35 | if fn.Kind() != reflect.Func {
36 | return nil, errors.New("function type required")
37 | }
38 |
39 | if t.NumIn() != 2 {
40 | return nil, fmt.Errorf("function '%v' must accept 2 arguments", t.Name())
41 | }
42 | if t.NumOut() != 1 || t.Out(0) != tError {
43 | return nil, fmt.Errorf("function '%v' does not return errors", t.Name())
44 | }
45 |
46 | ta0 := t.In(0)
47 | if ta0.Kind() != reflect.Ptr {
48 | return nil, fmt.Errorf("first argument in function '%v' must be a pointer", t.Name())
49 | }
50 |
51 | ta1 := t.In(1)
52 | if ta1 != tExtVisitor {
53 | return nil, fmt.Errorf("second arument in function '%v' must be structform.ExtVisitor", t.Name())
54 | }
55 |
56 | fptr := *((*userFoldFn)(stunsafe.UnsafeFnPtr(fn)))
57 | return fptr, nil
58 | }
59 |
60 | func liftUserPtrFn(f userFoldFn) reFoldFn {
61 | return func(c *foldContext, v reflect.Value) error {
62 | if v.IsNil() {
63 | return f(nil, c.visitor)
64 | }
65 | return f(stunsafe.ReflValuePtr(v.Elem()), c.visitor)
66 | }
67 | }
68 |
69 | func liftUserValueFn(f userFoldFn) reFoldFn {
70 | return func(c *foldContext, v reflect.Value) error {
71 | return f(stunsafe.ReflValuePtr(v), c.visitor)
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/gotype/stacks.generated.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | // This file has been generated from 'stacks.yml', do not edit
19 | package gotype
20 |
21 | import (
22 | "reflect"
23 | "unsafe"
24 |
25 | structform "github.com/elastic/go-structform"
26 | )
27 |
28 | type unfolderStack struct {
29 | current unfolder
30 | stack []unfolder
31 | stack0 [32]unfolder
32 | }
33 |
34 | type reflectValueStack struct {
35 | current reflect.Value
36 | stack []reflect.Value
37 | stack0 [32]reflect.Value
38 | }
39 |
40 | type ptrStack struct {
41 | current unsafe.Pointer
42 | stack []unsafe.Pointer
43 | stack0 [32]unsafe.Pointer
44 | }
45 |
46 | type keyStack struct {
47 | current string
48 | stack []string
49 | stack0 [32]string
50 | }
51 |
52 | type idxStack struct {
53 | current int
54 | stack []int
55 | stack0 [32]int
56 | }
57 |
58 | type structformTypeStack struct {
59 | current structform.BaseType
60 | stack []structform.BaseType
61 | stack0 [32]structform.BaseType
62 | }
63 |
64 | func (s *unfolderStack) init(v unfolder) {
65 | s.current = v
66 | s.stack = s.stack0[:0]
67 | }
68 |
69 | func (s *unfolderStack) push(v unfolder) {
70 | s.stack = append(s.stack, s.current)
71 | s.current = v
72 | }
73 |
74 | func (s *unfolderStack) pop() unfolder {
75 | old := s.current
76 | last := len(s.stack) - 1
77 | s.current = s.stack[last]
78 | s.stack = s.stack[:last]
79 | return old
80 | }
81 |
82 | func (s *reflectValueStack) init(v reflect.Value) {
83 | s.current = v
84 | s.stack = s.stack0[:0]
85 | }
86 |
87 | func (s *reflectValueStack) push(v reflect.Value) {
88 | s.stack = append(s.stack, s.current)
89 | s.current = v
90 | }
91 |
92 | func (s *reflectValueStack) pop() reflect.Value {
93 | old := s.current
94 | last := len(s.stack) - 1
95 | s.current = s.stack[last]
96 | s.stack = s.stack[:last]
97 | return old
98 | }
99 |
100 | func (s *ptrStack) init() {
101 | s.current = nil
102 | s.stack = s.stack0[:0]
103 | }
104 |
105 | func (s *ptrStack) push(v unsafe.Pointer) {
106 | s.stack = append(s.stack, s.current)
107 | s.current = v
108 | }
109 |
110 | func (s *ptrStack) pop() unsafe.Pointer {
111 | old := s.current
112 | last := len(s.stack) - 1
113 | s.current = s.stack[last]
114 | s.stack = s.stack[:last]
115 | return old
116 | }
117 |
118 | func (s *keyStack) init() {
119 | s.current = ""
120 | s.stack = s.stack0[:0]
121 | }
122 |
123 | func (s *keyStack) push(v string) {
124 | s.stack = append(s.stack, s.current)
125 | s.current = v
126 | }
127 |
128 | func (s *keyStack) pop() string {
129 | old := s.current
130 | last := len(s.stack) - 1
131 | s.current = s.stack[last]
132 | s.stack = s.stack[:last]
133 | return old
134 | }
135 |
136 | func (s *idxStack) init() {
137 | s.current = -1
138 | s.stack = s.stack0[:0]
139 | }
140 |
141 | func (s *idxStack) push(v int) {
142 | s.stack = append(s.stack, s.current)
143 | s.current = v
144 | }
145 |
146 | func (s *idxStack) pop() int {
147 | old := s.current
148 | last := len(s.stack) - 1
149 | s.current = s.stack[last]
150 | s.stack = s.stack[:last]
151 | return old
152 | }
153 |
154 | func (s *structformTypeStack) init() {
155 | s.current = structform.AnyType
156 | s.stack = s.stack0[:0]
157 | }
158 |
159 | func (s *structformTypeStack) push(v structform.BaseType) {
160 | s.stack = append(s.stack, s.current)
161 | s.current = v
162 | }
163 |
164 | func (s *structformTypeStack) pop() structform.BaseType {
165 | old := s.current
166 | last := len(s.stack) - 1
167 | s.current = s.stack[last]
168 | s.stack = s.stack[:last]
169 | return old
170 | }
171 |
--------------------------------------------------------------------------------
/gotype/stacks.yml:
--------------------------------------------------------------------------------
1 | # Licensed to Elasticsearch B.V. under one or more contributor
2 | # license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright
4 | # ownership. Elasticsearch B.V. licenses this file to you under
5 | # the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | data.stacks:
19 | - name: unfolderStack
20 | type: unfolder
21 | - name: reflectValueStack
22 | type: reflect.Value
23 | - name: ptrStack
24 | init: 'nil'
25 | type: unsafe.Pointer
26 | - name: keyStack
27 | type: string
28 | init: '""'
29 | - name: idxStack
30 | type: int
31 | init: -1
32 | - name: structformTypeStack
33 | type: structform.BaseType
34 | init: structform.AnyType
35 |
36 | main: |
37 | package gotype
38 |
39 | {{ range .stacks }}
40 | type {{ .name }} struct {
41 | current {{ .type }}
42 | stack []{{ .type }}
43 | stack0 [{{ if .size0 }}{{ .size0 }}{{ else }}32{{ end }}]{{ .type }}
44 | }
45 | {{ end }}
46 |
47 | {{ range .stacks }}
48 | func (s *{{ .name }}) init({{ if isnil .init }}v {{ .type }}{{end}}) {
49 | s.current = {{ if isnil .init }}v{{ else }}{{ .init }}{{end}}
50 | s.stack = s.stack0[:0]
51 | }
52 |
53 | func (s *{{ .name }}) push(v {{ .type }}) {
54 | s.stack = append(s.stack, s.current)
55 | s.current = v
56 | }
57 |
58 | func (s *{{ .name }}) pop() {{ .type }} {
59 | old := s.current
60 | last := len(s.stack) - 1
61 | s.current = s.stack[last]
62 | s.stack = s.stack[:last]
63 | return old
64 | }
65 | {{ end }}
66 |
--------------------------------------------------------------------------------
/gotype/symbols.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | type symbolCache struct {
21 | m map[string]*symbol
22 | lst symbolList
23 | max int
24 | }
25 |
26 | type symbol struct {
27 | value string
28 | prev *symbol
29 | next *symbol
30 | }
31 |
32 | type symbolList symbol
33 |
34 | func (c *symbolCache) init(max int) {
35 | c.max = max
36 | c.m = make(map[string]*symbol, max)
37 | c.lst = symbolList{}
38 | c.lst.prev = (*symbol)(&c.lst)
39 | c.lst.next = (*symbol)(&c.lst)
40 | }
41 |
42 | func (c *symbolCache) enabled() bool {
43 | return c.m != nil
44 | }
45 |
46 | func (c *symbolCache) get(in []byte) string {
47 | if !c.enabled() {
48 | return string(in)
49 | }
50 |
51 | if sym := c.lookup(bytes2Str(in)); sym != nil {
52 | return sym.value
53 | }
54 |
55 | str := string(in)
56 | c.add(str)
57 | return str
58 | }
59 |
60 | func (c *symbolCache) lookup(value string) *symbol {
61 | sym := c.m[value]
62 | if sym != nil {
63 | removeLst(sym)
64 | c.lst.append(sym)
65 | }
66 | return sym
67 | }
68 |
69 | func (c *symbolCache) add(value string) {
70 | if len(c.m) == c.max {
71 | old := c.lst.pop()
72 | delete(c.m, old.value)
73 | }
74 |
75 | sym := &symbol{value: value}
76 | c.m[value] = sym
77 | c.lst.append(sym)
78 | }
79 |
80 | func (l *symbolList) empty() bool {
81 | s := (*symbol)(l)
82 | return s.next == s && s.prev == s
83 | }
84 |
85 | func (l *symbolList) append(sym *symbol) {
86 | head := (*symbol)(l)
87 |
88 | sym.prev = head.prev
89 | sym.next = head
90 | head.prev.next = sym
91 | head.prev = sym
92 | }
93 |
94 | func (l *symbolList) pop() (sym *symbol) {
95 | if !l.empty() {
96 | sym = l.next
97 | removeLst(sym)
98 | }
99 | return
100 | }
101 |
102 | func removeLst(s *symbol) {
103 | s.prev.next = s.next
104 | s.next.prev = s.prev
105 | }
106 |
--------------------------------------------------------------------------------
/gotype/tags.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | import "strings"
21 |
22 | // tagOptions represents additional per field options that have
23 | // been parsed from the struct tags.
24 | //
25 | // Available options are:
26 | // - squash, inline: The field must be a map[string]... or another struct.
27 | // All fields from the struct will be treated like they belong to the current
28 | // struct.
29 | // - omit: The field is never reported
30 | // - omitempty: The field is not reported if the value is assumed to be empty.
31 | // Strings, arrays, maps of 0 length and nil pointers are always assumed to be empty.
32 | // Custom types can implement the `IsZero() bool` method (IsZeroer interface). If the
33 | // `IsZero` method is true and `omitempty` has been set, the field will be ignored.
34 | type tagOptions struct {
35 | squash bool
36 | omitEmpty bool
37 | omit bool
38 | }
39 |
40 | var defaultTagOptions = tagOptions{
41 | squash: false,
42 | omitEmpty: false,
43 | omit: false,
44 | }
45 |
46 | func parseTags(tag string) (string, tagOptions) {
47 | s := strings.Split(tag, ",")
48 | if len(s) == 0 {
49 | return "", defaultTagOptions
50 | }
51 |
52 | if s[0] == "-" {
53 | opts := defaultTagOptions
54 | opts.omit = true
55 | return "", opts
56 | }
57 |
58 | opts := defaultTagOptions
59 | for _, opt := range s[1:] {
60 | switch strings.TrimSpace(opt) {
61 | case "squash", "inline":
62 | opts.squash = true
63 | case "omitempty":
64 | opts.omitEmpty = true
65 | case "omit":
66 | opts.omit = true
67 | }
68 | }
69 | return strings.TrimSpace(s[0]), opts
70 | }
71 |
--------------------------------------------------------------------------------
/gotype/types.yml:
--------------------------------------------------------------------------------
1 | # Licensed to Elasticsearch B.V. under one or more contributor
2 | # license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright
4 | # ownership. Elasticsearch B.V. licenses this file to you under
5 | # the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | data.numTypes: [
19 | uint, uint8, uint16, uint32, uint64,
20 | int, int8, int16, int32, int64,
21 | float32, float64
22 | ]
23 |
24 | data.primitiveTypes: [
25 | bool,
26 | string,
27 | uint, uint8, uint16, uint32, uint64,
28 | int, int8, int16, int32, int64,
29 | float32, float64
30 | ]
31 |
32 | data.mapTypes:
33 | AnyType: 'interface{}'
34 | ByteType: uint8
35 | StringType: string
36 | BoolType: bool
37 | ZeroType: 'interface{}'
38 | IntType: int
39 | Int8Type: int8
40 | Int16Type: int16
41 | Int32Type: int32
42 | Int64Type: int64
43 | UintType: uint
44 | Uint8Type: uint8
45 | Uint16Type: uint16
46 | Uint32Type: uint32
47 | Uint64Type: uint64
48 | Float32Type: float32
49 | Float64Type: float64
50 |
51 | data.mapReflTypes:
52 | AnyType: tInterface
53 | ByteType: tByte
54 | StringType: tString
55 | BoolType: tBool
56 | ZeroType: tInterface
57 | IntType: tInt
58 | Int8Type: tInt8
59 | Int16Type: tInt16
60 | Int32Type: tInt32
61 | Int64Type: tInt64
62 | UintType: tUint
63 | Uint8Type: tUint8
64 | Uint16Type: tUint16
65 | Uint32Type: tUint32
66 | Uint64Type: tUint64
67 | Float32Type: tFloat32
68 | Float64Type: tFloat64
69 |
--------------------------------------------------------------------------------
/gotype/unfold_arr.yml:
--------------------------------------------------------------------------------
1 | # Licensed to Elasticsearch B.V. under one or more contributor
2 | # license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright
4 | # ownership. Elasticsearch B.V. licenses this file to you under
5 | # the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | import:
19 | - unfold_templates.yml
20 |
21 | main: |
22 | package gotype
23 |
24 | import "github.com/urso/go-structform"
25 |
26 | {{/* defined 'lifted' pointer slice unfolders into reflection based unfolders */}}
27 | var (
28 | unfolderReflArrIfc = liftGoUnfolder(newUnfolderArrIfc())
29 | {{ range data.primitiveTypes }}
30 | {{ $t := capitalize . }}
31 | unfolderReflArr{{ $t }} = liftGoUnfolder(newUnfolderArr{{ $t }}())
32 | {{ end }}
33 | )
34 |
35 | {{/* define pointer based unfolder types */}}
36 | {{ invoke "makeTypeWithName" "name" "Ifc" "type" "interface{}" }}
37 | {{ template "makeType" "bool" }}
38 | {{ template "makeType" "string" }}
39 | {{ range .numTypes }}
40 | {{ template "makeType" . }}
41 | {{ end }}
42 |
43 | {{/* create visitor callbacks */}}
44 | {{ invoke "onIfcFns" "name" "unfolderArrIfc" "fn" "append" }}
45 | {{ invoke "onBoolFns" "name" "unfolderArrBool" "fn" "append" }}
46 | {{ invoke "onStringFns" "name" "unfolderArrString" "fn" "append" }}
47 | {{ range .numTypes }}
48 | {{ $type := . }}
49 | {{ $name := capitalize $type | printf "unfolderArr%v" }}
50 | {{ invoke "onNumberFns" "name" $name "type" $type "fn" "append" }}
51 | {{ end }}
52 |
53 | {{ template "arrIfc" }}
54 |
55 |
56 | # makeTypeWithName(name, type)
57 | templates.makeTypeWithName: |
58 | {{ $type := .type }}
59 | {{ $name := capitalize .name | printf "unfolderArr%v" }}
60 | {{ $startName := capitalize .name | printf "unfoldArrStart%v" }}
61 |
62 | {{ invoke "makeUnfoldType" "name" $name }}
63 | {{ invoke "makeUnfoldType" "name" $startName "base" "unfolderErrArrayStart" }}
64 |
65 | func (u *{{ $name }} ) initState(ctx *unfoldCtx, ptr unsafe.Pointer) {
66 | ctx.unfolder.push(u)
67 | ctx.unfolder.push(new{{ $startName | capitalize}}())
68 | ctx.idx.push(0)
69 | ctx.ptr.push(ptr)
70 | }
71 |
72 | func (u * {{ $name }} ) cleanup(ctx *unfoldCtx) {
73 | ctx.unfolder.pop()
74 | ctx.idx.pop()
75 | ctx.ptr.pop()
76 | }
77 |
78 | func (u * {{ $startName }}) cleanup(ctx *unfoldCtx) {
79 | ctx.unfolder.pop()
80 | }
81 |
82 | func (u *{{ $startName }} ) ptr(ctx *unfoldCtx) *[]{{ $type }} {
83 | return (*[]{{ $type }})(ctx.ptr.current)
84 | }
85 |
86 | func (u *{{ $name }} ) ptr(ctx *unfoldCtx) *[]{{ $type }} {
87 | return (*[]{{ $type }})(ctx.ptr.current)
88 | }
89 |
90 | func (u *{{ $startName }}) OnArrayStart(ctx *unfoldCtx, l int, baseType structform.BaseType) error {
91 | to := u.ptr(ctx)
92 | if l < 0 {
93 | l = 0
94 | }
95 |
96 | if *to == nil && l > 0 {
97 | *to = make([]{{ $type }}, l)
98 | } else if l < len(*to) {
99 | *to = (*to)[:l]
100 | }
101 |
102 | u.cleanup(ctx)
103 | return nil
104 | }
105 |
106 | func (u *{{ $name }} ) OnArrayFinished(ctx *unfoldCtx) error {
107 | u.cleanup(ctx)
108 | return nil
109 | }
110 |
111 | func (u *{{ $name }} ) append(ctx *unfoldCtx, v {{ $type }}) error {
112 | idx := &ctx.idx
113 | to := u.ptr(ctx)
114 | if len(*to) <= idx.current {
115 | *to = append(*to, v)
116 | } else {
117 | (*to)[idx.current] = v
118 | }
119 |
120 | idx.current++
121 | return nil
122 | }
123 |
124 | templates.arrIfc: |
125 |
126 | func unfoldIfcStartSubArray(ctx *unfoldCtx, l int, baseType structform.BaseType) error {
127 | _, ptr, unfolder := makeArrayPtr(ctx, l, baseType)
128 | ctx.ptr.push(ptr) // store pointer for use in 'Finish'
129 | ctx.baseType.push(baseType)
130 | unfolder.initState(ctx, ptr)
131 | return ctx.unfolder.current.OnArrayStart(ctx, l, baseType)
132 | }
133 |
134 | func unfoldIfcFinishSubArray(ctx *unfoldCtx) (interface{}, error) {
135 | child := ctx.ptr.pop()
136 | bt := ctx.baseType.pop()
137 | switch bt {
138 | {{ range $bt, $gt := data.mapTypes }}
139 | case structform.{{ $bt }}:
140 | value := *(*[]{{ $gt }})(child)
141 | last := len(ctx.valueBuffer.arrays) - 1
142 | ctx.valueBuffer.arrays = ctx.valueBuffer.arrays[:last]
143 | return value, nil
144 | {{ end }}
145 | default:
146 | return nil, errTODO()
147 | }
148 | }
149 |
150 | func makeArrayPtr(ctx *unfoldCtx, l int, bt structform.BaseType) (interface{}, unsafe.Pointer, ptrUnfolder) {
151 | switch bt {
152 | {{ range $bt, $gt := data.mapTypes }}
153 | case structform.{{ $bt }}:
154 | idx := len(ctx.valueBuffer.arrays)
155 | ctx.valueBuffer.arrays = append(ctx.valueBuffer.arrays, nil)
156 | arrPtr := &ctx.valueBuffer.arrays[idx]
157 | ptr := unsafe.Pointer(arrPtr)
158 | to := (*[]{{ $gt }})(ptr)
159 | {{- if or (eq $bt "AnyType") (eq $bt "ZeroType") }}
160 | unfolder := newUnfolderArrIfc()
161 | {{ else }}
162 | unfolder := newUnfolderArr{{ $gt | capitalize }}()
163 | {{ end }}
164 | return to, ptr, unfolder
165 | {{ end }}
166 | default:
167 | panic("invalid type code")
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/gotype/unfold_err.yml:
--------------------------------------------------------------------------------
1 | # Licensed to Elasticsearch B.V. under one or more contributor
2 | # license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright
4 | # ownership. Elasticsearch B.V. licenses this file to you under
5 | # the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | import:
19 | - unfold_templates.yml
20 |
21 | data.errorUnfolders:
22 | unfolderNoTarget: errNotInitialized
23 | unfolderErrUnknown: errUnsupported
24 | unfolderErrArrayStart: errExpectedArray
25 | unfolderErrObjectStart: errExpectedObject
26 | unfolderErrExpectKey: errExpectedObjectKey
27 |
28 | main: |
29 | package gotype
30 |
31 | {{ range $name, $err := data.errorUnfolders }}
32 | type {{ $name }} struct {}
33 | {{ end }}
34 |
35 | {{ range $name, $err := data.errorUnfolders }}
36 |
37 | func (*{{ $name }}) OnNil(*unfoldCtx) error { return {{ $err }} }
38 | func (*{{ $name }}) OnBool(*unfoldCtx, bool) error { return {{ $err }} }
39 | func (*{{ $name }}) OnString(*unfoldCtx, string) error { return {{ $err }} }
40 | func (*{{ $name }}) OnStringRef(*unfoldCtx, []byte) error { return {{ $err }} }
41 | func (*{{ $name }}) OnInt8(*unfoldCtx, int8) error { return {{ $err }} }
42 | func (*{{ $name }}) OnInt16(*unfoldCtx, int16) error { return {{ $err }} }
43 | func (*{{ $name }}) OnInt32(*unfoldCtx, int32) error { return {{ $err }} }
44 | func (*{{ $name }}) OnInt64(*unfoldCtx, int64) error { return {{ $err }} }
45 | func (*{{ $name }}) OnInt(*unfoldCtx, int) error { return {{ $err }} }
46 | func (*{{ $name }}) OnByte(*unfoldCtx, byte) error { return {{ $err }} }
47 | func (*{{ $name }}) OnUint8(*unfoldCtx, uint8) error { return {{ $err }} }
48 | func (*{{ $name }}) OnUint16(*unfoldCtx, uint16) error { return {{ $err }} }
49 | func (*{{ $name }}) OnUint32(*unfoldCtx, uint32) error { return {{ $err }} }
50 | func (*{{ $name }}) OnUint64(*unfoldCtx, uint64) error { return {{ $err }} }
51 | func (*{{ $name }}) OnUint(*unfoldCtx, uint) error { return {{ $err }} }
52 | func (*{{ $name }}) OnFloat32(*unfoldCtx, float32) error { return {{ $err }} }
53 | func (*{{ $name }}) OnFloat64(*unfoldCtx, float64) error { return {{ $err }} }
54 | func (*{{ $name }}) OnArrayStart(*unfoldCtx, int, structform.BaseType) error { return {{ $err }} }
55 | func (*{{ $name }}) OnArrayFinished(*unfoldCtx) error { return {{ $err }} }
56 | func (*{{ $name }}) OnChildArrayDone(*unfoldCtx) error { return {{ $err }} }
57 | func (*{{ $name }}) OnObjectStart(*unfoldCtx, int, structform.BaseType) error { return {{ $err }} }
58 | func (*{{ $name }}) OnObjectFinished(*unfoldCtx) error { return {{ $err }} }
59 | func (*{{ $name }}) OnKey(*unfoldCtx, string) error { return {{ $err }} }
60 | func (*{{ $name }}) OnKeyRef(*unfoldCtx, []byte) error { return {{ $err }} }
61 | func (*{{ $name }}) OnChildObjectDone(*unfoldCtx) error { return {{ $err }} }
62 |
63 | {{ end }}
64 |
--------------------------------------------------------------------------------
/gotype/unfold_ignore.yml:
--------------------------------------------------------------------------------
1 | # Licensed to Elasticsearch B.V. under one or more contributor
2 | # license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright
4 | # ownership. Elasticsearch B.V. licenses this file to you under
5 | # the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | main: |
19 | package gotype
20 |
21 | {{ invoke "makeIgnoreType" "type" "" }}
22 |
23 | func (*unfolderIgnore) onValue(ctx *unfoldCtx) error {
24 | ctx.unfolder.pop()
25 | return nil
26 | }
27 |
28 | {{ invoke "makeIgnoreType" "type" "Arr" }}
29 |
30 | func (*unfolderIgnoreArr) onValue(ctx *unfoldCtx) error {
31 | return nil
32 | }
33 |
34 | func (*unfolderIgnoreArr) OnArrayFinished(ctx *unfoldCtx) error {
35 | ctx.unfolder.pop()
36 | return nil
37 | }
38 |
39 | {{ invoke "makeIgnoreType" "type" "Obj" }}
40 |
41 | func (*unfolderIgnoreObj) onValue(ctx *unfoldCtx) error {
42 | return nil
43 | }
44 |
45 | func (*unfolderIgnoreObj) OnObjectFinished(ctx *unfoldCtx) error {
46 | ctx.unfolder.pop()
47 | return nil
48 | }
49 |
50 | templates.makeIgnoreType: |
51 | {{ $type := .type }}
52 | {{ $tUnfolder := printf "unfolderIgnore%v" $type }}
53 |
54 | type unfoldIgnore{{ $type }}Value struct {}
55 | type unfoldIgnore{{ $type }}Ptr struct {}
56 | type {{ $tUnfolder }} struct {
57 | unfolderErrUnknown
58 | }
59 |
60 | var (
61 | _singletonUnfoldIgnore{{ $type }}Value = &unfoldIgnore{{ $type }}Value{}
62 | _singletonUnfoldIgnore{{ $type }}Ptr = &unfoldIgnore{{ $type }}Ptr{}
63 | _singleton{{ $tUnfolder }} = &{{ $tUnfolder }}{}
64 | )
65 |
66 | func (*unfoldIgnore{{ $type }}Value) initState(ctx *unfoldCtx, _ reflect.Value) {
67 | ctx.unfolder.push(_singleton{{ $tUnfolder }})
68 | }
69 |
70 | func (*unfoldIgnore{{ $type }}Ptr) initState(ctx *unfoldCtx, _ unsafe.Pointer) {
71 | ctx.unfolder.push(_singleton{{ $tUnfolder }})
72 | }
73 |
74 | func (u *{{ $tUnfolder }}) OnNil(ctx *unfoldCtx) error { return u.onValue(ctx) }
75 | func (u *{{ $tUnfolder }}) OnBool(ctx *unfoldCtx, _ bool) error { return u.onValue(ctx) }
76 | func (u *{{ $tUnfolder }}) OnString(ctx *unfoldCtx, _ string) error { return u.onValue(ctx) }
77 | func (u *{{ $tUnfolder }}) OnInt8(ctx *unfoldCtx, _ int8) error { return u.onValue(ctx) }
78 | func (u *{{ $tUnfolder }}) OnInt16(ctx *unfoldCtx, _ int16) error { return u.onValue(ctx) }
79 | func (u *{{ $tUnfolder }}) OnInt32(ctx *unfoldCtx, _ int32) error { return u.onValue(ctx) }
80 | func (u *{{ $tUnfolder }}) OnInt64(ctx *unfoldCtx, _ int64) error { return u.onValue(ctx) }
81 | func (u *{{ $tUnfolder }}) OnInt(ctx *unfoldCtx, _ int) error { return u.onValue(ctx) }
82 | func (u *{{ $tUnfolder }}) OnByte(ctx *unfoldCtx, _ byte) error { return u.onValue(ctx) }
83 | func (u *{{ $tUnfolder }}) OnUint8(ctx *unfoldCtx, _ uint8) error { return u.onValue(ctx) }
84 | func (u *{{ $tUnfolder }}) OnUint16(ctx *unfoldCtx, _ uint16) error { return u.onValue(ctx) }
85 | func (u *{{ $tUnfolder }}) OnUint32(ctx *unfoldCtx, _ uint32) error { return u.onValue(ctx) }
86 | func (u *{{ $tUnfolder }}) OnUint64(ctx *unfoldCtx, _ uint64) error { return u.onValue(ctx) }
87 | func (u *{{ $tUnfolder }}) OnUint(ctx *unfoldCtx, _ uint) error { return u.onValue(ctx) }
88 | func (u *{{ $tUnfolder }}) OnFloat32(ctx *unfoldCtx, _ float32) error { return u.onValue(ctx) }
89 | func (u *{{ $tUnfolder }}) OnFloat64(ctx *unfoldCtx, _ float64) error { return u.onValue(ctx) }
90 |
91 | func (u *{{ $tUnfolder }}) OnArrayStart(ctx *unfoldCtx, _ int, _ structform.BaseType) error {
92 | _singletonUnfoldIgnoreArrPtr.initState(ctx, nil)
93 | return nil
94 | }
95 |
96 | func (u *{{ $tUnfolder }}) OnChildArrayDone(ctx *unfoldCtx) error {
97 | return u.onValue(ctx)
98 | }
99 |
100 | func (u *{{ $tUnfolder }}) OnObjectStart(ctx *unfoldCtx, _ int, _ structform.BaseType) error {
101 | _singletonUnfoldIgnoreObjPtr.initState(ctx, nil)
102 | return nil
103 | }
104 |
105 | func (u *{{ $tUnfolder }}) OnChildObjectDone(ctx *unfoldCtx) error {
106 | return u.onValue(ctx)
107 | }
108 |
--------------------------------------------------------------------------------
/gotype/unfold_lookup.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | /*
21 | func lookupReflUnfolder(t reflect.Type) (reflUnfolder, error) {
22 | // we always expect a pointer to a value
23 | bt := t.Elem()
24 |
25 | switch bt.Kind() {
26 | case reflect.Array:
27 | switch bt.Elem().Kind() {
28 | case reflect.Int:
29 | return liftGoUnfolder(newUnfolderArrInt()), nil
30 | }
31 |
32 | case reflect.Slice:
33 |
34 | case reflect.Map:
35 | if bt.Key().Kind() != reflect.String {
36 | return nil, errMapRequiresStringKey
37 | }
38 |
39 | switch bt.Elem().Kind() {
40 | case reflect.Interface:
41 | return liftGoUnfolder(newUnfolderMapIfc()), nil
42 | }
43 |
44 | case reflect.Struct:
45 |
46 | }
47 |
48 | return nil, errTODO()
49 | }
50 | */
51 |
--------------------------------------------------------------------------------
/gotype/unfold_lookup_go.yml:
--------------------------------------------------------------------------------
1 | # Licensed to Elasticsearch B.V. under one or more contributor
2 | # license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright
4 | # ownership. Elasticsearch B.V. licenses this file to you under
5 | # the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | import:
19 | - unfold_templates.yml
20 |
21 | main: |
22 | package gotype
23 |
24 | func lookupUserPrimitiveConstructor(t reflect.Type) func(reflect.Value) ptrUnfolder {
25 | switch t.Kind() {
26 | {{- range data.primitiveTypes }}
27 | case reflect.{{ capitalize . }}:
28 | return {{ capitalize . | printf "newUserUnfolder%v" }}
29 | {{ end }}
30 | default:
31 | return nil
32 | }
33 | }
34 |
35 | func lookupGoTypeUnfolder(to interface{}) (unsafe.Pointer, ptrUnfolder) {
36 | switch ptr := to.(type) {
37 | case *interface{}:
38 | return unsafe.Pointer(ptr), newUnfolderIfc()
39 | case *[]interface{}:
40 | return unsafe.Pointer(ptr), newUnfolderArrIfc()
41 | case *map[string]interface{}:
42 | return unsafe.Pointer(ptr), newUnfolderMapIfc()
43 |
44 | {{ range data.primitiveTypes }}
45 | case *{{ . }}:
46 | return unsafe.Pointer(ptr), newUnfolder{{ . | capitalize }}()
47 | case *[]{{ . }}:
48 | return unsafe.Pointer(ptr), newUnfolderArr{{ . | capitalize }}()
49 | case *map[string]{{ . }}:
50 | return unsafe.Pointer(ptr), newUnfolderMap{{ . | capitalize }}()
51 | {{ end }}
52 | default:
53 | return nil, nil
54 | }
55 | }
56 |
57 | func lookupGoPtrUnfolder(t reflect.Type) (ptrUnfolder) {
58 | switch t.Kind() {
59 | case reflect.Interface:
60 | return newUnfolderIfc()
61 | {{ range data.primitiveTypes }}
62 | case reflect.{{ . | capitalize }}:
63 | return newUnfolder{{ . | capitalize }}()
64 | {{ end }}
65 |
66 | case reflect.Slice:
67 | et := t.Elem()
68 | switch et.Kind() {
69 | case reflect.Interface:
70 | return newUnfolderArrIfc()
71 | {{ range data.primitiveTypes }}
72 | case reflect.{{ . | capitalize }}:
73 | return newUnfolderArr{{ . | capitalize }}()
74 | {{ end }}
75 | }
76 |
77 | case reflect.Map:
78 | if t.Key().Kind() != reflect.String {
79 | return nil
80 | }
81 |
82 | et := t.Elem()
83 | switch et.Kind() {
84 | case reflect.Interface:
85 | return newUnfolderMapIfc()
86 | {{ range data.primitiveTypes }}
87 | case reflect.{{ . | capitalize }}:
88 | return newUnfolderMap{{ . | capitalize }}()
89 | {{ end }}
90 | }
91 |
92 | }
93 |
94 | return nil
95 | }
96 |
97 | func lookupReflUnfolder(ctx *unfoldCtx, t reflect.Type, withUser bool) (reflUnfolder, error) {
98 | if withUser {
99 | if f := lookupReflUser(ctx, t); f != nil {
100 | return f, nil
101 | }
102 | }
103 |
104 | if t.Implements(tExpander) {
105 | return newExpanderInit(), nil
106 | }
107 |
108 | if f := ctx.reg.find(t); f != nil {
109 | return f, nil
110 | }
111 |
112 | f, err := buildReflUnfolder(ctx, t)
113 | if err != nil {
114 | return nil, err
115 | }
116 |
117 | ctx.reg.set(t, f)
118 | return f, nil
119 | }
120 |
121 | func lookupReflUser(ctx *unfoldCtx, t reflect.Type) reflUnfolder {
122 | if ctx.userReg != nil {
123 | return ctx.userReg[t]
124 | }
125 | return nil
126 | }
127 |
128 | func buildReflUnfolder(ctx *unfoldCtx, t reflect.Type) (reflUnfolder, error) {
129 | // we always expect a pointer
130 | bt := t.Elem()
131 |
132 | switch bt.Kind() {
133 | case reflect.Interface:
134 | return unfolderReflIfc, nil
135 | {{ range data.primitiveTypes }}
136 | case reflect.{{ . | capitalize }}:
137 | return unfolderRefl{{ . | capitalize }}, nil
138 | {{ end }}
139 |
140 | case reflect.Array:
141 | return nil, errTODO()
142 |
143 | case reflect.Ptr:
144 | unfolderElem, err := lookupReflUnfolder(ctx, bt, true)
145 | if err != nil {
146 | return nil, err
147 | }
148 | return newUnfolderReflPtr(unfolderElem), nil
149 |
150 | case reflect.Slice:
151 | et := bt.Elem()
152 |
153 | if unfolderElem := lookupReflUser(ctx, et); unfolderElem != nil {
154 | return newUnfolderReflSlice(unfolderElem), nil
155 | }
156 |
157 | if reflect.PtrTo(et).Implements(tExpander) {
158 | return newUnfolderReflSlice(newExpanderInit()), nil
159 | }
160 |
161 | switch et.Kind() {
162 | case reflect.Interface:
163 | return unfolderReflArrIfc, nil
164 | {{ range data.primitiveTypes }}
165 | case reflect.{{ . | capitalize }}:
166 | return unfolderReflArr{{ . | capitalize }}, nil
167 | {{ end }}
168 | }
169 |
170 | unfolderElem, err := lookupReflUnfolder(ctx, reflect.PtrTo(et), false)
171 | if err != nil {
172 | return nil, err
173 | }
174 | return newUnfolderReflSlice(unfolderElem), nil
175 |
176 | case reflect.Map:
177 | et := bt.Elem()
178 |
179 | if unfolderElem := lookupReflUser(ctx, et); unfolderElem != nil {
180 | return newUnfolderReflMap(unfolderElem), nil
181 | }
182 |
183 | if reflect.PtrTo(et).Implements(tExpander) {
184 | return newUnfolderReflMap(newExpanderInit()), nil
185 | }
186 |
187 | switch et.Kind() {
188 | case reflect.Interface:
189 | return unfolderReflMapIfc, nil
190 | {{ range data.primitiveTypes }}
191 | case reflect.{{ . | capitalize }}:
192 | return unfolderReflMap{{ . | capitalize }}, nil
193 | {{ end }}
194 | }
195 |
196 | unfolderElem, err := lookupReflUnfolder(ctx, reflect.PtrTo(et), false)
197 | if err != nil {
198 | return nil, err
199 | }
200 | return newUnfolderReflMap(unfolderElem), nil
201 |
202 | case reflect.Struct:
203 | return createUnfolderReflStruct(ctx, t)
204 |
205 | default:
206 | return nil, errTODO()
207 | }
208 | }
209 |
--------------------------------------------------------------------------------
/gotype/unfold_map.yml:
--------------------------------------------------------------------------------
1 | # Licensed to Elasticsearch B.V. under one or more contributor
2 | # license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright
4 | # ownership. Elasticsearch B.V. licenses this file to you under
5 | # the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | import:
19 | - unfold_templates.yml
20 |
21 | main: |
22 | package gotype
23 |
24 | import "github.com/urso/go-structform"
25 |
26 | {{/* defined 'lifted' pointer map unfolders into reflection based unfolders */}}
27 | var (
28 | unfolderReflMapIfc = liftGoUnfolder(newUnfolderMapIfc())
29 | {{ range data.primitiveTypes }}
30 | {{ $t := capitalize . }}
31 | unfolderReflMap{{ $t }} = liftGoUnfolder(newUnfolderMap{{ $t }}())
32 | {{ end }}
33 | )
34 |
35 | {{/* define pointer based unfolder types */}}
36 | {{ invoke "makeTypeWithName" "name" "Ifc" "type" "interface{}" }}
37 | {{ template "makeType" "bool" }}
38 | {{ template "makeType" "string" }}
39 | {{ range .numTypes }}
40 | {{ template "makeType" . }}
41 | {{ end }}
42 |
43 | {{/* create value visitor callbacks */}}
44 | {{ invoke "onIfcFns" "name" "unfolderMapIfc" "fn" "put" }}
45 | {{ invoke "onBoolFns" "name" "unfolderMapBool" "fn" "put" }}
46 | {{ invoke "onStringFns" "name" "unfolderMapString" "fn" "put" }}
47 | {{ range .numTypes }}
48 | {{ $type := . }}
49 | {{ $name := capitalize $type | printf "unfolderMap%v" }}
50 | {{ invoke "onNumberFns" "name" $name "type" $type "fn" "put" }}
51 | {{ end }}
52 |
53 | {{ template "mapIfc" }}
54 |
55 |
56 | # makeTypeWithName(name, type)
57 | templates.makeTypeWithName: |
58 | {{ $type := .type }}
59 | {{ $name := capitalize .name | printf "unfolderMap%v" }}
60 | {{ $startName := capitalize .name | printf "unfoldMapStart%v" }}
61 | {{ $keyName := capitalize .name | printf "unfoldMapKey%v" }}
62 |
63 | {{ invoke "makeUnfoldType" "name" $name }}
64 | {{ invoke "makeUnfoldType" "name" $startName "base" "unfolderErrObjectStart" }}
65 | {{ invoke "makeUnfoldType" "name" $keyName "base" "unfolderErrExpectKey" }}
66 |
67 | func (u *{{ $name }} ) initState(ctx *unfoldCtx, ptr unsafe.Pointer) {
68 | ctx.unfolder.push(new{{ $keyName | capitalize}}())
69 | ctx.unfolder.push(new{{ $startName | capitalize}}())
70 | ctx.ptr.push(ptr)
71 | }
72 |
73 | func (u * {{ $keyName }} ) cleanup(ctx *unfoldCtx) {
74 | ctx.unfolder.pop()
75 | ctx.ptr.pop()
76 | }
77 |
78 | func (u * {{ $startName }}) cleanup(ctx *unfoldCtx) {
79 | ctx.unfolder.pop()
80 | }
81 |
82 |
83 | func (u *{{ $name }} ) ptr(ctx *unfoldCtx) *map[string]{{ $type }} {
84 | return (*map[string]{{ $type }})(ctx.ptr.current)
85 | }
86 |
87 |
88 | func (u *{{ $startName }} ) OnObjectStart(ctx *unfoldCtx, l int, baseType structform.BaseType) error {
89 | // TODO: validate baseType
90 |
91 | u.cleanup(ctx)
92 | return nil
93 | }
94 |
95 | func (u *{{ $keyName }} ) OnKeyRef(ctx *unfoldCtx, key []byte) error {
96 | return u.OnKey(ctx, ctx.keyCache.get(key))
97 | }
98 |
99 | func (u *{{ $keyName }} ) OnKey(ctx *unfoldCtx, key string) error {
100 | ctx.key.push(key)
101 | ctx.unfolder.current = new{{ $name | capitalize }}()
102 | return nil
103 | }
104 |
105 | func (u *{{ $keyName }} ) OnObjectFinished(ctx *unfoldCtx) error {
106 | u.cleanup(ctx)
107 | return nil
108 | }
109 |
110 | func (u *{{ $name }} ) put(ctx *unfoldCtx, v {{ $type }}) error {
111 | to := u.ptr(ctx)
112 | if *to == nil {
113 | *to = map[string]{{ $type }}{}
114 | }
115 | (*to)[ctx.key.pop()] = v
116 |
117 | ctx.unfolder.current = new{{ $keyName | capitalize }}()
118 | return nil
119 | }
120 |
121 | templates.mapIfc: |
122 | func unfoldIfcStartSubMap(ctx *unfoldCtx, l int, baseType structform.BaseType) error {
123 | _, ptr, unfolder := makeMapPtr(ctx, l, baseType)
124 | ctx.ptr.push(ptr)
125 | ctx.baseType.push(baseType)
126 | unfolder.initState(ctx, ptr)
127 | return ctx.unfolder.current.OnObjectStart(ctx, l, baseType)
128 | }
129 |
130 | func unfoldIfcFinishSubMap(ctx *unfoldCtx) (interface{}, error) {
131 | child := ctx.ptr.pop()
132 | bt := ctx.baseType.pop()
133 | switch bt {
134 | {{ range $bt, $gt := data.mapTypes }}
135 | case structform.{{ $bt }}:
136 | value := *(*map[string]{{ $gt }})(child)
137 | {{- if or (eq $bt "AnyType") (eq $bt "ZeroType") }}
138 | last := len(ctx.valueBuffer.mapAny)-1
139 | ctx.valueBuffer.mapAny = ctx.valueBuffer.mapAny[:last]
140 | {{ else }}
141 | last := len(ctx.valueBuffer.mapPrimitive)-1
142 | ctx.valueBuffer.mapPrimitive = ctx.valueBuffer.mapPrimitive[:last]
143 | {{ end -}}
144 | return value, nil
145 |
146 | {{ end }}
147 | default:
148 | return nil, errTODO()
149 | }
150 | }
151 |
152 | func makeMapPtr(ctx *unfoldCtx, l int, bt structform.BaseType) (interface{}, unsafe.Pointer, ptrUnfolder) {
153 | switch bt {
154 | {{ range $bt, $gt := data.mapTypes }}
155 | case structform.{{ $bt }}:
156 | {{- if or (eq $bt "AnyType") (eq $bt "ZeroType") }}
157 | idx := len(ctx.valueBuffer.mapAny)
158 | ctx.valueBuffer.mapAny = append(ctx.valueBuffer.mapAny, nil)
159 | to := &ctx.valueBuffer.mapAny[idx]
160 | ptr := unsafe.Pointer(to)
161 | unfolder := newUnfolderMapIfc()
162 | return to, ptr, unfolder
163 | {{ else }}
164 | idx := len(ctx.valueBuffer.mapPrimitive)
165 | ctx.valueBuffer.mapPrimitive = append(ctx.valueBuffer.mapPrimitive, nil)
166 | mapPtr := &ctx.valueBuffer.mapPrimitive[idx]
167 | ptr := unsafe.Pointer(mapPtr)
168 | to := (*map[string]{{ $gt }})(ptr)
169 | unfolder := newUnfolderMap{{ $gt | capitalize }}()
170 | return to, ptr, unfolder
171 | {{ end }}
172 |
173 | {{ end }}
174 | default:
175 | panic("invalid type code")
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/gotype/unfold_opts.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | import (
21 | "reflect"
22 | )
23 |
24 | type initUnfoldOptions struct {
25 | unfoldFns map[reflect.Type]reflUnfolder
26 | }
27 |
28 | type UnfoldOption func(*initUnfoldOptions) error
29 |
30 | func applyUnfoldOpts(opts []UnfoldOption) (i initUnfoldOptions, err error) {
31 | for _, o := range opts {
32 | if err = o(&i); err != nil {
33 | break
34 | }
35 | }
36 | return i, err
37 | }
38 |
39 | // Unfolders accepts a list of primitive, processing, or stateful unfolders.
40 | //
41 | // Primitive unfolder must implement a function matching the type: func(to *Target, from P) error
42 | // Where to is an arbitrary go type that the result should be written to and
43 | // P must be one of: bool, string, uint(8|16|32|64), int(8|16|32|64), float(32|64)
44 | //
45 | // Processing unfolders first unfold a structure into a temporary structure, followed
46 | // by a post-processing function used to fill in the original target. Processing unfolders
47 | // for type T have the signature:
48 | // func(to *T) (cell interface{}, process func(to *T, cell interface{}) error)
49 | //
50 | // A processing unfolder returns a temporary value for unfolding. The Unfolder will process
51 | // the temporary value (held in cell), like any regular supported value.
52 | // The process function is executed if the parsing step did succeed.
53 | // The address to the target structure and the original cell are reported to the process function,
54 | // reducing the need for allocation storage on the heap in most simple cases.
55 | //
56 | // Stateful unfolders have the function signature: func(to *T) UnfoldState.
57 | // The state returned by the initialization function is used for parsing.
58 | // Although stateful unfolders allow for the most complex unfolding possible,
59 | // they add the most overhead in managing state and allocations. If possible
60 | // prefer primitive unfolders, followed by processing unfolder.
61 | func Unfolders(in ...interface{}) UnfoldOption {
62 | unfolders, err := makeUserUnfolderFns(in)
63 | if err != nil || len(unfolders) == 0 {
64 | return func(_ *initUnfoldOptions) error { return err }
65 | }
66 |
67 | return func(o *initUnfoldOptions) error {
68 | if o.unfoldFns == nil {
69 | o.unfoldFns = map[reflect.Type]reflUnfolder{}
70 | }
71 |
72 | for k, v := range unfolders {
73 | o.unfoldFns[k] = v
74 | }
75 | return nil
76 | }
77 | }
78 |
79 | func makeUserUnfolderFns(in []interface{}) (map[reflect.Type]reflUnfolder, error) {
80 | M := map[reflect.Type]reflUnfolder{}
81 |
82 | for _, cur := range in {
83 | if cur == nil {
84 | continue
85 | }
86 |
87 | t, unfolder, err := makeUserUnfolder(reflect.ValueOf(cur))
88 | if err != nil {
89 | return nil, err
90 | }
91 |
92 | M[t] = unfolder
93 | }
94 |
95 | return M, nil
96 | }
97 |
--------------------------------------------------------------------------------
/gotype/unfold_primitive.yml:
--------------------------------------------------------------------------------
1 | # Licensed to Elasticsearch B.V. under one or more contributor
2 | # license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright
4 | # ownership. Elasticsearch B.V. licenses this file to you under
5 | # the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | import:
19 | - unfold_templates.yml
20 |
21 | main: |
22 | package gotype
23 |
24 | var (
25 | {{/* defined 'lifted' pointer primitive unfolders into reflection based unfolders */}}
26 | unfolderReflIfc = liftGoUnfolder(newUnfolderIfc())
27 | {{ range data.primitiveTypes }}
28 | {{ $t := capitalize . }}
29 | unfolderRefl{{ $t }} = liftGoUnfolder(newUnfolder{{ $t }}())
30 | {{ end }}
31 | )
32 |
33 | {{/* define pointer based unfolder types */}}
34 | {{ invoke "makeTypeWithName" "name" "ifc" "type" "interface{}" }}
35 | {{ template "makeType" "bool" }}
36 | {{ template "makeType" "string" }}
37 | {{ range .numTypes }}
38 | {{ template "makeType" . }}
39 | {{ end }}
40 |
41 | {{/* create value visitor callbacks */}}
42 | {{ invoke "onIfcFns" "name" "unfolderIfc" "fn" "assign" }}
43 | {{ invoke "onBoolFns" "name" "unfolderBool" "fn" "assign" }}
44 | {{ invoke "onStringFns" "name" "unfolderString" "fn" "assign" }}
45 | {{ range .numTypes }}
46 | {{ $type := . }}
47 | {{ $name := capitalize . | printf "unfolder%v" }}
48 | {{ invoke "onNumberFns" "name" $name "type" $type "fn" "assign" }}
49 | {{ end }}
50 |
51 | /*
52 | func (*unfolderIfc) OnArrayStart(ctx *unfoldCtx, l int, bt structform.BaseType) error {
53 | return unfoldIfcStartSubArray(ctx, l, bt)
54 | }
55 |
56 | func (u *unfolderIfc) OnChildArrayDone(ctx *unfoldCtx) error {
57 | v, err := unfoldIfcFinishSubArray(ctx)
58 | if err == nil {
59 | err = u.assign(ctx, v)
60 | }
61 | return err
62 | }
63 | */
64 |
65 | # makeTypeWithName(name, type, [base])
66 | templates.makeTypeWithName: |
67 | {{ $type := .type }}
68 | {{ $name := capitalize .name | printf "unfolder%v" }}
69 | {{ invoke "makeUnfoldType" "type" $type "name" $name "base" .base }}
70 |
71 | func (u *{{ $name }} ) initState(ctx *unfoldCtx, ptr unsafe.Pointer) {
72 | ctx.unfolder.push(u)
73 | ctx.ptr.push(ptr)
74 | }
75 |
76 | func (u *{{ $name }} ) cleanup(ctx *unfoldCtx) {
77 | ctx.unfolder.pop()
78 | ctx.ptr.pop()
79 | }
80 |
81 | func (u *{{ $name }} ) ptr(ctx *unfoldCtx) *{{ $type }} {
82 | return (*{{ $type }})(ctx.ptr.current)
83 | }
84 |
85 | func (u *{{ $name }}) assign(ctx *unfoldCtx, v {{ $type }}) error {
86 | *u.ptr(ctx) = v
87 | u.cleanup(ctx)
88 | return nil
89 | }
90 |
--------------------------------------------------------------------------------
/gotype/unfold_refl.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | import (
21 | "reflect"
22 | "unsafe"
23 |
24 | structform "github.com/elastic/go-structform"
25 | )
26 |
27 | type liftedReflUnfolder struct{ unfolder ptrUnfolder }
28 |
29 | type unfolderReflSlice struct {
30 | elem reflUnfolder
31 | }
32 |
33 | type unfolderReflSliceStart struct {
34 | unfolderErrArrayStart
35 | }
36 |
37 | type unfolderReflMap struct {
38 | shared unfolderReflMapShared
39 | }
40 |
41 | type unfolderReflMapShared struct {
42 | waitKey *unfolderReflMapOnKey
43 | waitElem *unfolderReflMapOnElem
44 | }
45 |
46 | type unfolderReflMapStart struct {
47 | unfolderErrObjectStart
48 | }
49 |
50 | type unfolderReflMapOnKey struct {
51 | unfolderErrExpectKey
52 | shared *unfolderReflMapShared
53 | }
54 |
55 | type unfolderReflMapOnElem struct {
56 | shared *unfolderReflMapShared
57 | elem reflUnfolder
58 | }
59 |
60 | type unfolderReflPtr struct {
61 | elem reflUnfolder
62 | }
63 |
64 | var (
65 | _singletonUnfolderReflSliceStart = &unfolderReflSliceStart{}
66 | _singletonUnfolderReflMapStart = &unfolderReflMapStart{}
67 | )
68 |
69 | func liftGoUnfolder(u ptrUnfolder) *liftedReflUnfolder { return &liftedReflUnfolder{u} }
70 |
71 | func (u *liftedReflUnfolder) initState(ctx *unfoldCtx, v reflect.Value) {
72 | ptr := unsafe.Pointer(v.Pointer())
73 | u.unfolder.initState(ctx, ptr)
74 | }
75 |
76 | func newUnfolderReflSlice(elem reflUnfolder) *unfolderReflSlice {
77 | return &unfolderReflSlice{elem}
78 | }
79 |
80 | func (u *unfolderReflSlice) initState(ctx *unfoldCtx, v reflect.Value) {
81 | ctx.value.push(v)
82 | ctx.unfolder.push(u)
83 | ctx.idx.push(0)
84 | ctx.unfolder.push(_singletonUnfolderReflSliceStart)
85 | }
86 |
87 | func (u *unfolderReflSlice) cleanup(ctx *unfoldCtx) {
88 | ctx.idx.pop()
89 | ctx.value.pop()
90 | ctx.unfolder.pop()
91 | }
92 |
93 | func (u *unfolderReflSliceStart) cleanup(ctx *unfoldCtx) {
94 | ctx.unfolder.pop()
95 | }
96 |
97 | func (u *unfolderReflSliceStart) OnArrayStart(ctx *unfoldCtx, l int, baseType structform.BaseType) error {
98 |
99 | ptr := ctx.value.current
100 | v := ptr.Elem()
101 |
102 | if l < 0 {
103 | l = 0
104 | }
105 |
106 | if v.IsNil() && l > 0 {
107 | v.Set(reflect.MakeSlice(v.Type(), l, l))
108 | } else if !v.IsNil() && l < v.Len() {
109 | v.SetLen(l)
110 | }
111 |
112 | u.cleanup(ctx)
113 | return nil
114 | }
115 |
116 | func (u *unfolderReflSlice) OnArrayFinished(ctx *unfoldCtx) error {
117 | u.cleanup(ctx)
118 | return nil
119 | }
120 |
121 | func (u *unfolderReflSlice) prepare(ctx *unfoldCtx) reflect.Value {
122 | // make space for some more element
123 | ptr := ctx.value.current
124 | idx := &ctx.idx
125 | v := ptr.Elem()
126 |
127 | switch {
128 | case v.Len() > idx.current:
129 |
130 | case v.Cap() > idx.current:
131 | v.SetLen(idx.current + 1)
132 |
133 | default:
134 | v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem())))
135 | }
136 |
137 | elem := v.Index(idx.current).Addr()
138 | idx.current++
139 |
140 | return elem
141 | }
142 |
143 | func (u *unfolderReflSlice) OnObjectFinished(_ *unfoldCtx) error {
144 | return errUnsupported
145 | }
146 |
147 | func newUnfolderReflMap(elem reflUnfolder) *unfolderReflMap {
148 | u := &unfolderReflMap{}
149 | u.shared.waitKey = &unfolderReflMapOnKey{shared: &u.shared}
150 | u.shared.waitElem = &unfolderReflMapOnElem{shared: &u.shared, elem: elem}
151 | return u
152 | }
153 |
154 | func (u *unfolderReflMap) initState(ctx *unfoldCtx, v reflect.Value) {
155 | ctx.value.push(v)
156 | ctx.unfolder.push(u.shared.waitKey)
157 | ctx.unfolder.push(_singletonUnfolderReflMapStart)
158 | }
159 |
160 | func (u *unfolderReflMapStart) OnObjectStart(ctx *unfoldCtx, l int, bt structform.BaseType) error {
161 | ctx.unfolder.pop()
162 | return nil
163 | }
164 |
165 | func (u *unfolderReflMapOnKey) OnKey(ctx *unfoldCtx, key string) error {
166 | ctx.key.push(key)
167 | ctx.unfolder.current = u.shared.waitElem
168 | return nil
169 | }
170 |
171 | func (u *unfolderReflMapOnKey) OnKeyRef(ctx *unfoldCtx, key []byte) error {
172 | return u.OnKey(ctx, ctx.keyCache.get(key))
173 | }
174 |
175 | func (u *unfolderReflMapOnKey) OnObjectFinished(ctx *unfoldCtx) error {
176 | ctx.unfolder.pop()
177 | ctx.value.pop()
178 | return nil
179 | }
180 |
181 | func (u *unfolderReflMapOnElem) prepare(ctx *unfoldCtx) reflect.Value {
182 | ptr := ctx.value.current
183 | v := ptr.Elem()
184 | et := v.Type().Elem()
185 |
186 | target := reflect.New(et)
187 | ctx.value.push(target)
188 | return target
189 | }
190 |
191 | func (u *unfolderReflMapOnElem) process(ctx *unfoldCtx) {
192 | ptr := ctx.value.pop()
193 | v := ptr.Elem()
194 |
195 | ptr = ctx.value.current
196 | m := ptr.Elem()
197 | m.SetMapIndex(reflect.ValueOf(ctx.key.pop()), v)
198 |
199 | ctx.unfolder.current = u.shared.waitKey
200 | }
201 |
202 | func (u *unfolderReflMapOnElem) OnObjectFinished(_ *unfoldCtx) error { return errExpectedObjectValue }
203 | func (u *unfolderReflMapOnElem) OnArrayFinished(_ *unfoldCtx) error { return errUnsupported }
204 |
205 | func newUnfolderReflPtr(elem reflUnfolder) *unfolderReflPtr {
206 | return &unfolderReflPtr{elem}
207 | }
208 |
209 | func (u *unfolderReflPtr) initState(ctx *unfoldCtx, v reflect.Value) {
210 | ctx.value.push(v)
211 | ctx.unfolder.push(u)
212 | }
213 |
214 | func (u *unfolderReflPtr) cleanup(ctx *unfoldCtx) {
215 | ctx.value.pop()
216 | ctx.unfolder.pop()
217 | }
218 |
219 | func (u *unfolderReflPtr) prepare(ctx *unfoldCtx) reflect.Value {
220 | ptr := ctx.value.current
221 |
222 | v := ptr.Elem()
223 | target := reflect.New(v.Type().Elem())
224 | ctx.value.push(target)
225 | return target
226 | }
227 |
228 | func (u *unfolderReflPtr) process(ctx *unfoldCtx) {
229 | v := ctx.value.pop()
230 | ptr := ctx.value.current.Elem()
231 | ptr.Set(v)
232 | u.cleanup(ctx)
233 | }
234 |
235 | func (u *unfolderReflPtr) OnObjectFinished(_ *unfoldCtx) error { return errUnsupported }
236 | func (u *unfolderReflPtr) OnArrayFinished(_ *unfoldCtx) error { return errUnsupported }
237 |
--------------------------------------------------------------------------------
/gotype/unfold_refl.yml:
--------------------------------------------------------------------------------
1 | # Licensed to Elasticsearch B.V. under one or more contributor
2 | # license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright
4 | # ownership. Elasticsearch B.V. licenses this file to you under
5 | # the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | import:
19 | - unfold_templates.yml
20 |
21 | main: |
22 | package gotype
23 |
24 | func (u *unfolderReflSlice) OnNil(ctx *unfoldCtx) error {
25 | u.prepare(ctx)
26 | return nil
27 | }
28 |
29 | {{ invoke "makeReflPrimitives" "type" "unfolderReflSlice" }}
30 | {{ invoke "makeReflChildArrays" "type" "unfolderReflSlice" }}
31 | {{ invoke "makeReflChildObjects" "type" "unfolderReflSlice" }}
32 |
33 | func (u *unfolderReflMapOnElem) OnNil(ctx *unfoldCtx) error {
34 | ptr := ctx.value.current
35 | m := ptr.Elem()
36 | v := reflect.Zero(m.Type().Elem())
37 | m.SetMapIndex(reflect.ValueOf(ctx.key.pop()), v)
38 |
39 | ctx.unfolder.current = u.shared.waitKey
40 | return nil
41 | }
42 |
43 | {{ invoke "makeReflPrimitives" "type" "unfolderReflMapOnElem" "process" "process" }}
44 | {{ invoke "makeReflChildArrays" "type" "unfolderReflMapOnElem" "process" "process" }}
45 | {{ invoke "makeReflChildObjects" "type" "unfolderReflMapOnElem" "process" "process" "error" "errExpectedObjectValue" }}
46 |
47 | func (u *unfolderReflPtr) OnNil(ctx *unfoldCtx) error {
48 | ptr := ctx.value.current
49 | v := ptr.Elem()
50 | v.Set(reflect.Zero(v.Type()))
51 | u.cleanup(ctx)
52 | return nil
53 | }
54 |
55 | {{ invoke "makeReflPrimitives" "type" "unfolderReflPtr" "process" "process" }}
56 | {{ invoke "makeReflChildArrays" "type" "unfolderReflPtr" "process" "process" }}
57 | {{ invoke "makeReflChildObjects" "type" "unfolderReflPtr" "process" "process" }}
58 |
59 | # makeReflPrimitiveCallbacks(type, [process])
60 | templates.makeReflPrimitives: |
61 | {{ $type := .type}}
62 | {{ $process := .process }}
63 |
64 | func (u *{{ $type }}) OnByte(ctx *unfoldCtx, v byte) error {
65 | elem := u.prepare(ctx)
66 | u.elem.initState(ctx, elem)
67 | err := ctx.unfolder.current.OnByte(ctx, v)
68 | {{ if $process }}
69 | if err == nil {
70 | u.{{ $process }}(ctx)
71 | }
72 | {{ end }}
73 | return err
74 | }
75 |
76 | func (u *{{ $type }}) OnStringRef(ctx *unfoldCtx, v []byte) error {
77 | return u.OnString(ctx, string(v))
78 | }
79 |
80 | {{ range data.primitiveTypes }}
81 | func (u *{{ $type }}) On{{ . | capitalize}}(ctx *unfoldCtx, v {{ . }}) error {
82 | elem := u.prepare(ctx)
83 | u.elem.initState(ctx, elem)
84 | err := ctx.unfolder.current.On{{ . | capitalize }}(ctx, v)
85 | {{ if $process }}
86 | if err == nil {
87 | u.{{ $process }}(ctx)
88 | }
89 | {{ end }}
90 | return err
91 | }
92 | {{ end }}
93 |
94 | # makeReflChildArrays(type, [process])
95 | templates.makeReflChildArrays: |
96 | {{ $type := .type}}
97 | {{ $process := .process }}
98 |
99 | func (u *{{ $type }}) OnArrayStart(ctx *unfoldCtx, l int, bt structform.BaseType) error {
100 | elem := u.prepare(ctx)
101 | u.elem.initState(ctx, elem)
102 | return ctx.unfolder.current.OnArrayStart(ctx, l, bt)
103 | }
104 |
105 | func (u *{{ $type }}) OnChildArrayDone(ctx *unfoldCtx) error {
106 | {{ if $process }}
107 | u.{{ $process }}(ctx)
108 | {{ end }}
109 | return nil
110 | }
111 |
112 | # makeReflChildObjects(type, [process], [error])
113 | templates.makeReflChildObjects: |
114 | {{ $type := .type}}
115 | {{ $process := .process }}
116 | {{ $error := default "errUnsupported" .error }}
117 |
118 | func (u *{{ $type }}) OnObjectStart(ctx *unfoldCtx, l int, bt structform.BaseType) error {
119 | elem := u.prepare(ctx)
120 | u.elem.initState(ctx, elem)
121 | return ctx.unfolder.current.OnObjectStart(ctx, l, bt)
122 | }
123 |
124 | func (u *{{ $type }}) OnKey(_ *unfoldCtx, _ string) error {
125 | return {{ $error }}
126 | }
127 |
128 | func (u *{{ $type }}) OnKeyRef(_ *unfoldCtx, _ []byte) error {
129 | return {{ $error }}
130 | }
131 |
132 | func (u *{{ $type }}) OnChildObjectDone(ctx *unfoldCtx) error {
133 | {{ if $process }}
134 | u.{{ $process }}(ctx)
135 | {{ end }}
136 | return nil
137 | }
138 |
139 |
--------------------------------------------------------------------------------
/gotype/unfold_struct.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package gotype
19 |
20 | import (
21 | "fmt"
22 | "reflect"
23 | "strings"
24 | "unicode"
25 | "unicode/utf8"
26 | "unsafe"
27 |
28 | structform "github.com/elastic/go-structform"
29 | )
30 |
31 | type unfolderStruct struct {
32 | unfolderErrExpectKey
33 | fields map[string]fieldUnfolder
34 | }
35 |
36 | type unfolderStructStart struct {
37 | unfolderErrObjectStart
38 | }
39 |
40 | type fieldUnfolder struct {
41 | offset uintptr
42 | initState func(ctx *unfoldCtx, sp unsafe.Pointer)
43 | }
44 |
45 | var (
46 | _singletonUnfolderStructStart = &unfolderStructStart{}
47 |
48 | _ignoredField = &fieldUnfolder{
49 | initState: _singletonUnfoldIgnorePtr.initState,
50 | }
51 | )
52 |
53 | func createUnfolderReflStruct(ctx *unfoldCtx, t reflect.Type) (*unfolderStruct, error) {
54 | // assume t is pointer to struct
55 | t = t.Elem()
56 |
57 | fields, err := fieldUnfolders(ctx, t)
58 | if err != nil {
59 | return nil, err
60 | }
61 |
62 | u := &unfolderStruct{fields: fields}
63 | return u, nil
64 | }
65 |
66 | func fieldUnfolders(ctx *unfoldCtx, t reflect.Type) (map[string]fieldUnfolder, error) {
67 | count := t.NumField()
68 | fields := map[string]fieldUnfolder{}
69 |
70 | for i := 0; i < count; i++ {
71 | st := t.Field(i)
72 |
73 | name := st.Name
74 | rune, _ := utf8.DecodeRuneInString(name)
75 | if !unicode.IsUpper(rune) {
76 | continue
77 | }
78 |
79 | tagName, tagOpts := parseTags(st.Tag.Get(ctx.opts.tag))
80 | if tagOpts.omit {
81 | continue
82 | }
83 |
84 | if tagOpts.squash {
85 | if st.Type.Kind() != reflect.Struct {
86 | return nil, errSquashNeedObject
87 | }
88 |
89 | sub, err := fieldUnfolders(ctx, st.Type)
90 | if err != nil {
91 | return nil, err
92 | }
93 |
94 | for name, fu := range sub {
95 | fu.offset += st.Offset
96 | if _, exists := fields[name]; exists {
97 | return nil, fmt.Errorf("duplicate field name %v", name)
98 | }
99 |
100 | fields[name] = fu
101 | }
102 | } else {
103 | if tagName != "" {
104 | name = tagName
105 | } else {
106 | name = strings.ToLower(name)
107 | }
108 |
109 | if _, exists := fields[name]; exists {
110 | return nil, fmt.Errorf("duplicate field name %v", name)
111 | }
112 |
113 | fu, err := makeFieldUnfolder(ctx, st)
114 | if err != nil {
115 | return nil, err
116 | }
117 |
118 | fields[name] = fu
119 | }
120 | }
121 |
122 | return fields, nil
123 | }
124 |
125 | func makeFieldUnfolder(ctx *unfoldCtx, st reflect.StructField) (fieldUnfolder, error) {
126 | fu := fieldUnfolder{offset: st.Offset}
127 | targetType := reflect.PtrTo(st.Type)
128 |
129 | if uu := lookupReflUser(ctx, targetType); uu != nil {
130 | fu.initState = wrapReflUnfolder(st.Type, uu)
131 | } else if targetType.Implements(tExpander) {
132 | fu.initState = wrapReflUnfolder(st.Type, newExpanderInit())
133 | } else if pu := lookupGoPtrUnfolder(st.Type); pu != nil {
134 | fu.initState = pu.initState
135 | } else {
136 | ru, err := lookupReflUnfolder(ctx, targetType, false)
137 | if err != nil {
138 | return fu, err
139 | }
140 |
141 | if su, ok := ru.(*unfolderStruct); ok {
142 | fu.initState = su.initStatePtr
143 | } else {
144 | fu.initState = wrapReflUnfolder(st.Type, ru)
145 | }
146 | }
147 |
148 | return fu, nil
149 | }
150 |
151 | func wrapReflUnfolder(t reflect.Type, ru reflUnfolder) func(*unfoldCtx, unsafe.Pointer) {
152 | return func(ctx *unfoldCtx, ptr unsafe.Pointer) {
153 | v := reflect.NewAt(t, ptr)
154 | ru.initState(ctx, v)
155 | }
156 | }
157 |
158 | func (u *unfolderStruct) initState(ctx *unfoldCtx, v reflect.Value) {
159 | u.initStatePtr(ctx, unsafe.Pointer(v.Pointer()))
160 | }
161 |
162 | func (u *unfolderStruct) initStatePtr(ctx *unfoldCtx, ptr unsafe.Pointer) {
163 | ctx.ptr.push(ptr)
164 | ctx.unfolder.push(u)
165 | ctx.unfolder.push(_singletonUnfolderStructStart)
166 | }
167 |
168 | func (u *unfolderStructStart) OnObjectStart(ctx *unfoldCtx, l int, bt structform.BaseType) error {
169 | ctx.unfolder.pop()
170 | return nil
171 | }
172 |
173 | func (u *unfolderStruct) OnObjectFinished(ctx *unfoldCtx) error {
174 | ctx.unfolder.pop()
175 | ctx.ptr.pop()
176 | return nil
177 | }
178 |
179 | func (u *unfolderStruct) OnChildObjectDone(ctx *unfoldCtx) error { return nil }
180 | func (u *unfolderStruct) OnChildArrayDone(ctx *unfoldCtx) error { return nil }
181 |
182 | func (u *unfolderStruct) OnKeyRef(ctx *unfoldCtx, key []byte) error {
183 | return u.OnKey(ctx, bytes2Str(key))
184 | }
185 |
186 | func (u *unfolderStruct) OnKey(ctx *unfoldCtx, key string) error {
187 | field, exists := u.fields[key]
188 | if !exists {
189 | _ignoredField.initState(ctx, nil)
190 | return nil
191 | }
192 |
193 | structPtr := ctx.ptr.current
194 | fieldPtr := unsafe.Pointer(uintptr(structPtr) + field.offset)
195 | field.initState(ctx, fieldPtr)
196 | return nil
197 | }
198 |
--------------------------------------------------------------------------------
/gotype/unfold_templates.yml:
--------------------------------------------------------------------------------
1 | # Licensed to Elasticsearch B.V. under one or more contributor
2 | # license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright
4 | # ownership. Elasticsearch B.V. licenses this file to you under
5 | # the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | import:
19 | - "types.yml"
20 |
21 | # makeUnfoldType(name, [.base])
22 | templates.makeUnfoldType: |
23 | {{ $name := .name }}
24 | {{ $base := default "unfolderErrUnknown" .base }}
25 |
26 | type {{ $name }} struct {
27 | {{ $base }}
28 | }
29 |
30 | var _singleton{{ $name | capitalize }} = &{{ $name }}{}
31 |
32 | func new{{ $name | capitalize }}() *{{ $name }} {
33 | return _singleton{{ $name | capitalize }}
34 | }
35 |
36 | # makeType(.) -> invokes makeTypeWithName(name, type)
37 | templates.makeType: |
38 | {{ invoke "makeTypeWithName" "name" (capitalize .) "type" . }}
39 |
40 | # makeBoolFns(name, fn)
41 | templates.onBoolFns: |
42 | {{ invoke "onNil" "name" .name "fn" .fn "default" "false" }}
43 | {{ invoke "onBool" "name" .name "fn" .fn }}
44 |
45 | # makeStringFns(name, fn)
46 | templates.onStringFns: |
47 | {{ invoke "onNil" "name" .name "fn" .fn "default" "\"\"" }}
48 | {{ invoke "onString" "name" .name "fn" .fn }}
49 |
50 | # makeNumberFns(name, fn)
51 | templates.onNumberFns: |
52 | {{ invoke "onNil" "name" .name "fn" .fn "default" "0" }}
53 | {{ invoke "onNumber" "name" .name "type" .type "fn" .fn }}
54 |
55 | # onIfcFns(name, fn)
56 | templates.onIfcFns: |
57 | {{ invoke "onNil" "name" .name "fn" .fn "default" "nil" }}
58 | {{ invoke "onBool" "name" .name "fn" .fn }}
59 | {{ invoke "onString" "name" .name "fn" .fn }}
60 | {{ invoke "onNumber" "name" .name "type" "(interface{})" "fn" .fn }}
61 |
62 | func (*{{ .name }} ) OnArrayStart(ctx *unfoldCtx, l int, bt structform.BaseType) error {
63 | return unfoldIfcStartSubArray(ctx, l, bt)
64 | }
65 |
66 | func (u *{{ .name }}) OnChildArrayDone(ctx *unfoldCtx) error {
67 | v, err := unfoldIfcFinishSubArray(ctx)
68 | if err == nil {
69 | err = u.{{ .fn }}(ctx, v)
70 | }
71 | return err
72 | }
73 |
74 | func (*{{ .name }}) OnObjectStart(ctx *unfoldCtx, l int, bt structform.BaseType) error {
75 | return unfoldIfcStartSubMap(ctx, l, bt)
76 | }
77 |
78 | func (u *{{ .name }}) OnChildObjectDone(ctx *unfoldCtx) error {
79 | v, err := unfoldIfcFinishSubMap(ctx)
80 | if err == nil {
81 | err = u.{{ .fn }}(ctx, v)
82 | }
83 | return err
84 | }
85 |
86 |
87 | # onBool(name, fn)
88 | templates.onBool: |
89 | func (u *{{ .name }}) OnBool(ctx *unfoldCtx, v bool) error { return u.{{ .fn }} (ctx, v) }
90 |
91 | # onString(name, fn)
92 | templates.onString: |
93 | func (u *{{ .name }}) OnString(ctx *unfoldCtx, v string) error { return u.{{ .fn }} (ctx, v) }
94 | func (u *{{ .name }}) OnStringRef(ctx *unfoldCtx, v []byte) error {
95 | return u.OnString(ctx, string(v))
96 | }
97 |
98 |
99 | # onNil(name, fn, default)
100 | templates.onNil: |
101 | func (u *{{ .name }}) OnNil(ctx *unfoldCtx) error {
102 | return u.{{ .fn }}(ctx, {{ .default }})
103 | }
104 |
105 |
106 | # onNumber(name, fn, type)
107 | templates.onNumber: |
108 | {{ $name := .name }}
109 | {{ $fn := .fn }}
110 | {{ $type := .type }}
111 |
112 | func (u *{{ $name }}) OnByte(ctx *unfoldCtx, v byte) error {
113 | return u.{{ $fn }}(ctx, {{ $type }}(v))
114 | }
115 | {{ range $t := data.numTypes }}
116 | func (u *{{ $name }}) On{{ $t | capitalize}}(ctx *unfoldCtx, v {{ $t }}) error {
117 | return u.{{ $fn }}(ctx, {{ $type }}(v))
118 | }
119 | {{ end }}
120 |
--------------------------------------------------------------------------------
/gotype/unfold_user_primitive.yml:
--------------------------------------------------------------------------------
1 | # Licensed to Elasticsearch B.V. under one or more contributor
2 | # license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright
4 | # ownership. Elasticsearch B.V. licenses this file to you under
5 | # the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | import:
19 | - unfold_templates.yml
20 |
21 | main: |
22 | package gotype
23 |
24 | {{/* define pointer based user unfolder types */}}
25 | {{ template "makeType" "bool" }}
26 | {{ template "makeType" "string" }}
27 | {{ range .numTypes }}
28 | {{ template "makeType" . }}
29 | {{ end }}
30 |
31 | {{/* create value visitor callbacks */}}
32 | {{ invoke "onBoolFns" "name" "userUnfolderBool" "fn" "process" }}
33 | {{ invoke "onStringFns" "name" "userUnfolderString" "fn" "process" }}
34 | {{ range .numTypes }}
35 | {{ $type := . }}
36 | {{ $name := capitalize . | printf "userUnfolder%v" }}
37 | {{ invoke "onNumberFns" "name" $name "type" $type "fn" "process" }}
38 | {{ end }}
39 |
40 | # makeTypeWithName(name, type, [base])
41 | templates.makeTypeWithName: |
42 | {{ $type := .type }}
43 | {{ $name := capitalize .name | printf "userUnfolder%v" }}
44 | {{ invoke "makeUserUnfoldType" "type" $type "name" $name "base" .base }}
45 |
46 | func (u *{{ $name }} ) initState(ctx *unfoldCtx, ptr unsafe.Pointer) {
47 | ctx.unfolder.push(u)
48 | ctx.ptr.push(ptr)
49 | }
50 |
51 | func (u *{{ $name }} ) cleanup(ctx *unfoldCtx) {
52 | ctx.unfolder.pop()
53 | ctx.ptr.pop()
54 | }
55 |
56 | func (u *{{ $name }}) process(ctx *unfoldCtx, v {{ $type }}) error {
57 | err := u.fn(ctx.ptr.current, v)
58 | u.cleanup(ctx)
59 | return err
60 | }
61 |
62 | templates.makeUserUnfoldType: |
63 | {{ $type := .type }}
64 | {{ $name := .name }}
65 | {{ $cbname := .name | printf "%vCB" }}
66 | {{ $base := default "unfolderErrUnknown" .base }}
67 |
68 | type (
69 | {{ $name }} struct {
70 | {{ $base }}
71 | fn {{ $cbname }}
72 | }
73 |
74 | {{ $cbname }} func(unsafe.Pointer, {{ $type }}) error
75 | )
76 |
77 | func new{{ $name | capitalize }}(fn reflect.Value) ptrUnfolder {
78 | return &{{ $name }}{
79 | fn: *((*{{ $cbname }})(stunsafe.UnsafeFnPtr(fn))),
80 | }
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/internal/unsafe/unsafe.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package unsafe
19 |
20 | import (
21 | "reflect"
22 | "runtime"
23 | "unsafe"
24 | )
25 |
26 | type emptyInterface struct {
27 | typ unsafe.Pointer
28 | word unsafe.Pointer
29 | }
30 |
31 | func Str2Bytes(s string) (b []byte) {
32 | sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
33 | bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
34 | bh.Data = sh.Data
35 | bh.Cap = sh.Len
36 | bh.Len = sh.Len
37 | runtime.KeepAlive(s)
38 | return
39 | }
40 |
41 | func Bytes2Str(b []byte) (s string) {
42 | bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
43 | sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
44 | sh.Data = bh.Data
45 | sh.Len = bh.Len
46 | runtime.KeepAlive(b)
47 | return
48 | }
49 |
50 | // IfcValuePtr extracts the underlying values pointer from an empty interface{}
51 | // value.
52 | // Note: this might beome more unsafe in future go-versions,
53 | // if primitive values < pointer size will be stored by value in the
54 | // `interface{}` type.
55 | func IfcValuePtr(v interface{}) unsafe.Pointer {
56 | ifc := (*emptyInterface)(unsafe.Pointer(&v))
57 | return ifc.word
58 | }
59 |
60 | // ReflValuePtr extracts the pointer value from a reflect.Value instance.
61 | // With reflect.Value basically being similar to `interface{}` augmented with additional
62 | // flags to execute checks, we map the value into an empty interface value (no methods)
63 | // and extract the actual values pointer.
64 | // Note: this might beome more unsafe in future go-versions,
65 | // if primitive values < pointer size will be stored by value in the
66 | // `interface{}` type.
67 | func ReflValuePtr(v reflect.Value) unsafe.Pointer {
68 | ifc := (*emptyInterface)(unsafe.Pointer(&v))
69 | return ifc.word
70 | }
71 |
72 | // Returns a newly (allocated on heap) function pointer. The unsafe.Pointer returned
73 | // can be used to cast a function type into a function with other(compatible)
74 | // type (e.g. passing pointers only).
75 | func UnsafeFnPtr(fn interface{}) unsafe.Pointer {
76 | var v reflect.Value
77 | if tmp, ok := fn.(reflect.Value); ok {
78 | v = tmp
79 | } else {
80 | v = reflect.ValueOf(fn)
81 | }
82 |
83 | tmp := reflect.New(v.Type())
84 | tmp.Elem().Set(v)
85 | return unsafe.Pointer(tmp.Pointer())
86 | }
87 |
--------------------------------------------------------------------------------
/json/decode.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package json
19 |
20 | import (
21 | "io"
22 |
23 | structform "github.com/elastic/go-structform"
24 | )
25 |
26 | type Decoder struct {
27 | in io.Reader
28 | buffer []byte
29 | p Parser
30 | }
31 |
32 | func NewDecoder(in io.Reader, buffer int, vs structform.Visitor) *Decoder {
33 | dec := &Decoder{
34 | buffer: make([]byte, 0, buffer),
35 | in: in,
36 | }
37 | dec.p.init(vs)
38 | return dec
39 | }
40 |
41 | func NewBytesDecoder(b []byte, vs structform.Visitor) *Decoder {
42 | dec := &Decoder{
43 | buffer: b,
44 | in: nil,
45 | }
46 | dec.p.init(vs)
47 | return dec
48 | }
49 |
50 | func (dec *Decoder) Next() error {
51 | var (
52 | n int
53 | err error
54 | reported bool
55 | )
56 |
57 | for !reported {
58 | if len(dec.buffer) == 0 {
59 | if dec.in == nil {
60 | if err := dec.p.finalize(); err != nil {
61 | return err
62 | }
63 | return io.EOF
64 | }
65 |
66 | n, err := dec.in.Read(dec.buffer)
67 | dec.buffer = dec.buffer[:n]
68 | if n == 0 && err != nil {
69 | return err
70 | }
71 | }
72 |
73 | n, reported, err = dec.p.feedUntil(dec.buffer)
74 | if err != nil {
75 | return err
76 | }
77 |
78 | dec.buffer = dec.buffer[n:]
79 | if reported {
80 | return nil
81 | }
82 | }
83 |
84 | return nil
85 | }
86 |
--------------------------------------------------------------------------------
/json/defs.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package json
19 |
20 | import "github.com/elastic/go-structform/internal/unsafe"
21 |
22 | var (
23 | nullSymbol = []byte("null")
24 | trueSymbol = []byte("true")
25 | falseSymbol = []byte("false")
26 | commaSymbol = []byte(",")
27 |
28 | invalidCharSym = []byte(`\ufffd`)
29 | )
30 |
31 | func str2Bytes(s string) []byte {
32 | return unsafe.Str2Bytes(s)
33 | }
34 |
35 | func bytes2Str(b []byte) string {
36 | return unsafe.Bytes2Str(b)
37 | }
38 |
--------------------------------------------------------------------------------
/json/json.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package json
19 |
--------------------------------------------------------------------------------
/json/json_test.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package json
19 |
20 | import (
21 | "bytes"
22 | "io"
23 | "math"
24 | "strings"
25 | "testing"
26 |
27 | "github.com/stretchr/testify/assert"
28 | "github.com/stretchr/testify/require"
29 |
30 | structform "github.com/elastic/go-structform"
31 | "github.com/elastic/go-structform/sftest"
32 | )
33 |
34 | func TestEncParseConsistent(t *testing.T) {
35 | testEncParseConsistent(t, Parse)
36 | }
37 |
38 | func TestEncDecoderConsistent(t *testing.T) {
39 | testEncParseConsistent(t, func(content []byte, to structform.Visitor) error {
40 | dec := NewBytesDecoder(content, to)
41 | err := dec.Next()
42 | if err == io.EOF {
43 | err = nil
44 | }
45 | return err
46 | })
47 | }
48 |
49 | func TestEncParseBytesConsistent(t *testing.T) {
50 | testEncParseConsistent(t, func(content []byte, to structform.Visitor) error {
51 | p := NewParser(to)
52 | for _, b := range content {
53 | err := p.feed([]byte{b})
54 | if err != nil {
55 | return err
56 | }
57 | }
58 | return p.finalize()
59 | })
60 | }
61 |
62 | func testEncParseConsistent(
63 | t *testing.T,
64 | parse func([]byte, structform.Visitor) error,
65 | ) {
66 | sftest.TestEncodeParseConsistent(t, sftest.Samples,
67 | func() (structform.Visitor, func(structform.Visitor) error) {
68 | buf := bytes.NewBuffer(nil)
69 | vs := NewVisitor(buf)
70 |
71 | return vs, func(to structform.Visitor) error {
72 | return parse(buf.Bytes(), to)
73 | }
74 | })
75 | }
76 |
77 | func TestStringEncoding(t *testing.T) {
78 | type testCase struct {
79 | in string
80 | htmlEscape bool
81 | expected string
82 | }
83 |
84 | cases := map[string]testCase{
85 | "no escaping required": testCase{
86 | in: "hello world",
87 | expected: `"hello world"`,
88 | },
89 | "json required escaping": testCase{
90 | in: `"hello \nworld"`,
91 | htmlEscape: false,
92 | expected: `"\"hello \\nworld\""`,
93 | },
94 | "html escape with json required escaping": testCase{
95 | in: `"hello \nworld"`,
96 | htmlEscape: true,
97 | expected: `"\"hello \\nworld\""`,
98 | },
99 | "html with html escaping enabled": testCase{
100 | in: "world",
101 | htmlEscape: true,
102 | expected: `"\u003chello\u003eworld\u003c/hello\u003e"`,
103 | },
104 | "html without html escaping": testCase{
105 | in: "world",
106 | htmlEscape: false,
107 | expected: `"world"`,
108 | },
109 | "html with double quotes": testCase{
110 | in: ``,
111 | htmlEscape: true,
112 | expected: `"\u003chello id=\"hola\"\u003e"`,
113 | },
114 | "html with single quotes": testCase{
115 | in: ``,
116 | htmlEscape: true,
117 | expected: `"\u003chello id='hola'\u003e"`,
118 | },
119 | }
120 |
121 | for name, test := range cases {
122 | in, htmlEscape, expected := test.in, test.htmlEscape, test.expected
123 |
124 | t.Run(name, func(t *testing.T) {
125 | buf := &bytes.Buffer{}
126 | visitor := NewVisitor(buf)
127 | visitor.SetEscapeHTML(htmlEscape)
128 | visitor.OnString(in)
129 |
130 | actual := buf.String()
131 | assert.Equal(t, expected, actual)
132 | })
133 | }
134 | }
135 |
136 | func TestEncodeIgnoreSpecialFloatValues(t *testing.T) {
137 | cases := map[string]struct {
138 | tokens sftest.Recording
139 | want string
140 | }{
141 | "float64 NaN": {
142 | tokens: sftest.Recording{
143 | sftest.Float64Rec{math.NaN()},
144 | },
145 | want: `null`,
146 | },
147 | "float64 +Inf": {
148 | tokens: sftest.Recording{
149 | sftest.Float64Rec{math.Inf(1)},
150 | },
151 | want: `null`,
152 | },
153 | "float64 -Inf": {
154 | tokens: sftest.Recording{
155 | sftest.Float64Rec{math.Inf(-1)},
156 | },
157 | want: `null`,
158 | },
159 | }
160 |
161 | for name, test := range cases {
162 | t.Run(name, func(t *testing.T) {
163 | var buf strings.Builder
164 | visitor := NewVisitor(&buf)
165 | visitor.SetIgnoreInvalidFloat(true)
166 |
167 | err := test.tokens.Replay(visitor)
168 | require.NoError(t, err)
169 |
170 | require.Equal(t, test.want, buf.String())
171 | })
172 | }
173 | }
174 |
175 | func TestEncodeExplicitRadixPoint(t *testing.T) {
176 | cases := map[string]struct {
177 | tokens sftest.Recording
178 | want string
179 | }{
180 | "1e+10": {
181 | tokens: sftest.Recording{
182 | sftest.Float64Rec{1e+10},
183 | },
184 | want: `1.0e+10`,
185 | },
186 | "1.1e+10": {
187 | tokens: sftest.Recording{
188 | sftest.Float64Rec{1.1e+10},
189 | },
190 | want: `1.1e+10`,
191 | },
192 | "1": {
193 | tokens: sftest.Recording{
194 | sftest.Float64Rec{1},
195 | },
196 | want: `1.0`,
197 | },
198 | "1.1": {
199 | tokens: sftest.Recording{
200 | sftest.Float64Rec{1.1},
201 | },
202 | want: `1.1`,
203 | },
204 | }
205 |
206 | for name, test := range cases {
207 | t.Run(name, func(t *testing.T) {
208 | var buf strings.Builder
209 | visitor := NewVisitor(&buf)
210 | visitor.SetExplicitRadixPoint(true)
211 |
212 | err := test.tokens.Replay(visitor)
213 | require.NoError(t, err)
214 |
215 | require.Equal(t, test.want, buf.String())
216 | })
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/json/state_string.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | // Code generated by "stringer -type=state"; DO NOT EDIT.
19 |
20 | package json
21 |
22 | import "strconv"
23 |
24 | const _state_name = "failedStatestartStatearrStatearrStateValuearrStateNextdictStatedictFieldStatedictNextFieldStatedictFieldValuedictFieldValueSepdictFieldStateEndnullStatetrueStatefalseStatestringStatenumberState"
25 |
26 | var _state_index = [...]uint8{0, 11, 21, 29, 42, 54, 63, 77, 95, 109, 126, 143, 152, 161, 171, 182, 193}
27 |
28 | func (i state) String() string {
29 | if i >= state(len(_state_index)-1) {
30 | return "state(" + strconv.FormatInt(int64(i), 10) + ")"
31 | }
32 | return _state_name[_state_index[i]:_state_index[i+1]]
33 | }
34 |
--------------------------------------------------------------------------------
/map.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package structform
19 |
20 | type extObjVisitor struct {
21 | Visitor
22 | }
23 |
24 | func (e extObjVisitor) OnStringObject(m map[string]string) error {
25 | if err := e.OnObjectStart(len(m), StringType); err != nil {
26 | return err
27 | }
28 |
29 | for k, v := range m {
30 | if err := e.OnKey(k); err != nil {
31 | return err
32 | }
33 | if err := e.OnString(v); err != nil {
34 | return err
35 | }
36 | }
37 |
38 | return e.OnObjectFinished()
39 | }
40 |
41 | func (e extObjVisitor) OnBoolObject(m map[string]bool) error {
42 | if err := e.OnObjectStart(len(m), BoolType); err != nil {
43 | return err
44 | }
45 |
46 | for k, v := range m {
47 | if err := e.OnKey(k); err != nil {
48 | return err
49 | }
50 | if err := e.OnBool(v); err != nil {
51 | return err
52 | }
53 | }
54 |
55 | return e.OnObjectFinished()
56 | }
57 |
58 | func (e extObjVisitor) OnInt8Object(m map[string]int8) error {
59 | if err := e.OnObjectStart(len(m), Int8Type); err != nil {
60 | return err
61 | }
62 |
63 | for k, v := range m {
64 | if err := e.OnKey(k); err != nil {
65 | return err
66 | }
67 | if err := e.OnInt8(v); err != nil {
68 | return err
69 | }
70 | }
71 |
72 | return e.OnObjectFinished()
73 | }
74 |
75 | func (e extObjVisitor) OnInt16Object(m map[string]int16) error {
76 | if err := e.OnObjectStart(len(m), Int16Type); err != nil {
77 | return err
78 | }
79 |
80 | for k, v := range m {
81 | if err := e.OnKey(k); err != nil {
82 | return err
83 | }
84 | if err := e.OnInt16(v); err != nil {
85 | return err
86 | }
87 | }
88 |
89 | return e.OnObjectFinished()
90 | }
91 |
92 | func (e extObjVisitor) OnInt32Object(m map[string]int32) error {
93 | if err := e.OnObjectStart(len(m), Int32Type); err != nil {
94 | return err
95 | }
96 |
97 | for k, v := range m {
98 | if err := e.OnKey(k); err != nil {
99 | return err
100 | }
101 | if err := e.OnInt32(v); err != nil {
102 | return err
103 | }
104 | }
105 |
106 | return e.OnObjectFinished()
107 | }
108 |
109 | func (e extObjVisitor) OnInt64Object(m map[string]int64) error {
110 | if err := e.OnObjectStart(len(m), Int64Type); err != nil {
111 | return err
112 | }
113 |
114 | for k, v := range m {
115 | if err := e.OnKey(k); err != nil {
116 | return err
117 | }
118 | if err := e.OnInt64(v); err != nil {
119 | return err
120 | }
121 | }
122 |
123 | return e.OnObjectFinished()
124 | }
125 |
126 | func (e extObjVisitor) OnIntObject(m map[string]int) error {
127 | if err := e.OnObjectStart(len(m), IntType); err != nil {
128 | return err
129 | }
130 |
131 | for k, v := range m {
132 | if err := e.OnKey(k); err != nil {
133 | return err
134 | }
135 | if err := e.OnInt(v); err != nil {
136 | return err
137 | }
138 | }
139 |
140 | return e.OnObjectFinished()
141 | }
142 |
143 | func (e extObjVisitor) OnUint8Object(m map[string]uint8) error {
144 | if err := e.OnObjectStart(len(m), Uint8Type); err != nil {
145 | return err
146 | }
147 |
148 | for k, v := range m {
149 | if err := e.OnKey(k); err != nil {
150 | return err
151 | }
152 | if err := e.OnUint8(v); err != nil {
153 | return err
154 | }
155 | }
156 |
157 | return e.OnObjectFinished()
158 | }
159 |
160 | func (e extObjVisitor) OnUint16Object(m map[string]uint16) error {
161 | if err := e.OnObjectStart(len(m), Uint16Type); err != nil {
162 | return err
163 | }
164 |
165 | for k, v := range m {
166 | if err := e.OnKey(k); err != nil {
167 | return err
168 | }
169 | if err := e.OnUint16(v); err != nil {
170 | return err
171 | }
172 | }
173 |
174 | return e.OnObjectFinished()
175 | }
176 |
177 | func (e extObjVisitor) OnUint32Object(m map[string]uint32) error {
178 | if err := e.OnObjectStart(len(m), Uint32Type); err != nil {
179 | return err
180 | }
181 |
182 | for k, v := range m {
183 | if err := e.OnKey(k); err != nil {
184 | return err
185 | }
186 | if err := e.OnUint32(v); err != nil {
187 | return err
188 | }
189 | }
190 |
191 | return e.OnObjectFinished()
192 | }
193 |
194 | func (e extObjVisitor) OnUint64Object(m map[string]uint64) error {
195 | if err := e.OnObjectStart(len(m), Uint64Type); err != nil {
196 | return err
197 | }
198 |
199 | for k, v := range m {
200 | if err := e.OnKey(k); err != nil {
201 | return err
202 | }
203 | if err := e.OnUint64(v); err != nil {
204 | return err
205 | }
206 | }
207 |
208 | return e.OnObjectFinished()
209 | }
210 |
211 | func (e extObjVisitor) OnUintObject(m map[string]uint) error {
212 | if err := e.OnObjectStart(len(m), UintType); err != nil {
213 | return err
214 | }
215 |
216 | for k, v := range m {
217 | if err := e.OnKey(k); err != nil {
218 | return err
219 | }
220 | if err := e.OnUint(v); err != nil {
221 | return err
222 | }
223 | }
224 |
225 | return e.OnObjectFinished()
226 | }
227 |
228 | func (e extObjVisitor) OnFloat32Object(m map[string]float32) error {
229 | if err := e.OnObjectStart(len(m), Float32Type); err != nil {
230 | return err
231 | }
232 |
233 | for k, v := range m {
234 | if err := e.OnKey(k); err != nil {
235 | return err
236 | }
237 | if err := e.OnFloat32(v); err != nil {
238 | return err
239 | }
240 | }
241 |
242 | return e.OnObjectFinished()
243 | }
244 |
245 | func (e extObjVisitor) OnFloat64Object(m map[string]float64) error {
246 | if err := e.OnObjectStart(len(m), Float64Type); err != nil {
247 | return err
248 | }
249 |
250 | for k, v := range m {
251 | if err := e.OnKey(k); err != nil {
252 | return err
253 | }
254 | if err := e.OnFloat64(v); err != nil {
255 | return err
256 | }
257 | }
258 |
259 | return e.OnObjectFinished()
260 | }
261 |
--------------------------------------------------------------------------------
/sftest/cases.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package sftest
19 |
20 | import structform "github.com/elastic/go-structform"
21 |
22 | var Samples = concatSamples(
23 | SamplesPrimitives,
24 | SamplesArr,
25 | SamplesObj,
26 | SamplesCombinations,
27 | )
28 |
29 | var SamplesPrimitives = []Recording{
30 | // simple primitives
31 | {NilRec{}}, // "null"
32 | {BoolRec{true}}, // "true"
33 | {BoolRec{false}}, // "false"
34 | {StringRec{"test"}},
35 | {StringRec{`test with " being special`}},
36 | {StringRec{""}},
37 |
38 | // int types
39 | {IntRec{8}},
40 | {IntRec{42}},
41 | {IntRec{100}},
42 | {IntRec{-90}},
43 | {IntRec{12345678}},
44 | {IntRec{-12345678}},
45 | {Int8Rec{8}},
46 | {Int8Rec{42}},
47 | {Int8Rec{100}},
48 | {Int8Rec{-90}},
49 | {Int16Rec{8}},
50 | {Int16Rec{42}},
51 | {Int16Rec{100}},
52 | {Int16Rec{-90}},
53 | {Int16Rec{500}},
54 | {Int16Rec{-500}},
55 | {Int32Rec{8}},
56 | {Int32Rec{42}},
57 | {Int32Rec{100}},
58 | {Int32Rec{-90}},
59 | {Int32Rec{500}},
60 | {Int32Rec{-500}},
61 | {Int32Rec{12345678}},
62 | {Int32Rec{-12345678}},
63 | {Int64Rec{8}},
64 | {Int64Rec{42}},
65 | {Int64Rec{100}},
66 | {Int64Rec{-90}},
67 | {Int64Rec{500}},
68 | {Int64Rec{-500}},
69 | {Int64Rec{123456781234}},
70 | {Int64Rec{-123456781234}},
71 |
72 | // uint types
73 | {UintRec{8}},
74 | {UintRec{42}},
75 | {UintRec{100}},
76 | {UintRec{12345678}},
77 | {Uint8Rec{8}},
78 | {Uint8Rec{42}},
79 | {Uint8Rec{100}},
80 | {ByteRec{8}},
81 | {ByteRec{42}},
82 | {ByteRec{100}},
83 | {Uint16Rec{8}},
84 | {Uint16Rec{42}},
85 | {Uint16Rec{100}},
86 | {Uint16Rec{500}},
87 | {Uint32Rec{8}},
88 | {Uint32Rec{42}},
89 | {Uint32Rec{100}},
90 | {Uint32Rec{500}},
91 | {Uint32Rec{12345678}},
92 | {Uint64Rec{8}},
93 | {Uint64Rec{42}},
94 | {Uint64Rec{100}},
95 | {Uint64Rec{500}},
96 | {Uint64Rec{123456781234}},
97 |
98 | // float types
99 | {Float32Rec{3.14}},
100 | {Float32Rec{-3.14}},
101 | {Float64Rec{3.14}},
102 | {Float64Rec{-3.14}},
103 | }
104 |
105 | var SamplesArr = []Recording{
106 | // empty arrays `[]`
107 | Arr(0, structform.AnyType),
108 | Arr(-1, structform.AnyType),
109 |
110 | // nested empty array `[[]]`
111 | Arr(1, structform.AnyType,
112 | Arr(0, structform.AnyType),
113 | ),
114 | Arr(-1, structform.AnyType,
115 | Arr(0, structform.AnyType),
116 | ),
117 | Arr(-1, structform.AnyType,
118 | Arr(-1, structform.AnyType),
119 | ),
120 |
121 | // array with arbitrary values
122 | Arr(-1, structform.AnyType,
123 | NilRec{},
124 | BoolRec{true},
125 | BoolRec{false},
126 | IntRec{1},
127 | Int64Rec{12345678910},
128 | Float32Rec{3.14},
129 | Float64Rec{7e+09},
130 | StringRec{"test"},
131 | ),
132 | Arr(2, structform.AnyType,
133 | Int8Rec{1},
134 | BoolRec{true},
135 | ),
136 | {
137 | Int8ArrRec{[]int8{1, 2, 3}},
138 | },
139 | {
140 | StringArrRec{[]string{"a", "b", "c"}},
141 | },
142 | }
143 |
144 | var SamplesObj = []Recording{
145 | // empty object '{}'
146 | Obj(-1, structform.AnyType),
147 | Obj(0, structform.AnyType),
148 |
149 | Obj(-1, structform.AnyType,
150 | "a", NilRec{},
151 | ),
152 |
153 | // objects
154 | Obj(-1, structform.AnyType,
155 | "a", StringRec{"test"}),
156 | Obj(1, structform.StringType,
157 | "a", StringRec{"test"}),
158 | Obj(-1, structform.AnyType,
159 | "a", BoolRec{true},
160 | "b", BoolRec{false},
161 | ),
162 | Obj(2, structform.AnyType,
163 | "a", BoolRec{true},
164 | "b", BoolRec{false},
165 | ),
166 | Obj(-1, structform.BoolType,
167 | "a", BoolRec{true},
168 | "b", BoolRec{false},
169 | ),
170 | Obj(2, structform.BoolType,
171 | "a", BoolRec{true},
172 | "b", BoolRec{false},
173 | ),
174 | Obj(-1, structform.AnyType,
175 | "a", UintRec{1},
176 | "b", Float64Rec{3.14},
177 | "c", StringRec{"test"},
178 | "d", BoolRec{true},
179 | ),
180 |
181 | // typed objects
182 | {
183 | StringObjRec{map[string]string{
184 | "a": "test1",
185 | "b": "test2",
186 | "c": "test3",
187 | }},
188 | },
189 | {
190 | UintObjRec{map[string]uint{
191 | "a": 1,
192 | "b": 2,
193 | "c": 3,
194 | }},
195 | },
196 | }
197 |
198 | var SamplesCombinations = []Recording{
199 | // objects in array
200 | Arr(-1, structform.AnyType,
201 | Obj(-1, structform.AnyType)),
202 | Arr(1, structform.AnyType,
203 | Obj(0, structform.AnyType)),
204 | Arr(-1, structform.AnyType,
205 | Obj(-1, structform.AnyType,
206 | "a", IntRec{-1},
207 | ),
208 | Obj(1, structform.UintType,
209 | "a", UintRec{1},
210 | ),
211 | ),
212 | Arr(2, structform.AnyType,
213 | Obj(-1, structform.AnyType,
214 | "a", IntRec{-1},
215 | ),
216 | Obj(1, structform.UintType,
217 | "a", UintRec{1},
218 | ),
219 | ),
220 |
221 | // array in object
222 | Obj(-1, structform.AnyType,
223 | "a", Arr(3, structform.IntType,
224 | IntRec{1}, IntRec{2}, IntRec{3}),
225 | ),
226 | Obj(1, structform.AnyType,
227 | "a", Arr(3, structform.IntType,
228 | IntRec{1}, IntRec{2}, IntRec{3}),
229 | ),
230 | Obj(1, structform.AnyType,
231 | "a", Int8ArrRec{[]int8{1, 2, 3}},
232 | ),
233 | }
234 |
--------------------------------------------------------------------------------
/sftest/sftest_test.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package sftest
19 |
20 | import (
21 | "testing"
22 |
23 | structform "github.com/elastic/go-structform"
24 | )
25 |
26 | func TestRecordingConsistent(t *testing.T) {
27 | TestEncodeParseConsistent(t, Samples,
28 | func() (structform.Visitor, func(structform.Visitor) error) {
29 | buf := &Recording{}
30 | return buf, buf.Replay
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/sftest/util.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package sftest
19 |
20 | import structform "github.com/elastic/go-structform"
21 |
22 | func Arr(l int, t structform.BaseType, elems ...interface{}) []Record {
23 | a := []Record{ArrayStartRec{l, t}}
24 | for _, elem := range elems {
25 | switch v := elem.(type) {
26 | case Record:
27 | a = append(a, v)
28 | case []Record:
29 | a = append(a, v...)
30 | case Recording:
31 | a = append(a, v...)
32 | default:
33 | panic("invalid key type")
34 | }
35 | }
36 |
37 | return append(a, ArrayFinishRec{})
38 | }
39 |
40 | func Obj(l int, t structform.BaseType, kv ...interface{}) []Record {
41 | if len(kv)%2 != 0 {
42 | panic("invalid object")
43 | }
44 |
45 | a := []Record{ObjectStartRec{l, t}}
46 | for i := 0; i < len(kv); i += 2 {
47 | k := kv[i].(string)
48 | a = append(a, ObjectKeyRec{k})
49 |
50 | switch v := kv[i+1].(type) {
51 | case Record:
52 | a = append(a, v)
53 | case []Record:
54 | a = append(a, v...)
55 | case Recording:
56 | a = append(a, v...)
57 | default:
58 | panic("invalid key type")
59 | }
60 | }
61 |
62 | return append(a, ObjectFinishRec{})
63 | }
64 |
--------------------------------------------------------------------------------
/string.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package structform
19 |
20 | type extStrVisitor struct {
21 | v Visitor
22 | }
23 |
24 | func MakeStringRefVisitor(v Visitor) StringRefVisitor {
25 | if sv, ok := v.(StringRefVisitor); ok {
26 | return sv
27 | }
28 | return extStrVisitor{v}
29 | }
30 |
31 | func (ev extStrVisitor) OnStringRef(s []byte) error {
32 | return ev.v.OnString(string(s))
33 | }
34 |
35 | func (ev extStrVisitor) OnKeyRef(s []byte) error {
36 | return ev.v.OnKey(string(s))
37 | }
38 |
--------------------------------------------------------------------------------
/ubjson/decode.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package ubjson
19 |
20 | import (
21 | "io"
22 |
23 | structform "github.com/elastic/go-structform"
24 | )
25 |
26 | type Decoder struct {
27 | in io.Reader
28 | buffer []byte
29 | buffer0 []byte
30 | p Parser
31 | }
32 |
33 | func NewDecoder(in io.Reader, buffer int, vs structform.Visitor) *Decoder {
34 | dec := &Decoder{
35 | buffer0: make([]byte, buffer),
36 | in: in,
37 | }
38 | dec.p.init(vs)
39 | return dec
40 | }
41 |
42 | func NewBytesDecoder(b []byte, vs structform.Visitor) *Decoder {
43 | dec := &Decoder{
44 | buffer: b,
45 | buffer0: b[:0],
46 | in: nil,
47 | }
48 | dec.p.init(vs)
49 | return dec
50 | }
51 |
52 | func (dec *Decoder) Next() error {
53 | var (
54 | n int
55 | err error
56 | reported bool
57 | )
58 |
59 | for !reported {
60 | if len(dec.buffer) == 0 {
61 | if dec.in == nil {
62 | if err := dec.p.finalize(); err != nil {
63 | return err
64 | }
65 | return io.EOF
66 | }
67 |
68 | n, err := dec.in.Read(dec.buffer0)
69 | dec.buffer = dec.buffer0[:n]
70 | if n == 0 && err != nil {
71 | return err
72 | }
73 | }
74 |
75 | n, reported, err = dec.p.feedUntil(dec.buffer)
76 | if err != nil {
77 | return err
78 | }
79 |
80 | dec.buffer = dec.buffer[n:]
81 | if reported {
82 | return nil
83 | }
84 | }
85 |
86 | return nil
87 | }
88 |
--------------------------------------------------------------------------------
/ubjson/defs.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package ubjson
19 |
20 | import "github.com/elastic/go-structform/internal/unsafe"
21 |
22 | const (
23 | noMarker byte = 0
24 |
25 | // value markers
26 | nullMarker byte = 'Z'
27 | noopMarker byte = 'N'
28 | trueMarker byte = 'T'
29 | falseMarker byte = 'F'
30 | int8Marker byte = 'i'
31 | uint8Marker byte = 'U'
32 | int16Marker byte = 'I'
33 | int32Marker byte = 'l'
34 | int64Marker byte = 'L'
35 | float32Marker byte = 'd'
36 | float64Marker byte = 'D'
37 | highPrecMarker byte = 'H'
38 | charMarker byte = 'C'
39 | stringMarker byte = 'S'
40 |
41 | objStartMarker byte = '{'
42 | objEndMarker byte = '}'
43 | arrStartMarker byte = '['
44 | arrEndMarker byte = ']'
45 |
46 | countMarker byte = '#'
47 | typeMarker byte = '$'
48 | )
49 |
50 | func str2Bytes(s string) []byte {
51 | return unsafe.Str2Bytes(s)
52 | }
53 |
54 | func bytes2Str(b []byte) string {
55 | return unsafe.Bytes2Str(b)
56 | }
57 |
--------------------------------------------------------------------------------
/ubjson/stack.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package ubjson
19 |
20 | type stateStack struct {
21 | stack []state // state stack for nested arrays/objects
22 | stack0 [32]state
23 | current state
24 | }
25 |
26 | type lengthStack struct {
27 | stack []int64
28 | stack0 [32]int64
29 | current int64
30 | }
31 |
32 | func (s *stateStack) push(next state) {
33 | if s.current.stateType != stFail {
34 | s.stack = append(s.stack, s.current)
35 | }
36 | s.current = next
37 | }
38 |
39 | func (s *stateStack) pop() {
40 | if len(s.stack) == 0 {
41 | s.current = state{stFail, stStart}
42 | } else {
43 | last := len(s.stack) - 1
44 | s.current = s.stack[last]
45 | s.stack = s.stack[:last]
46 | }
47 | }
48 |
49 | func (s *lengthStack) push(l int64) {
50 | s.stack = append(s.stack, s.current)
51 | s.current = l
52 | }
53 |
54 | func (s *lengthStack) pop() int64 {
55 | if len(s.stack) == 0 {
56 | s.current = -1
57 | return -1
58 | } else {
59 | last := len(s.stack) - 1
60 | old := s.current
61 | s.current = s.stack[last]
62 | s.stack = s.stack[:last]
63 | return old
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/ubjson/statestep_string.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | // Code generated by "stringer -type=stateStep"; DO NOT EDIT.
19 |
20 | package ubjson
21 |
22 | import "strconv"
23 |
24 | const _stateStep_name = "stStartstNilstNoopstTruestFalsestInt8stUInt8stInt16stInt32stInt64stFloat32stFloat64stCharstWithLenstWithType0stWithType1stContstFieldNamestFieldNameLen"
25 |
26 | var _stateStep_index = [...]uint8{0, 7, 12, 18, 24, 31, 37, 44, 51, 58, 65, 74, 83, 89, 98, 109, 120, 126, 137, 151}
27 |
28 | func (i stateStep) String() string {
29 | if i >= stateStep(len(_stateStep_index)-1) {
30 | return "stateStep(" + strconv.FormatInt(int64(i), 10) + ")"
31 | }
32 | return _stateStep_name[_stateStep_index[i]:_stateStep_index[i+1]]
33 | }
34 |
--------------------------------------------------------------------------------
/ubjson/statetype_string.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | // Code generated by "stringer -type=stateType"; DO NOT EDIT.
19 |
20 | package ubjson
21 |
22 | import "strconv"
23 |
24 | const _stateType_name = "stFailstNextstFixedstHighPrecstStringstArraystArrayDynstArrayCountstArrayTypedstObjectstObjectDynstObjectCountstObjectTyped"
25 |
26 | var _stateType_index = [...]uint8{0, 6, 12, 19, 29, 37, 44, 54, 66, 78, 86, 97, 110, 123}
27 |
28 | func (i stateType) String() string {
29 | if i >= stateType(len(_stateType_index)-1) {
30 | return "stateType(" + strconv.FormatInt(int64(i), 10) + ")"
31 | }
32 | return _stateType_name[_stateType_index[i]:_stateType_index[i+1]]
33 | }
34 |
--------------------------------------------------------------------------------
/ubjson/ubjson_test.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package ubjson
19 |
20 | import (
21 | "bytes"
22 | "io"
23 | "testing"
24 |
25 | "github.com/elastic/go-structform"
26 | "github.com/elastic/go-structform/sftest"
27 | )
28 |
29 | func TestEncParseConsistent(t *testing.T) {
30 | testEncParseConsistent(t, Parse)
31 | }
32 |
33 | func TestEncDecoderConsistent(t *testing.T) {
34 | testEncParseConsistent(t, func(content []byte, to structform.Visitor) error {
35 | dec := NewBytesDecoder(content, to)
36 | err := dec.Next()
37 | if err == io.EOF {
38 | err = nil
39 | }
40 | return err
41 | })
42 | }
43 |
44 | func TestEncParseBytesConsistent(t *testing.T) {
45 | testEncParseConsistent(t, func(content []byte, to structform.Visitor) error {
46 | p := NewParser(to)
47 | for _, b := range content {
48 | err := p.feed([]byte{b})
49 | if err != nil {
50 | return err
51 | }
52 | }
53 | return p.finalize()
54 | })
55 | }
56 |
57 | func testEncParseConsistent(
58 | t *testing.T,
59 | parse func([]byte, structform.Visitor) error,
60 | ) {
61 | sftest.TestEncodeParseConsistent(t, sftest.Samples,
62 | func() (structform.Visitor, func(structform.Visitor) error) {
63 | buf := bytes.NewBuffer(nil)
64 | vs := NewVisitor(buf)
65 |
66 | return vs, func(to structform.Visitor) error {
67 | return parse(buf.Bytes(), to)
68 | }
69 | })
70 | }
71 |
--------------------------------------------------------------------------------
/visitor.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package structform
19 |
20 | // Visitor interface for accepting events. The Vistor defined the common Data
21 | // Model all serializers should accept and all deserializers must implement.
22 | type Visitor interface {
23 | ObjectVisitor
24 | ArrayVisitor
25 | ValueVisitor
26 | }
27 |
28 | // ExtVisitor interface defines the Extended Data Model. Usage and
29 | // implementation of the Extended Data Model is optional, but can speed up
30 | // operations.
31 | type ExtVisitor interface {
32 | Visitor
33 | ArrayValueVisitor
34 | ObjectValueVisitor
35 | StringRefVisitor
36 | }
37 |
38 | //go:generate stringer -type=BaseType
39 | type BaseType uint8
40 |
41 | const (
42 | AnyType BaseType = iota
43 | ByteType
44 | StringType
45 | BoolType
46 | ZeroType
47 | IntType
48 | Int8Type
49 | Int16Type
50 | Int32Type
51 | Int64Type
52 | UintType
53 | Uint8Type
54 | Uint16Type
55 | Uint32Type
56 | Uint64Type
57 | Float32Type
58 | Float64Type
59 | )
60 |
61 | // ObjectVisitor iterates all fields in a dictionary like structure.
62 | type ObjectVisitor interface {
63 | // OnObjectStart is called when a new object (key-value pairs) is going to be reported.
64 | // A call to OnKey or OnObjectFinished must follow directly.
65 | OnObjectStart(len int, baseType BaseType) error
66 |
67 | // OnArrayFinished indicates that there are no more key value pairs to report.
68 | OnObjectFinished() error
69 |
70 | // OnKey adds a new key to the object. A value must directly follow a call to OnKey.
71 | OnKey(s string) error
72 | }
73 |
74 | // ArrayVisitor defines the support for arrays/slices in the Data Model.
75 | type ArrayVisitor interface {
76 | // OnArrayStart is called whan a new array is going to be reported.
77 | //
78 | // The `len` argument should report the length if known. `len` MUST BE -1 if
79 | // the length of the array is not known. The BaseType should indicate the
80 | // element type of the array. If the element type is unknown or can be any
81 | // type (e.g. interface{}), AnyType must be used.
82 | OnArrayStart(len int, baseType BaseType) error
83 |
84 | // OnArrayFinished indicates that there are no more elements in the array.
85 | OnArrayFinished() error
86 | }
87 |
88 | // ValueVisitor defines the set of supported primitive types in the Data Model.
89 | type ValueVisitor interface {
90 | // untyped nil value
91 | OnNil() error
92 |
93 | OnBool(b bool) error
94 |
95 | OnString(s string) error
96 |
97 | // int
98 | OnInt8(i int8) error
99 | OnInt16(i int16) error
100 | OnInt32(i int32) error
101 | OnInt64(i int64) error
102 | OnInt(i int) error
103 |
104 | // uint
105 | OnByte(b byte) error
106 | OnUint8(u uint8) error
107 | OnUint16(u uint16) error
108 | OnUint32(u uint32) error
109 | OnUint64(u uint64) error
110 | OnUint(u uint) error
111 |
112 | // float
113 | OnFloat32(f float32) error
114 | OnFloat64(f float64) error
115 | }
116 |
117 | // ArrayValueVisitor passes arrays with known type. Implementation
118 | // of ArrayValueVisitor is optional.
119 | type ArrayValueVisitor interface {
120 | OnBoolArray([]bool) error
121 |
122 | OnStringArray([]string) error
123 |
124 | // int
125 | OnInt8Array([]int8) error
126 | OnInt16Array([]int16) error
127 | OnInt32Array([]int32) error
128 | OnInt64Array([]int64) error
129 | OnIntArray([]int) error
130 |
131 | // uint
132 | OnBytes([]byte) error
133 | OnUint8Array([]uint8) error
134 | OnUint16Array([]uint16) error
135 | OnUint32Array([]uint32) error
136 | OnUint64Array([]uint64) error
137 | OnUintArray([]uint) error
138 |
139 | // float
140 | OnFloat32Array([]float32) error
141 | OnFloat64Array([]float64) error
142 | }
143 |
144 | // ObjectValueVisitor passes map[string]T. Implementation
145 | // of ObjectValueVisitor is optional.
146 | type ObjectValueVisitor interface {
147 | OnBoolObject(map[string]bool) error
148 |
149 | OnStringObject(map[string]string) error
150 |
151 | // int
152 | OnInt8Object(map[string]int8) error
153 | OnInt16Object(map[string]int16) error
154 | OnInt32Object(map[string]int32) error
155 | OnInt64Object(map[string]int64) error
156 | OnIntObject(map[string]int) error
157 |
158 | // uint
159 | OnUint8Object(map[string]uint8) error
160 | OnUint16Object(map[string]uint16) error
161 | OnUint32Object(map[string]uint32) error
162 | OnUint64Object(map[string]uint64) error
163 | OnUintObject(map[string]uint) error
164 |
165 | // float
166 | OnFloat32Object(map[string]float32) error
167 | OnFloat64Object(map[string]float64) error
168 | }
169 |
170 | // StringRefVisitor handles strings by reference into a byte string.
171 | // The reference must be processed immediately, as the string passed
172 | // might get modified after the callback returns.
173 | type StringRefVisitor interface {
174 | OnStringRef(s []byte) error
175 | OnKeyRef(s []byte) error
176 | }
177 |
178 | type extVisitor struct {
179 | Visitor
180 | ObjectValueVisitor
181 | ArrayValueVisitor
182 | StringRefVisitor
183 | }
184 |
185 | // EnsureExtVisitor converts a Visitor into an ExtVisitor. If v already
186 | // implements ExtVisitor, it is directly implemented. If v only implements a
187 | // subset of ExtVisitor, then conversions for the missing interfaces will be
188 | // created.
189 | func EnsureExtVisitor(v Visitor) ExtVisitor {
190 | if ev, ok := v.(ExtVisitor); ok {
191 | return ev
192 | }
193 |
194 | e := &extVisitor{
195 | Visitor: v,
196 | }
197 | if ov, ok := v.(ObjectValueVisitor); ok {
198 | e.ObjectValueVisitor = ov
199 | } else {
200 | e.ObjectValueVisitor = extObjVisitor{v}
201 | }
202 | if av, ok := v.(ArrayValueVisitor); ok {
203 | e.ArrayValueVisitor = av
204 | } else {
205 | e.ArrayValueVisitor = extArrVisitor{v}
206 | }
207 | e.StringRefVisitor = MakeStringRefVisitor(v)
208 |
209 | return e
210 | }
211 |
--------------------------------------------------------------------------------
/visitors/expect_obj.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package visitors
19 |
20 | import (
21 | "errors"
22 |
23 | structform "github.com/elastic/go-structform"
24 | )
25 |
26 | type ExpectObjVisitor struct {
27 | active structform.ExtVisitor
28 | depth int
29 | }
30 |
31 | func NewExpectObjVisitor(target structform.ExtVisitor) *ExpectObjVisitor {
32 | return &ExpectObjVisitor{active: target}
33 | }
34 |
35 | func (e *ExpectObjVisitor) SetActive(a structform.ExtVisitor) {
36 | e.active = a
37 | e.depth = 0
38 | }
39 |
40 | func (e *ExpectObjVisitor) Done() bool {
41 | return e.depth == 0
42 | }
43 |
44 | func (v *ExpectObjVisitor) OnObjectStart(len int, baseType structform.BaseType) error {
45 | v.depth++
46 | if v.depth == 1 {
47 | return nil
48 | }
49 | return v.active.OnObjectStart(len, baseType)
50 | }
51 |
52 | func (v *ExpectObjVisitor) OnObjectFinished() error {
53 | v.depth--
54 | if v.depth == 0 {
55 | return nil
56 | }
57 | return v.active.OnObjectFinished()
58 | }
59 |
60 | func (v *ExpectObjVisitor) OnKey(s string) error {
61 | if err := v.check(); err != nil {
62 | return err
63 | }
64 | return v.active.OnKey(s)
65 | }
66 |
67 | func (v *ExpectObjVisitor) OnArrayStart(len int, baseType structform.BaseType) error {
68 | if err := v.check(); err != nil {
69 | return err
70 | }
71 | return v.active.OnArrayStart(len, baseType)
72 | }
73 |
74 | func (v *ExpectObjVisitor) OnArrayFinished() error {
75 | if err := v.check(); err != nil {
76 | return err
77 | }
78 | return v.active.OnArrayFinished()
79 | }
80 |
81 | func (v *ExpectObjVisitor) OnNil() error {
82 | if err := v.check(); err != nil {
83 | return err
84 | }
85 | return v.active.OnNil()
86 | }
87 |
88 | func (v *ExpectObjVisitor) OnBool(b bool) error {
89 | if err := v.check(); err != nil {
90 | return err
91 | }
92 | return v.active.OnBool(b)
93 | }
94 |
95 | func (v *ExpectObjVisitor) OnString(s string) error {
96 | if err := v.check(); err != nil {
97 | return err
98 | }
99 | return v.active.OnString(s)
100 | }
101 |
102 | func (v *ExpectObjVisitor) OnInt8(i int8) error {
103 | if err := v.check(); err != nil {
104 | return err
105 | }
106 | return v.active.OnInt8(i)
107 | }
108 |
109 | func (v *ExpectObjVisitor) OnInt16(i int16) error {
110 | if err := v.check(); err != nil {
111 | return err
112 | }
113 | return v.active.OnInt16(i)
114 | }
115 |
116 | func (v *ExpectObjVisitor) OnInt32(i int32) error {
117 | if err := v.check(); err != nil {
118 | return err
119 | }
120 | return v.active.OnInt32(i)
121 | }
122 |
123 | func (v *ExpectObjVisitor) OnInt64(i int64) error {
124 | if err := v.check(); err != nil {
125 | return err
126 | }
127 | return v.active.OnInt64(i)
128 | }
129 |
130 | func (v *ExpectObjVisitor) OnInt(i int) error {
131 | if err := v.check(); err != nil {
132 | return err
133 | }
134 | return v.active.OnInt(i)
135 | }
136 |
137 | func (v *ExpectObjVisitor) OnByte(b byte) error {
138 | if err := v.check(); err != nil {
139 | return err
140 | }
141 | return v.active.OnByte(b)
142 | }
143 |
144 | func (v *ExpectObjVisitor) OnUint8(u uint8) error {
145 | if err := v.check(); err != nil {
146 | return err
147 | }
148 | return v.active.OnUint8(u)
149 | }
150 |
151 | func (v *ExpectObjVisitor) OnUint16(u uint16) error {
152 | if err := v.check(); err != nil {
153 | return err
154 | }
155 | return v.active.OnUint16(u)
156 | }
157 |
158 | func (v *ExpectObjVisitor) OnUint32(u uint32) error {
159 | if err := v.check(); err != nil {
160 | return err
161 | }
162 | return v.active.OnUint32(u)
163 | }
164 |
165 | func (v *ExpectObjVisitor) OnUint64(u uint64) error {
166 | if err := v.check(); err != nil {
167 | return err
168 | }
169 | return v.active.OnUint64(u)
170 | }
171 |
172 | func (v *ExpectObjVisitor) OnUint(u uint) error {
173 | if err := v.check(); err != nil {
174 | return err
175 | }
176 | return v.active.OnUint(u)
177 | }
178 |
179 | func (v *ExpectObjVisitor) OnFloat32(f float32) error {
180 | if err := v.check(); err != nil {
181 | return err
182 | }
183 | return v.active.OnFloat32(f)
184 | }
185 |
186 | func (v *ExpectObjVisitor) OnFloat64(f float64) error {
187 | if err := v.check(); err != nil {
188 | return err
189 | }
190 | return v.active.OnFloat64(f)
191 | }
192 |
193 | func (v *ExpectObjVisitor) OnStringRef(s []byte) error {
194 | if err := v.check(); err != nil {
195 | return err
196 | }
197 | return v.active.OnStringRef(s)
198 | }
199 |
200 | func (v *ExpectObjVisitor) OnKeyRef(s []byte) error {
201 | if err := v.check(); err != nil {
202 | return err
203 | }
204 | return v.active.OnKeyRef(s)
205 | }
206 |
207 | func (v *ExpectObjVisitor) check() error {
208 | if v.depth == 0 {
209 | return errors.New("inline object is no object")
210 | }
211 | return nil
212 | }
213 |
--------------------------------------------------------------------------------
/visitors/nilVisitor.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package visitors
19 |
20 | import structform "github.com/elastic/go-structform"
21 |
22 | type emptyVisitor struct {
23 | }
24 |
25 | func NilVisitor() structform.Visitor {
26 | return (*emptyVisitor)(nil)
27 | }
28 |
29 | func (e *emptyVisitor) OnObjectStart(len int, baseType structform.BaseType) error {
30 | return nil
31 | }
32 |
33 | func (e *emptyVisitor) OnObjectFinished() error {
34 | return nil
35 | }
36 |
37 | func (e *emptyVisitor) OnKey(s string) error {
38 | return nil
39 | }
40 |
41 | func (e *emptyVisitor) OnArrayStart(len int, baseType structform.BaseType) error {
42 | return nil
43 | }
44 |
45 | func (e *emptyVisitor) OnArrayFinished() error {
46 | return nil
47 | }
48 |
49 | func (e *emptyVisitor) OnNil() error {
50 | return nil
51 | }
52 |
53 | func (e *emptyVisitor) OnBool(b bool) error {
54 | return nil
55 | }
56 |
57 | func (e *emptyVisitor) OnString(s string) error {
58 | return nil
59 | }
60 |
61 | func (e *emptyVisitor) OnInt8(i int8) error {
62 | return nil
63 | }
64 |
65 | func (e *emptyVisitor) OnInt16(i int16) error {
66 | return nil
67 | }
68 |
69 | func (e *emptyVisitor) OnInt32(i int32) error {
70 | return nil
71 | }
72 |
73 | func (e *emptyVisitor) OnInt64(i int64) error {
74 | return nil
75 | }
76 |
77 | func (e *emptyVisitor) OnInt(i int) error {
78 | return nil
79 | }
80 |
81 | func (e *emptyVisitor) OnByte(b byte) error {
82 | return nil
83 | }
84 |
85 | func (e *emptyVisitor) OnUint8(u uint8) error {
86 | return nil
87 | }
88 |
89 | func (e *emptyVisitor) OnUint16(u uint16) error {
90 | return nil
91 | }
92 |
93 | func (e *emptyVisitor) OnUint32(u uint32) error {
94 | return nil
95 | }
96 |
97 | func (e *emptyVisitor) OnUint64(u uint64) error {
98 | return nil
99 | }
100 |
101 | func (e *emptyVisitor) OnUint(u uint) error {
102 | return nil
103 | }
104 |
105 | func (e *emptyVisitor) OnFloat32(f float32) error {
106 | return nil
107 | }
108 |
109 | func (e *emptyVisitor) OnFloat64(f float64) error {
110 | return nil
111 | }
112 |
113 | func (e *emptyVisitor) OnBoolArray([]bool) error {
114 | return nil
115 | }
116 |
117 | func (e *emptyVisitor) OnStringArray([]string) error {
118 | return nil
119 | }
120 |
121 | func (e *emptyVisitor) OnInt8Array([]int8) error {
122 | return nil
123 | }
124 |
125 | func (e *emptyVisitor) OnInt16Array([]int16) error {
126 | return nil
127 | }
128 |
129 | func (e *emptyVisitor) OnInt32Array([]int32) error {
130 | return nil
131 | }
132 |
133 | func (e *emptyVisitor) OnInt64Array([]int64) error {
134 | return nil
135 | }
136 |
137 | func (e *emptyVisitor) OnIntArray([]int) error {
138 | return nil
139 | }
140 |
141 | func (e *emptyVisitor) OnBytes([]byte) error {
142 | return nil
143 | }
144 |
145 | func (e *emptyVisitor) OnUint8Array([]uint8) error {
146 | return nil
147 | }
148 |
149 | func (e *emptyVisitor) OnUint16Array([]uint16) error {
150 | return nil
151 | }
152 |
153 | func (e *emptyVisitor) OnUint32Array([]uint32) error {
154 | return nil
155 | }
156 |
157 | func (e *emptyVisitor) OnUint64Array([]uint64) error {
158 | return nil
159 | }
160 |
161 | func (e *emptyVisitor) OnUintArray([]uint) error {
162 | return nil
163 | }
164 |
165 | func (e *emptyVisitor) OnFloat32Array([]float32) error {
166 | return nil
167 | }
168 |
169 | func (e *emptyVisitor) OnFloat64Array([]float64) error {
170 | return nil
171 | }
172 |
173 | func (e *emptyVisitor) OnBoolObject(map[string]bool) error {
174 | return nil
175 | }
176 |
177 | func (e *emptyVisitor) OnStringObject(map[string]string) error {
178 | return nil
179 | }
180 |
181 | func (e *emptyVisitor) OnInt8Object(map[string]int8) error {
182 | return nil
183 | }
184 |
185 | func (e *emptyVisitor) OnInt16Object(map[string]int16) error {
186 | return nil
187 | }
188 |
189 | func (e *emptyVisitor) OnInt32Object(map[string]int32) error {
190 | return nil
191 | }
192 |
193 | func (e *emptyVisitor) OnInt64Object(map[string]int64) error {
194 | return nil
195 | }
196 |
197 | func (e *emptyVisitor) OnIntObject(map[string]int) error {
198 | return nil
199 | }
200 |
201 | func (e *emptyVisitor) OnUint8Object(map[string]uint8) error {
202 | return nil
203 | }
204 |
205 | func (e *emptyVisitor) OnUint16Object(map[string]uint16) error {
206 | return nil
207 | }
208 |
209 | func (e *emptyVisitor) OnUint32Object(map[string]uint32) error {
210 | return nil
211 | }
212 |
213 | func (e *emptyVisitor) OnUint64Object(map[string]uint64) error {
214 | return nil
215 | }
216 |
217 | func (e *emptyVisitor) OnUintObject(map[string]uint) error {
218 | return nil
219 | }
220 |
221 | func (e *emptyVisitor) OnFloat32Object(map[string]float32) error {
222 | return nil
223 | }
224 |
225 | func (e *emptyVisitor) OnFloat64Object(map[string]float64) error {
226 | return nil
227 | }
228 |
229 | func (e *emptyVisitor) OnStringRef(s []byte) error {
230 | return nil
231 | }
232 |
233 | func (e *emptyVisitor) OnKeyRef(s []byte) error {
234 | return nil
235 | }
236 |
--------------------------------------------------------------------------------
/visitors/stringer.go:
--------------------------------------------------------------------------------
1 | // Licensed to Elasticsearch B.V. under one or more contributor
2 | // license agreements. See the NOTICE file distributed with
3 | // this work for additional information regarding copyright
4 | // ownership. Elasticsearch B.V. licenses this file to you under
5 | // the Apache License, Version 2.0 (the "License"); you may
6 | // not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing,
12 | // software distributed under the License is distributed on an
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | // KIND, either express or implied. See the License for the
15 | // specific language governing permissions and limitations
16 | // under the License.
17 |
18 | package visitors
19 |
20 | import (
21 | "fmt"
22 |
23 | structform "github.com/elastic/go-structform"
24 | )
25 |
26 | type StringConvVisitor struct {
27 | active structform.ExtVisitor
28 | }
29 |
30 | func NewStringConvVisitor(target structform.ExtVisitor) *StringConvVisitor {
31 | return &StringConvVisitor{target}
32 | }
33 |
34 | func (v *StringConvVisitor) SetActive(a structform.ExtVisitor) {
35 | v.active = a
36 | }
37 |
38 | func (v *StringConvVisitor) OnObjectStart(l int, t structform.BaseType) error {
39 | return v.active.OnObjectStart(l, t)
40 | }
41 |
42 | func (v *StringConvVisitor) OnObjectFinished() error {
43 | return v.active.OnObjectFinished()
44 | }
45 |
46 | func (v *StringConvVisitor) OnKey(s string) error {
47 | return v.active.OnKey(s)
48 | }
49 |
50 | func (v *StringConvVisitor) OnKeyRef(s []byte) error {
51 | return v.active.OnKeyRef(s)
52 | }
53 |
54 | func (v *StringConvVisitor) OnArrayStart(l int, t structform.BaseType) error {
55 | return v.active.OnArrayStart(l, t)
56 | }
57 |
58 | func (v *StringConvVisitor) OnArrayFinished() error {
59 | return v.active.OnArrayFinished()
60 | }
61 |
62 | func (v *StringConvVisitor) OnNil() error {
63 | return v.OnString("")
64 | }
65 |
66 | func (v *StringConvVisitor) OnBool(b bool) error {
67 | t := "false"
68 | if b {
69 | t = "true"
70 | }
71 | return v.OnString(t)
72 | }
73 |
74 | func (v *StringConvVisitor) OnString(s string) error {
75 | return v.active.OnString(s)
76 | }
77 |
78 | func (v *StringConvVisitor) OnStringRef(b []byte) error {
79 | return v.active.OnStringRef(b)
80 | }
81 |
82 | func (v *StringConvVisitor) OnInt8(i int8) error {
83 | return v.OnInt64(int64(i))
84 | }
85 |
86 | func (v *StringConvVisitor) OnInt16(i int16) error {
87 | return v.OnInt64(int64(i))
88 | }
89 |
90 | func (v *StringConvVisitor) OnInt32(i int32) error {
91 | return v.OnInt64(int64(i))
92 | }
93 |
94 | func (v *StringConvVisitor) OnInt64(i int64) error {
95 | return v.OnString(fmt.Sprintf("%v", i))
96 | }
97 |
98 | func (v *StringConvVisitor) OnInt(i int) error {
99 | return v.OnInt64(int64(i))
100 | }
101 |
102 | func (v *StringConvVisitor) OnUint8(i uint8) error {
103 | return v.OnUint64(uint64(i))
104 | }
105 |
106 | func (v *StringConvVisitor) OnUint16(i uint16) error {
107 | return v.OnUint64(uint64(i))
108 | }
109 |
110 | func (v *StringConvVisitor) OnUint32(i uint32) error {
111 | return v.OnUint64(uint64(i))
112 | }
113 |
114 | func (v *StringConvVisitor) OnUint64(i uint64) error {
115 | return v.OnString(fmt.Sprintf("%v", i))
116 | }
117 |
118 | func (v *StringConvVisitor) OnUint(i uint) error {
119 | return v.OnUint64(uint64(i))
120 | }
121 |
122 | func (v *StringConvVisitor) OnFloat32(f float32) error {
123 | return v.OnString(fmt.Sprintf("%v", f))
124 | }
125 |
126 | func (v *StringConvVisitor) OnFloat64(f float64) error {
127 | return v.OnString(fmt.Sprintf("%v", f))
128 | }
129 |
--------------------------------------------------------------------------------