diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml new file mode 100644 index 0000000000000000000000000000000000000000..32bcc2e6e571121eee3c966f2f31bb86c5430e93 --- /dev/null +++ b/.github/workflows/automerge.yml @@ -0,0 +1,51 @@ +# File managed by web3-bot. DO NOT EDIT. +# See https://github.com/protocol/.github/ for details. + +# Automatically merge pull requests opened by web3-bot, as soon as (and only if) all tests pass. +# This reduces the friction associated with updating with our workflows. + +on: [ pull_request ] +name: Automerge + +jobs: + automerge-check: + if: github.event.pull_request.user.login == 'web3-bot' + runs-on: ubuntu-latest + outputs: + status: ${{ steps.should-automerge.outputs.status }} + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Check if we should automerge + id: should-automerge + run: | + for commit in $(git rev-list --first-parent origin/${{ github.event.pull_request.base.ref }}..${{ github.event.pull_request.head.sha }}); do + committer=$(git show --format=$'%ce' -s $commit) + echo "Committer: $committer" + if [[ "$committer" != "web3-bot@users.noreply.github.com" ]]; then + echo "Commit $commit wasn't committed by web3-bot, but by $committer." + echo "::set-output name=status::false" + exit + fi + done + echo "::set-output name=status::true" + automerge: + needs: automerge-check + runs-on: ubuntu-latest + if: ${{ needs.automerge-check.outputs.status == 'true' }} + steps: + - name: Wait on tests + uses: lewagon/wait-on-check-action@bafe56a6863672c681c3cf671f5e10b20abf2eaa # v0.2 + with: + ref: ${{ github.event.pull_request.head.sha }} + repo-token: ${{ secrets.GITHUB_TOKEN }} + wait-interval: 10 + running-workflow-name: 'automerge' # the name of this job + - name: Merge PR + uses: pascalgn/automerge-action@741c311a47881be9625932b0a0de1b0937aab1ae # v0.13.1 + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + MERGE_LABELS: "" + MERGE_METHOD: "squash" + MERGE_DELETE_BRANCH: true diff --git a/.github/workflows/go-check.yml b/.github/workflows/go-check.yml new file mode 100644 index 0000000000000000000000000000000000000000..00ce947c82a56a488b0fc018e4a7dbf2fad2e95e --- /dev/null +++ b/.github/workflows/go-check.yml @@ -0,0 +1,50 @@ +# File managed by web3-bot. DO NOT EDIT. +# See https://github.com/protocol/.github/ for details. + +on: [push, pull_request] +name: Go Checks + +jobs: + unit: + runs-on: ubuntu-latest + name: All + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - uses: actions/setup-go@v2 + with: + go-version: "1.16.x" + - name: Install staticcheck + run: go install honnef.co/go/tools/cmd/staticcheck@434f5f3816b358fe468fa83dcba62d794e7fe04b # 2021.1 (v0.2.0) + - name: Check that go.mod is tidy + uses: protocol/multiple-go-modules@v1.0 + with: + run: | + go mod tidy + if [[ -n $(git ls-files --other --exclude-standard --directory -- go.sum) ]]; then + echo "go.sum was added by go mod tidy" + exit 1 + fi + git diff --exit-code -- go.sum go.mod + - name: gofmt + if: ${{ success() || failure() }} # run this step even if the previous one failed + run: | + out=$(gofmt -s -l .) + if [[ -n "$out" ]]; then + echo $out | awk '{print "::error file=" $0 ",line=0,col=0::File is not gofmt-ed."}' + exit 1 + fi + - name: go vet + if: ${{ success() || failure() }} # run this step even if the previous one failed + uses: protocol/multiple-go-modules@v1.0 + with: + run: go vet ./... + - name: staticcheck + if: ${{ success() || failure() }} # run this step even if the previous one failed + uses: protocol/multiple-go-modules@v1.0 + with: + run: | + set -o pipefail + staticcheck ./... | sed -e 's@\(.*\)\.go@./\1.go@g' + diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml new file mode 100644 index 0000000000000000000000000000000000000000..4c7138b01d0c904d152e351b15e45ff2a413174d --- /dev/null +++ b/.github/workflows/go-test.yml @@ -0,0 +1,47 @@ +# File managed by web3-bot. DO NOT EDIT. +# See https://github.com/protocol/.github/ for details. + +on: [push, pull_request] +name: Go Test + +jobs: + unit: + strategy: + fail-fast: false + matrix: + os: [ "ubuntu", "windows", "macos" ] + go: [ "1.15.x", "1.16.x" ] + runs-on: ${{ matrix.os }}-latest + name: ${{ matrix.os}} (go ${{ matrix.go }}) + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go }} + - name: Go information + run: | + go version + go env + - name: Run tests + uses: protocol/multiple-go-modules@v1.0 + with: + run: go test -v -coverprofile coverage.txt ./... + - name: Run tests (32 bit) + if: ${{ matrix.os != 'macos' }} # can't run 32 bit tests on OSX. + uses: protocol/multiple-go-modules@v1.0 + env: + GOARCH: 386 + with: + run: go test -v ./... + - name: Run tests with race detector + if: ${{ matrix.os == 'ubuntu' }} # speed things up. Windows and OSX VMs are slow + uses: protocol/multiple-go-modules@v1.0 + with: + run: go test -v -race ./... + - name: Upload coverage to Codecov + uses: codecov/codecov-action@a1ed4b322b4b38cb846afb5a0ebfa17086917d27 # v1.5.0 + with: + file: coverage.txt + env_vars: OS=${{ matrix.os }}, GO=${{ matrix.go }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..2d830686d42dea576f9194b0eb41b15df24cdcc1 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +coverage.out diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..dfab88961c90fd41f90c5ab42b03a552ca342c2d --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,35 @@ +stages: + - build + - test + +variables: + BUILD_DIR: "/tmp/$CI_CONCURRENT_PROJECT_ID" + +before_script: + - mkdir -p $BUILD_DIR/src + - cd $BUILD_DIR/src + - if [ -d $CI_PROJECT_DIR ] + - then + - echo "soft link $CI_PROJECT_DIR exists" + - else + - echo "creating soft link $CI_PROJECT_DIR" + - ln -s $CI_PROJECT_DIR + - fi + - cd $CI_PROJECT_DIR + +build: + stage: build + tags: + - testing + script: + - echo $CI_JOB_STAGE + - go build + +test: + stage: test + tags: + - testing + script: + - echo $CI_JOB_STAGE + - go test -cover + coverage: '/coverage: \d+.\d+% of statements/' diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000000000000000000000000000000000000..fcd6df33ca47bab508f162576ebe1641f900afb8 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,13 @@ +Copyright 2020 Protocol Labs + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000000000000000000000000000000000000..9bddb3e81a9d27bb20c43b3fd7f7e88aff96cf4a --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,7 @@ +Copyright 2020 Protocol Labs + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index ba3b9e1fc927630a943c516671ff5fe74b9e1040..19798bc91f0d95e590b379c5b7fcce19344bc29f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,35 @@ -# go-codec-dagpb +# go-dagpb -dms3 go-codec-dagpb \ No newline at end of file +**An implementation of the IPLD [DAG-PB](https://gitlab.dms3.io/ld/specs/blob/master/block-layer/codecs/dag-pb.md) spec for [go-ld-prime](https://gitlab.dms3.io/ld/go-ld-prime/)** + +Use `Decode(ld.NodeAssembler, io.Reader)` and `Encode(ld.Node, io.Writer)` directly, or import this package to have this codec registered into the go-ld-prime CID link loader. + +Nodes encoded with this codec _must_ conform to the DAG-PB spec. Specifically, they should have the non-optional fields shown in the DAG-PB schema: + +```ldsch +type PBNode struct { + Links [PBLink] + Data optional Bytes +} + +type PBLink struct { + Hash Link + Name optional String + Tsize optional Int +} +``` + +Use `dagpb.Type.PBNode` and friends directly for strictness guarantees. Basic `ld.Node`s will need to have the appropraite fields (and no others) to successfully encode using this codec. + +## License & Copyright + +Copyright © 2020 Protocol Labs + +Licensed under either of + + * Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / http://www.apache.org/licenses/LICENSE-2.0) + * MIT ([LICENSE-MIT](LICENSE-MIT) / http://opensource.org/licenses/MIT) + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/basics_test.go b/basics_test.go new file mode 100644 index 0000000000000000000000000000000000000000..8eb34f9aa2269e1ab5ec71faee8ae6a2f770cd32 --- /dev/null +++ b/basics_test.go @@ -0,0 +1,322 @@ +package dagpb + +import ( + "bytes" + "encoding/hex" + "testing" + + "gitlab.dms3.io/dms3/go-cid" + "gitlab.dms3.io/ld/go-ld-prime" + "gitlab.dms3.io/ld/go-ld-prime/fluent" + cidlink "gitlab.dms3.io/ld/go-ld-prime/linking/cid" + basicnode "gitlab.dms3.io/ld/go-ld-prime/node/basic" +) + +type pbNode struct { + links []pbLink + data []byte +} + +func mkcid(t *testing.T, cidStr string) cid.Cid { + c, err := cid.Decode(cidStr) + if err != nil { + t.Fatal(err) + } + return c +} + +func validate(t *testing.T, actual ld.Node, expected pbNode) { + mi := actual.MapIterator() + _, isTyped := actual.(*_PBNode) + + hasLinks := false + hasData := false + for !mi.Done() { + key, val, err := mi.Next() + if err != nil { + t.Fatal(err) + } + keyStr, err := key.AsString() + if err != nil { + t.Fatal(err) + } + if keyStr == "Links" { + if val.Kind() != ld.Kind_List { + t.Fatal("Links is not a list") + } + if val.IsAbsent() { + t.Fatal("Links is absent") + } + if val.IsNull() { + t.Fatal("Links is null") + } + if val.Length() != int64(len(expected.links)) { + t.Fatal("non-empty Links list") + } + hasLinks = true + } else if keyStr == "Data" { + if isTyped && expected.data == nil { + if !val.IsAbsent() { + t.Fatalf("Empty Data is not marked as absent") + } + if val.Kind() != ld.Kind_Null { + t.Fatal("Empty Data is not null") + } + if val.IsNull() { + t.Fatal("Empty Data is null") + } + } + hasData = !isTyped || !val.IsAbsent() + if hasData { + if expected.data == nil { + t.Fatal("Got unexpected Data") + } else { + byts, err := val.AsBytes() + if err != nil { + t.Fatal(err) + } else if !bytes.Equal(expected.data, byts) { + t.Fatal("Got unexpected Data contents") + } + } + } + } else { + t.Fatalf("Unexpected map key: %v", keyStr) + } + } + if !hasLinks { + t.Fatal("Did not find Links") + } + if expected.data != nil && !hasData { + t.Fatal("Did not find Data") + } +} + +func runTest(t *testing.T, bytsHex string, expected pbNode) { + byts, _ := hex.DecodeString(bytsHex) + + roundTrip := func(t *testing.T, node ld.Node) { + var buf bytes.Buffer + if err := Encode(node, &buf); err != nil { + t.Fatal(err) + } + + // fmt.Printf("CMP\n\tFrom: %v\n\tTo: %v\n", hex.EncodeToString(byts), hex.EncodeToString(buf.Bytes())) + if !bytes.Equal(buf.Bytes(), byts) { + t.Fatal("Round-trip resulted in different bytes") + } + } + + t.Run("basicnode", func(t *testing.T) { + nb := basicnode.Prototype__Map{}.NewBuilder() + err := Decode(nb, bytes.NewReader(byts)) + if err != nil { + t.Fatal(err) + } + + node := nb.Build() + validate(t, node, expected) + roundTrip(t, node) + }) + + t.Run("typed", func(t *testing.T) { + nb := Type.PBNode.NewBuilder() + err := Decode(nb, bytes.NewReader(byts)) + if err != nil { + t.Fatal(err) + } + node := nb.Build() + validate(t, node, expected) + roundTrip(t, node) + }) +} + +func TestEmptyNode(t *testing.T) { + runTest(t, "", pbNode{}) +} + +func TestNodeWithData(t *testing.T) { + runTest(t, "0a050001020304", pbNode{data: []byte{00, 01, 02, 03, 04}}) +} + +func TestNodeWithDataZero(t *testing.T) { + runTest(t, "0a00", pbNode{data: []byte{}}) +} + +func TestNodeWithLink(t *testing.T) { + expected := pbNode{} + expected.links = append(expected.links, pbLink{hash: mkcid(t, "QmWDtUQj38YLW8v3q4A6LwPn4vYKEbuKWpgSm6bjKW6Xfe")}) + runTest(t, "12240a2212207521fe19c374a97759226dc5c0c8e674e73950e81b211f7dd3b6b30883a08a51", expected) +} + +func TestNodeWithLinkAndData(t *testing.T) { + expected := pbNode{data: []byte("some data")} + expected.links = append(expected.links, pbLink{hash: mkcid(t, "QmWDtUQj38YLW8v3q4A6LwPn4vYKEbuKWpgSm6bjKW6Xfe")}) + runTest(t, "12240a2212207521fe19c374a97759226dc5c0c8e674e73950e81b211f7dd3b6b30883a08a510a09736f6d652064617461", expected) +} + +func TestNodeWithTwoUnsortedLinks(t *testing.T) { + encoded := "12340a2212208ab7a6c5e74737878ac73863cb76739d15d4666de44e5756bf55a2f9e9ab5f431209736f6d65206c696e6b1880c2d72f12370a2212208ab7a6c5e74737878ac73863cb76739d15d4666de44e5756bf55a2f9e9ab5f44120f736f6d65206f74686572206c696e6b18080a09736f6d652064617461" + expected := pbNode{data: []byte("some data")} + expected.links = append(expected.links, pbLink{name: "some link", hasName: true, hash: mkcid(t, "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39U"), tsize: 100000000, hasTsize: true}) + expected.links = append(expected.links, pbLink{name: "some other link", hasName: true, hash: mkcid(t, "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V"), tsize: 8, hasTsize: true}) + + runTest(t, encoded, expected) + + // assembled in a rough order, Data coming first, links badly sorted + node := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(fma fluent.MapAssembler) { + fma.AssembleEntry("Data").AssignBytes([]byte("some data")) + fma.AssembleEntry("Links").CreateList(2, func(fla fluent.ListAssembler) { + fla.AssembleValue().CreateMap(3, func(fma fluent.MapAssembler) { + fma.AssembleEntry("Name").AssignString("some other link") + fma.AssembleEntry("Tsize").AssignInt(8) + fma.AssembleEntry("Hash").AssignLink(cidlink.Link{Cid: mkcid(t, "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V")}) + }) + fla.AssembleValue().CreateMap(3, func(fma fluent.MapAssembler) { + fma.AssembleEntry("Name").AssignString("some link") + fma.AssembleEntry("Tsize").AssignInt(100000000) + fma.AssembleEntry("Hash").AssignLink(cidlink.Link{Cid: mkcid(t, "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39U")}) + }) + }) + }) + + var buf bytes.Buffer + if err := Encode(node, &buf); err != nil { + t.Fatal(err) + } + if hex.EncodeToString(buf.Bytes()) != encoded { + t.Fatal("did not encode to expected bytes") + } +} + +func TestNodeWithStableSortedLinks(t *testing.T) { + cids := []string{ + "QmUGhP2X8xo9dsj45vqx1H6i5WqPqLqmLQsHTTxd3ke8mp", + "QmP7SrR76KHK9A916RbHG1ufy2TzNABZgiE23PjZDMzZXy", + "QmQg1v4o9xdT3Q14wh4S7dxZkDjyZ9ssFzFzyep1YrVJBY", + "QmdP6fartWRrydZCUjHgrJ4XpxSE4SAoRsWJZ1zJ4MWiuf", + "QmNNjUStxtMC1WaSZYiDW6CmAUrvd5Q2e17qnxPgVdwrwW", + "QmWJwqZBJWerHsN1b7g4pRDYmzGNnaMYuD3KSbnpaxsB2h", + "QmRXPSdysBS3dbUXe6w8oXevZWHdPQWaR2d3fggNsjvieL", + "QmTUZAXfws6zrhEksnMqLxsbhXZBQs4FNiarjXSYQqVrjC", + "QmNNk7dTdh8UofwgqLNauq6N78DPc6LKK2yBs1MFdx7Mbg", + "QmW5mrJfyqh7B4ywSvraZgnWjS3q9CLiYURiJpCX3aro5i", + "QmTFHZL5CkgNz19MdPnSuyLAi6AVq9fFp81zmPpaL2amED", + } + + node := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(fma fluent.MapAssembler) { + fma.AssembleEntry("Data").AssignBytes([]byte("some data")) + fma.AssembleEntry("Links").CreateList(int64(len(cids)), func(fla fluent.ListAssembler) { + for _, cid := range cids { + fla.AssembleValue().CreateMap(3, func(fma fluent.MapAssembler) { + fma.AssembleEntry("Name").AssignString("") + fma.AssembleEntry("Tsize").AssignInt(262158) + fma.AssembleEntry("Hash").AssignLink(cidlink.Link{Cid: mkcid(t, cid)}) + }) + } + }) + }) + + var buf bytes.Buffer + if err := Encode(node, &buf); err != nil { + t.Fatal(err) + } + nb := basicnode.Prototype__Map{}.NewBuilder() + err := Decode(nb, bytes.NewReader(buf.Bytes())) + if err != nil { + t.Fatal(err) + } + reencNode := nb.Build() + links, _ := reencNode.LookupByString("Links") + if links.Length() != int64(len(cids)) { + t.Fatal("Incorrect number of links after round-trip") + } + iter := links.ListIterator() + for !iter.Done() { + ii, n, _ := iter.Next() + h, _ := n.LookupByString("Hash") + l, _ := h.AsLink() + cl, _ := l.(cidlink.Link) + if cids[ii] != cl.String() { + t.Fatal("CIDs did not retain position after round-trip") + } + } + + if hex.EncodeToString(buf.Bytes()) != "122a0a2212205822d187bd40b04cc8ae7437888ebf844efac1729e098c8816d585d0fcc42b5b1200188e8010122a0a2212200b79badee10dc3f7781a7a9d0f020cc0f710b328c4975c2dbc30a170cd188e2c1200188e8010122a0a22122022ad631c69ee983095b5b8acd029ff94aff1dc6c48837878589a92b90dfea3171200188e8010122a0a221220df7fd08c4784fe6938c640df473646e4f16c7d0c6567ab79ec6981767fc3f01a1200188e8010122a0a22122000888c815ad7d055377bdb7b7779fc9740e548cb5dac90c71b9af9f51a879c2d1200188e8010122a0a221220766db372d015c5c700f538336556370165c889334791487a5e48d6080f1c99ea1200188e8010122a0a2212202f533004ceed74279b32c58eb0e3d2a23bc27ba14ab07298406c42bab8d543211200188e8010122a0a2212204c50cfdefa0209766f885919ac8ffc258e9253c3001ac23814f875d414d394731200188e8010122a0a22122000894611dfa192853020cbbade1a9a0a3f359d26e0d38caf4d72b9b306ff5a0b1200188e8010122a0a221220730ddba83e3147bbe10780b97ff0718c74c36037b97b3b79b45c4511806545811200188e8010122a0a22122048ea9d5d423f678d83d559d2349be8325527290b070c90fc1acd968f0bf70a061200188e80100a09736f6d652064617461" { + t.Fatal("Encoded form did not match expected") + } +} + +func TestNodeWithUnnamedLinks(t *testing.T) { + dataByts, _ := hex.DecodeString("080218cbc1819201208080e015208080e015208080e015208080e015208080e015208080e01520cbc1c10f") + expected := pbNode{data: dataByts} + expected.links = []pbLink{ + {name: "", hasName: true, hash: mkcid(t, "QmSbCgdsX12C4KDw3PDmpBN9iCzS87a5DjgSCoW9esqzXk"), tsize: 45623854, hasTsize: true}, + {name: "", hasName: true, hash: mkcid(t, "Qma4GxWNhywSvWFzPKtEswPGqeZ9mLs2Kt76JuBq9g3fi2"), tsize: 45623854, hasTsize: true}, + {name: "", hasName: true, hash: mkcid(t, "QmQfyxyys7a1e3mpz9XsntSsTGc8VgpjPj5BF1a1CGdGNc"), tsize: 45623854, hasTsize: true}, + {name: "", hasName: true, hash: mkcid(t, "QmSh2wTTZT4N8fuSeCFw7wterzdqbE93j1XDhfN3vQHzDV"), tsize: 45623854, hasTsize: true}, + {name: "", hasName: true, hash: mkcid(t, "QmVXsSVjwxMsCwKRCUxEkGb4f4B98gXVy3ih3v4otvcURK"), tsize: 45623854, hasTsize: true}, + {name: "", hasName: true, hash: mkcid(t, "QmZjhH97MEYwQXzCqSQbdjGDhXWuwW4RyikR24pNqytWLj"), tsize: 45623854, hasTsize: true}, + {name: "", hasName: true, hash: mkcid(t, "QmRs6U5YirCqC7taTynz3x2GNaHJZ3jDvMVAzaiXppwmNJ"), tsize: 32538395, hasTsize: true}, + } + + runTest( + t, + "122b0a2212203f29086b59b9e046b362b4b19c9371e834a9f5a80597af83be6d8b7d1a5ad33b120018aed4e015122b0a221220ae1a5afd7c770507dddf17f92bba7a326974af8ae5277c198cf13206373f7263120018aed4e015122b0a22122022ab2ebf9c3523077bd6a171d516ea0e1be1beb132d853778bcc62cd208e77f1120018aed4e015122b0a22122040a77fe7bc69bbef2491f7633b7c462d0bce968868f88e2cbcaae9d0996997e8120018aed4e015122b0a2212206ae1979b14dd43966b0241ebe80ac2a04ad48959078dc5affa12860648356ef6120018aed4e015122b0a221220a957d1f89eb9a861593bfcd19e0637b5c957699417e2b7f23c88653a240836c4120018aed4e015122b0a221220345f9c2137a2cd76d7b876af4bfecd01f80b7dd125f375cb0d56f8a2f96de2c31200189bfec10f0a2b080218cbc1819201208080e015208080e015208080e015208080e015208080e015208080e01520cbc1c10f", + expected) +} + +func TestNodeWithNamedLinks(t *testing.T) { + dataByts, _ := hex.DecodeString("0801") + expected := pbNode{data: dataByts} + expected.links = []pbLink{ + {name: "audio_only.m4a", hasName: true, hash: mkcid(t, "QmaUAwAQJNtvUdJB42qNbTTgDpzPYD1qdsKNtctM5i7DGB"), tsize: 23319629, hasTsize: true}, + {name: "chat.txt", hasName: true, hash: mkcid(t, "QmNVrxbB25cKTRuKg2DuhUmBVEK9NmCwWEHtsHPV6YutHw"), tsize: 996, hasTsize: true}, + {name: "playback.m3u", hasName: true, hash: mkcid(t, "QmUcjKzDLXBPmB6BKHeKSh6ZoFZjss4XDhMRdLYRVuvVfu"), tsize: 116, hasTsize: true}, + {name: "zoom_0.mp4", hasName: true, hash: mkcid(t, "QmQqy2SiEkKgr2cw5UbQ93TtLKEMsD8TdcWggR8q9JabjX"), tsize: 306281879, hasTsize: true}, + } + + runTest( + t, + "12390a221220b4397c02da5513563d33eef894bf68f2ccdf1bdfc14a976956ab3d1c72f735a0120e617564696f5f6f6e6c792e6d346118cda88f0b12310a221220025c13fcd1a885df444f64a4a82a26aea867b1148c68cb671e83589f971149321208636861742e74787418e40712340a2212205d44a305b9b328ab80451d0daa72a12a7bf2763c5f8bbe327597a31ee40d1e48120c706c61796261636b2e6d3375187412360a2212202539ed6e85f2a6f9097db9d76cffd49bf3042eb2e3e8e9af4a3ce842d49dea22120a7a6f6f6d5f302e6d70341897fb8592010a020801", + expected) +} + +func TestNodeAlternativeOrder(t *testing.T) { + // This input has Data before Links. + input, err := hex.DecodeString("0a040802180612240a221220cf92fdefcdc34cac009c8b05eb662be0618db9de55ecd42785e9ec6712f8df6512240a221220cf92fdefcdc34cac009c8b05eb662be0618db9de55ecd42785e9ec6712f8df65") + if err != nil { + t.Fatal(err) + } + nb := Type.PBNode.NewBuilder() + if err := DecodeBytes(nb, input); err != nil { + t.Fatal(err) + } + node := nb.Build() + + // We don't really care what the node looks like, or what the exact + // re-encode bytes are. But we do care that it's not exactly the same, + // but still the same length. + output, err := AppendEncode(nil, node) + if err != nil { + t.Fatal(err) + } + if bytes.Equal(input, output) { + t.Fatal("re-encoding should use canonical PBNode field order") + } + if len(input) != len(output) { + t.Fatal("re-encoding should have the same number of bytes") + } +} + +func TestNodeWithDataBetweenLinks(t *testing.T) { + // This input has one Links element, then Data, then another Links element. + // As per the spec, this should fail as a duplicate Links field. + input, err := hex.DecodeString("12240a221220cf92fdefcdc34cac009c8b05eb662be0618db9de55ecd42785e9ec6712f8df650a040802180612240a221220cf92fdefcdc34cac009c8b05eb662be0618db9de55ecd42785e9ec6712f8df65") + if err != nil { + t.Fatal(err) + } + nb := Type.PBNode.NewBuilder() + if err := DecodeBytes(nb, input); err == nil { + t.Fatal("expected Decode to fail") + } +} diff --git a/compat_test.go b/compat_test.go new file mode 100644 index 0000000000000000000000000000000000000000..ab7918359e3d14d9e32e155c318dd0dc97c91685 --- /dev/null +++ b/compat_test.go @@ -0,0 +1,362 @@ +package dagpb + +// mirrored in JavaScript @ https://gitlab.dms3.io/ld/js-dag-pb/blob/master/test/test-compat.js + +import ( + "bytes" + "encoding/hex" + "encoding/json" + "strings" + "testing" + + cid "gitlab.dms3.io/dms3/go-cid" + "gitlab.dms3.io/ld/go-ld-prime" + "gitlab.dms3.io/ld/go-ld-prime/fluent" + cidlink "gitlab.dms3.io/ld/go-ld-prime/linking/cid" + basicnode "gitlab.dms3.io/ld/go-ld-prime/node/basic" +) + +var dataZero []byte = make([]byte, 0) +var dataSome []byte = []byte{0, 1, 2, 3, 4} +var acid cid.Cid = _mkcid() +var zeroName string = "" +var someName string = "some name" +var zeroTsize uint64 = 0 +var someTsize uint64 = 1010 +var largeTsize uint64 = 9007199254740991 // JavaScript Number.MAX_SAFE_INTEGER + +type testCase struct { + name string + node *pbNode + expectedBytes string + expectedForm string + encodeError string + decodeError string +} + +var testCases = []testCase{ + { + name: "empty", + node: &pbNode{}, + expectedBytes: "", + expectedForm: `{ + "Links": [] +}`, + encodeError: "missing required fields: Links", + }, + { + name: "Data zero", + node: &pbNode{data: dataZero}, + expectedBytes: "0a00", + expectedForm: `{ + "Data": "", + "Links": [] +}`, + encodeError: "missing required fields: Links", + }, + { + name: "Data some", + node: &pbNode{data: dataSome}, + expectedBytes: "0a050001020304", + expectedForm: `{ + "Data": "0001020304", + "Links": [] +}`, + encodeError: "missing required fields: Links", + }, + { + name: "Links zero", + node: &pbNode{links: []pbLink{}}, + expectedBytes: "", + expectedForm: `{ + "Links": [] +}`, + }, + { + name: "Data some Links zero", + node: &pbNode{data: dataSome, links: []pbLink{}}, + expectedBytes: "0a050001020304", + expectedForm: `{ + "Data": "0001020304", + "Links": [] +}`, + }, + { + name: "Links empty", + node: &pbNode{links: []pbLink{{}}}, + expectedBytes: "1200", + encodeError: "missing required fields: Hash", + decodeError: "expected CID", + }, + { + name: "Data some Links empty", + node: &pbNode{data: dataSome, links: []pbLink{{}}}, + expectedBytes: "12000a050001020304", + encodeError: "missing required fields: Hash", + decodeError: "expected CID", + }, + { + name: "Links Hash zero", + expectedBytes: "12020a00", + decodeError: "expected CID", // error should come up from go-cid too + }, + { + name: "Links Hash some", + node: &pbNode{links: []pbLink{{hash: acid}}}, + expectedBytes: "120b0a09015500050001020304", + expectedForm: `{ + "Links": [ + { + "Hash": "015500050001020304" + } + ] +}`, + }, + { + name: "Links Name zero", + node: &pbNode{links: []pbLink{{name: zeroName, hasName: true}}}, + expectedBytes: "12021200", + encodeError: "missing required fields: Hash", + decodeError: "expected CID", + }, + { + name: "Links Hash some Name zero", + node: &pbNode{links: []pbLink{{hash: acid, name: zeroName, hasName: true}}}, + expectedBytes: "120d0a090155000500010203041200", + expectedForm: `{ + "Links": [ + { + "Hash": "015500050001020304", + "Name": "" + } + ] +}`, + }, + { + name: "Links Name some", + node: &pbNode{links: []pbLink{{name: someName, hasName: true}}}, + expectedBytes: "120b1209736f6d65206e616d65", + encodeError: "missing required fields: Hash", + decodeError: "expected CID", + }, + { + name: "Links Hash some Name some", + node: &pbNode{links: []pbLink{{hash: acid, name: someName, hasName: true}}}, + expectedBytes: "12160a090155000500010203041209736f6d65206e616d65", + expectedForm: `{ + "Links": [ + { + "Hash": "015500050001020304", + "Name": "some name" + } + ] +}`, + }, + { + name: "Links Tsize zero", + node: &pbNode{links: []pbLink{{tsize: zeroTsize, hasTsize: true}}}, + expectedBytes: "12021800", + encodeError: "missing required fields: Hash", + decodeError: "expected CID", + }, + { + name: "Links Hash some Tsize zero", + node: &pbNode{links: []pbLink{{hash: acid, tsize: zeroTsize, hasTsize: true}}}, + expectedBytes: "120d0a090155000500010203041800", + expectedForm: `{ + "Links": [ + { + "Hash": "015500050001020304", + "Tsize": 0 + } + ] +}`, + }, + { + name: "Links Tsize some", + node: &pbNode{links: []pbLink{{tsize: someTsize, hasTsize: true}}}, + expectedBytes: "120318f207", + encodeError: "missing required fields: Hash", + decodeError: "expected CID", + }, + { + name: "Links Hash some Tsize some", + node: &pbNode{links: []pbLink{{hash: acid, tsize: largeTsize, hasTsize: true}}}, + expectedBytes: "12140a0901550005000102030418ffffffffffffff0f", + expectedForm: `{ + "Links": [ + { + "Hash": "015500050001020304", + "Tsize": 9007199254740991 + } + ] +}`, + }, +} + +func TestCompat(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + verifyRoundTrip(t, tc) + }) + } +} + +func verifyRoundTrip(t *testing.T, tc testCase) { + var err error + var actualBytes string + var actualForm string + + if tc.node != nil { + node := buildNode(*tc.node) + actualBytes, err = nodeToString(t, node) + + if tc.encodeError != "" { + if err != nil { + if !strings.Contains(err.Error(), tc.encodeError) { + t.Fatalf("got unexpeced encode error: [%v] (expected [%v])", err.Error(), tc.encodeError) + } + } else { + t.Fatalf("did not get expected encode error: %v", tc.encodeError) + } + } else { + if err != nil { + t.Fatal(err) + } else { + if actualBytes != tc.expectedBytes { + t.Logf( + "Expected bytes: [%v]\nGot: [%v]\n", + tc.expectedBytes, + actualBytes) + t.Error("Did not match") + } + } + } + } + + actualForm, err = bytesToFormString(t, tc.expectedBytes, basicnode.Prototype__Map{}.NewBuilder()) + if tc.decodeError != "" { + if err != nil { + if !strings.Contains(err.Error(), tc.decodeError) { + t.Fatalf("got unexpeced decode error: [%v] (expected [%v])", err.Error(), tc.decodeError) + } + } else { + t.Fatalf("did not get expected decode error: %v", tc.decodeError) + } + } else { + if err != nil { + t.Fatal(err) + } + if actualForm != tc.expectedForm { + t.Logf( + "Expected form: [%v]\nGot: [%v]\n", + tc.expectedForm, + actualForm) + t.Error("Did not match") + } + } +} + +func buildNode(n pbNode) ld.Node { + return fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(fma fluent.MapAssembler) { + if n.data != nil { + fma.AssembleEntry("Data").AssignBytes(n.data) + } + if n.links != nil { + fma.AssembleEntry("Links").CreateList(int64(len(n.links)), func(fla fluent.ListAssembler) { + for _, link := range n.links { + fla.AssembleValue().CreateMap(3, func(fma fluent.MapAssembler) { + if link.hasName { + fma.AssembleEntry("Name").AssignString(link.name) + } + if link.hasTsize { + fma.AssembleEntry("Tsize").AssignInt(int64(link.tsize)) + } + if link.hash.ByteLen() != 0 { + fma.AssembleEntry("Hash").AssignLink(cidlink.Link{Cid: link.hash}) + } + }) + } + }) + } + }) +} + +func nodeToString(t *testing.T, node ld.Node) (string, error) { + var buf bytes.Buffer + err := Marshal(node, &buf) + if err != nil { + return "", err + } + h := hex.EncodeToString(buf.Bytes()) + t.Logf("[%v]\n", h) + return h, nil +} + +func bytesToFormString(t *testing.T, bytesHex string, nb ld.NodeBuilder) (string, error) { + byts, err := hex.DecodeString(bytesHex) + if err != nil { + return "", err + } + if err = Unmarshal(nb, bytes.NewReader(byts)); err != nil { + return "", err + } + + node := nb.Build() + str, err := json.MarshalIndent(cleanPBNode(t, node), "", "\t") + if err != nil { + return "", err + } + return string(str), nil +} + +// convert a ld.Node (PBLink) into a map for clean JSON marshalling +func cleanPBLink(t *testing.T, link ld.Node) map[string]interface{} { + if link == nil { + return nil + } + nl := make(map[string]interface{}) + hash, _ := link.LookupByString("Hash") + if hash != nil { + l, _ := hash.AsLink() + cl, _ := l.(cidlink.Link) + nl["Hash"] = hex.EncodeToString(cl.Bytes()) + } + name, _ := link.LookupByString("Name") + if name != nil { + name, _ := name.AsString() + nl["Name"] = name + } + tsize, _ := link.LookupByString("Tsize") + if tsize != nil { + tsize, _ := tsize.AsInt() + nl["Tsize"] = tsize + } + return nl +} + +// convert an ld.Node (PBNode) into a map for clean JSON marshalling +func cleanPBNode(t *testing.T, node ld.Node) map[string]interface{} { + nn := make(map[string]interface{}) + data, _ := node.LookupByString("Data") + if data != nil { + byts, _ := data.AsBytes() + nn["Data"] = hex.EncodeToString(byts) + } + links, _ := node.LookupByString("Links") + if links != nil { + linksList := make([]map[string]interface{}, links.Length()) + linksIter := links.ListIterator() + for !linksIter.Done() { + ii, link, _ := linksIter.Next() + linksList[ii] = cleanPBLink(t, link) + } + nn["Links"] = linksList + } + return nn +} + +func _mkcid() cid.Cid { + _, c, _ := cid.CidFromBytes([]byte{1, 85, 0, 5, 0, 1, 2, 3, 4}) + return c +} diff --git a/doc.go b/doc.go new file mode 100644 index 0000000000000000000000000000000000000000..4e20074fe9c49fb9da2b303b34197cb9d5a506fc --- /dev/null +++ b/doc.go @@ -0,0 +1,31 @@ +/* +Package dagpb provides an implementation of the LD DAG-PB spec +(https://gitlab.dms3.io/ld/specs/blob/master/block-layer/codecs/dag-pb.md) for +go-ld-prime (https://gitlab.dms3.io/ld/go-ld-prime/). + +Use Decode() and Encode() directly, or import this package to have this codec +registered into the go-ld-prime multicodec registry and available from the +cidlink.DefaultLinkSystem. + +Nodes encoded with this codec _must_ conform to the DAG-PB spec. Specifically, +they should have the non-optional fields shown in the DAG-PB schema: + + type PBNode struct { + Links [PBLink] + Data optional Bytes + } + + type PBLink struct { + Hash Link + Name optional String + Tsize optional Int + } + +Use dagpb.Type.PBNode and friends directly for strictness guarantees. Basic +ld.Node's will need to have the appropriate fields (and no others) to +successfully encode using this codec. +*/ +package dagpb + +//go:generate go run gen.go +//go:generate gofmt -w ldsch_minima.go ldsch_satisfaction.go ldsch_types.go diff --git a/gen.go b/gen.go new file mode 100644 index 0000000000000000000000000000000000000000..ac8bc4c0bf4af2d2db2e5a6867f111c76f8a6b60 --- /dev/null +++ b/gen.go @@ -0,0 +1,69 @@ +//go:build ignore +// +build ignore + +package main + +// based on https://gitlab.dms3.io/ld/go-ld-prime-proto/blob/master/gen/main.go + +import ( + "fmt" + "os" + + "gitlab.dms3.io/ld/go-ld-prime/schema" + gengo "gitlab.dms3.io/ld/go-ld-prime/schema/gen/go" +) + +func main() { + ts := schema.TypeSystem{} + ts.Init() + adjCfg := &gengo.AdjunctCfg{} + + pkgName := "dagpb" + + ts.Accumulate(schema.SpawnString("String")) + ts.Accumulate(schema.SpawnInt("Int")) + ts.Accumulate(schema.SpawnLink("Link")) + ts.Accumulate(schema.SpawnBytes("Bytes")) + + /* + type PBLink struct { + Hash Link + Name optional String + Tsize optional Int + } + */ + + ts.Accumulate(schema.SpawnStruct("PBLink", + []schema.StructField{ + schema.SpawnStructField("Hash", "Link", false, false), + schema.SpawnStructField("Name", "String", true, false), + schema.SpawnStructField("Tsize", "Int", true, false), + }, + schema.SpawnStructRepresentationMap(nil), + )) + ts.Accumulate(schema.SpawnList("PBLinks", "PBLink", false)) + + /* + type PBNode struct { + Links [PBLink] + Data optional Bytes + } + */ + + ts.Accumulate(schema.SpawnStruct("PBNode", + []schema.StructField{ + schema.SpawnStructField("Links", "PBLinks", false, false), + schema.SpawnStructField("Data", "Bytes", true, false), + }, + schema.SpawnStructRepresentationMap(nil), + )) + + if errs := ts.ValidateGraph(); errs != nil { + for _, err := range errs { + fmt.Printf("- %s\n", err) + } + os.Exit(1) + } + + gengo.Generate(".", pkgName, ts, adjCfg) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..198b2d802c0e743bc8dd24596c85d3bb85a013ff --- /dev/null +++ b/go.mod @@ -0,0 +1,9 @@ +module gitlab.dms3.io/ld/go-codec-dagpb + +go 1.15 + +require ( + gitlab.dms3.io/dms3/go-cid v0.0.3 + gitlab.dms3.io/ld/go-ld-prime v0.0.3 + google.golang.org/protobuf v1.27.1 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..3e723fac438f3d74e6b9c1d3025a1b22d5a746a9 --- /dev/null +++ b/go.sum @@ -0,0 +1,70 @@ +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/klauspost/cpuid/v2 v2.0.4 h1:g0I61F2K2DjRHz1cnxlkNSBIaePVoJIjjnHui8QHbiw= +github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= +github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= +github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= +github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= +github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multihash v0.0.15 h1:hWOPdrNqDjwHDx82vsYGSDZNyktOJJ2dzZJzFkOV1jM= +github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= +github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1 h1:CskT+S6Ay54OwxBGB0R3Rsx4Muto6UnEYTyKJbyRIAI= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= +github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +gitlab.dms3.io/dms3/go-cid v0.0.3 h1:5qZ1sl1Bi26naLz7Vsc8fjWcJKX8bR6njt3WPCteXac= +gitlab.dms3.io/dms3/go-cid v0.0.3/go.mod h1:qT/Q1NZD31UnWQ+rwsQgzGrrsQhpq7dYSlXf7ulDgtk= +gitlab.dms3.io/ld/go-ld-prime v0.0.3 h1:M4obYt4Swv8bCheUMy2kmnxP8MUz2QuF4bLiKTNlBgQ= +gitlab.dms3.io/ld/go-ld-prime v0.0.3/go.mod h1:legKOh9xuMrYxCAmU5CfRMbfHSrLmunq4aOUbNAb3hs= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY= +golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= diff --git a/ldsch_minima.go b/ldsch_minima.go new file mode 100644 index 0000000000000000000000000000000000000000..c103c1d001b1511ca3c43ed9dd00d67675c58e47 --- /dev/null +++ b/ldsch_minima.go @@ -0,0 +1,51 @@ +package dagpb + +// Code generated by go-ld-prime gengo. DO NOT EDIT. + +import ( + "fmt" + + "gitlab.dms3.io/ld/go-ld-prime" + "gitlab.dms3.io/ld/go-ld-prime/schema" +) + +const ( + midvalue = schema.Maybe(4) + allowNull = schema.Maybe(5) +) + +type maState uint8 + +const ( + maState_initial maState = iota + maState_midKey + maState_expectValue + maState_midValue + maState_finished +) + +type laState uint8 + +const ( + laState_initial laState = iota + laState_midValue + laState_finished +) + +type _ErrorThunkAssembler struct { + e error +} + +func (ea _ErrorThunkAssembler) BeginMap(_ int64) (ld.MapAssembler, error) { return nil, ea.e } +func (ea _ErrorThunkAssembler) BeginList(_ int64) (ld.ListAssembler, error) { return nil, ea.e } +func (ea _ErrorThunkAssembler) AssignNull() error { return ea.e } +func (ea _ErrorThunkAssembler) AssignBool(bool) error { return ea.e } +func (ea _ErrorThunkAssembler) AssignInt(int64) error { return ea.e } +func (ea _ErrorThunkAssembler) AssignFloat(float64) error { return ea.e } +func (ea _ErrorThunkAssembler) AssignString(string) error { return ea.e } +func (ea _ErrorThunkAssembler) AssignBytes([]byte) error { return ea.e } +func (ea _ErrorThunkAssembler) AssignLink(ld.Link) error { return ea.e } +func (ea _ErrorThunkAssembler) AssignNode(ld.Node) error { return ea.e } +func (ea _ErrorThunkAssembler) Prototype() ld.NodePrototype { + panic(fmt.Errorf("cannot get prototype from error-carrying assembler: already derailed with error: %w", ea.e)) +} diff --git a/ldsch_satisfaction.go b/ldsch_satisfaction.go new file mode 100644 index 0000000000000000000000000000000000000000..26460dafd33e2cb7b7958df7c940f8afb1796a26 --- /dev/null +++ b/ldsch_satisfaction.go @@ -0,0 +1,3416 @@ +package dagpb + +// Code generated by go-ld-prime gengo. DO NOT EDIT. + +import ( + ld "gitlab.dms3.io/ld/go-ld-prime" + "gitlab.dms3.io/ld/go-ld-prime/node/mixins" + "gitlab.dms3.io/ld/go-ld-prime/schema" +) + +func (n Bytes) Bytes() []byte { + return n.x +} +func (_Bytes__Prototype) FromBytes(v []byte) (Bytes, error) { + n := _Bytes{v} + return &n, nil +} + +type _Bytes__Maybe struct { + m schema.Maybe + v _Bytes +} +type MaybeBytes = *_Bytes__Maybe + +func (m MaybeBytes) IsNull() bool { + return m.m == schema.Maybe_Null +} +func (m MaybeBytes) IsAbsent() bool { + return m.m == schema.Maybe_Absent +} +func (m MaybeBytes) Exists() bool { + return m.m == schema.Maybe_Value +} +func (m MaybeBytes) AsNode() ld.Node { + switch m.m { + case schema.Maybe_Absent: + return ld.Absent + case schema.Maybe_Null: + return ld.Null + case schema.Maybe_Value: + return &m.v + default: + panic("unreachable") + } +} +func (m MaybeBytes) Must() Bytes { + if !m.Exists() { + panic("unbox of a maybe rejected") + } + return &m.v +} + +var _ ld.Node = (Bytes)(&_Bytes{}) +var _ schema.TypedNode = (Bytes)(&_Bytes{}) + +func (Bytes) Kind() ld.Kind { + return ld.Kind_Bytes +} +func (Bytes) LookupByString(string) (ld.Node, error) { + return mixins.Bytes{TypeName: "dagpb.Bytes"}.LookupByString("") +} +func (Bytes) LookupByNode(ld.Node) (ld.Node, error) { + return mixins.Bytes{TypeName: "dagpb.Bytes"}.LookupByNode(nil) +} +func (Bytes) LookupByIndex(idx int64) (ld.Node, error) { + return mixins.Bytes{TypeName: "dagpb.Bytes"}.LookupByIndex(0) +} +func (Bytes) LookupBySegment(seg ld.PathSegment) (ld.Node, error) { + return mixins.Bytes{TypeName: "dagpb.Bytes"}.LookupBySegment(seg) +} +func (Bytes) MapIterator() ld.MapIterator { + return nil +} +func (Bytes) ListIterator() ld.ListIterator { + return nil +} +func (Bytes) Length() int64 { + return -1 +} +func (Bytes) IsAbsent() bool { + return false +} +func (Bytes) IsNull() bool { + return false +} +func (Bytes) AsBool() (bool, error) { + return mixins.Bytes{TypeName: "dagpb.Bytes"}.AsBool() +} +func (Bytes) AsInt() (int64, error) { + return mixins.Bytes{TypeName: "dagpb.Bytes"}.AsInt() +} +func (Bytes) AsFloat() (float64, error) { + return mixins.Bytes{TypeName: "dagpb.Bytes"}.AsFloat() +} +func (Bytes) AsString() (string, error) { + return mixins.Bytes{TypeName: "dagpb.Bytes"}.AsString() +} +func (n Bytes) AsBytes() ([]byte, error) { + return n.x, nil +} +func (Bytes) AsLink() (ld.Link, error) { + return mixins.Bytes{TypeName: "dagpb.Bytes"}.AsLink() +} +func (Bytes) Prototype() ld.NodePrototype { + return _Bytes__Prototype{} +} + +type _Bytes__Prototype struct{} + +func (_Bytes__Prototype) NewBuilder() ld.NodeBuilder { + var nb _Bytes__Builder + nb.Reset() + return &nb +} + +type _Bytes__Builder struct { + _Bytes__Assembler +} + +func (nb *_Bytes__Builder) Build() ld.Node { + if *nb.m != schema.Maybe_Value { + panic("invalid state: cannot call Build on an assembler that's not finished") + } + return nb.w +} +func (nb *_Bytes__Builder) Reset() { + var w _Bytes + var m schema.Maybe + *nb = _Bytes__Builder{_Bytes__Assembler{w: &w, m: &m}} +} + +type _Bytes__Assembler struct { + w *_Bytes + m *schema.Maybe +} + +func (na *_Bytes__Assembler) reset() {} +func (_Bytes__Assembler) BeginMap(sizeHint int64) (ld.MapAssembler, error) { + return mixins.BytesAssembler{TypeName: "dagpb.Bytes"}.BeginMap(0) +} +func (_Bytes__Assembler) BeginList(sizeHint int64) (ld.ListAssembler, error) { + return mixins.BytesAssembler{TypeName: "dagpb.Bytes"}.BeginList(0) +} +func (na *_Bytes__Assembler) AssignNull() error { + switch *na.m { + case allowNull: + *na.m = schema.Maybe_Null + return nil + case schema.Maybe_Absent: + return mixins.BytesAssembler{TypeName: "dagpb.Bytes"}.AssignNull() + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + } + panic("unreachable") +} +func (_Bytes__Assembler) AssignBool(bool) error { + return mixins.BytesAssembler{TypeName: "dagpb.Bytes"}.AssignBool(false) +} +func (_Bytes__Assembler) AssignInt(int64) error { + return mixins.BytesAssembler{TypeName: "dagpb.Bytes"}.AssignInt(0) +} +func (_Bytes__Assembler) AssignFloat(float64) error { + return mixins.BytesAssembler{TypeName: "dagpb.Bytes"}.AssignFloat(0) +} +func (_Bytes__Assembler) AssignString(string) error { + return mixins.BytesAssembler{TypeName: "dagpb.Bytes"}.AssignString("") +} +func (na *_Bytes__Assembler) AssignBytes(v []byte) error { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + } + na.w.x = v + *na.m = schema.Maybe_Value + return nil +} +func (_Bytes__Assembler) AssignLink(ld.Link) error { + return mixins.BytesAssembler{TypeName: "dagpb.Bytes"}.AssignLink(nil) +} +func (na *_Bytes__Assembler) AssignNode(v ld.Node) error { + if v.IsNull() { + return na.AssignNull() + } + if v2, ok := v.(*_Bytes); ok { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + } + *na.w = *v2 + *na.m = schema.Maybe_Value + return nil + } + if v2, err := v.AsBytes(); err != nil { + return err + } else { + return na.AssignBytes(v2) + } +} +func (_Bytes__Assembler) Prototype() ld.NodePrototype { + return _Bytes__Prototype{} +} +func (Bytes) Type() schema.Type { + return nil /*TODO:typelit*/ +} +func (n Bytes) Representation() ld.Node { + return (*_Bytes__Repr)(n) +} + +type _Bytes__Repr = _Bytes + +var _ ld.Node = &_Bytes__Repr{} + +type _Bytes__ReprPrototype = _Bytes__Prototype +type _Bytes__ReprAssembler = _Bytes__Assembler + +func (n Int) Int() int64 { + return n.x +} +func (_Int__Prototype) FromInt(v int64) (Int, error) { + n := _Int{v} + return &n, nil +} + +type _Int__Maybe struct { + m schema.Maybe + v _Int +} +type MaybeInt = *_Int__Maybe + +func (m MaybeInt) IsNull() bool { + return m.m == schema.Maybe_Null +} +func (m MaybeInt) IsAbsent() bool { + return m.m == schema.Maybe_Absent +} +func (m MaybeInt) Exists() bool { + return m.m == schema.Maybe_Value +} +func (m MaybeInt) AsNode() ld.Node { + switch m.m { + case schema.Maybe_Absent: + return ld.Absent + case schema.Maybe_Null: + return ld.Null + case schema.Maybe_Value: + return &m.v + default: + panic("unreachable") + } +} +func (m MaybeInt) Must() Int { + if !m.Exists() { + panic("unbox of a maybe rejected") + } + return &m.v +} + +var _ ld.Node = (Int)(&_Int{}) +var _ schema.TypedNode = (Int)(&_Int{}) + +func (Int) Kind() ld.Kind { + return ld.Kind_Int +} +func (Int) LookupByString(string) (ld.Node, error) { + return mixins.Int{TypeName: "dagpb.Int"}.LookupByString("") +} +func (Int) LookupByNode(ld.Node) (ld.Node, error) { + return mixins.Int{TypeName: "dagpb.Int"}.LookupByNode(nil) +} +func (Int) LookupByIndex(idx int64) (ld.Node, error) { + return mixins.Int{TypeName: "dagpb.Int"}.LookupByIndex(0) +} +func (Int) LookupBySegment(seg ld.PathSegment) (ld.Node, error) { + return mixins.Int{TypeName: "dagpb.Int"}.LookupBySegment(seg) +} +func (Int) MapIterator() ld.MapIterator { + return nil +} +func (Int) ListIterator() ld.ListIterator { + return nil +} +func (Int) Length() int64 { + return -1 +} +func (Int) IsAbsent() bool { + return false +} +func (Int) IsNull() bool { + return false +} +func (Int) AsBool() (bool, error) { + return mixins.Int{TypeName: "dagpb.Int"}.AsBool() +} +func (n Int) AsInt() (int64, error) { + return n.x, nil +} +func (Int) AsFloat() (float64, error) { + return mixins.Int{TypeName: "dagpb.Int"}.AsFloat() +} +func (Int) AsString() (string, error) { + return mixins.Int{TypeName: "dagpb.Int"}.AsString() +} +func (Int) AsBytes() ([]byte, error) { + return mixins.Int{TypeName: "dagpb.Int"}.AsBytes() +} +func (Int) AsLink() (ld.Link, error) { + return mixins.Int{TypeName: "dagpb.Int"}.AsLink() +} +func (Int) Prototype() ld.NodePrototype { + return _Int__Prototype{} +} + +type _Int__Prototype struct{} + +func (_Int__Prototype) NewBuilder() ld.NodeBuilder { + var nb _Int__Builder + nb.Reset() + return &nb +} + +type _Int__Builder struct { + _Int__Assembler +} + +func (nb *_Int__Builder) Build() ld.Node { + if *nb.m != schema.Maybe_Value { + panic("invalid state: cannot call Build on an assembler that's not finished") + } + return nb.w +} +func (nb *_Int__Builder) Reset() { + var w _Int + var m schema.Maybe + *nb = _Int__Builder{_Int__Assembler{w: &w, m: &m}} +} + +type _Int__Assembler struct { + w *_Int + m *schema.Maybe +} + +func (na *_Int__Assembler) reset() {} +func (_Int__Assembler) BeginMap(sizeHint int64) (ld.MapAssembler, error) { + return mixins.IntAssembler{TypeName: "dagpb.Int"}.BeginMap(0) +} +func (_Int__Assembler) BeginList(sizeHint int64) (ld.ListAssembler, error) { + return mixins.IntAssembler{TypeName: "dagpb.Int"}.BeginList(0) +} +func (na *_Int__Assembler) AssignNull() error { + switch *na.m { + case allowNull: + *na.m = schema.Maybe_Null + return nil + case schema.Maybe_Absent: + return mixins.IntAssembler{TypeName: "dagpb.Int"}.AssignNull() + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + } + panic("unreachable") +} +func (_Int__Assembler) AssignBool(bool) error { + return mixins.IntAssembler{TypeName: "dagpb.Int"}.AssignBool(false) +} +func (na *_Int__Assembler) AssignInt(v int64) error { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + } + na.w.x = v + *na.m = schema.Maybe_Value + return nil +} +func (_Int__Assembler) AssignFloat(float64) error { + return mixins.IntAssembler{TypeName: "dagpb.Int"}.AssignFloat(0) +} +func (_Int__Assembler) AssignString(string) error { + return mixins.IntAssembler{TypeName: "dagpb.Int"}.AssignString("") +} +func (_Int__Assembler) AssignBytes([]byte) error { + return mixins.IntAssembler{TypeName: "dagpb.Int"}.AssignBytes(nil) +} +func (_Int__Assembler) AssignLink(ld.Link) error { + return mixins.IntAssembler{TypeName: "dagpb.Int"}.AssignLink(nil) +} +func (na *_Int__Assembler) AssignNode(v ld.Node) error { + if v.IsNull() { + return na.AssignNull() + } + if v2, ok := v.(*_Int); ok { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + } + *na.w = *v2 + *na.m = schema.Maybe_Value + return nil + } + if v2, err := v.AsInt(); err != nil { + return err + } else { + return na.AssignInt(v2) + } +} +func (_Int__Assembler) Prototype() ld.NodePrototype { + return _Int__Prototype{} +} +func (Int) Type() schema.Type { + return nil /*TODO:typelit*/ +} +func (n Int) Representation() ld.Node { + return (*_Int__Repr)(n) +} + +type _Int__Repr = _Int + +var _ ld.Node = &_Int__Repr{} + +type _Int__ReprPrototype = _Int__Prototype +type _Int__ReprAssembler = _Int__Assembler + +func (n Link) Link() ld.Link { + return n.x +} +func (_Link__Prototype) FromLink(v ld.Link) (Link, error) { + n := _Link{v} + return &n, nil +} + +type _Link__Maybe struct { + m schema.Maybe + v _Link +} +type MaybeLink = *_Link__Maybe + +func (m MaybeLink) IsNull() bool { + return m.m == schema.Maybe_Null +} +func (m MaybeLink) IsAbsent() bool { + return m.m == schema.Maybe_Absent +} +func (m MaybeLink) Exists() bool { + return m.m == schema.Maybe_Value +} +func (m MaybeLink) AsNode() ld.Node { + switch m.m { + case schema.Maybe_Absent: + return ld.Absent + case schema.Maybe_Null: + return ld.Null + case schema.Maybe_Value: + return &m.v + default: + panic("unreachable") + } +} +func (m MaybeLink) Must() Link { + if !m.Exists() { + panic("unbox of a maybe rejected") + } + return &m.v +} + +var _ ld.Node = (Link)(&_Link{}) +var _ schema.TypedNode = (Link)(&_Link{}) + +func (Link) Kind() ld.Kind { + return ld.Kind_Link +} +func (Link) LookupByString(string) (ld.Node, error) { + return mixins.Link{TypeName: "dagpb.Link"}.LookupByString("") +} +func (Link) LookupByNode(ld.Node) (ld.Node, error) { + return mixins.Link{TypeName: "dagpb.Link"}.LookupByNode(nil) +} +func (Link) LookupByIndex(idx int64) (ld.Node, error) { + return mixins.Link{TypeName: "dagpb.Link"}.LookupByIndex(0) +} +func (Link) LookupBySegment(seg ld.PathSegment) (ld.Node, error) { + return mixins.Link{TypeName: "dagpb.Link"}.LookupBySegment(seg) +} +func (Link) MapIterator() ld.MapIterator { + return nil +} +func (Link) ListIterator() ld.ListIterator { + return nil +} +func (Link) Length() int64 { + return -1 +} +func (Link) IsAbsent() bool { + return false +} +func (Link) IsNull() bool { + return false +} +func (Link) AsBool() (bool, error) { + return mixins.Link{TypeName: "dagpb.Link"}.AsBool() +} +func (Link) AsInt() (int64, error) { + return mixins.Link{TypeName: "dagpb.Link"}.AsInt() +} +func (Link) AsFloat() (float64, error) { + return mixins.Link{TypeName: "dagpb.Link"}.AsFloat() +} +func (Link) AsString() (string, error) { + return mixins.Link{TypeName: "dagpb.Link"}.AsString() +} +func (Link) AsBytes() ([]byte, error) { + return mixins.Link{TypeName: "dagpb.Link"}.AsBytes() +} +func (n Link) AsLink() (ld.Link, error) { + return n.x, nil +} +func (Link) Prototype() ld.NodePrototype { + return _Link__Prototype{} +} + +type _Link__Prototype struct{} + +func (_Link__Prototype) NewBuilder() ld.NodeBuilder { + var nb _Link__Builder + nb.Reset() + return &nb +} + +type _Link__Builder struct { + _Link__Assembler +} + +func (nb *_Link__Builder) Build() ld.Node { + if *nb.m != schema.Maybe_Value { + panic("invalid state: cannot call Build on an assembler that's not finished") + } + return nb.w +} +func (nb *_Link__Builder) Reset() { + var w _Link + var m schema.Maybe + *nb = _Link__Builder{_Link__Assembler{w: &w, m: &m}} +} + +type _Link__Assembler struct { + w *_Link + m *schema.Maybe +} + +func (na *_Link__Assembler) reset() {} +func (_Link__Assembler) BeginMap(sizeHint int64) (ld.MapAssembler, error) { + return mixins.LinkAssembler{TypeName: "dagpb.Link"}.BeginMap(0) +} +func (_Link__Assembler) BeginList(sizeHint int64) (ld.ListAssembler, error) { + return mixins.LinkAssembler{TypeName: "dagpb.Link"}.BeginList(0) +} +func (na *_Link__Assembler) AssignNull() error { + switch *na.m { + case allowNull: + *na.m = schema.Maybe_Null + return nil + case schema.Maybe_Absent: + return mixins.LinkAssembler{TypeName: "dagpb.Link"}.AssignNull() + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + } + panic("unreachable") +} +func (_Link__Assembler) AssignBool(bool) error { + return mixins.LinkAssembler{TypeName: "dagpb.Link"}.AssignBool(false) +} +func (_Link__Assembler) AssignInt(int64) error { + return mixins.LinkAssembler{TypeName: "dagpb.Link"}.AssignInt(0) +} +func (_Link__Assembler) AssignFloat(float64) error { + return mixins.LinkAssembler{TypeName: "dagpb.Link"}.AssignFloat(0) +} +func (_Link__Assembler) AssignString(string) error { + return mixins.LinkAssembler{TypeName: "dagpb.Link"}.AssignString("") +} +func (_Link__Assembler) AssignBytes([]byte) error { + return mixins.LinkAssembler{TypeName: "dagpb.Link"}.AssignBytes(nil) +} +func (na *_Link__Assembler) AssignLink(v ld.Link) error { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + } + na.w.x = v + *na.m = schema.Maybe_Value + return nil +} +func (na *_Link__Assembler) AssignNode(v ld.Node) error { + if v.IsNull() { + return na.AssignNull() + } + if v2, ok := v.(*_Link); ok { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + } + *na.w = *v2 + *na.m = schema.Maybe_Value + return nil + } + if v2, err := v.AsLink(); err != nil { + return err + } else { + return na.AssignLink(v2) + } +} +func (_Link__Assembler) Prototype() ld.NodePrototype { + return _Link__Prototype{} +} +func (Link) Type() schema.Type { + return nil /*TODO:typelit*/ +} +func (n Link) Representation() ld.Node { + return (*_Link__Repr)(n) +} + +type _Link__Repr = _Link + +var _ ld.Node = &_Link__Repr{} + +type _Link__ReprPrototype = _Link__Prototype +type _Link__ReprAssembler = _Link__Assembler + +func (n _PBLink) FieldHash() Link { + return &n.Hash +} +func (n _PBLink) FieldName() MaybeString { + return &n.Name +} +func (n _PBLink) FieldTsize() MaybeInt { + return &n.Tsize +} + +type _PBLink__Maybe struct { + m schema.Maybe + v PBLink +} +type MaybePBLink = *_PBLink__Maybe + +func (m MaybePBLink) IsNull() bool { + return m.m == schema.Maybe_Null +} +func (m MaybePBLink) IsAbsent() bool { + return m.m == schema.Maybe_Absent +} +func (m MaybePBLink) Exists() bool { + return m.m == schema.Maybe_Value +} +func (m MaybePBLink) AsNode() ld.Node { + switch m.m { + case schema.Maybe_Absent: + return ld.Absent + case schema.Maybe_Null: + return ld.Null + case schema.Maybe_Value: + return m.v + default: + panic("unreachable") + } +} +func (m MaybePBLink) Must() PBLink { + if !m.Exists() { + panic("unbox of a maybe rejected") + } + return m.v +} + +var ( + fieldName__PBLink_Hash = _String{"Hash"} + fieldName__PBLink_Name = _String{"Name"} + fieldName__PBLink_Tsize = _String{"Tsize"} +) +var _ ld.Node = (PBLink)(&_PBLink{}) +var _ schema.TypedNode = (PBLink)(&_PBLink{}) + +func (PBLink) Kind() ld.Kind { + return ld.Kind_Map +} +func (n PBLink) LookupByString(key string) (ld.Node, error) { + switch key { + case "Hash": + return &n.Hash, nil + case "Name": + if n.Name.m == schema.Maybe_Absent { + return ld.Absent, nil + } + return &n.Name.v, nil + case "Tsize": + if n.Tsize.m == schema.Maybe_Absent { + return ld.Absent, nil + } + return &n.Tsize.v, nil + default: + return nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: ld.PathSegmentOfString(key)} + } +} +func (n PBLink) LookupByNode(key ld.Node) (ld.Node, error) { + ks, err := key.AsString() + if err != nil { + return nil, err + } + return n.LookupByString(ks) +} +func (PBLink) LookupByIndex(idx int64) (ld.Node, error) { + return mixins.Map{TypeName: "dagpb.PBLink"}.LookupByIndex(0) +} +func (n PBLink) LookupBySegment(seg ld.PathSegment) (ld.Node, error) { + return n.LookupByString(seg.String()) +} +func (n PBLink) MapIterator() ld.MapIterator { + return &_PBLink__MapItr{n, 0} +} + +type _PBLink__MapItr struct { + n PBLink + idx int +} + +func (itr *_PBLink__MapItr) Next() (k ld.Node, v ld.Node, _ error) { + if itr.idx >= 3 { + return nil, nil, ld.ErrIteratorOverread{} + } + switch itr.idx { + case 0: + k = &fieldName__PBLink_Hash + v = &itr.n.Hash + case 1: + k = &fieldName__PBLink_Name + if itr.n.Name.m == schema.Maybe_Absent { + v = ld.Absent + break + } + v = &itr.n.Name.v + case 2: + k = &fieldName__PBLink_Tsize + if itr.n.Tsize.m == schema.Maybe_Absent { + v = ld.Absent + break + } + v = &itr.n.Tsize.v + default: + panic("unreachable") + } + itr.idx++ + return +} +func (itr *_PBLink__MapItr) Done() bool { + return itr.idx >= 3 +} + +func (PBLink) ListIterator() ld.ListIterator { + return nil +} +func (PBLink) Length() int64 { + return 3 +} +func (PBLink) IsAbsent() bool { + return false +} +func (PBLink) IsNull() bool { + return false +} +func (PBLink) AsBool() (bool, error) { + return mixins.Map{TypeName: "dagpb.PBLink"}.AsBool() +} +func (PBLink) AsInt() (int64, error) { + return mixins.Map{TypeName: "dagpb.PBLink"}.AsInt() +} +func (PBLink) AsFloat() (float64, error) { + return mixins.Map{TypeName: "dagpb.PBLink"}.AsFloat() +} +func (PBLink) AsString() (string, error) { + return mixins.Map{TypeName: "dagpb.PBLink"}.AsString() +} +func (PBLink) AsBytes() ([]byte, error) { + return mixins.Map{TypeName: "dagpb.PBLink"}.AsBytes() +} +func (PBLink) AsLink() (ld.Link, error) { + return mixins.Map{TypeName: "dagpb.PBLink"}.AsLink() +} +func (PBLink) Prototype() ld.NodePrototype { + return _PBLink__Prototype{} +} + +type _PBLink__Prototype struct{} + +func (_PBLink__Prototype) NewBuilder() ld.NodeBuilder { + var nb _PBLink__Builder + nb.Reset() + return &nb +} + +type _PBLink__Builder struct { + _PBLink__Assembler +} + +func (nb *_PBLink__Builder) Build() ld.Node { + if *nb.m != schema.Maybe_Value { + panic("invalid state: cannot call Build on an assembler that's not finished") + } + return nb.w +} +func (nb *_PBLink__Builder) Reset() { + var w _PBLink + var m schema.Maybe + *nb = _PBLink__Builder{_PBLink__Assembler{w: &w, m: &m}} +} + +type _PBLink__Assembler struct { + w *_PBLink + m *schema.Maybe + state maState + s int + f int + + cm schema.Maybe + ca_Hash _Link__Assembler + ca_Name _String__Assembler + ca_Tsize _Int__Assembler +} + +func (na *_PBLink__Assembler) reset() { + na.state = maState_initial + na.s = 0 + na.ca_Hash.reset() + na.ca_Name.reset() + na.ca_Tsize.reset() +} + +var ( + fieldBit__PBLink_Hash = 1 << 0 + fieldBit__PBLink_Name = 1 << 1 + fieldBit__PBLink_Tsize = 1 << 2 + fieldBits__PBLink_sufficient = 0 + 1<<0 +) + +func (na *_PBLink__Assembler) BeginMap(int64) (ld.MapAssembler, error) { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: it makes no sense to 'begin' twice on the same assembler!") + } + *na.m = midvalue + if na.w == nil { + na.w = &_PBLink{} + } + return na, nil +} +func (_PBLink__Assembler) BeginList(sizeHint int64) (ld.ListAssembler, error) { + return mixins.MapAssembler{TypeName: "dagpb.PBLink"}.BeginList(0) +} +func (na *_PBLink__Assembler) AssignNull() error { + switch *na.m { + case allowNull: + *na.m = schema.Maybe_Null + return nil + case schema.Maybe_Absent: + return mixins.MapAssembler{TypeName: "dagpb.PBLink"}.AssignNull() + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: cannot assign null into an assembler that's already begun working on recursive structures!") + } + panic("unreachable") +} +func (_PBLink__Assembler) AssignBool(bool) error { + return mixins.MapAssembler{TypeName: "dagpb.PBLink"}.AssignBool(false) +} +func (_PBLink__Assembler) AssignInt(int64) error { + return mixins.MapAssembler{TypeName: "dagpb.PBLink"}.AssignInt(0) +} +func (_PBLink__Assembler) AssignFloat(float64) error { + return mixins.MapAssembler{TypeName: "dagpb.PBLink"}.AssignFloat(0) +} +func (_PBLink__Assembler) AssignString(string) error { + return mixins.MapAssembler{TypeName: "dagpb.PBLink"}.AssignString("") +} +func (_PBLink__Assembler) AssignBytes([]byte) error { + return mixins.MapAssembler{TypeName: "dagpb.PBLink"}.AssignBytes(nil) +} +func (_PBLink__Assembler) AssignLink(ld.Link) error { + return mixins.MapAssembler{TypeName: "dagpb.PBLink"}.AssignLink(nil) +} +func (na *_PBLink__Assembler) AssignNode(v ld.Node) error { + if v.IsNull() { + return na.AssignNull() + } + if v2, ok := v.(*_PBLink); ok { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: cannot assign null into an assembler that's already begun working on recursive structures!") + } + if na.w == nil { + na.w = v2 + *na.m = schema.Maybe_Value + return nil + } + *na.w = *v2 + *na.m = schema.Maybe_Value + return nil + } + if v.Kind() != ld.Kind_Map { + return ld.ErrWrongKind{TypeName: "dagpb.PBLink", MethodName: "AssignNode", AppropriateKind: ld.KindSet_JustMap, ActualKind: v.Kind()} + } + itr := v.MapIterator() + for !itr.Done() { + k, v, err := itr.Next() + if err != nil { + return err + } + if err := na.AssembleKey().AssignNode(k); err != nil { + return err + } + if err := na.AssembleValue().AssignNode(v); err != nil { + return err + } + } + return na.Finish() +} +func (_PBLink__Assembler) Prototype() ld.NodePrototype { + return _PBLink__Prototype{} +} +func (ma *_PBLink__Assembler) valueFinishTidy() bool { + switch ma.f { + case 0: + switch ma.cm { + case schema.Maybe_Value: + ma.ca_Hash.w = nil + ma.cm = schema.Maybe_Absent + ma.state = maState_initial + return true + default: + return false + } + case 1: + switch ma.w.Name.m { + case schema.Maybe_Value: + ma.state = maState_initial + return true + default: + return false + } + case 2: + switch ma.w.Tsize.m { + case schema.Maybe_Value: + ma.state = maState_initial + return true + default: + return false + } + default: + panic("unreachable") + } +} +func (ma *_PBLink__Assembler) AssembleEntry(k string) (ld.NodeAssembler, error) { + switch ma.state { + case maState_initial: + // carry on + case maState_midKey: + panic("invalid state: AssembleEntry cannot be called when in the middle of assembling another key") + case maState_expectValue: + panic("invalid state: AssembleEntry cannot be called when expecting start of value assembly") + case maState_midValue: + if !ma.valueFinishTidy() { + panic("invalid state: AssembleEntry cannot be called when in the middle of assembling a value") + } // if tidy success: carry on + case maState_finished: + panic("invalid state: AssembleEntry cannot be called on an assembler that's already finished") + } + switch k { + case "Hash": + if ma.s&fieldBit__PBLink_Hash != 0 { + return nil, ld.ErrRepeatedMapKey{Key: &fieldName__PBLink_Hash} + } + ma.s += fieldBit__PBLink_Hash + ma.state = maState_midValue + ma.f = 0 + ma.ca_Hash.w = &ma.w.Hash + ma.ca_Hash.m = &ma.cm + return &ma.ca_Hash, nil + case "Name": + if ma.s&fieldBit__PBLink_Name != 0 { + return nil, ld.ErrRepeatedMapKey{Key: &fieldName__PBLink_Name} + } + ma.s += fieldBit__PBLink_Name + ma.state = maState_midValue + ma.f = 1 + ma.ca_Name.w = &ma.w.Name.v + ma.ca_Name.m = &ma.w.Name.m + return &ma.ca_Name, nil + case "Tsize": + if ma.s&fieldBit__PBLink_Tsize != 0 { + return nil, ld.ErrRepeatedMapKey{Key: &fieldName__PBLink_Tsize} + } + ma.s += fieldBit__PBLink_Tsize + ma.state = maState_midValue + ma.f = 2 + ma.ca_Tsize.w = &ma.w.Tsize.v + ma.ca_Tsize.m = &ma.w.Tsize.m + return &ma.ca_Tsize, nil + } + return nil, ld.ErrInvalidKey{TypeName: "dagpb.PBLink", Key: &_String{k}} +} +func (ma *_PBLink__Assembler) AssembleKey() ld.NodeAssembler { + switch ma.state { + case maState_initial: + // carry on + case maState_midKey: + panic("invalid state: AssembleKey cannot be called when in the middle of assembling another key") + case maState_expectValue: + panic("invalid state: AssembleKey cannot be called when expecting start of value assembly") + case maState_midValue: + if !ma.valueFinishTidy() { + panic("invalid state: AssembleKey cannot be called when in the middle of assembling a value") + } // if tidy success: carry on + case maState_finished: + panic("invalid state: AssembleKey cannot be called on an assembler that's already finished") + } + ma.state = maState_midKey + return (*_PBLink__KeyAssembler)(ma) +} +func (ma *_PBLink__Assembler) AssembleValue() ld.NodeAssembler { + switch ma.state { + case maState_initial: + panic("invalid state: AssembleValue cannot be called when no key is primed") + case maState_midKey: + panic("invalid state: AssembleValue cannot be called when in the middle of assembling a key") + case maState_expectValue: + // carry on + case maState_midValue: + panic("invalid state: AssembleValue cannot be called when in the middle of assembling another value") + case maState_finished: + panic("invalid state: AssembleValue cannot be called on an assembler that's already finished") + } + ma.state = maState_midValue + switch ma.f { + case 0: + ma.ca_Hash.w = &ma.w.Hash + ma.ca_Hash.m = &ma.cm + return &ma.ca_Hash + case 1: + ma.ca_Name.w = &ma.w.Name.v + ma.ca_Name.m = &ma.w.Name.m + return &ma.ca_Name + case 2: + ma.ca_Tsize.w = &ma.w.Tsize.v + ma.ca_Tsize.m = &ma.w.Tsize.m + return &ma.ca_Tsize + default: + panic("unreachable") + } +} +func (ma *_PBLink__Assembler) Finish() error { + switch ma.state { + case maState_initial: + // carry on + case maState_midKey: + panic("invalid state: Finish cannot be called when in the middle of assembling a key") + case maState_expectValue: + panic("invalid state: Finish cannot be called when expecting start of value assembly") + case maState_midValue: + if !ma.valueFinishTidy() { + panic("invalid state: Finish cannot be called when in the middle of assembling a value") + } // if tidy success: carry on + case maState_finished: + panic("invalid state: Finish cannot be called on an assembler that's already finished") + } + if ma.s&fieldBits__PBLink_sufficient != fieldBits__PBLink_sufficient { + err := ld.ErrMissingRequiredField{Missing: make([]string, 0)} + if ma.s&fieldBit__PBLink_Hash == 0 { + err.Missing = append(err.Missing, "Hash") + } + return err + } + ma.state = maState_finished + *ma.m = schema.Maybe_Value + return nil +} +func (ma *_PBLink__Assembler) KeyPrototype() ld.NodePrototype { + return _String__Prototype{} +} +func (ma *_PBLink__Assembler) ValuePrototype(k string) ld.NodePrototype { + panic("todo structbuilder mapassembler valueprototype") +} + +type _PBLink__KeyAssembler _PBLink__Assembler + +func (_PBLink__KeyAssembler) BeginMap(sizeHint int64) (ld.MapAssembler, error) { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.KeyAssembler"}.BeginMap(0) +} +func (_PBLink__KeyAssembler) BeginList(sizeHint int64) (ld.ListAssembler, error) { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.KeyAssembler"}.BeginList(0) +} +func (na *_PBLink__KeyAssembler) AssignNull() error { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.KeyAssembler"}.AssignNull() +} +func (_PBLink__KeyAssembler) AssignBool(bool) error { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.KeyAssembler"}.AssignBool(false) +} +func (_PBLink__KeyAssembler) AssignInt(int64) error { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.KeyAssembler"}.AssignInt(0) +} +func (_PBLink__KeyAssembler) AssignFloat(float64) error { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.KeyAssembler"}.AssignFloat(0) +} +func (ka *_PBLink__KeyAssembler) AssignString(k string) error { + if ka.state != maState_midKey { + panic("misuse: KeyAssembler held beyond its valid lifetime") + } + switch k { + case "Hash": + if ka.s&fieldBit__PBLink_Hash != 0 { + return ld.ErrRepeatedMapKey{Key: &fieldName__PBLink_Hash} + } + ka.s += fieldBit__PBLink_Hash + ka.state = maState_expectValue + ka.f = 0 + return nil + case "Name": + if ka.s&fieldBit__PBLink_Name != 0 { + return ld.ErrRepeatedMapKey{Key: &fieldName__PBLink_Name} + } + ka.s += fieldBit__PBLink_Name + ka.state = maState_expectValue + ka.f = 1 + return nil + case "Tsize": + if ka.s&fieldBit__PBLink_Tsize != 0 { + return ld.ErrRepeatedMapKey{Key: &fieldName__PBLink_Tsize} + } + ka.s += fieldBit__PBLink_Tsize + ka.state = maState_expectValue + ka.f = 2 + return nil + default: + return ld.ErrInvalidKey{TypeName: "dagpb.PBLink", Key: &_String{k}} + } +} +func (_PBLink__KeyAssembler) AssignBytes([]byte) error { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.KeyAssembler"}.AssignBytes(nil) +} +func (_PBLink__KeyAssembler) AssignLink(ld.Link) error { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.KeyAssembler"}.AssignLink(nil) +} +func (ka *_PBLink__KeyAssembler) AssignNode(v ld.Node) error { + if v2, err := v.AsString(); err != nil { + return err + } else { + return ka.AssignString(v2) + } +} +func (_PBLink__KeyAssembler) Prototype() ld.NodePrototype { + return _String__Prototype{} +} +func (PBLink) Type() schema.Type { + return nil /*TODO:typelit*/ +} +func (n PBLink) Representation() ld.Node { + return (*_PBLink__Repr)(n) +} + +type _PBLink__Repr _PBLink + +var ( + fieldName__PBLink_Hash_serial = _String{"Hash"} + fieldName__PBLink_Name_serial = _String{"Name"} + fieldName__PBLink_Tsize_serial = _String{"Tsize"} +) +var _ ld.Node = &_PBLink__Repr{} + +func (_PBLink__Repr) Kind() ld.Kind { + return ld.Kind_Map +} +func (n *_PBLink__Repr) LookupByString(key string) (ld.Node, error) { + switch key { + case "Hash": + return n.Hash.Representation(), nil + case "Name": + if n.Name.m == schema.Maybe_Absent { + return ld.Absent, ld.ErrNotExists{Segment: ld.PathSegmentOfString(key)} + } + return n.Name.v.Representation(), nil + case "Tsize": + if n.Tsize.m == schema.Maybe_Absent { + return ld.Absent, ld.ErrNotExists{Segment: ld.PathSegmentOfString(key)} + } + return n.Tsize.v.Representation(), nil + default: + return nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: ld.PathSegmentOfString(key)} + } +} +func (n *_PBLink__Repr) LookupByNode(key ld.Node) (ld.Node, error) { + ks, err := key.AsString() + if err != nil { + return nil, err + } + return n.LookupByString(ks) +} +func (_PBLink__Repr) LookupByIndex(idx int64) (ld.Node, error) { + return mixins.Map{TypeName: "dagpb.PBLink.Repr"}.LookupByIndex(0) +} +func (n _PBLink__Repr) LookupBySegment(seg ld.PathSegment) (ld.Node, error) { + return n.LookupByString(seg.String()) +} +func (n *_PBLink__Repr) MapIterator() ld.MapIterator { + end := 3 + if n.Tsize.m == schema.Maybe_Absent { + end = 2 + } else { + goto done + } + if n.Name.m == schema.Maybe_Absent { + end = 1 + } else { + goto done + } +done: + return &_PBLink__ReprMapItr{n, 0, end} +} + +type _PBLink__ReprMapItr struct { + n *_PBLink__Repr + idx int + end int +} + +func (itr *_PBLink__ReprMapItr) Next() (k ld.Node, v ld.Node, _ error) { +advance: + if itr.idx >= 3 { + return nil, nil, ld.ErrIteratorOverread{} + } + switch itr.idx { + case 0: + k = &fieldName__PBLink_Hash_serial + v = itr.n.Hash.Representation() + case 1: + k = &fieldName__PBLink_Name_serial + if itr.n.Name.m == schema.Maybe_Absent { + itr.idx++ + goto advance + } + v = itr.n.Name.v.Representation() + case 2: + k = &fieldName__PBLink_Tsize_serial + if itr.n.Tsize.m == schema.Maybe_Absent { + itr.idx++ + goto advance + } + v = itr.n.Tsize.v.Representation() + default: + panic("unreachable") + } + itr.idx++ + return +} +func (itr *_PBLink__ReprMapItr) Done() bool { + return itr.idx >= itr.end +} +func (_PBLink__Repr) ListIterator() ld.ListIterator { + return nil +} +func (rn *_PBLink__Repr) Length() int64 { + l := 3 + if rn.Name.m == schema.Maybe_Absent { + l-- + } + if rn.Tsize.m == schema.Maybe_Absent { + l-- + } + return int64(l) +} +func (_PBLink__Repr) IsAbsent() bool { + return false +} +func (_PBLink__Repr) IsNull() bool { + return false +} +func (_PBLink__Repr) AsBool() (bool, error) { + return mixins.Map{TypeName: "dagpb.PBLink.Repr"}.AsBool() +} +func (_PBLink__Repr) AsInt() (int64, error) { + return mixins.Map{TypeName: "dagpb.PBLink.Repr"}.AsInt() +} +func (_PBLink__Repr) AsFloat() (float64, error) { + return mixins.Map{TypeName: "dagpb.PBLink.Repr"}.AsFloat() +} +func (_PBLink__Repr) AsString() (string, error) { + return mixins.Map{TypeName: "dagpb.PBLink.Repr"}.AsString() +} +func (_PBLink__Repr) AsBytes() ([]byte, error) { + return mixins.Map{TypeName: "dagpb.PBLink.Repr"}.AsBytes() +} +func (_PBLink__Repr) AsLink() (ld.Link, error) { + return mixins.Map{TypeName: "dagpb.PBLink.Repr"}.AsLink() +} +func (_PBLink__Repr) Prototype() ld.NodePrototype { + return _PBLink__ReprPrototype{} +} + +type _PBLink__ReprPrototype struct{} + +func (_PBLink__ReprPrototype) NewBuilder() ld.NodeBuilder { + var nb _PBLink__ReprBuilder + nb.Reset() + return &nb +} + +type _PBLink__ReprBuilder struct { + _PBLink__ReprAssembler +} + +func (nb *_PBLink__ReprBuilder) Build() ld.Node { + if *nb.m != schema.Maybe_Value { + panic("invalid state: cannot call Build on an assembler that's not finished") + } + return nb.w +} +func (nb *_PBLink__ReprBuilder) Reset() { + var w _PBLink + var m schema.Maybe + *nb = _PBLink__ReprBuilder{_PBLink__ReprAssembler{w: &w, m: &m}} +} + +type _PBLink__ReprAssembler struct { + w *_PBLink + m *schema.Maybe + state maState + s int + f int + + cm schema.Maybe + ca_Hash _Link__ReprAssembler + ca_Name _String__ReprAssembler + ca_Tsize _Int__ReprAssembler +} + +func (na *_PBLink__ReprAssembler) reset() { + na.state = maState_initial + na.s = 0 + na.ca_Hash.reset() + na.ca_Name.reset() + na.ca_Tsize.reset() +} +func (na *_PBLink__ReprAssembler) BeginMap(int64) (ld.MapAssembler, error) { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: it makes no sense to 'begin' twice on the same assembler!") + } + *na.m = midvalue + if na.w == nil { + na.w = &_PBLink{} + } + return na, nil +} +func (_PBLink__ReprAssembler) BeginList(sizeHint int64) (ld.ListAssembler, error) { + return mixins.MapAssembler{TypeName: "dagpb.PBLink.Repr"}.BeginList(0) +} +func (na *_PBLink__ReprAssembler) AssignNull() error { + switch *na.m { + case allowNull: + *na.m = schema.Maybe_Null + return nil + case schema.Maybe_Absent: + return mixins.MapAssembler{TypeName: "dagpb.PBLink.Repr.Repr"}.AssignNull() + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: cannot assign null into an assembler that's already begun working on recursive structures!") + } + panic("unreachable") +} +func (_PBLink__ReprAssembler) AssignBool(bool) error { + return mixins.MapAssembler{TypeName: "dagpb.PBLink.Repr"}.AssignBool(false) +} +func (_PBLink__ReprAssembler) AssignInt(int64) error { + return mixins.MapAssembler{TypeName: "dagpb.PBLink.Repr"}.AssignInt(0) +} +func (_PBLink__ReprAssembler) AssignFloat(float64) error { + return mixins.MapAssembler{TypeName: "dagpb.PBLink.Repr"}.AssignFloat(0) +} +func (_PBLink__ReprAssembler) AssignString(string) error { + return mixins.MapAssembler{TypeName: "dagpb.PBLink.Repr"}.AssignString("") +} +func (_PBLink__ReprAssembler) AssignBytes([]byte) error { + return mixins.MapAssembler{TypeName: "dagpb.PBLink.Repr"}.AssignBytes(nil) +} +func (_PBLink__ReprAssembler) AssignLink(ld.Link) error { + return mixins.MapAssembler{TypeName: "dagpb.PBLink.Repr"}.AssignLink(nil) +} +func (na *_PBLink__ReprAssembler) AssignNode(v ld.Node) error { + if v.IsNull() { + return na.AssignNull() + } + if v2, ok := v.(*_PBLink); ok { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: cannot assign null into an assembler that's already begun working on recursive structures!") + } + if na.w == nil { + na.w = v2 + *na.m = schema.Maybe_Value + return nil + } + *na.w = *v2 + *na.m = schema.Maybe_Value + return nil + } + if v.Kind() != ld.Kind_Map { + return ld.ErrWrongKind{TypeName: "dagpb.PBLink.Repr", MethodName: "AssignNode", AppropriateKind: ld.KindSet_JustMap, ActualKind: v.Kind()} + } + itr := v.MapIterator() + for !itr.Done() { + k, v, err := itr.Next() + if err != nil { + return err + } + if err := na.AssembleKey().AssignNode(k); err != nil { + return err + } + if err := na.AssembleValue().AssignNode(v); err != nil { + return err + } + } + return na.Finish() +} +func (_PBLink__ReprAssembler) Prototype() ld.NodePrototype { + return _PBLink__ReprPrototype{} +} +func (ma *_PBLink__ReprAssembler) valueFinishTidy() bool { + switch ma.f { + case 0: + switch ma.cm { + case schema.Maybe_Value: + ma.cm = schema.Maybe_Absent + ma.state = maState_initial + return true + default: + return false + } + case 1: + switch ma.w.Name.m { + case schema.Maybe_Value: + ma.state = maState_initial + return true + default: + return false + } + case 2: + switch ma.w.Tsize.m { + case schema.Maybe_Value: + ma.state = maState_initial + return true + default: + return false + } + default: + panic("unreachable") + } +} +func (ma *_PBLink__ReprAssembler) AssembleEntry(k string) (ld.NodeAssembler, error) { + switch ma.state { + case maState_initial: + // carry on + case maState_midKey: + panic("invalid state: AssembleEntry cannot be called when in the middle of assembling another key") + case maState_expectValue: + panic("invalid state: AssembleEntry cannot be called when expecting start of value assembly") + case maState_midValue: + if !ma.valueFinishTidy() { + panic("invalid state: AssembleEntry cannot be called when in the middle of assembling a value") + } // if tidy success: carry on + case maState_finished: + panic("invalid state: AssembleEntry cannot be called on an assembler that's already finished") + } + switch k { + case "Hash": + if ma.s&fieldBit__PBLink_Hash != 0 { + return nil, ld.ErrRepeatedMapKey{Key: &fieldName__PBLink_Hash_serial} + } + ma.s += fieldBit__PBLink_Hash + ma.state = maState_midValue + ma.f = 0 + ma.ca_Hash.w = &ma.w.Hash + ma.ca_Hash.m = &ma.cm + return &ma.ca_Hash, nil + case "Name": + if ma.s&fieldBit__PBLink_Name != 0 { + return nil, ld.ErrRepeatedMapKey{Key: &fieldName__PBLink_Name_serial} + } + ma.s += fieldBit__PBLink_Name + ma.state = maState_midValue + ma.f = 1 + ma.ca_Name.w = &ma.w.Name.v + ma.ca_Name.m = &ma.w.Name.m + + return &ma.ca_Name, nil + case "Tsize": + if ma.s&fieldBit__PBLink_Tsize != 0 { + return nil, ld.ErrRepeatedMapKey{Key: &fieldName__PBLink_Tsize_serial} + } + ma.s += fieldBit__PBLink_Tsize + ma.state = maState_midValue + ma.f = 2 + ma.ca_Tsize.w = &ma.w.Tsize.v + ma.ca_Tsize.m = &ma.w.Tsize.m + + return &ma.ca_Tsize, nil + default: + } + return nil, ld.ErrInvalidKey{TypeName: "dagpb.PBLink.Repr", Key: &_String{k}} +} +func (ma *_PBLink__ReprAssembler) AssembleKey() ld.NodeAssembler { + switch ma.state { + case maState_initial: + // carry on + case maState_midKey: + panic("invalid state: AssembleKey cannot be called when in the middle of assembling another key") + case maState_expectValue: + panic("invalid state: AssembleKey cannot be called when expecting start of value assembly") + case maState_midValue: + if !ma.valueFinishTidy() { + panic("invalid state: AssembleKey cannot be called when in the middle of assembling a value") + } // if tidy success: carry on + case maState_finished: + panic("invalid state: AssembleKey cannot be called on an assembler that's already finished") + } + ma.state = maState_midKey + return (*_PBLink__ReprKeyAssembler)(ma) +} +func (ma *_PBLink__ReprAssembler) AssembleValue() ld.NodeAssembler { + switch ma.state { + case maState_initial: + panic("invalid state: AssembleValue cannot be called when no key is primed") + case maState_midKey: + panic("invalid state: AssembleValue cannot be called when in the middle of assembling a key") + case maState_expectValue: + // carry on + case maState_midValue: + panic("invalid state: AssembleValue cannot be called when in the middle of assembling another value") + case maState_finished: + panic("invalid state: AssembleValue cannot be called on an assembler that's already finished") + } + ma.state = maState_midValue + switch ma.f { + case 0: + ma.ca_Hash.w = &ma.w.Hash + ma.ca_Hash.m = &ma.cm + return &ma.ca_Hash + case 1: + ma.ca_Name.w = &ma.w.Name.v + ma.ca_Name.m = &ma.w.Name.m + + return &ma.ca_Name + case 2: + ma.ca_Tsize.w = &ma.w.Tsize.v + ma.ca_Tsize.m = &ma.w.Tsize.m + + return &ma.ca_Tsize + default: + panic("unreachable") + } +} +func (ma *_PBLink__ReprAssembler) Finish() error { + switch ma.state { + case maState_initial: + // carry on + case maState_midKey: + panic("invalid state: Finish cannot be called when in the middle of assembling a key") + case maState_expectValue: + panic("invalid state: Finish cannot be called when expecting start of value assembly") + case maState_midValue: + if !ma.valueFinishTidy() { + panic("invalid state: Finish cannot be called when in the middle of assembling a value") + } // if tidy success: carry on + case maState_finished: + panic("invalid state: Finish cannot be called on an assembler that's already finished") + } + if ma.s&fieldBits__PBLink_sufficient != fieldBits__PBLink_sufficient { + err := ld.ErrMissingRequiredField{Missing: make([]string, 0)} + if ma.s&fieldBit__PBLink_Hash == 0 { + err.Missing = append(err.Missing, "Hash") + } + return err + } + ma.state = maState_finished + *ma.m = schema.Maybe_Value + return nil +} +func (ma *_PBLink__ReprAssembler) KeyPrototype() ld.NodePrototype { + return _String__Prototype{} +} +func (ma *_PBLink__ReprAssembler) ValuePrototype(k string) ld.NodePrototype { + panic("todo structbuilder mapassembler repr valueprototype") +} + +type _PBLink__ReprKeyAssembler _PBLink__ReprAssembler + +func (_PBLink__ReprKeyAssembler) BeginMap(sizeHint int64) (ld.MapAssembler, error) { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.Repr.KeyAssembler"}.BeginMap(0) +} +func (_PBLink__ReprKeyAssembler) BeginList(sizeHint int64) (ld.ListAssembler, error) { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.Repr.KeyAssembler"}.BeginList(0) +} +func (na *_PBLink__ReprKeyAssembler) AssignNull() error { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.Repr.KeyAssembler"}.AssignNull() +} +func (_PBLink__ReprKeyAssembler) AssignBool(bool) error { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.Repr.KeyAssembler"}.AssignBool(false) +} +func (_PBLink__ReprKeyAssembler) AssignInt(int64) error { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.Repr.KeyAssembler"}.AssignInt(0) +} +func (_PBLink__ReprKeyAssembler) AssignFloat(float64) error { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.Repr.KeyAssembler"}.AssignFloat(0) +} +func (ka *_PBLink__ReprKeyAssembler) AssignString(k string) error { + if ka.state != maState_midKey { + panic("misuse: KeyAssembler held beyond its valid lifetime") + } + switch k { + case "Hash": + if ka.s&fieldBit__PBLink_Hash != 0 { + return ld.ErrRepeatedMapKey{Key: &fieldName__PBLink_Hash_serial} + } + ka.s += fieldBit__PBLink_Hash + ka.state = maState_expectValue + ka.f = 0 + return nil + case "Name": + if ka.s&fieldBit__PBLink_Name != 0 { + return ld.ErrRepeatedMapKey{Key: &fieldName__PBLink_Name_serial} + } + ka.s += fieldBit__PBLink_Name + ka.state = maState_expectValue + ka.f = 1 + return nil + case "Tsize": + if ka.s&fieldBit__PBLink_Tsize != 0 { + return ld.ErrRepeatedMapKey{Key: &fieldName__PBLink_Tsize_serial} + } + ka.s += fieldBit__PBLink_Tsize + ka.state = maState_expectValue + ka.f = 2 + return nil + } + return ld.ErrInvalidKey{TypeName: "dagpb.PBLink.Repr", Key: &_String{k}} +} +func (_PBLink__ReprKeyAssembler) AssignBytes([]byte) error { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.Repr.KeyAssembler"}.AssignBytes(nil) +} +func (_PBLink__ReprKeyAssembler) AssignLink(ld.Link) error { + return mixins.StringAssembler{TypeName: "dagpb.PBLink.Repr.KeyAssembler"}.AssignLink(nil) +} +func (ka *_PBLink__ReprKeyAssembler) AssignNode(v ld.Node) error { + if v2, err := v.AsString(); err != nil { + return err + } else { + return ka.AssignString(v2) + } +} +func (_PBLink__ReprKeyAssembler) Prototype() ld.NodePrototype { + return _String__Prototype{} +} + +func (n *_PBLinks) Lookup(idx int64) PBLink { + if n.Length() <= idx { + return nil + } + v := &n.x[idx] + return v +} +func (n *_PBLinks) LookupMaybe(idx int64) MaybePBLink { + if n.Length() <= idx { + return nil + } + v := &n.x[idx] + return &_PBLink__Maybe{ + m: schema.Maybe_Value, + v: v, + } +} + +var _PBLinks__valueAbsent = _PBLink__Maybe{m: schema.Maybe_Absent} + +func (n PBLinks) Iterator() *PBLinks__Itr { + return &PBLinks__Itr{n, 0} +} + +type PBLinks__Itr struct { + n PBLinks + idx int +} + +func (itr *PBLinks__Itr) Next() (idx int64, v PBLink) { + if itr.idx >= len(itr.n.x) { + return -1, nil + } + idx = int64(itr.idx) + v = &itr.n.x[itr.idx] + itr.idx++ + return +} +func (itr *PBLinks__Itr) Done() bool { + return itr.idx >= len(itr.n.x) +} + +type _PBLinks__Maybe struct { + m schema.Maybe + v _PBLinks +} +type MaybePBLinks = *_PBLinks__Maybe + +func (m MaybePBLinks) IsNull() bool { + return m.m == schema.Maybe_Null +} +func (m MaybePBLinks) IsAbsent() bool { + return m.m == schema.Maybe_Absent +} +func (m MaybePBLinks) Exists() bool { + return m.m == schema.Maybe_Value +} +func (m MaybePBLinks) AsNode() ld.Node { + switch m.m { + case schema.Maybe_Absent: + return ld.Absent + case schema.Maybe_Null: + return ld.Null + case schema.Maybe_Value: + return &m.v + default: + panic("unreachable") + } +} +func (m MaybePBLinks) Must() PBLinks { + if !m.Exists() { + panic("unbox of a maybe rejected") + } + return &m.v +} + +var _ ld.Node = (PBLinks)(&_PBLinks{}) +var _ schema.TypedNode = (PBLinks)(&_PBLinks{}) + +func (PBLinks) Kind() ld.Kind { + return ld.Kind_List +} +func (PBLinks) LookupByString(string) (ld.Node, error) { + return mixins.List{TypeName: "dagpb.PBLinks"}.LookupByString("") +} +func (n PBLinks) LookupByNode(k ld.Node) (ld.Node, error) { + idx, err := k.AsInt() + if err != nil { + return nil, err + } + return n.LookupByIndex(idx) +} +func (n PBLinks) LookupByIndex(idx int64) (ld.Node, error) { + if n.Length() <= idx { + return nil, ld.ErrNotExists{Segment: ld.PathSegmentOfInt(idx)} + } + v := &n.x[idx] + return v, nil +} +func (n PBLinks) LookupBySegment(seg ld.PathSegment) (ld.Node, error) { + i, err := seg.Index() + if err != nil { + return nil, ld.ErrInvalidSegmentForList{TypeName: "dagpb.PBLinks", TroubleSegment: seg, Reason: err} + } + return n.LookupByIndex(i) +} +func (PBLinks) MapIterator() ld.MapIterator { + return nil +} +func (n PBLinks) ListIterator() ld.ListIterator { + return &_PBLinks__ListItr{n, 0} +} + +type _PBLinks__ListItr struct { + n PBLinks + idx int +} + +func (itr *_PBLinks__ListItr) Next() (idx int64, v ld.Node, _ error) { + if itr.idx >= len(itr.n.x) { + return -1, nil, ld.ErrIteratorOverread{} + } + idx = int64(itr.idx) + x := &itr.n.x[itr.idx] + v = x + itr.idx++ + return +} +func (itr *_PBLinks__ListItr) Done() bool { + return itr.idx >= len(itr.n.x) +} + +func (n PBLinks) Length() int64 { + return int64(len(n.x)) +} +func (PBLinks) IsAbsent() bool { + return false +} +func (PBLinks) IsNull() bool { + return false +} +func (PBLinks) AsBool() (bool, error) { + return mixins.List{TypeName: "dagpb.PBLinks"}.AsBool() +} +func (PBLinks) AsInt() (int64, error) { + return mixins.List{TypeName: "dagpb.PBLinks"}.AsInt() +} +func (PBLinks) AsFloat() (float64, error) { + return mixins.List{TypeName: "dagpb.PBLinks"}.AsFloat() +} +func (PBLinks) AsString() (string, error) { + return mixins.List{TypeName: "dagpb.PBLinks"}.AsString() +} +func (PBLinks) AsBytes() ([]byte, error) { + return mixins.List{TypeName: "dagpb.PBLinks"}.AsBytes() +} +func (PBLinks) AsLink() (ld.Link, error) { + return mixins.List{TypeName: "dagpb.PBLinks"}.AsLink() +} +func (PBLinks) Prototype() ld.NodePrototype { + return _PBLinks__Prototype{} +} + +type _PBLinks__Prototype struct{} + +func (_PBLinks__Prototype) NewBuilder() ld.NodeBuilder { + var nb _PBLinks__Builder + nb.Reset() + return &nb +} + +type _PBLinks__Builder struct { + _PBLinks__Assembler +} + +func (nb *_PBLinks__Builder) Build() ld.Node { + if *nb.m != schema.Maybe_Value { + panic("invalid state: cannot call Build on an assembler that's not finished") + } + return nb.w +} +func (nb *_PBLinks__Builder) Reset() { + var w _PBLinks + var m schema.Maybe + *nb = _PBLinks__Builder{_PBLinks__Assembler{w: &w, m: &m}} +} + +type _PBLinks__Assembler struct { + w *_PBLinks + m *schema.Maybe + state laState + + cm schema.Maybe + va _PBLink__Assembler +} + +func (na *_PBLinks__Assembler) reset() { + na.state = laState_initial + na.va.reset() +} +func (_PBLinks__Assembler) BeginMap(sizeHint int64) (ld.MapAssembler, error) { + return mixins.ListAssembler{TypeName: "dagpb.PBLinks"}.BeginMap(0) +} +func (na *_PBLinks__Assembler) BeginList(sizeHint int64) (ld.ListAssembler, error) { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: it makes no sense to 'begin' twice on the same assembler!") + } + *na.m = midvalue + if sizeHint < 0 { + sizeHint = 0 + } + if sizeHint > 0 { + na.w.x = make([]_PBLink, 0, sizeHint) + } + return na, nil +} +func (na *_PBLinks__Assembler) AssignNull() error { + switch *na.m { + case allowNull: + *na.m = schema.Maybe_Null + return nil + case schema.Maybe_Absent: + return mixins.ListAssembler{TypeName: "dagpb.PBLinks"}.AssignNull() + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: cannot assign null into an assembler that's already begun working on recursive structures!") + } + panic("unreachable") +} +func (_PBLinks__Assembler) AssignBool(bool) error { + return mixins.ListAssembler{TypeName: "dagpb.PBLinks"}.AssignBool(false) +} +func (_PBLinks__Assembler) AssignInt(int64) error { + return mixins.ListAssembler{TypeName: "dagpb.PBLinks"}.AssignInt(0) +} +func (_PBLinks__Assembler) AssignFloat(float64) error { + return mixins.ListAssembler{TypeName: "dagpb.PBLinks"}.AssignFloat(0) +} +func (_PBLinks__Assembler) AssignString(string) error { + return mixins.ListAssembler{TypeName: "dagpb.PBLinks"}.AssignString("") +} +func (_PBLinks__Assembler) AssignBytes([]byte) error { + return mixins.ListAssembler{TypeName: "dagpb.PBLinks"}.AssignBytes(nil) +} +func (_PBLinks__Assembler) AssignLink(ld.Link) error { + return mixins.ListAssembler{TypeName: "dagpb.PBLinks"}.AssignLink(nil) +} +func (na *_PBLinks__Assembler) AssignNode(v ld.Node) error { + if v.IsNull() { + return na.AssignNull() + } + if v2, ok := v.(*_PBLinks); ok { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: cannot assign null into an assembler that's already begun working on recursive structures!") + } + *na.w = *v2 + *na.m = schema.Maybe_Value + return nil + } + if v.Kind() != ld.Kind_List { + return ld.ErrWrongKind{TypeName: "dagpb.PBLinks", MethodName: "AssignNode", AppropriateKind: ld.KindSet_JustList, ActualKind: v.Kind()} + } + itr := v.ListIterator() + for !itr.Done() { + _, v, err := itr.Next() + if err != nil { + return err + } + if err := na.AssembleValue().AssignNode(v); err != nil { + return err + } + } + return na.Finish() +} +func (_PBLinks__Assembler) Prototype() ld.NodePrototype { + return _PBLinks__Prototype{} +} +func (la *_PBLinks__Assembler) valueFinishTidy() bool { + switch la.cm { + case schema.Maybe_Value: + la.va.w = nil + la.cm = schema.Maybe_Absent + la.state = laState_initial + la.va.reset() + return true + default: + return false + } +} +func (la *_PBLinks__Assembler) AssembleValue() ld.NodeAssembler { + switch la.state { + case laState_initial: + // carry on + case laState_midValue: + if !la.valueFinishTidy() { + panic("invalid state: AssembleValue cannot be called when still in the middle of assembling the previous value") + } // if tidy success: carry on + case laState_finished: + panic("invalid state: AssembleValue cannot be called on an assembler that's already finished") + } + la.w.x = append(la.w.x, _PBLink{}) + la.state = laState_midValue + row := &la.w.x[len(la.w.x)-1] + la.va.w = row + la.va.m = &la.cm + return &la.va +} +func (la *_PBLinks__Assembler) Finish() error { + switch la.state { + case laState_initial: + // carry on + case laState_midValue: + if !la.valueFinishTidy() { + panic("invalid state: Finish cannot be called when in the middle of assembling a value") + } // if tidy success: carry on + case laState_finished: + panic("invalid state: Finish cannot be called on an assembler that's already finished") + } + la.state = laState_finished + *la.m = schema.Maybe_Value + return nil +} +func (la *_PBLinks__Assembler) ValuePrototype(_ int64) ld.NodePrototype { + return _PBLink__Prototype{} +} +func (PBLinks) Type() schema.Type { + return nil /*TODO:typelit*/ +} +func (n PBLinks) Representation() ld.Node { + return (*_PBLinks__Repr)(n) +} + +type _PBLinks__Repr _PBLinks + +var _ ld.Node = &_PBLinks__Repr{} + +func (_PBLinks__Repr) Kind() ld.Kind { + return ld.Kind_List +} +func (_PBLinks__Repr) LookupByString(string) (ld.Node, error) { + return mixins.List{TypeName: "dagpb.PBLinks.Repr"}.LookupByString("") +} +func (nr *_PBLinks__Repr) LookupByNode(k ld.Node) (ld.Node, error) { + v, err := (PBLinks)(nr).LookupByNode(k) + if err != nil || v == ld.Null { + return v, err + } + return v.(PBLink).Representation(), nil +} +func (nr *_PBLinks__Repr) LookupByIndex(idx int64) (ld.Node, error) { + v, err := (PBLinks)(nr).LookupByIndex(idx) + if err != nil || v == ld.Null { + return v, err + } + return v.(PBLink).Representation(), nil +} +func (n _PBLinks__Repr) LookupBySegment(seg ld.PathSegment) (ld.Node, error) { + i, err := seg.Index() + if err != nil { + return nil, ld.ErrInvalidSegmentForList{TypeName: "dagpb.PBLinks.Repr", TroubleSegment: seg, Reason: err} + } + return n.LookupByIndex(i) +} +func (_PBLinks__Repr) MapIterator() ld.MapIterator { + return nil +} +func (nr *_PBLinks__Repr) ListIterator() ld.ListIterator { + return &_PBLinks__ReprListItr{(PBLinks)(nr), 0} +} + +type _PBLinks__ReprListItr _PBLinks__ListItr + +func (itr *_PBLinks__ReprListItr) Next() (idx int64, v ld.Node, err error) { + idx, v, err = (*_PBLinks__ListItr)(itr).Next() + if err != nil || v == ld.Null { + return + } + return idx, v.(PBLink).Representation(), nil +} +func (itr *_PBLinks__ReprListItr) Done() bool { + return (*_PBLinks__ListItr)(itr).Done() +} + +func (rn *_PBLinks__Repr) Length() int64 { + return int64(len(rn.x)) +} +func (_PBLinks__Repr) IsAbsent() bool { + return false +} +func (_PBLinks__Repr) IsNull() bool { + return false +} +func (_PBLinks__Repr) AsBool() (bool, error) { + return mixins.List{TypeName: "dagpb.PBLinks.Repr"}.AsBool() +} +func (_PBLinks__Repr) AsInt() (int64, error) { + return mixins.List{TypeName: "dagpb.PBLinks.Repr"}.AsInt() +} +func (_PBLinks__Repr) AsFloat() (float64, error) { + return mixins.List{TypeName: "dagpb.PBLinks.Repr"}.AsFloat() +} +func (_PBLinks__Repr) AsString() (string, error) { + return mixins.List{TypeName: "dagpb.PBLinks.Repr"}.AsString() +} +func (_PBLinks__Repr) AsBytes() ([]byte, error) { + return mixins.List{TypeName: "dagpb.PBLinks.Repr"}.AsBytes() +} +func (_PBLinks__Repr) AsLink() (ld.Link, error) { + return mixins.List{TypeName: "dagpb.PBLinks.Repr"}.AsLink() +} +func (_PBLinks__Repr) Prototype() ld.NodePrototype { + return _PBLinks__ReprPrototype{} +} + +type _PBLinks__ReprPrototype struct{} + +func (_PBLinks__ReprPrototype) NewBuilder() ld.NodeBuilder { + var nb _PBLinks__ReprBuilder + nb.Reset() + return &nb +} + +type _PBLinks__ReprBuilder struct { + _PBLinks__ReprAssembler +} + +func (nb *_PBLinks__ReprBuilder) Build() ld.Node { + if *nb.m != schema.Maybe_Value { + panic("invalid state: cannot call Build on an assembler that's not finished") + } + return nb.w +} +func (nb *_PBLinks__ReprBuilder) Reset() { + var w _PBLinks + var m schema.Maybe + *nb = _PBLinks__ReprBuilder{_PBLinks__ReprAssembler{w: &w, m: &m}} +} + +type _PBLinks__ReprAssembler struct { + w *_PBLinks + m *schema.Maybe + state laState + + cm schema.Maybe + va _PBLink__ReprAssembler +} + +func (na *_PBLinks__ReprAssembler) reset() { + na.state = laState_initial + na.va.reset() +} +func (_PBLinks__ReprAssembler) BeginMap(sizeHint int64) (ld.MapAssembler, error) { + return mixins.ListAssembler{TypeName: "dagpb.PBLinks.Repr"}.BeginMap(0) +} +func (na *_PBLinks__ReprAssembler) BeginList(sizeHint int64) (ld.ListAssembler, error) { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: it makes no sense to 'begin' twice on the same assembler!") + } + *na.m = midvalue + if sizeHint < 0 { + sizeHint = 0 + } + if sizeHint > 0 { + na.w.x = make([]_PBLink, 0, sizeHint) + } + return na, nil +} +func (na *_PBLinks__ReprAssembler) AssignNull() error { + switch *na.m { + case allowNull: + *na.m = schema.Maybe_Null + return nil + case schema.Maybe_Absent: + return mixins.ListAssembler{TypeName: "dagpb.PBLinks.Repr.Repr"}.AssignNull() + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: cannot assign null into an assembler that's already begun working on recursive structures!") + } + panic("unreachable") +} +func (_PBLinks__ReprAssembler) AssignBool(bool) error { + return mixins.ListAssembler{TypeName: "dagpb.PBLinks.Repr"}.AssignBool(false) +} +func (_PBLinks__ReprAssembler) AssignInt(int64) error { + return mixins.ListAssembler{TypeName: "dagpb.PBLinks.Repr"}.AssignInt(0) +} +func (_PBLinks__ReprAssembler) AssignFloat(float64) error { + return mixins.ListAssembler{TypeName: "dagpb.PBLinks.Repr"}.AssignFloat(0) +} +func (_PBLinks__ReprAssembler) AssignString(string) error { + return mixins.ListAssembler{TypeName: "dagpb.PBLinks.Repr"}.AssignString("") +} +func (_PBLinks__ReprAssembler) AssignBytes([]byte) error { + return mixins.ListAssembler{TypeName: "dagpb.PBLinks.Repr"}.AssignBytes(nil) +} +func (_PBLinks__ReprAssembler) AssignLink(ld.Link) error { + return mixins.ListAssembler{TypeName: "dagpb.PBLinks.Repr"}.AssignLink(nil) +} +func (na *_PBLinks__ReprAssembler) AssignNode(v ld.Node) error { + if v.IsNull() { + return na.AssignNull() + } + if v2, ok := v.(*_PBLinks); ok { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: cannot assign null into an assembler that's already begun working on recursive structures!") + } + *na.w = *v2 + *na.m = schema.Maybe_Value + return nil + } + if v.Kind() != ld.Kind_List { + return ld.ErrWrongKind{TypeName: "dagpb.PBLinks.Repr", MethodName: "AssignNode", AppropriateKind: ld.KindSet_JustList, ActualKind: v.Kind()} + } + itr := v.ListIterator() + for !itr.Done() { + _, v, err := itr.Next() + if err != nil { + return err + } + if err := na.AssembleValue().AssignNode(v); err != nil { + return err + } + } + return na.Finish() +} +func (_PBLinks__ReprAssembler) Prototype() ld.NodePrototype { + return _PBLinks__ReprPrototype{} +} +func (la *_PBLinks__ReprAssembler) valueFinishTidy() bool { + switch la.cm { + case schema.Maybe_Value: + la.va.w = nil + la.cm = schema.Maybe_Absent + la.state = laState_initial + la.va.reset() + return true + default: + return false + } +} +func (la *_PBLinks__ReprAssembler) AssembleValue() ld.NodeAssembler { + switch la.state { + case laState_initial: + // carry on + case laState_midValue: + if !la.valueFinishTidy() { + panic("invalid state: AssembleValue cannot be called when still in the middle of assembling the previous value") + } // if tidy success: carry on + case laState_finished: + panic("invalid state: AssembleValue cannot be called on an assembler that's already finished") + } + la.w.x = append(la.w.x, _PBLink{}) + la.state = laState_midValue + row := &la.w.x[len(la.w.x)-1] + la.va.w = row + la.va.m = &la.cm + return &la.va +} +func (la *_PBLinks__ReprAssembler) Finish() error { + switch la.state { + case laState_initial: + // carry on + case laState_midValue: + if !la.valueFinishTidy() { + panic("invalid state: Finish cannot be called when in the middle of assembling a value") + } // if tidy success: carry on + case laState_finished: + panic("invalid state: Finish cannot be called on an assembler that's already finished") + } + la.state = laState_finished + *la.m = schema.Maybe_Value + return nil +} +func (la *_PBLinks__ReprAssembler) ValuePrototype(_ int64) ld.NodePrototype { + return _PBLink__ReprPrototype{} +} + +func (n _PBNode) FieldLinks() PBLinks { + return &n.Links +} +func (n _PBNode) FieldData() MaybeBytes { + return &n.Data +} + +type _PBNode__Maybe struct { + m schema.Maybe + v PBNode +} +type MaybePBNode = *_PBNode__Maybe + +func (m MaybePBNode) IsNull() bool { + return m.m == schema.Maybe_Null +} +func (m MaybePBNode) IsAbsent() bool { + return m.m == schema.Maybe_Absent +} +func (m MaybePBNode) Exists() bool { + return m.m == schema.Maybe_Value +} +func (m MaybePBNode) AsNode() ld.Node { + switch m.m { + case schema.Maybe_Absent: + return ld.Absent + case schema.Maybe_Null: + return ld.Null + case schema.Maybe_Value: + return m.v + default: + panic("unreachable") + } +} +func (m MaybePBNode) Must() PBNode { + if !m.Exists() { + panic("unbox of a maybe rejected") + } + return m.v +} + +var ( + fieldName__PBNode_Links = _String{"Links"} + fieldName__PBNode_Data = _String{"Data"} +) +var _ ld.Node = (PBNode)(&_PBNode{}) +var _ schema.TypedNode = (PBNode)(&_PBNode{}) + +func (PBNode) Kind() ld.Kind { + return ld.Kind_Map +} +func (n PBNode) LookupByString(key string) (ld.Node, error) { + switch key { + case "Links": + return &n.Links, nil + case "Data": + if n.Data.m == schema.Maybe_Absent { + return ld.Absent, nil + } + return &n.Data.v, nil + default: + return nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: ld.PathSegmentOfString(key)} + } +} +func (n PBNode) LookupByNode(key ld.Node) (ld.Node, error) { + ks, err := key.AsString() + if err != nil { + return nil, err + } + return n.LookupByString(ks) +} +func (PBNode) LookupByIndex(idx int64) (ld.Node, error) { + return mixins.Map{TypeName: "dagpb.PBNode"}.LookupByIndex(0) +} +func (n PBNode) LookupBySegment(seg ld.PathSegment) (ld.Node, error) { + return n.LookupByString(seg.String()) +} +func (n PBNode) MapIterator() ld.MapIterator { + return &_PBNode__MapItr{n, 0} +} + +type _PBNode__MapItr struct { + n PBNode + idx int +} + +func (itr *_PBNode__MapItr) Next() (k ld.Node, v ld.Node, _ error) { + if itr.idx >= 2 { + return nil, nil, ld.ErrIteratorOverread{} + } + switch itr.idx { + case 0: + k = &fieldName__PBNode_Links + v = &itr.n.Links + case 1: + k = &fieldName__PBNode_Data + if itr.n.Data.m == schema.Maybe_Absent { + v = ld.Absent + break + } + v = &itr.n.Data.v + default: + panic("unreachable") + } + itr.idx++ + return +} +func (itr *_PBNode__MapItr) Done() bool { + return itr.idx >= 2 +} + +func (PBNode) ListIterator() ld.ListIterator { + return nil +} +func (PBNode) Length() int64 { + return 2 +} +func (PBNode) IsAbsent() bool { + return false +} +func (PBNode) IsNull() bool { + return false +} +func (PBNode) AsBool() (bool, error) { + return mixins.Map{TypeName: "dagpb.PBNode"}.AsBool() +} +func (PBNode) AsInt() (int64, error) { + return mixins.Map{TypeName: "dagpb.PBNode"}.AsInt() +} +func (PBNode) AsFloat() (float64, error) { + return mixins.Map{TypeName: "dagpb.PBNode"}.AsFloat() +} +func (PBNode) AsString() (string, error) { + return mixins.Map{TypeName: "dagpb.PBNode"}.AsString() +} +func (PBNode) AsBytes() ([]byte, error) { + return mixins.Map{TypeName: "dagpb.PBNode"}.AsBytes() +} +func (PBNode) AsLink() (ld.Link, error) { + return mixins.Map{TypeName: "dagpb.PBNode"}.AsLink() +} +func (PBNode) Prototype() ld.NodePrototype { + return _PBNode__Prototype{} +} + +type _PBNode__Prototype struct{} + +func (_PBNode__Prototype) NewBuilder() ld.NodeBuilder { + var nb _PBNode__Builder + nb.Reset() + return &nb +} + +type _PBNode__Builder struct { + _PBNode__Assembler +} + +func (nb *_PBNode__Builder) Build() ld.Node { + if *nb.m != schema.Maybe_Value { + panic("invalid state: cannot call Build on an assembler that's not finished") + } + return nb.w +} +func (nb *_PBNode__Builder) Reset() { + var w _PBNode + var m schema.Maybe + *nb = _PBNode__Builder{_PBNode__Assembler{w: &w, m: &m}} +} + +type _PBNode__Assembler struct { + w *_PBNode + m *schema.Maybe + state maState + s int + f int + + cm schema.Maybe + ca_Links _PBLinks__Assembler + ca_Data _Bytes__Assembler +} + +func (na *_PBNode__Assembler) reset() { + na.state = maState_initial + na.s = 0 + na.ca_Links.reset() + na.ca_Data.reset() +} + +var ( + fieldBit__PBNode_Links = 1 << 0 + fieldBit__PBNode_Data = 1 << 1 + fieldBits__PBNode_sufficient = 0 + 1<<0 +) + +func (na *_PBNode__Assembler) BeginMap(int64) (ld.MapAssembler, error) { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: it makes no sense to 'begin' twice on the same assembler!") + } + *na.m = midvalue + if na.w == nil { + na.w = &_PBNode{} + } + return na, nil +} +func (_PBNode__Assembler) BeginList(sizeHint int64) (ld.ListAssembler, error) { + return mixins.MapAssembler{TypeName: "dagpb.PBNode"}.BeginList(0) +} +func (na *_PBNode__Assembler) AssignNull() error { + switch *na.m { + case allowNull: + *na.m = schema.Maybe_Null + return nil + case schema.Maybe_Absent: + return mixins.MapAssembler{TypeName: "dagpb.PBNode"}.AssignNull() + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: cannot assign null into an assembler that's already begun working on recursive structures!") + } + panic("unreachable") +} +func (_PBNode__Assembler) AssignBool(bool) error { + return mixins.MapAssembler{TypeName: "dagpb.PBNode"}.AssignBool(false) +} +func (_PBNode__Assembler) AssignInt(int64) error { + return mixins.MapAssembler{TypeName: "dagpb.PBNode"}.AssignInt(0) +} +func (_PBNode__Assembler) AssignFloat(float64) error { + return mixins.MapAssembler{TypeName: "dagpb.PBNode"}.AssignFloat(0) +} +func (_PBNode__Assembler) AssignString(string) error { + return mixins.MapAssembler{TypeName: "dagpb.PBNode"}.AssignString("") +} +func (_PBNode__Assembler) AssignBytes([]byte) error { + return mixins.MapAssembler{TypeName: "dagpb.PBNode"}.AssignBytes(nil) +} +func (_PBNode__Assembler) AssignLink(ld.Link) error { + return mixins.MapAssembler{TypeName: "dagpb.PBNode"}.AssignLink(nil) +} +func (na *_PBNode__Assembler) AssignNode(v ld.Node) error { + if v.IsNull() { + return na.AssignNull() + } + if v2, ok := v.(*_PBNode); ok { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: cannot assign null into an assembler that's already begun working on recursive structures!") + } + if na.w == nil { + na.w = v2 + *na.m = schema.Maybe_Value + return nil + } + *na.w = *v2 + *na.m = schema.Maybe_Value + return nil + } + if v.Kind() != ld.Kind_Map { + return ld.ErrWrongKind{TypeName: "dagpb.PBNode", MethodName: "AssignNode", AppropriateKind: ld.KindSet_JustMap, ActualKind: v.Kind()} + } + itr := v.MapIterator() + for !itr.Done() { + k, v, err := itr.Next() + if err != nil { + return err + } + if err := na.AssembleKey().AssignNode(k); err != nil { + return err + } + if err := na.AssembleValue().AssignNode(v); err != nil { + return err + } + } + return na.Finish() +} +func (_PBNode__Assembler) Prototype() ld.NodePrototype { + return _PBNode__Prototype{} +} +func (ma *_PBNode__Assembler) valueFinishTidy() bool { + switch ma.f { + case 0: + switch ma.cm { + case schema.Maybe_Value: + ma.ca_Links.w = nil + ma.cm = schema.Maybe_Absent + ma.state = maState_initial + return true + default: + return false + } + case 1: + switch ma.w.Data.m { + case schema.Maybe_Value: + ma.state = maState_initial + return true + default: + return false + } + default: + panic("unreachable") + } +} +func (ma *_PBNode__Assembler) AssembleEntry(k string) (ld.NodeAssembler, error) { + switch ma.state { + case maState_initial: + // carry on + case maState_midKey: + panic("invalid state: AssembleEntry cannot be called when in the middle of assembling another key") + case maState_expectValue: + panic("invalid state: AssembleEntry cannot be called when expecting start of value assembly") + case maState_midValue: + if !ma.valueFinishTidy() { + panic("invalid state: AssembleEntry cannot be called when in the middle of assembling a value") + } // if tidy success: carry on + case maState_finished: + panic("invalid state: AssembleEntry cannot be called on an assembler that's already finished") + } + switch k { + case "Links": + if ma.s&fieldBit__PBNode_Links != 0 { + return nil, ld.ErrRepeatedMapKey{Key: &fieldName__PBNode_Links} + } + ma.s += fieldBit__PBNode_Links + ma.state = maState_midValue + ma.f = 0 + ma.ca_Links.w = &ma.w.Links + ma.ca_Links.m = &ma.cm + return &ma.ca_Links, nil + case "Data": + if ma.s&fieldBit__PBNode_Data != 0 { + return nil, ld.ErrRepeatedMapKey{Key: &fieldName__PBNode_Data} + } + ma.s += fieldBit__PBNode_Data + ma.state = maState_midValue + ma.f = 1 + ma.ca_Data.w = &ma.w.Data.v + ma.ca_Data.m = &ma.w.Data.m + return &ma.ca_Data, nil + } + return nil, ld.ErrInvalidKey{TypeName: "dagpb.PBNode", Key: &_String{k}} +} +func (ma *_PBNode__Assembler) AssembleKey() ld.NodeAssembler { + switch ma.state { + case maState_initial: + // carry on + case maState_midKey: + panic("invalid state: AssembleKey cannot be called when in the middle of assembling another key") + case maState_expectValue: + panic("invalid state: AssembleKey cannot be called when expecting start of value assembly") + case maState_midValue: + if !ma.valueFinishTidy() { + panic("invalid state: AssembleKey cannot be called when in the middle of assembling a value") + } // if tidy success: carry on + case maState_finished: + panic("invalid state: AssembleKey cannot be called on an assembler that's already finished") + } + ma.state = maState_midKey + return (*_PBNode__KeyAssembler)(ma) +} +func (ma *_PBNode__Assembler) AssembleValue() ld.NodeAssembler { + switch ma.state { + case maState_initial: + panic("invalid state: AssembleValue cannot be called when no key is primed") + case maState_midKey: + panic("invalid state: AssembleValue cannot be called when in the middle of assembling a key") + case maState_expectValue: + // carry on + case maState_midValue: + panic("invalid state: AssembleValue cannot be called when in the middle of assembling another value") + case maState_finished: + panic("invalid state: AssembleValue cannot be called on an assembler that's already finished") + } + ma.state = maState_midValue + switch ma.f { + case 0: + ma.ca_Links.w = &ma.w.Links + ma.ca_Links.m = &ma.cm + return &ma.ca_Links + case 1: + ma.ca_Data.w = &ma.w.Data.v + ma.ca_Data.m = &ma.w.Data.m + return &ma.ca_Data + default: + panic("unreachable") + } +} +func (ma *_PBNode__Assembler) Finish() error { + switch ma.state { + case maState_initial: + // carry on + case maState_midKey: + panic("invalid state: Finish cannot be called when in the middle of assembling a key") + case maState_expectValue: + panic("invalid state: Finish cannot be called when expecting start of value assembly") + case maState_midValue: + if !ma.valueFinishTidy() { + panic("invalid state: Finish cannot be called when in the middle of assembling a value") + } // if tidy success: carry on + case maState_finished: + panic("invalid state: Finish cannot be called on an assembler that's already finished") + } + if ma.s&fieldBits__PBNode_sufficient != fieldBits__PBNode_sufficient { + err := ld.ErrMissingRequiredField{Missing: make([]string, 0)} + if ma.s&fieldBit__PBNode_Links == 0 { + err.Missing = append(err.Missing, "Links") + } + return err + } + ma.state = maState_finished + *ma.m = schema.Maybe_Value + return nil +} +func (ma *_PBNode__Assembler) KeyPrototype() ld.NodePrototype { + return _String__Prototype{} +} +func (ma *_PBNode__Assembler) ValuePrototype(k string) ld.NodePrototype { + panic("todo structbuilder mapassembler valueprototype") +} + +type _PBNode__KeyAssembler _PBNode__Assembler + +func (_PBNode__KeyAssembler) BeginMap(sizeHint int64) (ld.MapAssembler, error) { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.KeyAssembler"}.BeginMap(0) +} +func (_PBNode__KeyAssembler) BeginList(sizeHint int64) (ld.ListAssembler, error) { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.KeyAssembler"}.BeginList(0) +} +func (na *_PBNode__KeyAssembler) AssignNull() error { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.KeyAssembler"}.AssignNull() +} +func (_PBNode__KeyAssembler) AssignBool(bool) error { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.KeyAssembler"}.AssignBool(false) +} +func (_PBNode__KeyAssembler) AssignInt(int64) error { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.KeyAssembler"}.AssignInt(0) +} +func (_PBNode__KeyAssembler) AssignFloat(float64) error { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.KeyAssembler"}.AssignFloat(0) +} +func (ka *_PBNode__KeyAssembler) AssignString(k string) error { + if ka.state != maState_midKey { + panic("misuse: KeyAssembler held beyond its valid lifetime") + } + switch k { + case "Links": + if ka.s&fieldBit__PBNode_Links != 0 { + return ld.ErrRepeatedMapKey{Key: &fieldName__PBNode_Links} + } + ka.s += fieldBit__PBNode_Links + ka.state = maState_expectValue + ka.f = 0 + return nil + case "Data": + if ka.s&fieldBit__PBNode_Data != 0 { + return ld.ErrRepeatedMapKey{Key: &fieldName__PBNode_Data} + } + ka.s += fieldBit__PBNode_Data + ka.state = maState_expectValue + ka.f = 1 + return nil + default: + return ld.ErrInvalidKey{TypeName: "dagpb.PBNode", Key: &_String{k}} + } +} +func (_PBNode__KeyAssembler) AssignBytes([]byte) error { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.KeyAssembler"}.AssignBytes(nil) +} +func (_PBNode__KeyAssembler) AssignLink(ld.Link) error { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.KeyAssembler"}.AssignLink(nil) +} +func (ka *_PBNode__KeyAssembler) AssignNode(v ld.Node) error { + if v2, err := v.AsString(); err != nil { + return err + } else { + return ka.AssignString(v2) + } +} +func (_PBNode__KeyAssembler) Prototype() ld.NodePrototype { + return _String__Prototype{} +} +func (PBNode) Type() schema.Type { + return nil /*TODO:typelit*/ +} +func (n PBNode) Representation() ld.Node { + return (*_PBNode__Repr)(n) +} + +type _PBNode__Repr _PBNode + +var ( + fieldName__PBNode_Links_serial = _String{"Links"} + fieldName__PBNode_Data_serial = _String{"Data"} +) +var _ ld.Node = &_PBNode__Repr{} + +func (_PBNode__Repr) Kind() ld.Kind { + return ld.Kind_Map +} +func (n *_PBNode__Repr) LookupByString(key string) (ld.Node, error) { + switch key { + case "Links": + return n.Links.Representation(), nil + case "Data": + if n.Data.m == schema.Maybe_Absent { + return ld.Absent, ld.ErrNotExists{Segment: ld.PathSegmentOfString(key)} + } + return n.Data.v.Representation(), nil + default: + return nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: ld.PathSegmentOfString(key)} + } +} +func (n *_PBNode__Repr) LookupByNode(key ld.Node) (ld.Node, error) { + ks, err := key.AsString() + if err != nil { + return nil, err + } + return n.LookupByString(ks) +} +func (_PBNode__Repr) LookupByIndex(idx int64) (ld.Node, error) { + return mixins.Map{TypeName: "dagpb.PBNode.Repr"}.LookupByIndex(0) +} +func (n _PBNode__Repr) LookupBySegment(seg ld.PathSegment) (ld.Node, error) { + return n.LookupByString(seg.String()) +} +func (n *_PBNode__Repr) MapIterator() ld.MapIterator { + end := 2 + if n.Data.m == schema.Maybe_Absent { + end = 1 + } else { + goto done + } +done: + return &_PBNode__ReprMapItr{n, 0, end} +} + +type _PBNode__ReprMapItr struct { + n *_PBNode__Repr + idx int + end int +} + +func (itr *_PBNode__ReprMapItr) Next() (k ld.Node, v ld.Node, _ error) { +advance: + if itr.idx >= 2 { + return nil, nil, ld.ErrIteratorOverread{} + } + switch itr.idx { + case 0: + k = &fieldName__PBNode_Links_serial + v = itr.n.Links.Representation() + case 1: + k = &fieldName__PBNode_Data_serial + if itr.n.Data.m == schema.Maybe_Absent { + itr.idx++ + goto advance + } + v = itr.n.Data.v.Representation() + default: + panic("unreachable") + } + itr.idx++ + return +} +func (itr *_PBNode__ReprMapItr) Done() bool { + return itr.idx >= itr.end +} +func (_PBNode__Repr) ListIterator() ld.ListIterator { + return nil +} +func (rn *_PBNode__Repr) Length() int64 { + l := 2 + if rn.Data.m == schema.Maybe_Absent { + l-- + } + return int64(l) +} +func (_PBNode__Repr) IsAbsent() bool { + return false +} +func (_PBNode__Repr) IsNull() bool { + return false +} +func (_PBNode__Repr) AsBool() (bool, error) { + return mixins.Map{TypeName: "dagpb.PBNode.Repr"}.AsBool() +} +func (_PBNode__Repr) AsInt() (int64, error) { + return mixins.Map{TypeName: "dagpb.PBNode.Repr"}.AsInt() +} +func (_PBNode__Repr) AsFloat() (float64, error) { + return mixins.Map{TypeName: "dagpb.PBNode.Repr"}.AsFloat() +} +func (_PBNode__Repr) AsString() (string, error) { + return mixins.Map{TypeName: "dagpb.PBNode.Repr"}.AsString() +} +func (_PBNode__Repr) AsBytes() ([]byte, error) { + return mixins.Map{TypeName: "dagpb.PBNode.Repr"}.AsBytes() +} +func (_PBNode__Repr) AsLink() (ld.Link, error) { + return mixins.Map{TypeName: "dagpb.PBNode.Repr"}.AsLink() +} +func (_PBNode__Repr) Prototype() ld.NodePrototype { + return _PBNode__ReprPrototype{} +} + +type _PBNode__ReprPrototype struct{} + +func (_PBNode__ReprPrototype) NewBuilder() ld.NodeBuilder { + var nb _PBNode__ReprBuilder + nb.Reset() + return &nb +} + +type _PBNode__ReprBuilder struct { + _PBNode__ReprAssembler +} + +func (nb *_PBNode__ReprBuilder) Build() ld.Node { + if *nb.m != schema.Maybe_Value { + panic("invalid state: cannot call Build on an assembler that's not finished") + } + return nb.w +} +func (nb *_PBNode__ReprBuilder) Reset() { + var w _PBNode + var m schema.Maybe + *nb = _PBNode__ReprBuilder{_PBNode__ReprAssembler{w: &w, m: &m}} +} + +type _PBNode__ReprAssembler struct { + w *_PBNode + m *schema.Maybe + state maState + s int + f int + + cm schema.Maybe + ca_Links _PBLinks__ReprAssembler + ca_Data _Bytes__ReprAssembler +} + +func (na *_PBNode__ReprAssembler) reset() { + na.state = maState_initial + na.s = 0 + na.ca_Links.reset() + na.ca_Data.reset() +} +func (na *_PBNode__ReprAssembler) BeginMap(int64) (ld.MapAssembler, error) { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: it makes no sense to 'begin' twice on the same assembler!") + } + *na.m = midvalue + if na.w == nil { + na.w = &_PBNode{} + } + return na, nil +} +func (_PBNode__ReprAssembler) BeginList(sizeHint int64) (ld.ListAssembler, error) { + return mixins.MapAssembler{TypeName: "dagpb.PBNode.Repr"}.BeginList(0) +} +func (na *_PBNode__ReprAssembler) AssignNull() error { + switch *na.m { + case allowNull: + *na.m = schema.Maybe_Null + return nil + case schema.Maybe_Absent: + return mixins.MapAssembler{TypeName: "dagpb.PBNode.Repr.Repr"}.AssignNull() + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: cannot assign null into an assembler that's already begun working on recursive structures!") + } + panic("unreachable") +} +func (_PBNode__ReprAssembler) AssignBool(bool) error { + return mixins.MapAssembler{TypeName: "dagpb.PBNode.Repr"}.AssignBool(false) +} +func (_PBNode__ReprAssembler) AssignInt(int64) error { + return mixins.MapAssembler{TypeName: "dagpb.PBNode.Repr"}.AssignInt(0) +} +func (_PBNode__ReprAssembler) AssignFloat(float64) error { + return mixins.MapAssembler{TypeName: "dagpb.PBNode.Repr"}.AssignFloat(0) +} +func (_PBNode__ReprAssembler) AssignString(string) error { + return mixins.MapAssembler{TypeName: "dagpb.PBNode.Repr"}.AssignString("") +} +func (_PBNode__ReprAssembler) AssignBytes([]byte) error { + return mixins.MapAssembler{TypeName: "dagpb.PBNode.Repr"}.AssignBytes(nil) +} +func (_PBNode__ReprAssembler) AssignLink(ld.Link) error { + return mixins.MapAssembler{TypeName: "dagpb.PBNode.Repr"}.AssignLink(nil) +} +func (na *_PBNode__ReprAssembler) AssignNode(v ld.Node) error { + if v.IsNull() { + return na.AssignNull() + } + if v2, ok := v.(*_PBNode); ok { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + case midvalue: + panic("invalid state: cannot assign null into an assembler that's already begun working on recursive structures!") + } + if na.w == nil { + na.w = v2 + *na.m = schema.Maybe_Value + return nil + } + *na.w = *v2 + *na.m = schema.Maybe_Value + return nil + } + if v.Kind() != ld.Kind_Map { + return ld.ErrWrongKind{TypeName: "dagpb.PBNode.Repr", MethodName: "AssignNode", AppropriateKind: ld.KindSet_JustMap, ActualKind: v.Kind()} + } + itr := v.MapIterator() + for !itr.Done() { + k, v, err := itr.Next() + if err != nil { + return err + } + if err := na.AssembleKey().AssignNode(k); err != nil { + return err + } + if err := na.AssembleValue().AssignNode(v); err != nil { + return err + } + } + return na.Finish() +} +func (_PBNode__ReprAssembler) Prototype() ld.NodePrototype { + return _PBNode__ReprPrototype{} +} +func (ma *_PBNode__ReprAssembler) valueFinishTidy() bool { + switch ma.f { + case 0: + switch ma.cm { + case schema.Maybe_Value: + ma.cm = schema.Maybe_Absent + ma.state = maState_initial + return true + default: + return false + } + case 1: + switch ma.w.Data.m { + case schema.Maybe_Value: + ma.state = maState_initial + return true + default: + return false + } + default: + panic("unreachable") + } +} +func (ma *_PBNode__ReprAssembler) AssembleEntry(k string) (ld.NodeAssembler, error) { + switch ma.state { + case maState_initial: + // carry on + case maState_midKey: + panic("invalid state: AssembleEntry cannot be called when in the middle of assembling another key") + case maState_expectValue: + panic("invalid state: AssembleEntry cannot be called when expecting start of value assembly") + case maState_midValue: + if !ma.valueFinishTidy() { + panic("invalid state: AssembleEntry cannot be called when in the middle of assembling a value") + } // if tidy success: carry on + case maState_finished: + panic("invalid state: AssembleEntry cannot be called on an assembler that's already finished") + } + switch k { + case "Links": + if ma.s&fieldBit__PBNode_Links != 0 { + return nil, ld.ErrRepeatedMapKey{Key: &fieldName__PBNode_Links_serial} + } + ma.s += fieldBit__PBNode_Links + ma.state = maState_midValue + ma.f = 0 + ma.ca_Links.w = &ma.w.Links + ma.ca_Links.m = &ma.cm + return &ma.ca_Links, nil + case "Data": + if ma.s&fieldBit__PBNode_Data != 0 { + return nil, ld.ErrRepeatedMapKey{Key: &fieldName__PBNode_Data_serial} + } + ma.s += fieldBit__PBNode_Data + ma.state = maState_midValue + ma.f = 1 + ma.ca_Data.w = &ma.w.Data.v + ma.ca_Data.m = &ma.w.Data.m + + return &ma.ca_Data, nil + default: + } + return nil, ld.ErrInvalidKey{TypeName: "dagpb.PBNode.Repr", Key: &_String{k}} +} +func (ma *_PBNode__ReprAssembler) AssembleKey() ld.NodeAssembler { + switch ma.state { + case maState_initial: + // carry on + case maState_midKey: + panic("invalid state: AssembleKey cannot be called when in the middle of assembling another key") + case maState_expectValue: + panic("invalid state: AssembleKey cannot be called when expecting start of value assembly") + case maState_midValue: + if !ma.valueFinishTidy() { + panic("invalid state: AssembleKey cannot be called when in the middle of assembling a value") + } // if tidy success: carry on + case maState_finished: + panic("invalid state: AssembleKey cannot be called on an assembler that's already finished") + } + ma.state = maState_midKey + return (*_PBNode__ReprKeyAssembler)(ma) +} +func (ma *_PBNode__ReprAssembler) AssembleValue() ld.NodeAssembler { + switch ma.state { + case maState_initial: + panic("invalid state: AssembleValue cannot be called when no key is primed") + case maState_midKey: + panic("invalid state: AssembleValue cannot be called when in the middle of assembling a key") + case maState_expectValue: + // carry on + case maState_midValue: + panic("invalid state: AssembleValue cannot be called when in the middle of assembling another value") + case maState_finished: + panic("invalid state: AssembleValue cannot be called on an assembler that's already finished") + } + ma.state = maState_midValue + switch ma.f { + case 0: + ma.ca_Links.w = &ma.w.Links + ma.ca_Links.m = &ma.cm + return &ma.ca_Links + case 1: + ma.ca_Data.w = &ma.w.Data.v + ma.ca_Data.m = &ma.w.Data.m + + return &ma.ca_Data + default: + panic("unreachable") + } +} +func (ma *_PBNode__ReprAssembler) Finish() error { + switch ma.state { + case maState_initial: + // carry on + case maState_midKey: + panic("invalid state: Finish cannot be called when in the middle of assembling a key") + case maState_expectValue: + panic("invalid state: Finish cannot be called when expecting start of value assembly") + case maState_midValue: + if !ma.valueFinishTidy() { + panic("invalid state: Finish cannot be called when in the middle of assembling a value") + } // if tidy success: carry on + case maState_finished: + panic("invalid state: Finish cannot be called on an assembler that's already finished") + } + if ma.s&fieldBits__PBNode_sufficient != fieldBits__PBNode_sufficient { + err := ld.ErrMissingRequiredField{Missing: make([]string, 0)} + if ma.s&fieldBit__PBNode_Links == 0 { + err.Missing = append(err.Missing, "Links") + } + return err + } + ma.state = maState_finished + *ma.m = schema.Maybe_Value + return nil +} +func (ma *_PBNode__ReprAssembler) KeyPrototype() ld.NodePrototype { + return _String__Prototype{} +} +func (ma *_PBNode__ReprAssembler) ValuePrototype(k string) ld.NodePrototype { + panic("todo structbuilder mapassembler repr valueprototype") +} + +type _PBNode__ReprKeyAssembler _PBNode__ReprAssembler + +func (_PBNode__ReprKeyAssembler) BeginMap(sizeHint int64) (ld.MapAssembler, error) { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.Repr.KeyAssembler"}.BeginMap(0) +} +func (_PBNode__ReprKeyAssembler) BeginList(sizeHint int64) (ld.ListAssembler, error) { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.Repr.KeyAssembler"}.BeginList(0) +} +func (na *_PBNode__ReprKeyAssembler) AssignNull() error { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.Repr.KeyAssembler"}.AssignNull() +} +func (_PBNode__ReprKeyAssembler) AssignBool(bool) error { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.Repr.KeyAssembler"}.AssignBool(false) +} +func (_PBNode__ReprKeyAssembler) AssignInt(int64) error { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.Repr.KeyAssembler"}.AssignInt(0) +} +func (_PBNode__ReprKeyAssembler) AssignFloat(float64) error { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.Repr.KeyAssembler"}.AssignFloat(0) +} +func (ka *_PBNode__ReprKeyAssembler) AssignString(k string) error { + if ka.state != maState_midKey { + panic("misuse: KeyAssembler held beyond its valid lifetime") + } + switch k { + case "Links": + if ka.s&fieldBit__PBNode_Links != 0 { + return ld.ErrRepeatedMapKey{Key: &fieldName__PBNode_Links_serial} + } + ka.s += fieldBit__PBNode_Links + ka.state = maState_expectValue + ka.f = 0 + return nil + case "Data": + if ka.s&fieldBit__PBNode_Data != 0 { + return ld.ErrRepeatedMapKey{Key: &fieldName__PBNode_Data_serial} + } + ka.s += fieldBit__PBNode_Data + ka.state = maState_expectValue + ka.f = 1 + return nil + } + return ld.ErrInvalidKey{TypeName: "dagpb.PBNode.Repr", Key: &_String{k}} +} +func (_PBNode__ReprKeyAssembler) AssignBytes([]byte) error { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.Repr.KeyAssembler"}.AssignBytes(nil) +} +func (_PBNode__ReprKeyAssembler) AssignLink(ld.Link) error { + return mixins.StringAssembler{TypeName: "dagpb.PBNode.Repr.KeyAssembler"}.AssignLink(nil) +} +func (ka *_PBNode__ReprKeyAssembler) AssignNode(v ld.Node) error { + if v2, err := v.AsString(); err != nil { + return err + } else { + return ka.AssignString(v2) + } +} +func (_PBNode__ReprKeyAssembler) Prototype() ld.NodePrototype { + return _String__Prototype{} +} + +func (n String) String() string { + return n.x +} +func (_String__Prototype) fromString(w *_String, v string) error { + *w = _String{v} + return nil +} +func (_String__Prototype) FromString(v string) (String, error) { + n := _String{v} + return &n, nil +} + +type _String__Maybe struct { + m schema.Maybe + v _String +} +type MaybeString = *_String__Maybe + +func (m MaybeString) IsNull() bool { + return m.m == schema.Maybe_Null +} +func (m MaybeString) IsAbsent() bool { + return m.m == schema.Maybe_Absent +} +func (m MaybeString) Exists() bool { + return m.m == schema.Maybe_Value +} +func (m MaybeString) AsNode() ld.Node { + switch m.m { + case schema.Maybe_Absent: + return ld.Absent + case schema.Maybe_Null: + return ld.Null + case schema.Maybe_Value: + return &m.v + default: + panic("unreachable") + } +} +func (m MaybeString) Must() String { + if !m.Exists() { + panic("unbox of a maybe rejected") + } + return &m.v +} + +var _ ld.Node = (String)(&_String{}) +var _ schema.TypedNode = (String)(&_String{}) + +func (String) Kind() ld.Kind { + return ld.Kind_String +} +func (String) LookupByString(string) (ld.Node, error) { + return mixins.String{TypeName: "dagpb.String"}.LookupByString("") +} +func (String) LookupByNode(ld.Node) (ld.Node, error) { + return mixins.String{TypeName: "dagpb.String"}.LookupByNode(nil) +} +func (String) LookupByIndex(idx int64) (ld.Node, error) { + return mixins.String{TypeName: "dagpb.String"}.LookupByIndex(0) +} +func (String) LookupBySegment(seg ld.PathSegment) (ld.Node, error) { + return mixins.String{TypeName: "dagpb.String"}.LookupBySegment(seg) +} +func (String) MapIterator() ld.MapIterator { + return nil +} +func (String) ListIterator() ld.ListIterator { + return nil +} +func (String) Length() int64 { + return -1 +} +func (String) IsAbsent() bool { + return false +} +func (String) IsNull() bool { + return false +} +func (String) AsBool() (bool, error) { + return mixins.String{TypeName: "dagpb.String"}.AsBool() +} +func (String) AsInt() (int64, error) { + return mixins.String{TypeName: "dagpb.String"}.AsInt() +} +func (String) AsFloat() (float64, error) { + return mixins.String{TypeName: "dagpb.String"}.AsFloat() +} +func (n String) AsString() (string, error) { + return n.x, nil +} +func (String) AsBytes() ([]byte, error) { + return mixins.String{TypeName: "dagpb.String"}.AsBytes() +} +func (String) AsLink() (ld.Link, error) { + return mixins.String{TypeName: "dagpb.String"}.AsLink() +} +func (String) Prototype() ld.NodePrototype { + return _String__Prototype{} +} + +type _String__Prototype struct{} + +func (_String__Prototype) NewBuilder() ld.NodeBuilder { + var nb _String__Builder + nb.Reset() + return &nb +} + +type _String__Builder struct { + _String__Assembler +} + +func (nb *_String__Builder) Build() ld.Node { + if *nb.m != schema.Maybe_Value { + panic("invalid state: cannot call Build on an assembler that's not finished") + } + return nb.w +} +func (nb *_String__Builder) Reset() { + var w _String + var m schema.Maybe + *nb = _String__Builder{_String__Assembler{w: &w, m: &m}} +} + +type _String__Assembler struct { + w *_String + m *schema.Maybe +} + +func (na *_String__Assembler) reset() {} +func (_String__Assembler) BeginMap(sizeHint int64) (ld.MapAssembler, error) { + return mixins.StringAssembler{TypeName: "dagpb.String"}.BeginMap(0) +} +func (_String__Assembler) BeginList(sizeHint int64) (ld.ListAssembler, error) { + return mixins.StringAssembler{TypeName: "dagpb.String"}.BeginList(0) +} +func (na *_String__Assembler) AssignNull() error { + switch *na.m { + case allowNull: + *na.m = schema.Maybe_Null + return nil + case schema.Maybe_Absent: + return mixins.StringAssembler{TypeName: "dagpb.String"}.AssignNull() + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + } + panic("unreachable") +} +func (_String__Assembler) AssignBool(bool) error { + return mixins.StringAssembler{TypeName: "dagpb.String"}.AssignBool(false) +} +func (_String__Assembler) AssignInt(int64) error { + return mixins.StringAssembler{TypeName: "dagpb.String"}.AssignInt(0) +} +func (_String__Assembler) AssignFloat(float64) error { + return mixins.StringAssembler{TypeName: "dagpb.String"}.AssignFloat(0) +} +func (na *_String__Assembler) AssignString(v string) error { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + } + na.w.x = v + *na.m = schema.Maybe_Value + return nil +} +func (_String__Assembler) AssignBytes([]byte) error { + return mixins.StringAssembler{TypeName: "dagpb.String"}.AssignBytes(nil) +} +func (_String__Assembler) AssignLink(ld.Link) error { + return mixins.StringAssembler{TypeName: "dagpb.String"}.AssignLink(nil) +} +func (na *_String__Assembler) AssignNode(v ld.Node) error { + if v.IsNull() { + return na.AssignNull() + } + if v2, ok := v.(*_String); ok { + switch *na.m { + case schema.Maybe_Value, schema.Maybe_Null: + panic("invalid state: cannot assign into assembler that's already finished") + } + *na.w = *v2 + *na.m = schema.Maybe_Value + return nil + } + if v2, err := v.AsString(); err != nil { + return err + } else { + return na.AssignString(v2) + } +} +func (_String__Assembler) Prototype() ld.NodePrototype { + return _String__Prototype{} +} +func (String) Type() schema.Type { + return nil /*TODO:typelit*/ +} +func (n String) Representation() ld.Node { + return (*_String__Repr)(n) +} + +type _String__Repr = _String + +var _ ld.Node = &_String__Repr{} + +type _String__ReprPrototype = _String__Prototype +type _String__ReprAssembler = _String__Assembler diff --git a/ldsch_types.go b/ldsch_types.go new file mode 100644 index 0000000000000000000000000000000000000000..87ef681af507020c4e6845e2e65855a40af0b1fd --- /dev/null +++ b/ldsch_types.go @@ -0,0 +1,76 @@ +package dagpb + +// Code generated by go-ld-prime gengo. DO NOT EDIT. + +import ( + ld "gitlab.dms3.io/ld/go-ld-prime" +) + +var _ ld.Node = nil // suppress errors when this dependency is not referenced +// Type is a struct embeding a NodePrototype/Type for every Node implementation in this package. +// One of its major uses is to start the construction of a value. +// You can use it like this: +// +// dagpb.Type.YourTypeName.NewBuilder().BeginMap() //... +// +// and: +// +// dagpb.Type.OtherTypeName.NewBuilder().AssignString("x") // ... +// +var Type typeSlab + +type typeSlab struct { + Bytes _Bytes__Prototype + Bytes__Repr _Bytes__ReprPrototype + Int _Int__Prototype + Int__Repr _Int__ReprPrototype + Link _Link__Prototype + Link__Repr _Link__ReprPrototype + PBLink _PBLink__Prototype + PBLink__Repr _PBLink__ReprPrototype + PBLinks _PBLinks__Prototype + PBLinks__Repr _PBLinks__ReprPrototype + PBNode _PBNode__Prototype + PBNode__Repr _PBNode__ReprPrototype + String _String__Prototype + String__Repr _String__ReprPrototype +} + +// --- type definitions follow --- + +// Bytes matches the LD Schema type "Bytes". It has bytes kind. +type Bytes = *_Bytes +type _Bytes struct{ x []byte } + +// Int matches the LD Schema type "Int". It has int kind. +type Int = *_Int +type _Int struct{ x int64 } + +// Link matches the LD Schema type "Link". It has link kind. +type Link = *_Link +type _Link struct{ x ld.Link } + +// PBLink matches the LD Schema type "PBLink". It has Struct type-kind, and may be interrogated like map kind. +type PBLink = *_PBLink +type _PBLink struct { + Hash _Link + Name _String__Maybe + Tsize _Int__Maybe +} + +// PBLinks matches the LD Schema type "PBLinks". It has list kind. +type PBLinks = *_PBLinks +type _PBLinks struct { + x []_PBLink +} + +// PBNode matches the LD Schema type "PBNode". It has Struct type-kind, and may be interrogated like map kind. +type PBNode = *_PBNode +type _PBNode struct { + Links _PBLinks + Data _Bytes__Maybe +} + +// String matches the LD Schema type "String". It has string kind. +type String = *_String +type _String struct{ x string } diff --git a/marshal.go b/marshal.go new file mode 100644 index 0000000000000000000000000000000000000000..b79b409a81170da8fc041dcc53f4d230bde5e62e --- /dev/null +++ b/marshal.go @@ -0,0 +1,184 @@ +package dagpb + +import ( + "fmt" + "io" + "sort" + + "gitlab.dms3.io/dms3/go-cid" + ld "gitlab.dms3.io/ld/go-ld-prime" + cidlink "gitlab.dms3.io/ld/go-ld-prime/linking/cid" + "google.golang.org/protobuf/encoding/protowire" +) + +type pbLink struct { + hash cid.Cid + name string + hasName bool + tsize uint64 + hasTsize bool +} + +// Encode provides an LD codec encode interface for DAG-PB data. Provide a +// conforming Node and a destination for bytes to marshal a DAG-PB LD Node. +// The Node must strictly conform to the DAG-PB schema +// (https://gitlab.dms3.io/ld/specs/blob/master/block-layer/codecs/dag-pb.md). +// For safest use, build Nodes using the Type.PBNode type. +// This function is registered via the go-ld-prime link loader for multicodec +// code 0x70 when this package is invoked via init. +func Encode(node ld.Node, w io.Writer) error { + // 1KiB can be allocated on the stack, and covers most small nodes + // without having to grow the buffer and cause allocations. + enc := make([]byte, 0, 1024) + + enc, err := AppendEncode(enc, node) + if err != nil { + return err + } + _, err = w.Write(enc) + return err +} + +// AppendEncode is like Encode, but it uses a destination buffer directly. +// This means less copying of bytes, and if the destination has enough capacity, +// fewer allocations. +func AppendEncode(enc []byte, inNode ld.Node) ([]byte, error) { + // Wrap in a typed node for some basic schema form checking + builder := Type.PBNode.NewBuilder() + if err := builder.AssignNode(inNode); err != nil { + return enc, err + } + node := builder.Build() + + links, err := node.LookupByString("Links") + if err != nil { + return enc, err + } + + if links.Length() > 0 { + // collect links into a slice so we can properly sort for encoding + pbLinks := make([]pbLink, links.Length()) + + linksIter := links.ListIterator() + for !linksIter.Done() { + ii, link, err := linksIter.Next() + if err != nil { + return enc, err + } + + { // Hash (required) + d, err := link.LookupByString("Hash") + if err != nil { + return enc, err + } + l, err := d.AsLink() + if err != nil { + return enc, err + } + if err != nil { + return enc, err + } + cl, ok := l.(cidlink.Link) + if !ok { + // this _should_ be taken care of by the Typed conversion above with + // "missing required fields: Hash" + return enc, fmt.Errorf("invalid DAG-PB form (link must have a Hash)") + } + pbLinks[ii].hash = cl.Cid + } + + { // Name (optional) + nameNode, err := link.LookupByString("Name") + if err != nil { + return enc, err + } + if !nameNode.IsAbsent() { + name, err := nameNode.AsString() + if err != nil { + return enc, err + } + pbLinks[ii].name = name + pbLinks[ii].hasName = true + } + } + + { // Tsize (optional) + tsizeNode, err := link.LookupByString("Tsize") + if err != nil { + return enc, err + } + if !tsizeNode.IsAbsent() { + tsize, err := tsizeNode.AsInt() + if err != nil { + return enc, err + } + if tsize < 0 { + return enc, fmt.Errorf("Link has negative Tsize value [%v]", tsize) + } + utsize := uint64(tsize) + pbLinks[ii].tsize = utsize + pbLinks[ii].hasTsize = true + } + } + } // for + + // links must be strictly sorted by Name before encoding, leaving stable + // ordering where the names are the same (or absent) + sort.Stable(pbLinkSlice(pbLinks)) + for _, link := range pbLinks { + hash := link.hash.Bytes() + + size := 0 + size += protowire.SizeTag(2) + size += protowire.SizeBytes(len(hash)) + if link.hasName { + size += protowire.SizeTag(2) + size += protowire.SizeBytes(len(link.name)) + } + if link.hasTsize { + size += protowire.SizeTag(3) + size += protowire.SizeVarint(uint64(link.tsize)) + } + + enc = protowire.AppendTag(enc, 2, 2) // field & wire type for Links + enc = protowire.AppendVarint(enc, uint64(size)) + + enc = protowire.AppendTag(enc, 1, 2) // field & wire type for Hash + enc = protowire.AppendBytes(enc, hash) + if link.hasName { + enc = protowire.AppendTag(enc, 2, 2) // field & wire type for Name + enc = protowire.AppendString(enc, link.name) + } + if link.hasTsize { + enc = protowire.AppendTag(enc, 3, 0) // field & wire type for Tsize + enc = protowire.AppendVarint(enc, uint64(link.tsize)) + } + } + } // if links + + // Data (optional) + data, err := node.LookupByString("Data") + if err != nil { + return enc, err + } + if !data.IsAbsent() { + byts, err := data.AsBytes() + if err != nil { + return enc, err + } + enc = protowire.AppendTag(enc, 1, 2) // field & wire type for Data + enc = protowire.AppendBytes(enc, byts) + } + + return enc, err +} + +type pbLinkSlice []pbLink + +func (ls pbLinkSlice) Len() int { return len(ls) } +func (ls pbLinkSlice) Swap(a, b int) { ls[a], ls[b] = ls[b], ls[a] } +func (ls pbLinkSlice) Less(a, b int) bool { return pbLinkLess(ls[a], ls[b]) } + +func pbLinkLess(a pbLink, b pbLink) bool { + return a.name < b.name +} diff --git a/multicodec.go b/multicodec.go new file mode 100644 index 0000000000000000000000000000000000000000..a6e7897d6a97432e356ddaa1bdf3d8b90f0054b6 --- /dev/null +++ b/multicodec.go @@ -0,0 +1,48 @@ +package dagpb + +import ( + "io" + + ld "gitlab.dms3.io/ld/go-ld-prime" + cidlink "gitlab.dms3.io/ld/go-ld-prime/linking/cid" + "gitlab.dms3.io/ld/go-ld-prime/multicodec" + "gitlab.dms3.io/ld/go-ld-prime/traversal" +) + +var ( + _ ld.Decoder = Decode + _ ld.Encoder = Encode +) + +func init() { + multicodec.RegisterDecoder(0x70, Decode) + multicodec.RegisterEncoder(0x70, Encode) +} + +// AddSupportToChooser takes an existing node prototype chooser and subs in +// PBNode for the dag-pb multicodec code. +func AddSupportToChooser(existing traversal.LinkTargetNodePrototypeChooser) traversal.LinkTargetNodePrototypeChooser { + return func(lnk ld.Link, lnkCtx ld.LinkContext) (ld.NodePrototype, error) { + if lnk, ok := lnk.(cidlink.Link); ok && lnk.Cid.Prefix().Codec == 0x70 { + return Type.PBNode, nil + } + return existing(lnk, lnkCtx) + } +} + +// We switched to simpler API names after v1.0.0, so keep the old names around +// as deprecated forwarding funcs until a future v2+. +// TODO: consider deprecating Marshal/Unmarshal too, since it's a bit +// unnecessary to have two supported names for each API. + +// Deprecated: use Decode instead. +func Decoder(na ld.NodeAssembler, r io.Reader) error { return Decode(na, r) } + +// Deprecated: use Decode instead. +func Unmarshal(na ld.NodeAssembler, r io.Reader) error { return Decode(na, r) } + +// Deprecated: use Encode instead. +func Encoder(inNode ld.Node, w io.Writer) error { return Encode(inNode, w) } + +// Deprecated: use Encode instead. +func Marshal(inNode ld.Node, w io.Writer) error { return Encode(inNode, w) } diff --git a/unmarshal.go b/unmarshal.go new file mode 100644 index 0000000000000000000000000000000000000000..229ce6620bf248fcdb4978b1168cea8175a1a491 --- /dev/null +++ b/unmarshal.go @@ -0,0 +1,268 @@ +package dagpb + +import ( + "fmt" + "io" + "io/ioutil" + + "gitlab.dms3.io/dms3/go-cid" + ld "gitlab.dms3.io/ld/go-ld-prime" + cidlink "gitlab.dms3.io/ld/go-ld-prime/linking/cid" + "google.golang.org/protobuf/encoding/protowire" +) + +// ErrIntOverflow is returned a varint overflows during decode, it indicates +// malformed data +var ErrIntOverflow = fmt.Errorf("protobuf: varint overflow") + +// Decode provides an LD codec decode interface for DAG-PB data. Provide a +// compatible NodeAssembler and a byte source to unmarshal a DAG-PB LD Node. +// Use the NodeAssembler from the PBNode type for safest construction +// (Type.PBNode.NewBuilder()). A Map assembler will also work. +// This function is registered via the go-ld-prime link loader for multicodec +// code 0x70 when this package is invoked via init. +func Decode(na ld.NodeAssembler, in io.Reader) error { + var src []byte + if buf, ok := in.(interface{ Bytes() []byte }); ok { + src = buf.Bytes() + } else { + var err error + src, err = ioutil.ReadAll(in) + if err != nil { + return err + } + } + return DecodeBytes(na, src) +} + +// DecodeBytes is like Decode, but it uses an input buffer directly. +// Decode will grab or read all the bytes from an io.Reader anyway, so this can +// save having to copy the bytes or create a bytes.Buffer. +func DecodeBytes(na ld.NodeAssembler, src []byte) error { + remaining := src + + ma, err := na.BeginMap(2) + if err != nil { + return err + } + var links ld.ListAssembler + + haveData := false + haveLinks := false + for { + if len(remaining) == 0 { + break + } + + fieldNum, wireType, n := protowire.ConsumeTag(remaining) + if n < 0 { + return protowire.ParseError(n) + } + remaining = remaining[n:] + + if wireType != 2 { + return fmt.Errorf("protobuf: (PBNode) invalid wireType, expected 2, got %d", wireType) + } + + // Note that we allow Data and Links to come in either order, + // since the spec defines that decoding "should" accept either form. + // This is for backwards compatibility with older dms3 data. + + switch fieldNum { + case 1: + if haveData { + return fmt.Errorf("protobuf: (PBNode) duplicate Data section") + } + + chunk, n := protowire.ConsumeBytes(remaining) + if n < 0 { + return protowire.ParseError(n) + } + remaining = remaining[n:] + + if links != nil { + // Links came before Data. + // Finish them before we start Data. + if err := links.Finish(); err != nil { + return err + } + links = nil + } + + if err := ma.AssembleKey().AssignString("Data"); err != nil { + return err + } + if err := ma.AssembleValue().AssignBytes(chunk); err != nil { + return err + } + haveData = true + + case 2: + bytesLen, n := protowire.ConsumeVarint(remaining) + if n < 0 { + return protowire.ParseError(n) + } + remaining = remaining[n:] + + if links == nil { + if haveLinks { + return fmt.Errorf("protobuf: (PBNode) duplicate Links section") + } + + // The repeated "Links" part begins. + if err := ma.AssembleKey().AssignString("Links"); err != nil { + return err + } + links, err = ma.AssembleValue().BeginList(0) + if err != nil { + return err + } + } + + curLink, err := links.AssembleValue().BeginMap(3) + if err != nil { + return err + } + if err := unmarshalLink(remaining[:bytesLen], curLink); err != nil { + return err + } + remaining = remaining[bytesLen:] + if err := curLink.Finish(); err != nil { + return err + } + haveLinks = true + + default: + return fmt.Errorf("protobuf: (PBNode) invalid fieldNumber, expected 1 or 2, got %d", fieldNum) + } + } + + if links != nil { + // We had some links at the end, so finish them. + if err := links.Finish(); err != nil { + return err + } + + } else if !haveLinks { + // We didn't have any links. + // Since we always want a Links field, add one here. + if err := ma.AssembleKey().AssignString("Links"); err != nil { + return err + } + links, err := ma.AssembleValue().BeginList(0) + if err != nil { + return err + } + if err := links.Finish(); err != nil { + return err + } + } + return ma.Finish() +} + +func unmarshalLink(remaining []byte, ma ld.MapAssembler) error { + haveHash := false + haveName := false + haveTsize := false + for { + if len(remaining) == 0 { + break + } + + fieldNum, wireType, n := protowire.ConsumeTag(remaining) + if n < 0 { + return protowire.ParseError(n) + } + remaining = remaining[n:] + + switch fieldNum { + case 1: + if haveHash { + return fmt.Errorf("protobuf: (PBLink) duplicate Hash section") + } + if haveName { + return fmt.Errorf("protobuf: (PBLink) invalid order, found Name before Hash") + } + if haveTsize { + return fmt.Errorf("protobuf: (PBLink) invalid order, found Tsize before Hash") + } + if wireType != 2 { + return fmt.Errorf("protobuf: (PBLink) wrong wireType (%d) for Hash", wireType) + } + + chunk, n := protowire.ConsumeBytes(remaining) + if n < 0 { + return protowire.ParseError(n) + } + remaining = remaining[n:] + + _, c, err := cid.CidFromBytes(chunk) + if err != nil { + return fmt.Errorf("invalid Hash field found in link, expected CID (%v)", err) + } + if err := ma.AssembleKey().AssignString("Hash"); err != nil { + return err + } + if err := ma.AssembleValue().AssignLink(cidlink.Link{Cid: c}); err != nil { + return err + } + haveHash = true + + case 2: + if haveName { + return fmt.Errorf("protobuf: (PBLink) duplicate Name section") + } + if haveTsize { + return fmt.Errorf("protobuf: (PBLink) invalid order, found Tsize before Name") + } + if wireType != 2 { + return fmt.Errorf("protobuf: (PBLink) wrong wireType (%d) for Name", wireType) + } + + chunk, n := protowire.ConsumeBytes(remaining) + if n < 0 { + return protowire.ParseError(n) + } + remaining = remaining[n:] + + if err := ma.AssembleKey().AssignString("Name"); err != nil { + return err + } + if err := ma.AssembleValue().AssignString(string(chunk)); err != nil { + return err + } + haveName = true + + case 3: + if haveTsize { + return fmt.Errorf("protobuf: (PBLink) duplicate Tsize section") + } + if wireType != 0 { + return fmt.Errorf("protobuf: (PBLink) wrong wireType (%d) for Tsize", wireType) + } + + v, n := protowire.ConsumeVarint(remaining) + if n < 0 { + return protowire.ParseError(n) + } + remaining = remaining[n:] + + if err := ma.AssembleKey().AssignString("Tsize"); err != nil { + return err + } + if err := ma.AssembleValue().AssignInt(int64(v)); err != nil { + return err + } + haveTsize = true + + default: + return fmt.Errorf("protobuf: (PBLink) invalid fieldNumber, expected 1, 2 or 3, got %d", fieldNum) + } + } + + if !haveHash { + return fmt.Errorf("invalid Hash field found in link, expected CID") + } + + return nil +}