[
  {
    "path": ".gitattributes",
    "content": "**/testdata/fuzz/** binary\n"
  },
  {
    "path": ".github/actions/go-test-setup/action.yml",
    "content": "name: go-ipld-prime custom action setup\ndescription: Adds additional options to `go test` to skip behavior tests in the main test executions\nruns:\n  using: \"composite\"\n  steps:\n    - name: Disable codegen behavior tests\n      shell: bash\n      run: |\n        echo \"GOFLAGS=$GOFLAGS -tags=skipgenbehavtests\" >> $GITHUB_ENV\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"gomod\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n  - package-ecosystem: \"gomod\"\n    directory: \"/storage/dsadapter/\"\n    schedule:\n      interval: \"weekly\"\n  - package-ecosystem: \"gomod\"\n    directory: \"/storage/benchmarks/\"\n    schedule:\n      interval: \"weekly\"\n  - package-ecosystem: \"gomod\"\n    directory: \"/storage/bsadapter/\"\n    schedule:\n      interval: \"weekly\"\n  - package-ecosystem: \"gomod\"\n    directory: \"/storage/bsrvadapter/\"\n    schedule:\n      interval: \"weekly\"\n"
  },
  {
    "path": ".github/workflows/generated-pr.yml",
    "content": "name: Close Generated PRs\n\non:\n  schedule:\n    - cron: '0 0 * * *'\n  workflow_dispatch:\n\npermissions:\n  issues: write\n  pull-requests: write\n\njobs:\n  stale:\n    uses: ipdxco/unified-github-workflows/.github/workflows/reusable-generated-pr.yml@v1\n"
  },
  {
    "path": ".github/workflows/go-check.yml",
    "content": "name: Go Checks\n\non:\n  pull_request:\n  push:\n    branches: [\"master\"]\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  go-check:\n    uses: ipdxco/unified-github-workflows/.github/workflows/go-check.yml@v1.0\n"
  },
  {
    "path": ".github/workflows/go-test-prime.yml",
    "content": "on: [push, pull_request]\nname: Go Test (go-ipld-prime custom)\n\n# Similar to go-test.yml but runs only on Linux and doesn't run tests with\n# coverpkg so we can properly execute the codegen behavior tests which are\n# skipped in go-test.yml execution.\n\njobs:\n  unit:\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ \"ubuntu\" ]\n        go: [ \"1.24.x\", \"1.25.x\" ]\n    runs-on: ${{ format('{0}-latest', matrix.os) }}\n    name: ${{ matrix.os }} (go ${{ matrix.go }})\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          submodules: recursive\n      - uses: actions/setup-go@v2\n        with:\n          go-version: ${{ matrix.go }}\n      - name: Go information\n        run: |\n          go version\n          go env\n      - name: Run tests\n        uses: protocol/multiple-go-modules@v1.2\n        with:\n          run: |\n            go test -v ./...\n"
  },
  {
    "path": ".github/workflows/go-test.yml",
    "content": "name: Go Test\n\non:\n  pull_request:\n  push:\n    branches: [\"master\"]\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  go-test:\n    uses: ipdxco/unified-github-workflows/.github/workflows/go-test.yml@v1.0\n    secrets:\n      CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/release-check.yml",
    "content": "name: Release Checker\n\non:\n  pull_request_target:\n    paths: [ 'version.json' ]\n    types: [ opened, synchronize, reopened, labeled, unlabeled ]\n  workflow_dispatch:\n\npermissions:\n  contents: write\n  pull-requests: write\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  release-check:\n    uses: ipdxco/unified-github-workflows/.github/workflows/release-check.yml@v1.0\n"
  },
  {
    "path": ".github/workflows/releaser.yml",
    "content": "name: Releaser\n\non:\n  push:\n    paths: [ 'version.json' ]\n  workflow_dispatch:\n\npermissions:\n  contents: write\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.sha }}\n  cancel-in-progress: true\n\njobs:\n  releaser:\n    uses: ipdxco/unified-github-workflows/.github/workflows/releaser.yml@v1.0\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: Close Stale Issues\n\non:\n  schedule:\n    - cron: '0 0 * * *'\n  workflow_dispatch:\n\npermissions:\n  issues: write\n  pull-requests: write\n\njobs:\n  stale:\n    uses: ipdxco/unified-github-workflows/.github/workflows/reusable-stale-issue.yml@v1\n"
  },
  {
    "path": ".github/workflows/tagpush.yml",
    "content": "name: Tag Push Checker\n\non:\n  push:\n    tags:\n      - v*\n\npermissions:\n  contents: read\n  issues: write\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  releaser:\n    uses: ipdxco/unified-github-workflows/.github/workflows/tagpush.yml@v1.0\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \".ipld\"]\n\tpath = .ipld\n\turl = https://github.com/ipld/ipld/\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "CHANGELOG\n=========\n\nHere is collected some brief notes on major changes over time, sorted by tag in which they are first available.\n\nOf course for the \"detailed changelog\", you can always check the commit log!  But hopefully this summary _helps_.\n\nNote about version numbering: All release tags are in the \"v0.${x}\" range.  _We do not expect to make a v1 release._\nNonetheless, this should not be taken as a statement that the library isn't _usable_ already.\nMuch of this code is used in other libraries and products, and we do take some care about making changes.\n(If you're ever wondering about stability of a feature, ask -- or contribute more tests ;))\n\n- [Planned/Upcoming Changes](#planned-upcoming-changes)\n- [Released Changes Log](#released-changes)\n\n\nPlanned/Upcoming Changes\n------------------------\n\nHere are some outlines of changes we intend to make that affect the public API:\n\n- **IPLD Amend**: is likely to land soon; it implements a more efficient underlying architecture to support IPLD Patch and related features. IPLD Amend adds an interface to allow incremental changes to `Node`s in an efficient way. Whereas IPLD Patch is a protocol for expressing changes. We're still working on figuring out exactly where it fits in the stack and making sure it won't be disruptive but early benchmarks are very promising for both Patch and traversal-based transforms. See https://github.com/ipld/go-ipld-prime/pull/445 for more.\n- **Layered `Node` implementation optimizations**: When layering different implementations of `Node` builders or consumers, having to defer through basicnode types can lead to large inefficiencies of memory and speed. We are looking at ways to improve this situation, including ways to *assemble* layered assemblers. See https://github.com/ipld/go-ipld-prime/issues/443 for discussion and some initial plans.\n- **Selectors**: There have been some recurring wishes to do something about the Selector package layout.  There's no intended or prioritized date for this.  See https://github.com/ipld/go-ipld-prime/issues/236 for more.\n- **Absent / \"Not found\" values**: There may be some upcoming changes to exactly how \"not found\" values are handled in order to clarify and standardize the subject.  There's no finalized date for this.  See https://github.com/ipld/go-ipld-prime/issues/360 for more.\n\nReleased Changes\n----------------\n\n### v0.21.0\n\n_2023 August 10_\n\ngo-ipld-prime's release policy says that:\n\n> even numbers should be easy upgrades; odd numbers may change things\n\nThis release is an odd number, and it does change some minor things.\n\n#### 🛠 Breaking\n\n* **Build**: The minimum version of Go has been bumped from 1.18 to **1.19**.\n* **Dependencies**: The go-cid dependency was upgraded from v0.3.2 to **v0.4.1**. This is a relatively minor change but the introduction of `ErrInvalidCid` wrapping may be breaking for some users.\n* **Selectors**: Remove hard error when a traversal encounters a slice matcher with a node that is not a string or bytes, by @rvagg [#529](https://github.com/ipld/go-ipld-prime/pull/529)\n\n#### 🔦 Features\n\n* **Traversal**: `Preloader` functionality, by @hannahhoward and @rvagg [#452](https://github.com/ipld/go-ipld-prime/pull/452)\n  * See the [traversal](https://pkg.go.dev/github.com/ipld/go-ipld-prime/traversal) package documentation for more information on how a `Preloader` can be used to introduce parallelism into a traversal. The [Lassie](https://github.com/filecoin-project/lassie) project is currently using this functionality to speed up Bitswap block fetching; future releases of go-ipld-prime may include additional functionality being prototyped in Lassie to manage parallelism and caching.\n* **Schemas**: Support `listpairs` struct representation in DSL parsing, by @rvagg [#514](https://github.com/ipld/go-ipld-prime/pull/514)\n* **Schemas**: Support `inline` union representation in DSL parsing, by @rvagg [#527](https://github.com/ipld/go-ipld-prime/pull/527)\n* **Bindnode**: Support `listpairs` struct representation, by @rvagg [#514](https://github.com/ipld/go-ipld-prime/pull/514)\n* **Selectors**: Support negative values for slice matcher's `From` and `To`, by @rvagg [#530](https://github.com/ipld/go-ipld-prime/pull/530)\n  * The slice matcher is currently being used to support byte-range fetching for the [IPFS Trustless Gateway](https://specs.ipfs.tech/http-gateways/trustless-gateway/) specification. Work is ongoing and can be seen in both the [Lassie](https://github.com/filecoin-project/lassie) and [Frisbii](https://github.com/filecoin-project/lassie) projects.\n  * _Please note that this feature is currently considered **experimental** and shoule be used with care and with the expectation that it may change in the near future. Expect a release or two before this feature is considered stable._\n\n#### 🩹 Fixes\n\n* **Traversal**: `StartAtPath` work properly for matching walks, by @rvagg [#500](https://github.com/ipld/go-ipld-prime/pull/500)\n* **Traversal**: `WalkTransforming()` work properly, by @EdSchouten [#516](https://github.com/ipld/go-ipld-prime/pull/516)\n* **Basicnode**: `basic.NewInt()` returns a pointer like other constructors, by @hacdias [#525](https://github.com/ipld/go-ipld-prime/pull/525)\n* **Selectors**: Cache offsets for sequential reads in slice matcher, by @rvagg [#529](https://github.com/ipld/go-ipld-prime/pull/529)\n\n#### 🌟 Thanks!\n\nThanks to @hacdias and @EdSchouten for their first contributions to go-ipld-prime!\n\n### v0.20.0\n\ngo-ipld-prime's release policy says that:\n\n> even numbers should be easy upgrades; odd numbers may change things\n\nAs such, v0.20.0 is a relatively minor release with a grab-bag of small improvements and fixes.\n\n_2023 February 11_\n\nSchema errors can now [`errors.Is`](https://pkg.go.dev/errors#Is):\n\n* \\[[`61c9ab10d4`](https://github.com/ipld/go-ipld-prime/commit/61c9ab10d4)] - **feat**: support errors.Is for schema errors (Ian Davis) [#476](https://github.com/ipld/go-ipld-prime/pull/476)\n\nSchema DMT (schema/dmt) is now more usable from the outside and has a new `ConcatenateSchemas` function that can be used to combine two schemas into one:\n\n* \\[[`db9d8a7512`](https://github.com/ipld/go-ipld-prime/commit/db9d8a7512)] - Export schema/dmt.TypeSystem. (Eric Myhre) [#483](https://github.com/ipld/go-ipld-prime/pull/483)\n* \\[[`39818c169a`](https://github.com/ipld/go-ipld-prime/commit/39818c169a)] - Add a SchemaConcatenate operation. (Eric Myhre) [#483](https://github.com/ipld/go-ipld-prime/pull/483)\n* \\[[`c68ba53c67`](https://github.com/ipld/go-ipld-prime/commit/c68ba53c67)] - More accurate name for structure that contains easy access to prototypes. (Eric Myhre) [#483](https://github.com/ipld/go-ipld-prime/pull/483)\n* \\[[`2ecabf1217`](https://github.com/ipld/go-ipld-prime/commit/2ecabf1217)] - Add several pieces of docs to schema/dmt. (Eric Myhre)\n* \\[[`33475f0448`](https://github.com/ipld/go-ipld-prime/commit/33475f0448)] - Fix mispatched package declaration. (Eric Myhre)\n\nThe DAG-CBOR codec now has an `DontParseBeyondEnd` option (default `false`) that allows it to parse undelimited streamed objects. This matches the same functionality already in DAG-JSON and should only be used for specialised cases:\n\n* \\[[`7b00b1490f`](https://github.com/ipld/go-ipld-prime/commit/7b00b1490f)] - feat(dagcbor): mode to allow parsing undelimited streamed objects (Rod Vagg) [#490](https://github.com/ipld/go-ipld-prime/pull/490)\n\n`datamodel.Copy` got some direct test coverage and will now complain if you try to copy a `nil` node:\n\n* \\[[`f4bb2daa27`](https://github.com/ipld/go-ipld-prime/commit/f4bb2daa27)] - fix(datamodel): add tests to Copy, make it complain on nil (Rod Vagg) [#491](https://github.com/ipld/go-ipld-prime/pull/491)\n\nThe LinkSystem data loading check will compare links (CIDs) to ensure it loaded what you wanted; this now properly supports the case where your link is a pointer:\n\n* \\[[`1fc56b8e7a`](https://github.com/ipld/go-ipld-prime/commit/1fc56b8e7a)] - Fix hash mismatch error on matching link pointer (Masih H. Derkani) [#480](https://github.com/ipld/go-ipld-prime/pull/480)\n\n### v0.19.0\n\n_2022 October 13_\n\ngo-ipld-prime's release policy says that:\n\n> even numbers should be easy upgrades; odd numbers may change things\n\nThe major change in this release is a bump to Go 1.18.\n\n#### 🛠 Breaking Changes\n\nUpdate go.mod to Go 1.18.\n\n#### 🔦 Highlights\n\n* **Codecs**: [Correct JSON codec Bytes handling](https://github.com/ipld/go-ipld-prime/pull/472). This change does not impact DAG-JSON, which is the generally recommended codec for JSON output as the JSON codec cannot properly handle Bytes or Links.\n* **Dependencies**:\n  * Update to go-multihash@v0.2.1: https://github.com/multiformats/go-multihash/releases/tag/v0.2.1\n  * Update to go-multicodec@v0.6.0: https://github.com/multiformats/go-multicodec/releases/tag/v0.6.0\n  * Update to go-cid@v0.3.2: https://github.com/ipfs/go-cid/compare/v0.2.0...v0.3.2\n\n### v0.18.0\n\n_2022 August 01_\n\ngo-ipld-prime's release policy says that:\n\n> even numbers should be easy upgrades; odd numbers may change things\n\nSo, as an even number, this v0.18.0 release should be a smooth ride for upgraders from v0.17.0. We have 3 major feature additions, all focused on [Bindnode](https://pkg.go.dev/github.com/ipld/go-ipld-prime/node/bindnode).\n\n#### 🔦 Highlights\n\n* **Bindnode**: [Custom Go type converters](https://github.com/ipld/go-ipld-prime/pull/414) - Bindnode performs bidirectional mapping of Go types to the IPLD Data Model, and in doing so, it assumes a straightforward mapping of values to their encoded forms. But there are common cases where a Go type doesn't have a straightforward path to serialization, either because the encoded form needs a custom layout, or because bindnode doesn't have enough information to infer a serialization pattern. Custom Go type converters for bindnode allow a user to supply a pair of converter functions for a Go type that dictate how to map that type to an IPLD Data Model kind. See the **[bindnode documentation](https://pkg.go.dev/github.com/ipld/go-ipld-prime/node/bindnode)** for more information.\n* **Bindnode**: [Type registry](https://github.com/ipld/go-ipld-prime/pull/437) - Setting up Go type mappings with Bindnode involves some boilerplate. A basic type registry is now available that takes some of this boilerplate away; giving you a single place to register, and perform conversions to and from Go types, Data Model (`Node`) forms or directly through serialization. See the **[bindnode/registry documentation](https://pkg.go.dev/github.com/ipld/go-ipld-prime/node/bindnode/registry)** for more information.\n* **Bindnode** [Full `uint64` support](https://github.com/ipld/go-ipld-prime/pull/414/commits/87211682cb963ef1c98fa63909f67a8b02d1108c) - the `uint64` support introduced in go-ipld-prime@v0.17.0 has been wired into Bindnode. The Data Model (`Node`) forms expose integers as `int64` values, which is lossy for unsigned 64-bit integers. Bindnode Go types using `uint64` values are now lossless in round-trips through serialization to codecs that support the full range (DAG-CBOR most notably).\n\nYou can see all of these new features in action using Filecoin Go types, allowing a mapping between Go types, Data Model (`Node`) forms, and their DAG-CBOR serialized forms with [data-transfer vouchers](https://github.com/filecoin-project/go-fil-markets/pull/713). These features also allow us to interact with the original Go types, without modification, including `big.Int` serialization to `Bytes`, Filecoin `Signature` serialization to a byte-prefix discriminated `Bytes` and more. Since the Go types are unchanged, they can also simultaneously support [cbor-gen](https://github.com/whyrusleeping/cbor-gen) serialization, allowing an easier migration path.\n\n### v0.17.0\n\n_2022 Jun 15_\n\ngo-ipld-prime's release policy says that:\n\n> even numbers should be easy upgrades; odd numbers may change things\n\nIn that spirit, this v0.17.0 release includes some potentially breaking changes. Although minor, they are marked below and they may lead to behavioral changes in your use of this library.\n\n#### 🛠 Breaking Changes\n\n* **Codecs**:\n  * DAG-CBOR, DAG-JSON: [Error on `cid.Undef` links in dag{json,cbor} encoding](https://github.com/ipld/go-ipld-prime/pull/433) - previously, encoding Link nodes that were empty CIDs (uninitialized zero-value or explicitly `cid.Undef`) would have passed through the DAG-CBOR or DAG-JSON codecs, silently producing erroneous output that wouldn't successfully pass back through a decode. (Rod Vagg)\n* **Bindnode**:\n  * [Panic early if API has been passed ptr-to-ptr](https://github.com/ipld/go-ipld-prime/pull/427) - previous usage of bindnode using pointers-to-pointers may have deferred (or in some cases avoided) panics until deeper usage of the API, this change makes it earlier to make it clear that pointer-to-pointer is not appropriate usage. (Rod Vagg)\n* **Build**:\n  * [Drop Go 1.16.x testing & begin testing Go 1.18.x](https://github.com/ipld/go-ipld-prime/pull/394) (Daniel Martí)\n  * Note also that in this release, the [github.com/ipfs/**go-cid**](https://github.com/ipfs/go-cid) dependency is upgraded from 0.0.4 to 0.2.0 which includes a breaking change with the removal of the `cid.Codecs` and `cid.CodecToStr` maps which may disruptive. See [the go-cid@0.2.0 release page for details](https://github.com/ipfs/go-cid/releases/tag/v0.2.0).\n\n#### 🔦 Highlights\n\n* **Data Model**:\n  * [Introduce `UIntNode` interface, used within DAG-CBOR codec to quietly support full uint64 range](https://github.com/ipld/go-ipld-prime/pull/413) (Rod Vagg)\n* **Bindnode**:\n  * Fuzzing and hardening for production use (Daniel Martí)\n  * Refuse to decode empty union values (Daniel Martí)\n  * [Allow nilable types for IPLD `optional`/`nullable`](https://github.com/ipld/go-ipld-prime/pull/401) (Daniel Martí)\n  * [More helpful error message for common enum value footgun](https://github.com/ipld/go-ipld-prime/pull/430) (Rod Vagg)\n  * [Infer links and `Any` from Go types](https://github.com/ipld/go-ipld-prime/pull/432) (Rod Vagg)\n* **Schemas**:\n  * DMT: Proper checking for unknown union members (Daniel Martí)\n  * DMT: Enum representations must be valid members (Daniel Martí)\n  * DMT: Reject duplicate or missing union representation members (Daniel Martí)\n  * DSL: [Support `stringjoin` struct representation and `stringprefix` union representation](https://github.com/ipld/go-ipld-prime/pull/397) (Eric Evenchick)\n  * DMT, DSL: [Enable inline types](https://github.com/ipld/go-ipld-prime/pull/404) (Rod Vagg)\n* **Patch**:\n  * [Add initial version of IPLD Patch feature](https://github.com/ipld/go-ipld-prime/pull/350) (Eric Myhre) *(helped across the line by mauve and Rod Vagg)*\n* **Codecs**:\n  * DAG-CBOR: [Reject extraneous content after valid (complete) CBOR object](https://github.com/ipld/go-ipld-prime/pull/386) (Rod Vagg)\n  * DAG-CBOR: [add `DecodeOptions.ExperimentalDeterminism`](https://github.com/ipld/go-ipld-prime/pull/390) (currently only checking map sorting order) (Daniel Martí)\n  * Printer: [Fix printing of floats](https://github.com/ipld/go-ipld-prime/pull/412) (Dustin Long)\n  * DAG-JSON: [Add option to not parse beyond end of structure](https://github.com/ipld/go-ipld-prime/pull/435) (Petar Maymounkov)\n* **Build**:\n  * Fix [macOS](https://github.com/ipld/go-ipld-prime/pull/400) and [Windows](https://github.com/ipld/go-ipld-prime/pull/405) testing (Rod Vagg)\n  * [Fix 32-bit build support](https://github.com/ipld/go-ipld-prime/pull/407) (Rod Vagg)\n  * [Make staticcheck and govet happy across codebase](https://github.com/ipld/go-ipld-prime/pull/406) (Rod Vagg)\n  * Enable full [unified-ci](https://github.com/protocol/.github) GitHub Actions suite, including auto-updating (Rod Vagg)\n  * [Enable dependabot, with monthly checks](https://github.com/ipld/go-ipld-prime/pull/417) (and update all dependencies) (Rod Vagg)\n\nSpecial thanks to **Daniel Martí** for many bindnode improvements and hardening, fuzzing across the library and improvements to the Schema DMT and DSL.\n\n### v0.16.0\n\n_2022 March 09_\n\n- New: `traversal.WalkTransforming` is finally implemented!  (It's been a stub for quite a while.)  This works similarly to the other transform features, but can do more than change to the structure during a single walk.\n- New: Selectors support partial/ranged match on bytes or strings nodes.  (This is also a new feature for Selectors, recently specified.)\n  [[#375](https://github.com/ipld/go-ipld-prime/pull/375); seealso specs in [ipld#184](https://github.com/ipld/ipld/pull/184)]\n- New: there's a `datamodel.LargeBytesNode` interface, which makes it possible to handle \"large\" blobs of bytes as a `Node`, without necessarily forcing them all into memory at once.  (This is optional; you add the methods to match the interface if your Node implementation supports the feature.)\n  [[#372](https://github.com/ipld/go-ipld-prime/pull/372)]\n\t- Slightly more specifically: this interface is `Node` plus a method that returns an `io.ReadSeeker`.  (Pretty standard golang I/O and byte slice management concepts should carry you from there in the usual ways.)\n\t- This is a **really big deal** -- for example, this means that an [ADL](https://ipld.io/docs/advanced-data-layouts/) can support reading of arbitrarily large bytes without an issue.  (Hello, transparently readable large sharded blobs!)\n- New: there's a \"resume\" (or, skipahead) mechanism for traversals and selectors.  Engage it by simply setting the `traversal.Config.StartAtPath` field.\n  [[#358](https://github.com/ipld/go-ipld-prime/pull/358)]\n- New: `dagcbor` now has a `EncodedLength(Node) int` function, which can calculate the expected serial message length without actually encoding.  (The usefulness of this may be situational, but it's there if you want it.)\n- Improved: `bindnode`, yet again, in more ways that can easily be summarized.\n\t- Better support for pointers in more places in your golang types.\n\t- Many panics either fixed or routed into calmer errors.\n\t- Unsigned intergers are now supported in your golang types.\n\t- Some fixes for AssignNode working correctly (e.g. at the type or representation level, as appropriate; sometimes previously it would use the type level incorrectly).\n\t- Various fixes to handling absent fields correctly.\n\t- A `datamodel.Node` can now be used for an `any` field.\n- Fixed: selectors now behave correctly for a recursion clause that just contains a recursion edge immedately.  (It's still not a sensible selector, really, but it's valid.)  Previously this would panic, which was nasty.\n- Fixed: `bindnode` now correctly doesn't include absent fields in the count of length when looking at the representation-level view of structs.\n- Improved: all our batteries-included codecs double check while encoding that the number iterator steps over a map matches its self-reported length.  (This doesn't matter in many cases, but does defend you a little better against a `Node` implementation with a bug, if you happen to be so unlucky.)\n- Improved: miscellaneous performance work in the `schema/*` area.\n\nThank you to @mvdan, @warpfork, @hannahhoward, @rvagg, @willscott, @arajasek and others\nfor all their work that went into making this release (as well as all the point releases in v0.14.x leading up to it) happen.\n\nFinally, please note that we're starting to try out some new (and slightly more formal) governance and review and merge processes.\nCheck out https://github.com/ipld/go-ipld-prime/issues/370 for more information.\nThe aim is to make things generally more inclusive and involve more contributors!\nThis is still experimental and may be subject to change, but if you'd like to have better expectations about who can review and what the process should be like, we hope this will be a step in a helpful direction.\n(Feedback about this experiment welcome!)\n\n\n### v0.14.x\n\n(There were releases `v0.14.1`, `v0.14.2`, `v0.14.3`, and `v0.14.4` -- but all were in rapid succession, very minor, and hitting the same areas; we'll keep the notes brief and condensed.)\n\n- New: Selectors can include clauses for signalling the use of ADLs!\n  [[#301](https://github.com/ipld/go-ipld-prime/pull/301); seealso specs in [ipld#149](https://github.com/ipld/ipld/pull/149)+[ipld#170](https://github.com/ipld/ipld/pull/170)]\n\t- Also kindly note that there are expected to be many ways of signalling ADL invocations -- this is only one of them.\n\t  See the IPLD website for more on this topic as a whole: https://ipld.io/docs/advanced-data-layouts/signalling/\n- Improved: `bindnode`, in ways more various than can easily be summarized.\n\t- The `cidlink.Link` type can be bound to links in the data.\n\t- Enums are now supported.\n\t- The `any` typekind is now supported.\n- Improved: both the `schema/dmt` and `schema/dsl` packages (and in some cases, the `schema` package itself) continue to be improved and become more complete.\n\t- Structs with tuple representation are now supported.\n\t- Enums with int representation are now supported.\n\t- The `any` typekind is now supported.\n- Changed: the dag-json codec will tolerate padded base64 in bytes content upon read.  It does so silently.  (It is not still possible to emit this kind of serial data with this library; it is noncanonical.)\n  [[#309](https://github.com/ipld/go-ipld-prime/pull/309)]\n- Changed: the cbor and dag-cbor codec will now tolerate CBOR's \"undef\" token.  It will coerce it to a null token when reading.  Previously, encountering the undef token would result in a parse error.  (It is still not possible to emit this token with this library.)\n  [[#308](https://github.com/ipld/go-ipld-prime/pull/308)]\n- New: the `traversal` package gained a `WalkLocal` function.  This simply does a walk that does not cross any links.\n\n\n### v0.14.0\n\n_2021 November 11_\n\nThis release is a smooth-sailing release, and mostly contains new features, quality-of-life improvements,\nand some significant improvements to the completeness and usability of features that have been in development across previous releases.\nThere shouldn't be a lot of surprises, and upgrading should be easy.\n\nSome of the biggest improvements include: `bindnode` now supports most IPLD features and is increasingly stable;\nthe `schema` system now has functioning `schema/dmt` and `schema/dsl` packages, and can parse schema documents smoothly(!);\nif you haven't seen the `printer` package that first quietly appeared in `v0.12.2`, you should definitely check it out now;\nand we have some new `storage` APIs that might be worth checking out, too.\nThere are also many, many other smaller improvements.\n\nSee the complete list and further deatils below\n(and don't forget to check out the notes under the other `v0.12.*` headings, if you haven't absorbed those updates already, too!):\n\n- New: `datamodel.Copy`: a helper function to do a shallow copy from one node to another.\n\t- You don't often need this, because nodes are supposed to be immutable!\n\t  But it still sometimes comes in handy, for example, if you want to change the memory layout you're using by moving data into a different node implementation.\n- Improved: documentation of APIs.  (Especially, for subtler bits like `NodeAssembler.AssignNode`.)\n- New: `datamodel.Link` now requires a `Binary()` function.  In contrast to `Link.String()` (which is supposed to return something printable), `Link.Binary()` should give you the rawest thing possible.  (It's equivalent to `go-cid.CID.KeyString`.)\n- New: **a new storage API**, including one **batteries-included** filesystem storage implementation, and **adapters** to several other different storage APIs.  [[#265](https://github.com/ipld/go-ipld-prime/pull/265), [#279](https://github.com/ipld/go-ipld-prime/pull/279)]\n\t- The primary goal of this is the \"batteries included\" part: using the new `storage/fsstore` package, you should now be able to make simple applications with IPLD and use a simple sharded disk storage system (it'll look vaguely like a `.git/objects` directory), and do it in about five minutes and without pulling in any additional complex dependencies.\n\t- If you want to develop new storage systems or make adapters to them: the APIs in `storage` package are designed to be implemented easily.\n\t\t- The `storage` APIs are designed entirely around types found in the golang standard library.  You do not need to import anything in the `storage` package in order to implement its interfaces!\n\t\t- The minimal APIs that a storage system has to implement are _very_ small.  Two functions.  Every additional feature, or optimization that you can offer: those all have their own interfaces, and we use feature-detection on them.  You can implement as much or as little as you like.\n\t- As a user of the storage APIs: use the functions in the `storage` package.  Those functions take a storage system as a parameter, and will do feature detection _for you_.\n\t\t- This means you can always write your code to call the APIs you _want_, and the `storage` functions will figure out how to map it onto the storage system that you _have_ (whatever it supports) in the most efficient way it can.\n\t- As a user of the `LinkSystem` API: you can ignore most of this!  If you want to use the new `storage` APIs, there are setup methods on `LinkSystem` that will take them as a parameter.  If you have existing code wired up with the previous APIs, it still works too.\n\t- As someone who already has code and wonders how to migrate:\n\t\t- If you're using the `linking.Storage*Opener` API: you don't have to do anything.  Those still work too.\n\t\t- If you were using code from other repos like `ipfs/go-ipfs-blockstore` or `ipfs/go-datastore` or so on: those have adapters now in the `storage/*adapter` packages!  You should now be able to use those more easily, with less custom glue code.  (There's also now a migration readme in the repo root: check that out.)\n\t- If you would like to ask: \"is it fast?\" -- yes.  You'll find that the new `storage/fsstore`, our batteries-included filesystem storage system, is comparable (or beating) the `go-ds-flatfs` package that you may have been using in the past.  (More benchmarks and any performance improvement patches will of course be welcome -- but at the very least, there's no reason to hold back on using the new system.)\n- New: `LinkSystem` has some new methods: `LoadRaw` and `LoadPlusRaw` give you the ability to get data model nodes loaded, and _also_ receive the raw binary blobs.\n\t- This can be useful if you're building an application that's piping data around to other serial APIs without necessarily transforming it.  (No need to reserialize if that's your journey.)\n- New: a CLI tool has begun development!\n\t- ... and almost immediately been removed again, to live in its own repo: check out https://github.com/ipld/go-ipldtool .\n- Improved: many more things about `bindnode`.\n\t- `bindnode` now understands `go-cid.CID` fields.\n\t- Kinded unions are much more completely supported.\n\t- Many TODO panics have gone away, replaced by finished features.\n\t- `bindnode` will increasingly check that the golang types you give it can be structurally matched to the schema if you provide one, which gives better errors earlier, and increases the ease and safety of use drastically.\n- Improved: the `schema/dmt` and `schema/dsl` packages are increasingly complete.\n\t- There are also now helper functions in the root package which will do the whole journey of \"load a file, parse the Schema DSL, compile and typecheck the DMT, and give you the type info in handy golang interfaces\", all at once!  Check out `ipld.LoadSchema`!\n- New: there is a codegen feature for `bindnode` which will produce very terse golang structs matching a schema and ready to be bound back to `bindnode`!\n\t- This competes with the older `gengo` code generator -- by comparison, the `bindnode` code generator produces much, _much_ less code.  (However, be advised that the performance characteristics are probably also markedly different; and we do not have sufficient benchmarks to comment on this at this time.)\n- Internal: many tests are being ported to `quicktest`.  There should be no external impact to this, but we look forward to removing some of the other test libraries from our dependency tree in the near future.\n- Improved: `printer` now supports links and bytes!\n- Improved: `printer` is now more resilient and works even on relatively misbehaved `Node` implementations, such as those which implement `schema.TypedNode` but then rudely and nonsensically return nil type info.  (We don't expect all code to be resilient against misbehaved `Node` implementations... but for a debug tool in particular?  It's good to have it handle as much as it can.)\n\n\nThis, and the last few releases tagged in the `v0.12.*` series, include invaluable contributions from\n@mvdan, @warpfork, @rvagg, @willscott, @masih, @hannahhoward, @aschmahmann, @ribasushi,\nand probably yet more others who have contributed through code and design reviews,\nor by using these libraries and demanding they continue to become better.\nThanks to each and every one of the people who carry this project forward!\n\n\n### v0.12.3\n\n_2021 September 30_\n\n(This is a minor release; we'll keep the notes brief.)\n\n- Fixed: using `SkipMe` in a traversal now skips only that subtree of nodes, not the remainder of the block!\n  [[#251](https://github.com/ipld/go-ipld-prime/pull/251)]\n- New: `traversal` features now have budgets!  You can set a \"budget\" value, and watch it monotonically decrement as your operations procede.  This makes it easy to put limits on the amount of work you'll do.\n  [[#260](https://github.com/ipld/go-ipld-prime/pull/260)]\n- New: `traversal` features can be configured to visit links they encounter only once (and ignore them if seen again).\n  [[#252](https://github.com/ipld/go-ipld-prime/pull/252)]\n\t- Note that this is not without caveats: this is not merely an optimization; enabling it _may_ produce logically different outcomes, depending on what your selector is.\n\t  This is because links are ignored when seen again, even if they're seen for a different _reason_, via a different path, etc.\n- Fixed: a very nasty off-by-one in unions produced by the \"gogen\" codegen.\n  [[#257](https://github.com/ipld/go-ipld-prime/pull/257)]\n- Improved: the test suites for typed nodes now provide much better coverage (to prevent something like the above from happening again, even in other implementations).\n- New: `schema/dsl`!  This package contains parsers for the IPLD Schema DSL, and produces data structures in `schema/dmt` form.\n- Removed: other misc partially-complete packages.  (This will surely bother no one; it's just cleanup.)\n- Removed: `codec/jst`.  If you were using that, [`jst` has its own repo](https://github.com/warpfork/go-jst/) now.\n- Improved: `traversal` now uses the error wrapping (\"`%w`\") feature in more places.\n- Changed: `printer` keeps empty maps and lists and strings on a single line.\n- Changed: `schema.TypeName` is now just an alias of `string`.  This may result in somewhat less casting; or, you might not notice it.\n- Improved: the `schema/dmt` package continues to be improved and become more complete.\n\t- Some changes also track fixes in the schema spec, upstream.  (Or caused those fixes!)\n- New/Improved: the `schema` package describes several more things which it always should have.  Enums, for example.\n\n\n\n### v0.12.2\n\n_2021 September 8_\n\n(This is a minor release; we'll keep the notes brief.)\n\n- New: the `printer` package has appeared, and aims to provide an information-rich, debug-readable, human-friendly output of data from an IPLD node tree. [[#238](https://github.com/ipld/go-ipld-prime/pull/238/)]\n\t- This works for both plain data model data, and for typed data, and annotates type information if present.\n\t- Note that this is _not_ a codec: it's specifically _richer_ than that.  Conversely, this printer format is not designed to be parsed back to data model data.  Use a codec for a codec's job; use the printer for debugging and inspection jobs.\n- Fixed/Improved: more things about the `bindnode` system.  (It's still early and improving fast.)\n- Fixed: json codec, cbor codec, and their dag variants all now return ErrUnexpectedEOF in the conditions you'd expect.  (Previously they sometimes just returned EOF, which could be surprising.)\n- Changed/Improved: the `schema/dmt` package is now implemented using `bindnode`, and there's a more complete `Compile()` feature.  (This is still very early, in this tag.  More to come here soon.)\n\n\n\n### v0.12.1\n\n_2021 August 30_\n\n(This is a minor release; we'll keep the notes brief.)\n\n- Fixed/Improved: many things about the `bindnode` system.  (It's still early and improving fast.)\n- Changed: the strings for `schema.TypeKind_*` are lowercase.  (The docs and specs all act this way, and always have; it was a strange error for this code to have titlecase.)\n- New: the root package contains more helper methods for encoding and decoding operations\n\n\n\n### v0.12.0\n\n_2021 August 19_\n\nThis release is a momentous one.  It contains a sizable refactor:\nwe've extracted some of the most key interfaces to a new package, called `datamodel`!\n\nIt's also an even numbered release tag, which we generally use to indicate \"upgrading should be smooth sailing\".\nSurprisingly, despite the magnitude of the refactor, we mean that, too.\nGolang's \"alias\" feature has been used _heavily_ for this change process,\nand downstream code that worked on the previous release should continue to work on this release too, without syntactic changes.\n\nWhy did we do this?\n\nThe root package, `ipld`, is now going to be a place where we can put helpful functions.\nSynthesis functions that put all the pieces of IPLD together for you.\nThe functions you're probably looking for; the high-level stuff that gets work done.\n\nPreviously, the root package was _guts_: the lowest level interfaces, the more core stuff...\nwhich was cool to see (arguably), but tended not to be the things you'd want to see _first_ as a new user.\nAnd because everything _else_ in the world depended on those interface,\nwe could never put interesting high-level functions in the same package\n(or if we tried, compilation would fail, because of import cycles)...\nwhich meant any time we wanted to add helper functions for getting useful work done,\nwe'd be stuck cramming them off into subpackages somewhere.\nWhile this worked, the discoverability for a new user was terribly arduous.\n\nWe hope this pivot to how we organize the code helps you find your way through IPLD!\n\nWe haven't yet added many of the new helper features to the updated root package.\nThose will come in the very near future.\n(Follow along with commits on the master branch if you want to try the new APIs early!)\nThis release is being made just to cover the refactor, before we steam along any further.\n\nYour existing code should continue working without changes because the root `ipld` package\nstill contains all the same types -- just as aliases.\nYou can choose to update your code to use the types where they've moved to\n(which is mostly the `datamodel` package), or, if you prefer... just leave it as-is.\nSome aliases may be removed over time; if so, they'll be marked with a comment to that effect,\nand there should be plenty of warning and time to change.\n\nIn some cases, continuing to use the `ipld` package directly will remain acceptable indefinitely.\nThe new intention is that common work should often be possible to do only by\nimporting the `ipld` package, and users should only need to dive into\nthe more specific subpackages if they been to need direct access to more detailed APIs\nfor performance or other reasons.\n\nThat's it for the big refactor news.\n\nThere's also some sweet new features in bindnode,\nand a few other important fixes to recently introduced features.\n\nIn detail:\n\n- Changed: that massive refactor, described above.  Gosh it's big.\n  [[#228](https://github.com/ipld/go-ipld-prime/pull/228)]\n- New: the selectors system is tested against the language-agnostic selector specs, from the IPLD specs+docs repo!\n  [[#231](https://github.com/ipld/go-ipld-prime/pull/231)]\n\t- This uses a new fixture format, called [testmark](https://github.com/warpfork/go-testmark#what-is-the-testmark-format), which is managed by a library called [go-testmark](https://pkg.go.dev/github.com/warpfork/go-testmark).\n\t- The fixtures are drawn in by a git submodule.  The actual fixture content remains in the [ipld/ipld](https://github.com/ipld/ipld/) repo.\n\t- These new tests will be run if you have cloned the git submodule (and of course, by CI).  If you do not clone the submodule that contains the fixtures, the tests will quietly skip.\n\t- We hope this will be a template for how to do more testing in the future, while keeping it closely coordinated with specs, and in sync with other implementations of IPLD in other languages!\n- Improved: bindnode: in a variety of ways.\n  [[#226](https://github.com/ipld/go-ipld-prime/pull/226)]\n\t- Several error messages are improved.\n\t- Kinded unions support complex recipients even for string kinds.  (E.g., putting a struct with stringjoin representation inside a kinded union now works correctly.)\n\t- Stringprefix unions now work even with no explicit delimiter.\n\t- Please note that bindnode is, and remains, considered experimental.  While we're improving it, it's still something to use at your own risk.\n- Changed/Improved: bindnode: unions are now handled completely differently (and much better).\n  [[#223](https://github.com/ipld/go-ipld-prime/pull/223)]\n\t- In short: now they expect a golang struct which has a field for each of the possible members, and each of them should be a pointer.  This is type safe and works reasonably idiomatically in golang.\n\t- This is a fairly huge improvement, because it fixes the \"bindnode unions force downshift into anonymous types\" problem, which was tracked as [issue#210](https://github.com/ipld/go-ipld-prime/issues/210).\n- Fixed: the selector `ExploreRecursive.stopAt` feature now actually... works.  It was completely broken when it was introduced in the last release.  (Tests.  They're important.)\n  [[#229](https://github.com/ipld/go-ipld-prime/pull/229)]\n\t- Notice how we've also now got selector tests driven by fixtures appearing in this release.  Hopefully that decreases the odds of something like this happening again.\n\n\n\n### v0.11.0\n\n_2021 August 12_\n\nThis release is an odd numbered release, which means it may contain breaking changes.\n\nUnfortunately, the changes here may be particularly, tricky, as well -- for the most part, they're not compile-time detectable.\nThey're behavioral changes.  Much more subtle.  Run tests on your systems before accepting these changes.\nSpecifically: several codecs now enforce sorting when emitting serial data.\n\nThere's also some details of what's changing that makes it milder than it first sounds:\nmost of the changes are around codecs becoming *more* spec-compliant.\nSo, for example, if you were using another IPLD library that always enforced sorting on e.g. DAG-CBOR,\nyou won't be surprised or experience it much like a \"change\" when using this version of go-ipld-prime, which now also enforces such sorting in that codec.\n\nAlso!  At least one huge and awesome new feature: `bindnode`.\nThis is a new implementation of `ipld.Node` which can bind to native golang structures using reflection,\nwhich provides a new and easy-to-use way to move data in and out of golang structures (or traverse them, etc!) with IPLD interfaces and codecs.\n\nSee the full change list for details:\n\n- New: some new helpful constructors for making Selectors out of serial forms can now be found in the `traversal/selector/parse` package.\n  [[#199](https://github.com/ipld/go-ipld-prime/pull/199)]\n\t- Some constants are also included which show some examples of creating common selectors from JSON.\n- Fixed: cbor, dag-cbor, json, and dag-json codecs now all accept parsing a block that contains just a null token alone.  (Previously, this returned an \"unexpected EOF\" error, which was silly.)\n  [[#217](https://github.com/ipld/go-ipld-prime/pull/217)]\n- Fixed (upstream): json floats are actually supported.  (You might've had this already, if anything dragged in a newer version of the `refmt` library.  We just make sure to require this ourselves in our `go.mod` file now.)\n  [[#215](https://github.com/ipld/go-ipld-prime/pull/215)]\n- New: Selectors now support some kinds of conditions.  Specifically, `ExploreRecursive` clauses can contain a `stopAt` condition, and the condition system now supports `Condition_IsLink`, which can be used to do an equality check for CIDs.\n  [[#214](https://github.com/ipld/go-ipld-prime/pull/214)]\n- Fixed: in codegen'd types, the `LinkTargetNodePrototype` on links was returning the wrong prototype; now it returns the right one.\n  [[#211](https://github.com/ipld/go-ipld-prime/pull/211)]\n- New: `schema.TypedPrototype` interface, which is like `ipld.NodePrototype` but also has methods for asking `Type() schema.Type` and `Representation() ipld.NodePrototype`, both of which should probably instantly make sense to you.\n  [[#195](https://github.com/ipld/go-ipld-prime/pull/195)]\n- Changed: the dag-json and dag-cbor codecs now apply sorting.\n  [[#203](https://github.com/ipld/go-ipld-prime/pull/203), [#204](https://github.com/ipld/go-ipld-prime/pull/204)]\n\t- This means all serial data created with these codecs is sorted as advised by their respective specifications.\n\t  Previously, the implementations of these codecs was order-preserving, and emitted data in whatever order the `ipld.Node` yielded it.\n\t- There may be new performance costs originating from this sorting.\n\t- The codecs do not reject other orderings when parsing serial data.\n\t  The `ipld.Node` trees resulting from deserialization will still preserve the serialized order.\n\t  However, it has now become impossible to re-encode data in that same preserved order.\n\t- If doing your own encoding, there are customization options in `dagcbor.EncodeOptions.MapSortMode` and `dagjson.EncodeOptions.MapSortMode`.\n\t  (However, note that these options are not available to you while using any systems that only operate in terms of multicodec codes.)\n\t- _Be cautious of this change._  It is now extremely easy to write code which puts data into an `ipld.Node` in memory in one order,\n\t  then save and load that data using these codecs, and end up with different data as a result because the sorting changes the order of data.\n\t  For some applications, this may not be a problem; for others, it may be surprising.\n\t  In particular, mind this carefully in the presense of other order-sensitive logic -- for example,\n\t  such as when using Selectors, whose behaviors also depend on ordering of data returned when iterating over an `ipld.Node`.\n- Fixed/Changed: the dag-json codec no longer emits whitespace (!).  It is now spec-compliant.\n  [[#202](https://github.com/ipld/go-ipld-prime/pull/202)]\n\t- This means hashes of content produced by dag-json codec will change.  This is unfortunate, but the previous implementation was woefully and wildly out of sync with the spec, and addressing that is a predominating concern.\n- Removed: `fluent/quip` has been dropped.  `fluent/qp` is superior.  `fluent/quip` was too easy to use incorrectly, so we no longer offer it.\n  [[#197](https://github.com/ipld/go-ipld-prime/pull/197)]\n\t- This was an experimental package introduced a few releases ago, together with caveats that we may choose to drop it.  The warning was purposeful!\n\t  We don't believe that this will be too painful of a change; not many things depended on the `fluent/quip` variant, and those that did should not be difficult to rewrite to `fluent/qp`.\n- New: `node/basic.Chooser` is a function that implements `traversal.LinkTargetNodePrototypeChooser`.  It's a small handy quality-of-life increase if you need to supply such a function, which is common.\n  [[#198](https://github.com/ipld/go-ipld-prime/pull/198)]\n- New: `bindnode`!  **This is a huge feature.**  The beginnings of it may have been visible in v0.10.0, but it's grown into a usable thing we're ready to talk about.\n\t- Bindnode lets you write golang types and structures, and \"bind\" them into being IPLD Nodes and supporting Data Model operations by using golang reflection.\n\t- The result of working with `bindnode` is somewhere between using basicnode and using codegen:\n\t  it's going to provide some structural constraints (like codegen) and provide moderate performance (it lets you use structs rather than memory-expensive maps; but reflection is still going to be slower than codegen).\n\t- However, most importantly, `bindnode` is *nice to use*.  It doesn't have a huge barrier to entry like codegen does.\n\t- `bindnode` can be used with _or without_ IPLD Schemas.  For basic golang types, a schema can be inferred automatically.  For more advanced features (e.g. any representation customization), you can provide a Schema.\n\t- Please note that though it is now usable, bindnode remains _in development_.  There is not yet any promise that it will be frozen against changes.\n\t\t- In fact, several changes are expected; in particular, be advised there is some sizable change expected around the shape of golang types expected for unions.\n- Improved: tests for behavior of schema typed nodes are now extracted to a package, where they are reusable.\n\t- The same tests now cover the `bindnode` implementation, as well as being used in tests of our codegen outputs.\n\t- Previously, these tests were already mostly agnostic of implementation, but had been thrown into packages in a way that made them hard to reuse.\n- Improved (or Fixed, depending on your point of view): dag-json codec now supports bytes as per the spec.\n  [[#166](https://github.com/ipld/go-ipld-prime/pull/166),[#216](https://github.com/ipld/go-ipld-prime/pull/216)]\n\t- Bytes are encoded in roughly this form: `{\"/\":{\"bytes\":\"base64data\"}}`.\n\t- Note: the json codec does _not_ include this behavior; this is behavior specific to dag-json.\n\n\n\n### v0.10.0\n\n_2021 June 02_\n\nv0.10.0 is a mild release, containing _no_ breaking changes, but lots of cool new stuff.  Update at your earliest convenience.\n\nThere's a bunch of cool new features in here, some of which are significant power-ups for the ecosystem (e.g. the `NodeReifier` API), so we recommend updating as soon as possible.\n\nThere's also some sizable performance improvements available for generated code, so go forth and update your generated code too!\n\nCheck out the full feature list:\n\n- New: an `ipld.DeepEqual` method lets you easily compare two `ipld.Node` for equality.  (This is useful in case you have nodes with two different internal implementations, different memory layouts, etc, such that native golang equality would not be semantically correct.)\n  [[#174](https://github.com/ipld/go-ipld-prime/pull/174)]\n- New: the multicodec package exposes a `multicodec.Registry` type, and also some `multicodec.List*` methods.\n  [[#172](https://github.com/ipld/go-ipld-prime/pull/172), [#176](https://github.com/ipld/go-ipld-prime/pull/176)]\n\t- Please be cautious of using these `List*` methods.  It's very possible to create race conditions with these, especially if using them on the global default registry instance.\n\t  If we detect that these access methods seem to produce a source of bugs and design errors in downstream usage, they will be removed.\n\t  Consider doing whatever you're doing by buildling your own registry systems, and attaching whatever semantics your system desires to those systems, rather than shoehorning this intentionally limited system into doing things it isn't made to do.\n- Improved: the dag-json codec now actually supports bytes!\n  (Perhaps surprisingly, this was a relatively recent addition to the dag-json spec.  We've now caught up with it.)\n  [[#166](https://github.com/ipld/go-ipld-prime/pull/166)]\n- Improved: the codegen system now gofmt's the generated code immediately.  You no longer need to do this manually in a separate step.\n  [[#163](https://github.com/ipld/go-ipld-prime/pull/163)]\n- Improved: the codegen system is slightly faster at emitting code (due to use of more buffering during writes).\n  [[#161](https://github.com/ipld/go-ipld-prime/pull/161)]\n- Improved: the codegen system will now avoid pointers in the generated \"Maybe\" types, if they're known to be small in memory (and thus, reasonable to inline).\n  [[#160](https://github.com/ipld/go-ipld-prime/pull/160)]\n\t- This is quite likely to result in performance improvements for most programs, as it decreases the number of small memory allocations done, and amount of time spent on dereferencing, cache misses, etc.\n\t  Some workloads demonstrated over 10% speed increases, and 40% decreases in allocation counts.\n\t  (Of course, run your own benchmarks; not all workloads are equal.)\n- New: `ipld.LinkSystem` now contains a \"reification\" hook system.  **This is really cool.**\n\t- The center of this is the `ipld.LinkSystem.NodeReifier` field, and the `ipld.NodeReifier` function type.\n\t- The `ipld.NodeReifier` function type is simply `func(LinkContext, Node, *LinkSystem) (Node, error)`.\n\t- The purpose and intention of this is: you can use this hooking point in order to decide where to engage advanced IPLD features like [ADLs](https://ipld.io/glossary/#adl).\n\t  One can use a `NodeReifier` to decide what ADLs to use and when... even when in the middle of a traversal.\n\t- For example: one could write a NodeReifier that says \"when I'm in a path that ends with '`foosys/*/hamt`', i'm going to try to load that as if it's a HAMT ADL\".\n\t  With that hook in place, you'd then be able to walks over whole forests of data with `traversal.*` functions, and they would automatically load the relevant ADL for you transparently every time that pattern is encountered, without disrupting or complicating the walk.\n\t- In the future, we might begin to offer more structural and declaratively configurable approaches to this, and eventually, attempt to standardize them.\n\t  For now: you can build any solution you like using this hook system.  (And we'll probably plug in any future declarative systems via these same hooks, too.)\n\t- All this appeared in [#158](https://github.com/ipld/go-ipld-prime/pull/158).\n- New: `ipld.LinkSystem` now contains a boolean flag for `TrustedStorage`.  If set to true, it will cause methods like `Load` to _skip hashing_ when loading content.  **_Do not do this unless you know what you're doing._**\n  [[#149](https://github.com/ipld/go-ipld-prime/pull/149)]\n- New: a json (as opposed to dag-json) codec is now available from this repo.  It does roughly what you'd expect.  (It's like dag-json, but explicitly rejects encoding links and bytes, and correspondingly does not have dag-json's special decoding behaviors that produce those kinds.)\n  [[#152](https://github.com/ipld/go-ipld-prime/pull/152)]\n- New: a cbor (as opposed to dag-cbor) codec is now available from this repo.  Same story as the json codec: it just explicitly doesn't support links (because you should use dag-cbor if you want that).\n  [[#153](https://github.com/ipld/go-ipld-prime/pull/153)]\n\nThis contained a ton of contributions from lots of people: especially thanks to @mvdan, @hannahhoward, and @willscott for invaluable contributions.\n\n\n\n### v0.9.0\n\n_2021 March 15_\n\nv0.9.0 is a pretty significant release, including several neat new convenience features, but most noticeably, significantly reworking how linking works.\n\nAlmost any code that deals with storing and linking data will need some adaptation to handle this release.\nWe're sorry about the effort this may require, but it should be worth it.\nThe new LinkSystem API should let us introduce a lot more convenience features in the future, and do so *without* pushing additional breakage out to downstream users; this is an investment in the future.\n\nThe bullet points below contain all the fun details.\n\nNote that a v0.8.0 release version has been skipped.\nWe use odd numbers to indicate the existence of significant changes;\nand while usually we try to tag an even-number release between each odd number release so that migrations can be smoothed out,\nin this case there simply weren't enough interesting points in between to be worth doing so.\n\n- Change: linking has been significantly reworked, and now primarily works through the `ipld.LinkSystem` type.\n\t- This is cool, because it makes a lot of things less circuitous.  Previously, working with links was a complicated combination of Loader and Storer functions, the Link interface contained the Load method, it was just... complicated to figure out where to start.  Now, the answer is simple and constant: \"Start with LinkSystem\".  Clearer to use; clearer to document; and also coincidentally a lot clearer to develop for, internally.\n\t- The PR can be found here: https://github.com/ipld/go-ipld-prime/pull/143\n\t- `Link.Load` -> `LinkSystem.Load` (or, new: `LinkSystem.Fill`, which lets you control memory allocation more explicitly).\n\t- `LinkBuilder.Build` -> `LinkSystem.Store`.\n\t- `LinkSystem.ComputeLink` is a new feature that produces a Link without needing to store the data anywhere.\n\t- The `ipld.Loader` function is now most analogous to `ipld.BlockReadOpener`.  You now put it into use by assigning it to a `LinkLoader`'s `StorageReadOpener` field.\n\t- The `ipld.Storer` function is now most analogous to `ipld.BlockWriteOpener`.  You now put it into use by assigning it to a `LinkLoader`'s `StorageWriteOpener` field.\n\t- 99% of the time, you'll probably start with `linking/cid.DefaultLinkSystem()`.  You can assign to fields of this to customize it further, but it'll get you started with multihashes and multicodecs and all the behavior you expect when working with CIDs.\n\t\t- (So, no -- the `cidlink` package hasn't gone anywhere.  Hopefully it's a bit less obtrusive now, but it's still here.)\n\t- The `traversal` package's `Config` struct now uses a `LinkSystem` instead of a `Loader` and `Storer` pair, as you would now probably expect.\n\t\t- If you had code that was also previously passing around `Loader` and `Storer`, it's likely a similar pattern of change will be the right direction for that code.\n\t- In the _future_, further improvements will come from this: we're now much, much closer to making a bunch of transitive dependencies become optional (especially, various hashers, which currently, whenever you pull in the `linking/cid` package, come due to `go-cid`, and are quite large).  When these improvements land (again, they're not in this release), you'll need to update your applications to import hashers you need if they're not in the golang standard library.  For now: there's no change.\n- Change: multicodec registration is now in the `go-ipld-prime/multicodec` package.\n\t- Previously, this registry was in the `linking/cid` package.  These things are now better decoupled.\n\t- This will require packages which register codecs to make some very small updates: e.g. `s/cidlink.RegisterMulticodecDecoder/multicodec.RegisterDecoder/`, and correspondingly, update the package imports at the top of the file.\n- New: some pre-made storage options (e.g. satisfying the `ipld.StorageReadOpener` and `ipld.StorageWriteOpener` function interfaces) have appeared!  Find these in the `go-ipld-prime/storage` package.\n\t- Currently this only includes a simple in-memory storage option.  This may be useful for testing and examples, but probably not much else :)\n\t- These are mostly intended to be illustrative.  You should still expect to find better storage mechanisms in other repos.\n- Change: some function names in codec packages are ever-so-slightly updated.  (They're verbs now, instead of nouns, which makes sense because they're functions.  I have no idea what I was thinking with the previous naming.  Sorry.)\n\t- `s/dagjson.Decoder/dagjson.Decode/g`\n\t- `s/dagjson.Decoder/dagjson.Encode/g`\n\t- `s/dagcbor.Decoder/dagcbor.Decode/g`\n\t- `s/dagcbor.Encoder/dagcbor.Encode/g`\n\t- If you've only been using these indirectly, via their multicodec indicators, you won't have to update anything at all to account for this change.\n- New: several new forms of helpers to make it syntactically easy to create new IPLD data trees with golang code!\n\t- Check out the `go-ipld-prime/fluent/quip` package!  See https://github.com/ipld/go-ipld-prime/pull/134, where it was introduced, for more details.\n\t- Check out the `go-ipld-prime/fluent/qp` package!  See https://github.com/ipld/go-ipld-prime/pull/138, where it was introduced, for more details.\n\t- Both of these offer variations on `fluent` which have much lower costs to use.  (`fluent` incurs allocations during operation, which has a noticable impact on performance if used in a \"hot\" code path.  Neither of these two new solutions do!)\n\t- For now, both `quip` and `qp` will be maintained.  They have similar goals, but different syntaxes.  If one is shown drastically more popular over time, we might begin to consider deprecating one in favor of the other, but we'll need lots of data before considering that.\n\t- We won't be removing the `fluent` package anytime soon, but we probably wouldn't recommend building new stuff on it.  `qp` and `quip` are both drastically preferable for performance reasons.\n- New: there is now an interface called `ipld.ADL` which can be used for a certain kind of feature detection.\n\t- This is an experimental new concept and likely subject to change.\n\t- The one key trait we've found all ADLs tend to share right now is that they have a \"synthesized\" view and \"substrate\" view of their data.  So: the `ipld.ADL` interface states that a thing is an `ipld.Node` (for the synthesized view), and from it you should be able to access a `Substrate() ipld.Node`, and that's about it.\n\n\n\n### v0.7.0\n\n_2020 December 31_\n\nv0.7.0 is a small release that makes a couple of breaking changes since v0.6.0.\nHowever, the good news is: they're all very small changes, and we've kept them in a tiny group,\nso if you're already on v0.6.0, this update should be easy.\nAnd we've got scripts to help you.\n\nThere's also one cool new feature: `traversal.FocusedTransform` is now available to help you make mutations to large documents conveniently.\n\n- Change: all interfaces and APIs now use golang `int64` rather than golang `int`.  [#125](https://github.com/ipld/go-ipld-prime/pull/125)\n\t- This is necessary because the IPLD Data Model specifies that integers must be \"at least 2^53\" in range, and so since go-ipld-prime may also be used on 32-bit architectures, it is necessary that we not use the `int` type, which would fail to be Data Model-compliant on those architectures.\n\t- The following GNU sed lines should assist this transition in your code, although some other changes that are more difficult automate may also be necessary:\n\t\t```\n\t\tsed -ri 's/(func.* AsInt.*)\\<int\\>/\\1int64/g' **/*.go\n\t\tsed -ri 's/(func.* AssignInt.*)\\<int\\>/\\1int64/g' **/*.go\n\t\tsed -ri 's/(func.* Length.*)\\<int\\>/\\1int64/g' **/*.go\n\t\tsed -ri 's/(func.* LookupByIndex.*)\\<int\\>/\\1int64/g' **/*.go\n\t\tsed -ri 's/(func.* Next.*)\\<int\\>/\\1int64/g' **/*.go\n\t\tsed -ri 's/(func.* ValuePrototype.*)\\<int\\>/\\1int64/g' **/*.go\n\t\t```\n- Change: we've renamed the types talking about \"kinds\" for greater clarity.  `ipld.ReprKind` is now just `ipld.Kind`; `schema.Kind` is now `schema.TypeKind`.  We expect to use \"kind\" and \"typekind\" consistently in prose and documentation from now on, as well.  [#127](https://github.com/ipld/go-ipld-prime/pull/127)\n\t- Pretty much everyone who's used this library has said \"ReprKind\" didn't really make sense as a type name, so, uh, yeah.  You were all correct.  It's fixed now.\n\t- \"kind\" now always means \"IPLD Data Model kind\", and \"typekind\" now always means \"the kinds which an IPLD Schema type can have\".\n\t- You can find more examples of how we expect to use this in a sentence from now on in the discussion that lead to the rename: https://github.com/ipld/go-ipld-prime/issues/94#issuecomment-745307919\n\t- The following GNU sed lines should assist this transition in your code:\n\t\t```\n\t\tsed -ri 's/\\<Kind\\(\\)/TypeKind()/g' **/*.go\n\t\tsed -ri 's/\\<Kind_/TypeKind_/g' **/*.go\n\t\tsed -i 's/\\<Kind\\>/TypeKind/g' **/*.go\n\t\tsed -i 's/ReprKind/Kind/g' **/*.go\n\t\t```\n- Feature: `traversal.FocusedTransform` works now!  :tada:  You can use this to take a node, say what path inside it you want to update, and then give it an updated value.  Super handy.  [#130](https://github.com/ipld/go-ipld-prime/pull/130)\n\n\n### v0.6.0\n\n_2020 December 14_\n\nv0.6.0 is a feature-packed release and has a few bugfixes, and _no_ significant breaking changes.  Update at your earliest convenience.\n\nMost of the features have to do with codegen, which we now consider to be in **alpha** -- go ahead and use it!  (We're starting to self-host some things in it, so any changes will definitely be managed from here on out.)\nA few other small handy helper APIs have appeared as well; see the detailed notes for those.\n\nLike with the last couple of releases, our intent is to follow this smooth-sailing change with another release shortly which will include some minor but noticable API changes, and that release may require you to make some code changes.\nTherefore, we suggest upgrading to this one first, beacuse it's an easy waypoint before the next change.\n\n- Feature: codegen is a reasonably usable alpha!  We now encourage trying it out (but still only for those willing to experience an \"alpha\" level of friction -- UX still rough, and we know it).\n\t- Consult the feature table in the codegen package readme: many major features of IPLD Schemas are now supported.\n\t\t- Structs with tuple representations?  Yes.\n\t\t- Keyed unions?  Yes.\n\t\t- Structs with stringjoin representations?  Yes.  Including nested?  _Yes_.\n\t\t- Lots of powerful stuff is now available to use.\n\t\t- See [the feature table in the codegen readme](https://github.com/ipld/go-ipld-prime/blob/v0.6.0/schema/gen/go/README.md#completeness) for details.\n\t- Many generated types now have more methods for accessing them in typed ways (in addition to the usual `ipld.Node` interfaces, which can access the same data, but lose explicit typing).  [#106](https://github.com/ipld/go-ipld-prime/pull/106)\n\t\t- Maps and lists now have both lookup methods and iterators which know the type of the child keys and values explicitly.\n\t- Cool: when generating unions, you can choose between different implementation strategies (favoring either interfaces, or embedded values) by using Adjunct Config.  This lets you tune for either speed (reduced allocation count) or memory footprint (less allocation size, but more granular allocations).\n\t\t- See notes in [#60](https://github.com/ipld/go-ipld-prime/pull/60) for more detail on this.  We'll be aiming to make configurability of this more approachable and better documented in future releases, as we move towards codegen tools usable as CLI tools.\n\t- Cyclic references in types are now supported.\n\t\t- ... mostly.  Some manual configuration may sometimes be required to make sure the generated structure wouldn't have an infinite memory size.  We'll keep working on making this smoother in the future.\n\t- Field symbol overrides now work properly.  (E.g., if you have a schema with a field called \"type\", you can make that work now.  Just needs a field symbol override in the Adjunct Config when doing codegen!)\n\t- Codegen'd link types now implemented the `schema.TypedLinkNode` interface where applicable.\n\t- Structs now actually validate all required fields are present before allowing themselves to finish building.  Ditto for their map representations.\n\t- Much more testing.  And we've got a nice new declarative testcase system that makes it easier to write descriptions of how data should behave (at both the typed and representation view levels), and then just call one function to run exhaustive tests to make sure it looks the same from every inspectable API.\n\t- Change: codegen now outputs a fixed set of files.  (Previously, it output one file per type in your schema.)  This makes codegen much more managable; if you remove a type from your schema, you don't have to chase down the orphaned file.  It's also just plain less clutter to look at on the filesystem.\n- Demo: as proof of the kind of work that can be done now with codegen, we've implemented the IPLD Schema schema -- the schema that describes IPLD Schema declarations -- using codegen.  It's pretty neat.\n\t- Future: we'll be replacing most of the current current `schema` package with code based on this generated stuff.  Not there yet, though.  Taking this slow.\n\t\t- You can see the drafts of this, along with new features based on it, in [#107](https://github.com/ipld/go-ipld-prime/pull/107).\n- Feature: the `schema` typesystem info packages are improved.\n\t- Cyclic references in types are now supported.\n\t\t- (Mind that there are still some caveats about this when fed to codegen, though.)\n\t- Graph completeness is now validated (e.g. missing type references emit useful errors)!\n- Feature: there's a `traversal.Get` function.  It's like `traversal.Focus`, but just returns the reached data instead of dragging you through a callback.  Handy.\n- Feature/bugfix: the DAG-CBOR codec now includes resource budgeting limits.  This means it's a lot harder for a badly-formed (or maliciously formed!) message to cause you to run out of memory while processing it.  [#85](https://github.com/ipld/go-ipld-prime/pull/85)\n- Bugfix: several other panics from the DAG-CBOR codec on malformed data are now nice politely-returned errors, as they should be.\n- Bugfix: in codegen, there was a parity break between the AssembleEntry method and AssembleKey+AssembleValue in generated struct NodeAssemblers.  This has been fixed.\n- Minor: ErrNoSuchField now uses PathSegment instead of a string.  You probably won't notice (but this was important interally: we need it so we're able to describe structs with tuple representations).\n- Bugfix: an error path during CID creation is no longer incorrectly dropped.  (I don't think anyone ever ran into this; it only handled situations where the CID parameters were in some way invalid.  But anyway, it's fixed now.)\n- Performance: when `cidlink.Link.Load` is used, it will do feature detection on its `io.Reader`, and if it looks like an already-in-memory buffer, take shortcuts that do bulk operations.  I've heard this can reduce memory pressure and allocation counts nicely in applications where that's a common scenario.\n- Feature: there's now a `fluent.Reflect` convenience method.  Its job is to take some common golang structs like maps and slices of primitives, and flip them into an IPLD Node tree.  [#81](https://github.com/ipld/go-ipld-prime/pull/81)\n\t- This isn't very high-performance, so we don't really recommend using it in production code (certainly not in any hot paths where performance matters)... but it's dang convenient sometimes.\n- Feature: there's now a `traversal.SelectLinks` convenience method.  Its job is to walk a node tree and return a list of all the link nodes.  [#110](https://github.com/ipld/go-ipld-prime/pull/110)\n\t- This is both convenient, and faster than doing the same thing using general-purpose Selectors (we implemented it as a special case).\n- Demo: you can now find a \"rot13\" ADL in the `adl/rot13adl` package.  This might be useful reference material if you're interested in writing an ADL and wondering what that entails.  [#98](https://github.com/ipld/go-ipld-prime/pull/98)\n- In progress: we've started working on some new library features for working with data as streams of \"tokens\".  You can find some of this in the new `codec/codectools` package.\n\t- Functions are available for taking a stream of tokens and feeding them into a NodeAssembler; and for taking a Node and reading it out as a stream of tokens.\n\t- The main goal in mind for this is to provide reusable components to make it easier to implement new codecs.  But maybe there will be other uses for this feature too!\n\t- These APIs are brand new and are _extremely subject to change_, much more so than any other packages in this repo.  If you work with them at this stage, _do_ expect to need to update your code when things shift.\n\n\n### v0.5.0\n\n_2020 July 2_\n\nv0.5.0 is a small release -- it just contains a bunch of renames.\nThere are _no_ semantic changes bundled with this (it's _just_ renames) so this should be easy to absorb.\n\n- Renamed: `NodeStyle` -> `NodePrototype`.\n\t- Reason: it seems to fit better!  See https://github.com/ipld/go-ipld-prime/issues/54 for a full discussion.\n\t- This should be a \"sed refactor\" -- the change is purely naming, not semantics, so it should be easy to update your code for.\n\t- This also affects some package-scoped vars named `Style`; they're accordingly also renamed to `Prototype`.\n\t- This also affects several methods such as `KeyStyle` and `ValueStyle`; they're accordingly also renamed to `KeyPrototype` and `ValuePrototype`.\n- Renamed: `(Node).Lookup{Foo}` -> `(Node).LookupBy{Foo}`.\n\t- Reason: The former phrasing makes it sound like the \"{Foo}\" component of the name describes what it returns, but in fact what it describes is the type of the param (which is necessary, since Golang lacks function overloading parametric polymorphism).  Adding the preposition should make this less likely to mislead (even though it does make the method name moderately longer).\n\t- This should be a \"sed refactor\" -- the change is purely naming, not semantics, so it should be easy to update your code for.\n- Renamed: `(Node).Lookup` -> `(Node).LookupNode`.\n\t- Reason: The shortest and least-qualified name, 'Lookup', should be reserved for the best-typed variant of the method, which is only present on codegenerated types (and not present on the Node interface at all, due to Golang's limited polymorphism).\n\t- This should be a \"sed refactor\" -- the change is purely naming, not semantics, so it should be easy to update your code for.  (The change itself in the library was fairly literally `s/Lookup(/LookupNode(/g`, and then `s/\"Lookup\"/\"LookupNode\"/g` to catch a few error message strings, so consumers shouldn't have it much harder.)\n\t- Note: combined with the above rename, this method overall becomes `(Node).LookupByNode`.\n- Renamed: `ipld.Undef` -> `ipld.Absent`, and `(Node).IsUndefined` -> `(Node).IsAbsent`.\n\t- Reason: \"absent\" has emerged as a much, much better description of what this value means.  \"Undefined\" sounds nebulous and carries less meaning.  In long-form prose docs written recently, \"absent\" consistently fits the sentence flow much better.  Let's just adopt \"absent\" consistently and do away with \"undefined\".\n\t- This should be a \"sed refactor\" -- the change is purely naming, not semantics, so it should be easy to update your code for.\n\n\n### v0.4.0\n\nv0.4.0 contains some misceleanous features and documentation improvements -- perhaps most notably, codegen is re-introduced and more featureful than previous rounds -- but otherwise isn't too shocking.\nThis tag mostly exists as a nice stopping point before the next version coming up (which is planned to include several API changes).\n\n- Docs: several new example functions should now appear in the godoc for how to use the linking APIs.\n- Feature: codegen is back!  Use it if you dare.\n\t- Generated code is now up to date with the present versions of the core interfaces (e.g., it's updated for the NodeAssembler world).\n\t- We've got a nice big feature table in the codegen package readme now!  Consult that to see which features of IPLD Schemas now have codegen support.\n\t- There are now several implemented and working (and robustly tested) examples of codegen for various representation strategies for the same types.  (For example, struct-with-stringjoin-representation.)  Neat!\n\t- This edition of codegen uses some neat tricks to not just maintain immutability contracts, but even prevent the creation of zero-value objects which could potentially be used to evade validation phases on objects that have validation rules.  (This is a bit experimental; we'll see how it goes.)\n\t- There are oodles and oodles of deep documentation of architecture design choices recorded in \"HACKME_*\" documents in the codegen package that you may enjoy if you want to contribute or understand why generated things are the way they are.\n\t- Testing infrastructure for codegen is now solid.  Running tests for the codegen package will: exercise the generation itself; AND make sure the generated code compiles; AND run behavioral tests against it: the whole gamut, all from regular `go test`.\n\t- The \"node/gendemo\" package contains a real example of codegen output... and it's connected to the same tests and benchmarks as other node implementations.  (Are the gen'd types fast?  yes.  yes they are.)\n\t- There's still lots more to go: interacting with the codegen system still requires writing code to interact with as a library, as we aren't shipping a CLI frontend to it yet; and many other features are still in development as well.  But you're welcome to take it for a spin if you're eager!\n- Feature: introduce JSON Tables Codec (\"JST\"), in the `codec/jst` package.  This is a codec that emits bog-standard JSON, but leaning in on the non-semantic whitespace to produce aligned output, table-like, for pleasant human reading.  (If you've used `column -t` before in the shell: it's like that.)\n\t- This package may be a temporary guest in this repo; it will probably migrate to its own repo soon.  (It's a nice exercise of our core interfaces, though, so it incubated here.)\n- I'm quietly shifting the versioning up to the 0.x range.  (Honestly, I thought it was already there, heh.)  That makes this this \"v0.4\".\n\n\n### v0.0.3\n\nv0.0.3 contained a massive rewrite which pivoted us to using NodeAssembler patterns.\nCode predating this version will need significant updates to match; but, the performance improvements that result should be more than worth it.\n\n- Constructing new nodes has a major pivot towards using \"NodeAssembler\" pattern: https://github.com/ipld/go-ipld-prime/pull/49\n\t- This was a massively breaking change: it pivoted from bottom-up composition to top-down assembly: allocating large chunks of structured memory up front and filling them in, rather than stitching together trees over fragmented heap memory with lots of pointers\n- \"NodeStyle\" and \"NodeBuilder\" and \"NodeAssembler\" are all now separate concepts:\n\t- NodeStyle is more or less a builder factory (forgive me -- but it's important: you can handle these without causing allocations, and that matters).\n\t  Use NodeStyle to tell library functions what kind of in-memory representation you want to use for your data.  (Typically `basicnode.Style.Any` will do -- but you have the control to choose others.)\n\t- NodeBuilder allocates and begins the assembly of a value (or a whole tree of values, which may be allocated all at once).\n\t- NodeAssembler is the recursive part of assembling a value (NodeBuilder implements NodeAssembler, but everywhere other than the root, you only use the NodeAssembler interface).\n- Assembly of trees of values now simply involves asking the assembler for a recursive node to give you assemblers for the keys and/or values, and then simply... using them.\n\t- This is much simpler (and also faster) to use than the previous system, which involved an awkward dance to ask about what kind the child nodes were, get builders for them, use those builders, then put the result pack in the parent, and so forth.\n- Creating new maps and lists now accepts a size hint argument.\n\t- This isn't strictly enforced (you can provide zero, or even a negative number to indicate \"I don't know\", and still add data to the assembler), but may improve efficiency by reducing reallocation costs to grow structures if the size can be estimated in advance.\n- Expect **sizable** performance improvements in this version, due to these interface changes.\n- Some packages were renamed in an effort to improve naming consistency and feel:\n\t- The default node implementations have moved: expect to replace `impl/free` in your package imports with `node/basic` (which is an all around better name, anyway).\n\t- The codecs packages have moved: replace `encoding` with `codec` in your package imports (that's all there is to it; nothing else changed).\n- Previous demos of code generation are currently broken / disabled / removed in this tag.\n\t- ...but they'll return in future versions, and you can follow along in branches if you wish.\n- Bugfix: dag-cbor codec now correctly handles marshalling when bytes come after a link in the same object. [[53](https://github.com/ipld/go-ipld-prime/pull/53)]\n\n### v0.0.2\n\n- Many various performance improvements, fixes, and docs improvements.\n- Many benchmarks and additional tests introduced.\n- Includes early demos of parts of the schema system, and early demos of code generation.\n- Mostly a checkpoint before beginning v0.0.3, which involved many large API reshapings.\n\n### v0.0.1\n\n- Our very first tag!\n- The central `Node` and `NodeBuilder` interfaces are already established, as is `Link`, `Loader`, and so forth.\n  You can already build generic data handling using IPLD Data Model concepts with these core interfaces.\n- Selectors and traversals are available.\n- Codecs for dag-cbor and dag-json are batteries-included in the repo.\n- There was quite a lot of work done before we even started tagging releases :)\n"
  },
  {
    "path": "HACKME.md",
    "content": "hackme\n======\n\nDesign rational are documented here.\n\nThis doc is not necessary reading for users of this package,\nbut if you're considering submitting patches -- or just trying to understand\nwhy it was written this way, and check for reasoning that might be dated --\nthen it might be useful reading.\n\nIt may also be an incomplete doc.  It's been written opportunistically.\nIf you don't understand the rationale for some things, try checking git history\n(many of the commit messages are downright bookish), or get in touch via\na github issue, irc, matrix, etc and ask!\n\n\nabout NodeAssembler and NodeBuilder\n-----------------------------------\n\nSee the godoc on these types.\n\nIn short, a `NodeBuilder` is for creating a new piece of memory;\na `NodeAssembler` is for instantiating some memory which you already have.\n\nGenerally, you'll start any function using a `NodeBuilder`, but then continue\nand recurse by passing on the `NodeAssembler`.\n\nSee the `./HACKME_builderBehaviors.md` doc for more details on\nhigh level rules and implementation patterns to look out for.\n\n\n\nabout NodePrototype\n---------------\n\n### NodePrototype promises information without allocations\n\nYou'll notice nearly every `ipld.NodePrototype` implementation is\na golang struct type with _zero fields_.\n\nThis is important.\nGetting a NodePrototype is generally expected to be \"free\" (i.e., zero allocations),\nwhile `NewBuilder` is allowed to be costly (usually causes at least one allocation).\nZero-member structs can be referred to by an interface without requiring an allocation,\nwhich is how it's possible ensure `NodePrototype` are always \"free\" to refer to.\n\n(Note that a `NodePrototype` that bundles some information like ADL configuration\nwill subvert this pattern -- but these are an exception, not the rule.)\n\n### NodePrototype reported by a Node\n\n`ipld.NodePrototype` is a type that opaquely represents some information about how\na node was constructed and is implemented.  The general contract for what\nshould happen when asking a node about its prototype\n(via the `ipld.Node.Prototype() NodePrototype` interface) is that prototype should contain\neffective instructions for how one could build a copy of that node, using\nthe same implementation details.\n\nBy example, if some node `n` was made as a `basicnode.plainString`,\nthen `n.Prototype()` will be `basicnode.Prototype.String`,\nand `n.Prototype().NewBuilder().AssignString(\"xyz\")` can be presumed to work.\n\nNote there are also limits to this: if a node was built in a flexible way,\nthe prototype it reports later may only report what it is now, and not return\nthat same flexibility again.\nBy example, if something was made as an \"any\" -- i.e.,\nvia `basicnode.Prototype.Any.NewBuilder()`, and then *happened* to be assigned a string value --\nthe resulting node will still carry a `Prototype()` property that returns\n`basicnode.Prototype.String` -- **not** `basicnode.Prototype.Any`.\n\n#### NodePrototype meets generic transformation\n\nOne of the core purposes of the `NodePrototype` interface (and all the different\nways you can get it from existing data) is to enable the `traversal` package\n(or other user-written packages like it) to do transformations on data.\n\n// work-in-progress warning: generic transformations are not fully implemented.\n\nWhen implementing a transformation that works over unknown data,\nthe signiture of function a user provides is roughly:\n`func(oldValue Node, acceptableValues NodePrototype) (Node, error)`.\n(This signiture may vary by the strategy taken by the transformation -- this\nsigniture is useful because it's capable of no-op'ing; an alternative signiture\nmight give the user a `NodeAssembler` instead of the `NodePrototype`.)\n\nIn this situation, the transformation system determines the `NodePrototype`\n(or `NodeAssembler`) to use by asking the parent value of the one we're visiting.\nThis is because we want to give the update function the ability to create\nany kind of value that would be accepted in this position -- not just create a\nvalue of the same prototype as the one currently there!  It is for this reason\nthe `oldValue.Prototype()` property can't be used directly.\n\nAt the root of such a transformation, we use the `node.Prototype()` property to\ndetermine how to get started building a new value.\n\n#### NodePrototype meets recursive assemblers\n\nAsking for a NodePrototype in a recursive assembly process tells you about what\nkind of node would be accepted in an `AssignNode(Node)` call.\nIt does *not* make any remark on the fact it's a key assembler or value assembler\nand might be wrapped with additional rules (such as map key uniqueness, field\nname expectations, etc).\n\n(Note that it's also not an exclusive statement about what `AssignNode(Node)` will\naccept; e.g. in many situations, while a `Prototype.MyStringType` might be the prototype\nreturned, any string kinded node can be used in `AssignNode(Node)` and will be\nappropriately converted.)\n\nAny of these paths counts as \"recursive assembly process\":\n\n- `MapAssembler.KeyPrototype()`\n- `MapAssembler.ValuePrototype(string)`\n- `MapAssembler.AssembleKey().Prototype()`\n- `MapAssembler.AssembleValue().Prototype()`\n- `ListAssembler.ValuePrototype()`\n- `ListAssembler.AssembleValue().Prototype()`\n\n### NodePrototype for carrying ADL configuration\n\n// work-in-progress warning: this is an intention of the design, but not implemented.\n"
  },
  {
    "path": "HACKME_builderBehaviors.md",
    "content": "hackme: NodeBuilder and NodeAssembler behaviors\n===============================================\n\nhigh level rules of builders and assemblers\n-------------------------------------------\n\n- Errors should be returned as soon as possible.\n\t- That means an error like \"repeated key in map\" should be returned by the key assembler!\n\t\t- Either 'NodeAssembler.AssignString' should return this (for simple keys on untyped maps, or on structs, etc)...\n\t\t- ... or 'MapAssembler.Finish' (in the case of complex keys in a typed map).\n\n- Logical integrity checks must be done locally -- recursive types rely on their contained types to report errors, and the recursive type wraps the assemblers of their contained type in order to check and correctly invalidate/rollback the recursive construction.\n\n- Recursive types tend to have a value assembler that wraps the child type's assembler in order to intercept relevant \"finish\" methods.\n\t- This is generally where that logic integrity check mentioned above is tracked; we need explicit confirmation that it *passes* before the parent's assembly should proceed.\n\t- Implementations may also need this moment to complete any assignment of the child value into position in the parent value.  But not all implementations need this -- some will have had all the child assembler effects applying directly to the final memory positions.\n\n- Assemblers should invalidate themselves as soon as they become \"finished\".\n\t- For maps and lists, that means the \"Finish\" methods.\n\t- For all the other scalars, the \"Assign*\" method itself means finished.\n\t- Or in other words: whatever method returns an `error`, that's what makes that assembler \"finished\".\n\t- The purpose of this is to prevent accidental mutation after any validations have been performed during the \"finish\" processing.\n\n- Many methods must be called in the right order, and the user must not hold onto references after calling \"finish\" methods on them.\n\t- The reason this is important is to enable assembler systems to aggressively reuse memory, thus increasing performance.\n\t- Thus, if you hold onto NodeAssembler reference after being finished with it... you can't assume it'll explicitly error if you call further methods on it, because it might now be operating again... _on a different target_.\n\t\t- In recursive structures, calling AssembleKey or AssembleValue might return pointer-identical assemblers (per warning in previous bullet), but the memory their assembly is targeted to should always advance -- it should never target already-assembled memory.\n\t- (If you're thinking \"the Rust memory model would be able to greatly enhance safety here!\"... yes.  Yes it would.)\n\t- When misuses of order are detected, these may cause panics (rather than error returns) (not all methods that can be so misused have error returns).\n\n\ndetailed rules and expectations for implementers\n------------------------------------------------\n\nThe expectations in the \"happy path\" are often clear.\nHere are also collected some details of exactly what should happen when an error has been reached,\nbut the caller tries to continue anyway.\n\n- while building maps:\n\t- assigning a key with 'AssembleKey':\n\t\t- in case of success: clearly 'AssembleValue' should be ready to use next.\n\t\t- in case of failure from repeated key:\n\t\t\t- the error must be returned immediately from either the 'NodeAssembler.AssignString' or the 'MapAssembler.Finish' method.\n\t\t\t\t- 'AssignString' for any simple keys; 'MapAssembler.Finish' may be relevant in the case of complex keys in a typed map.\n\t\t\t\t- implementers take note: this implies the `NodeAssembler` returned by `AssembleKey` has some way to refer to the map assembler that spawned it.\n\t\t\t- no side effect should be visible if 'AssembleKey' is called again next.\n\t\t\t\t- (typically this doesn't require extra code for the string case, but it may require some active zeroing in the complex key case.)\n\t\t\t\t- (remember to reset any internal flag for expecting 'AssembleValue' to be used next, and decrement any length pointers that were optimistically incremented!)\n\t\t\t\t- n.b. the \"no side effect\" rule here is for keys, not for values.\n\t\t\t\t\t- TODO/REVIEW: do we want the no-side-effect rule for values?  it might require nontrivial volumes of zeroing, and often in practice, this might be wasteful.\n\n- invalidation of assemblers:\n\t- is typically implemented by nil'ing the wip node they point to.\n\t\t- this means you get nil pointer dereference panics when attempting to use an assembler after it's finished... which is not the greatest error message.\n\t\t- but it does save us a lot of check code for a situation that the user certainly shouldn't get into in the first place.\n\t\t- (worth review: can we add that check code without extra runtime cost?  possibly, because the compiler might then skip its own implicit check branches.  might still increase SLOC noticeably in codegen output, though.)\n\t\t- worth noting there's a limit to how good this can be anyway: it's \"best effort\" error reporting: see the remarks on reuse of assembler memory in \"overall rules\" above.\n\t- it's systemically critical to not yield an assembler _ever again in the future_ that refers to some memory already considered finished.\n\t\t- even though we no longer return intermediate nodes, there's still many ways this could produce problems.  For example, complicating (if not outright breaking) COW sharing of segments of data.\n\t\t- in most situations, we get this for free, because the child assembler methods only go \"forward\" -- there's no backing up, lists have no random index insertion or update support, and maps actively reject dupe keys.\n\t\t- if you *do* make a system which exposes any of those features... be very careful; you will probably need to start tracking \"freeze\" flags on the data in order to retain systemic sanity.\n"
  },
  {
    "path": "HACKME_mergeStrategy.md",
    "content": "hacking: merge strategies\n=========================\n\nThis is a short document about how the maintainers of this repo handle branches and merging.\nIt's useful information for a developer wanting to contribute, but otherwise unimportant.\n\n---\n\nWe prefer to:\n\n1. Do development on a branch;\n2. Before merge, rebase onto master (if at all possible);\n\t- if there are individual commit hashes that should be preserved because they've been referenced outside the project, say so; we don't want to have to presume this by default.\n\t- rebasing your commits (or simply staging them carefully the first time; `git add -p` is your friend) for clarity of later readers is greatly appreciated.\n3. Merge, using the \"--no-ff\" strategy.  The github UI does fine at this.\n\nThere are a couple of reasons we prefer this:\n\n- Squashing, if appropriate, can be done by the author.  We don't use github's squash button because it's sometimes quite difficult to make a good combined commit message without effort to do so by the diff's author, so it's best left to that author to do themselves.\n- Generating a merge commit gives a good place for github to insert the PR link, if a PR has been used.  This is good info to have if someone is later reading git history and wants to see links to where other discussion may have taken place.\n- We *do* like fairly linearly history.  Emphasis on \"fairly\" -- it doesn't have to be perfectly lock-step ridgidly linear: but when doing `git log --graph`, we also want to not see more than a handful of lines running in parallel at once.  (Too many parallel branches at once is both unpleasant to read and review later, and can indicative of developmental process issues, so it's a good heuristic to minimize for multiple reasons.)  Rebasing before generating a merge commit does this: if consistently done, `git log --graph` will yield two parallel lines at all times.\n- Generating a merge commit, when combined with rebasing the commits on the branch right before merge, means `git log --graph` will group up the branch commits in a visually clear way.  Preserving this relation can be useful.  (Neither squashing nor rebase-without-merge approaches preserve this information.)\n\nMind, all of these rules are heuristics and \"rules of thumb\".  Some small changes are also perfectly reasonable to land with either a squash or rebase that appends them linearly onto history.\n\nThe maintainers may choose strategies as they see fit depending on the size of the content and the level of interest in preserving individual commits and their messages and relational history.\n\n\nWhat does this mean for PRs?\n----------------------------\n\n- Please keep PRs rebased on top of master as much as possible.\n\n- If you decide you want multiple commits with distinct messages, fine.  If you want to squash, also fine.\n\n- If you are linking to commit hashes and don't want them rebased, please comment about this;\n  otherwise, it should not be presumed we'll keep exact commit hashes reachable.\n  The maintainers also reserve the right to rebase or squash things at their own option;\n  we'll comment explicitly if committing to not do so, and it should not otherwise be presumed.\n\n- If you're not comfortable with rebase: fine.  Just be aware that if a PR branches off master for quite some time,\n  and it does become ready for merge later, the maintainers are likely to squash/rebase your work for you before merging.\n"
  },
  {
    "path": "HACKME_releases.md",
    "content": "# Making go-ipld-prime Releases\n\n## Versioning strategy\n\ngo-ipld-prime follows **[WarpVer](https://gist.github.com/warpfork/98d2f4060c68a565e8ad18ea4814c25f)**, a form of SemVer that never bumps the major version number and uses minor version numbers to indicate degree of *changeness*: **even numbers should be easy upgrades; odd numbers may change things**. The patch version number is rarely used in this scheme.\n\n## CHANGELOG.md\n\nThere is a CHANGELOG.md, it should be relevant and updated. Notable items in the commit history since the last release should be included. Where possible and practical, links to relevant pull requests or other issues with discussions on the items should be included.\n\nTo find the list of commits, it is recommended that you use a tool that can provide some extra metadata to help with matching commits to pull requests. [changelog-maker](https://github.com/nodejs/changelog-maker) can help with this (requires Node.js be installed and the `npx` command be available):\n\n```\nnpx changelog-maker --start-ref=v0.16.0  --reverse=true --find-matching-prs=true --md=true ipld go-ipld-prime\n```\n\nAlternatively, you can use `git log` and perform mapping to pull requests manually, e.g.:\n\n```\ngit log --all --graph --date-order --abbrev-commit --decorate --oneline\n```\n\n*(where `--start-ref` points to name of the previous release tag)*\n\n### Curate and summarize\n\nThe CHANGELOG should be informative for developers wanting to know what changes may pose a risk (highlight these!) and what changes introduce features they may be interested in using.\n\n1. Group commits to subsystem to create a two-level list. Subsections can include \"Data Model\", \"Schemas\", \"Bindnode\", \"Selectors\", \"Codecs\", and the meta-category of \"Build\" to describe changes local to the repository and not necessarily relevant to API consumers.\n2. If there are breaking, or potentially breaking changes, list them under a `#### 🛠 Breaking Changes` section.\n3. Otherwise, prune the list of commits down to the set of changes relevant to users, and list them under a `#### 🔦 Highlights` section.\n\nNote that there is also a **Planned/Upcoming Changes** section near the top of the CHANGELOG.md. Update this to remove _done_ items and add other items that may be nearing completion but not yet released.\n\n### Call-outs\n\nAdd \"special thanks\" call-outs to individuals who have contributed meaningful changes to the release.\n\n## Propose a release\n\nAfter updating the CHANGELOG.md entry, also bump the version number appropriately in **version.json** file so the auto-release procedure can take care of tagging for you.\n\nCommit and propose the changes via a pull request to ipld/go-ipld-prime.\n\n## Release\n\nAfter a reasonable amount of time for feedback (usually at least a full global business day), the changes can be merged and a release tag will be created by the GitHub Actions.\n\nUse the GitHub UI to make a [release](https://github.com/ipld/go-ipld-prime/releases), copying in the contents of the CHANGELOG.md for that release.\n\nDrop in a note to the appropriate Matrix/Discord/Slack channel(s) for IPLD about the release.\n\nOptional: Protocol Labs staff can send an email to shipped@protocol.ai to describe the release, these are typically well-read and appreciated.\n\n## Checklist\n\nPrior to opening a release proposal pull request, create an issue with the following markdown checklist to help ensure the requisite steps are taken. The issue can also be used to alert subscribed developers to the timeframe and the approximate scope of changes in the release.\n\n```markdown\n* [ ] Add new h3 to `CHANGELOG.md` under **Released Changes** with curated and subsystem-grouped list of changes and links to relevant PRs\n  * [ ] Highlight any potentially breaking or disruptive changes under \"🛠 Breaking Changes\", including extended descriptions to help users make compatibility judgements\n  * [ ] Add special-thanks call-outs to contributors making significant contributions\n* [ ] Update **Planned/Upcoming Changes** section to remove completed items and add newly upcoming, but incomplete items\n* [ ] Bump version number appropriately in `version.json`\n* [ ] Propose release via pull request, merge after enough time for async global feedback\n* [ ] Create GitHub [release](https://github.com/ipld/go-ipld-prime/releases) with the new tag, copying the new `CHANGELOG.md` contents\n* [ ] Announce on relevant Discord/Matrix/Slack channel(s)\n* [ ] (Optional) Announce to shipped@protocol.ai\n```\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2018 Eric Myhre\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "go-ipld-prime\n=============\n\n`go-ipld-prime` is an implementation of the IPLD spec interfaces,\na batteries-included codec implementations of IPLD for CBOR and JSON,\nand tooling for basic operations on IPLD objects (traversals, etc).\n\n\n\nAPI\n---\n\nThe API is split into several packages based on responsibly of the code.\nThe most central interfaces are the base package,\nbut you'll certainly need to import additional packages to get concrete implementations into action.\n\nRoughly speaking, the core package interfaces are all about the IPLD Data Model;\nthe `codec/*` packages contain functions for parsing serial data into the IPLD Data Model,\nand converting Data Model content back into serial formats;\nthe `traversal` package is an example of higher-order functions on the Data Model;\nconcrete `ipld.Node` implementations ready to use can be found in packages in the `node/*` directory;\nand several additional packages contain advanced features such as IPLD Schemas.\n\n(Because the codecs, as well as higher-order features like traversals, are\nimplemented in a separate package from the core interfaces or any of the Node implementations,\nyou can be sure they're not doing any funky \"magic\" -- all this stuff will work the same\nif you want to write your own extensions, whether for new Node implementations\nor new codecs, or new higher-order order functions!)\n\n- `github.com/ipld/go-ipld-prime` -- imported as just `ipld` -- contains the core interfaces for IPLD.  The most important interfaces are `Node`, `NodeBuilder`, `Path`, and `Link`.\n- `github.com/ipld/go-ipld-prime/node/basicnode` -- provides concrete implementations of `Node` and `NodeBuilder` which work for any kind of data, using unstructured memory.\n- `github.com/ipld/go-ipld-prime/node/bindnode` -- provides concrete implementations of `Node` and `NodeBuilder` which store data in native golang structures, interacting with it via reflection.  Also supports IPLD Schemas!\n- `github.com/ipld/go-ipld-prime/traversal` -- contains higher-order functions for traversing graphs of data easily.\n- `github.com/ipld/go-ipld-prime/traversal/selector` -- contains selectors, which are sort of like regexps, but for trees and graphs of IPLD data!\n- `github.com/ipld/go-ipld-prime/codec` -- parent package of all the codec implementations!\n- `github.com/ipld/go-ipld-prime/codec/dagcbor` -- implementations of marshalling and unmarshalling as CBOR (a fast, binary serialization format).\n- `github.com/ipld/go-ipld-prime/codec/dagjson` -- implementations of marshalling and unmarshalling as JSON (a popular human readable format).\n- `github.com/ipld/go-ipld-prime/linking/cid` -- imported as `cidlink` -- provides concrete implementations of `Link` as a CID.  Also, the multicodec registry.\n- `github.com/ipld/go-ipld-prime/schema` -- contains the `schema.Type` and `schema.TypedNode` interface declarations, which represent IPLD Schema type information.\n- `github.com/ipld/go-ipld-prime/node/typed` -- provides concrete implementations of `schema.TypedNode` which decorate a basic `Node` at runtime to have additional features described by IPLD Schemas.\n\n\nGetting Started\n---------------\n\nLet's say you want to create some data programmatically,\nand then serialize it, or save it as [blocks].\n\nYou've got a ton of different options, depending on what golang convention you want to use:\n\n- the `qp` package -- [example](https://pkg.go.dev/github.com/ipld/go-ipld-prime/fluent/qp#example-package)\n- the `bindnode` system, if you want to use golang types -- [example](https://pkg.go.dev/github.com/ipld/go-ipld-prime/node/bindnode#example-Wrap-NoSchema), [example with schema](https://pkg.go.dev/github.com/ipld/go-ipld-prime/node/bindnode#example-Wrap-WithSchema)\n- or the [`NodeBuilder`](https://pkg.go.dev/github.com/ipld/go-ipld-prime/datamodel#NodeBuilder) interfaces, raw (verbose; not recommended)\n- or even some codegen systems!\n\nOnce you've got a Node full of data,\nyou can serialize it:\n\nhttps://pkg.go.dev/github.com/ipld/go-ipld-prime#example-package-CreateDataAndMarshal\n\nBut probably you want to do more than that;\nprobably you want to store this data as a block,\nand get a CID that links back to it.\nFor this you use `LinkSystem`:\n\nhttps://pkg.go.dev/github.com/ipld/go-ipld-prime/linking#example-LinkSystem.Store\n\nHopefully these pointers give you some useful getting-started focal points.\nThe API docs should help from here on out.\nWe also highly recommend scanning the [godocs](https://pkg.go.dev/github.com/ipld/go-ipld-prime) for other pieces of example code, in various packages!\n\nLet us know in [issues](https://github.com/ipld/go-ipld-prime/issues), [chat, or other community spaces](https://ipld.io/docs/intro/community/) if you need more help,\nor have suggestions on how we can improve the getting-started experiences!\n\n\n\nOther IPLD Libraries\n--------------------\n\nThe IPLD specifications are designed to be language-agnostic.\nMany implementations exist in a variety of languages.\n\nFor overall behaviors and specifications, refer to the IPLD website, or its source, in IPLD meta repo:\n- https://ipld.io/\n- https://github.com/ipld/ipld/\nYou should find specs in the `specs/` dir there,\nhuman-friendly docs in the `docs/` dir,\nand information about _why_ things are designed the way they are mostly in the `design/` directories.\n\nThere are also pages in the IPLD website specifically about golang IPLD libraries,\nand your alternatives: https://ipld.io/libraries/golang/\n\n\n### distinctions from go-ipld-interface&go-ipld-cbor\n\nThis library (\"go ipld prime\") is the current head of development for golang IPLD,\nand we recommend new developments in golang be done using this library as the basis.\n\nHowever, several other libraries exist in golang for working with IPLD data.\nMost of these predate go-ipld-prime and no longer receive active development,\nbut since they do support a lot of other software, you may continue to seem them around for a while.\ngo-ipld-prime is generally **serially compatible** with these -- just like it is with IPLD libraries in other languages.\n\nIn terms of programmatic API and features, go-ipld-prime is a clean take on the IPLD interfaces,\nand chose to address several design decisions very differently than older generation of libraries:\n\n- **The Node interfaces map cleanly to the IPLD Data Model**;\n- Many features known to be legacy are dropped;\n- The Link implementations are purely CIDs (no \"name\" nor \"size\" properties);\n- The Path implementations are provided in the same box;\n- The JSON and CBOR implementations are provided in the same box;\n- Several odd dependencies on blockstore and other interfaces that were closely coupled with IPFS are replaced by simpler, less-coupled interfaces;\n- New features like IPLD Selectors are only available from go-ipld-prime;\n- New features like ADLs (Advanced Data Layouts), which provide features like transparent sharding and indexing for large data, are only available from go-ipld-prime;\n- Declarative transformations can be applied to IPLD data (defined in terms of the IPLD Data Model) using go-ipld-prime;\n- and many other small refinements.\n\nIn particular, the clean and direct mapping of \"Node\" to concepts in the IPLD Data Model\nensures a much more consistent set of rules when working with go-ipld-prime data, regardless of which codecs are involved.\n(Codec-specific embellishments and edge-cases were common in the previous generation of libraries.)\nThis clarity is also what provides the basis for features like Selectors, ADLs, and operations such as declarative transformations.\n\nMany of these changes had been discussed for the other IPLD codebases as well,\nbut we chose clean break v2 as a more viable project-management path.\nBoth go-ipld-prime and these legacy libraries can co-exist on the same import path, and both refer to the same kinds of serial data.\nProjects wishing to migrate can do so smoothly and at their leisure.\n\nWe now consider many of the earlier golang IPLD libraries to be defacto deprecated,\nand you should expect new features *here*, rather than in those libraries.\n(Those libraries still won't be going away anytime soon, but we really don't recommend new construction on them.)\n\n### migrating\n\n**For recommendations on where to start when migrating:**\nsee [README_migrationGuide](./README_migrationGuide.md).\nThat document will provide examples of which old concepts and API names map to which new APIs,\nand should help set you on the right track.\n\n### unixfsv1\n\nLots of people who hear about IPLD have heard about it through IPFS.\nIPFS has IPLD-native APIs, but IPFS *also* makes heavy use of a specific system called \"UnixFSv1\",\nso people often wonder if UnixFSv1 is supported in IPLD libraries.\n\nThe answer is \"yes\" -- but it's not part of the core.\n\nUnixFSv1 is now treated as an [ADL](https://ipld.io/glossary/#adl),\nand a go-ipld-prime compatible implementation can be found\nin the [ipfs/go-unixfsnode](https://github.com/ipfs/go-unixfsnode) repo.\n\nAdditionally, the codec used in UnixFSv1 -- dag-pb --\ncan be found implemented in the [ipld/go-codec-dagpb](https://github.com/ipld/go-codec-dagpb) repo.\n\nA \"some assembly required\" advisory may still be in effect for these pieces;\ncheck the readmes in those repos for details on what they support.\n\nThe move to making UnixFSv1 a non-core system has been an arduous retrofit.\nHowever, framing it as an ADL also provides many advantages:\n\n- it demonstrates that ADLs as a plugin system _work_, and others can develop new systems in this pattern!\n- it has made pathing over UnixFSv1 much more standard and well-defined\n- this standardization means systems like [Selectors](https://ipld.io/glossary/#selectors) work naturally over UnixFSv1...\n- ... which in turn means anything using them (ex: CAR export; graphsync; etc) can very easily be asked to produce a merkle-proof\n  for a path over UnixFSv1 data, without requiring the querier to know about the internals.  Whew!\n\nWe hope users and developers alike will find value in how these systems are now layered.\n\n\n\nChange Policy\n-------------\n\nThe go-ipld-prime library is ready to use, and we value stability highly.\n\nWe make releases periodically.\nHowever, using a commit hash to pin versions precisely when depending on this library is also perfectly acceptable.\n(Only commit hashes on the master branch can be expected to persist, however;\ndepending on a commit hash in a branch is not recommended.  See [development branches](#development-branches).)\n\nWe maintain a [CHANGELOG](CHANGELOG.md)!\nPlease read it, when updating!\n\nWe do make reasonable attempts to minimize the degree of changes to the library which will create \"breaking change\" experiences for downstream consumers,\nand we do document these in the changelog (often, even with specific migration instructions).\nHowever, we do also still recommend running your own compile and test suites as a matter of course after updating.\n\nYou can help make developing this library easier by staying up-to-date as a downstream consumer!\nWhen we do discover a need for API changes, we typically try to introduce the new API first,\nand do at least one release tag in which the old API is deprecated (but not yet removed).\nWe will all be able to develop software faster, together, as an ecosystem,\nif libraries can keep reasonably closely up-to-date with the most recent tags.\n\n\n### Version Names\n\nWhen a tag is made, version number steps in go-ipld-prime advance as follows:\n\n1. the number bumps when the lead maintainer says it does.\n2. even numbers should be easy upgrades; odd numbers may change things.\n3. the version will start with `v0.` until further notice.\n\n[This is WarpVer](https://gist.github.com/warpfork/98d2f4060c68a565e8ad18ea4814c25f).\n\nThese version numbers are provided as hints about what to expect,\nbut ultimately, you should always invoke your compiler and your tests to tell you about compatibility,\nas well as read the [changelog](CHANGELOG.md).\n\n\n### Updating\n\n**Read the [CHANGELOG](CHANGELOG.md).**\n\nReally, read it.  We put exact migration instructions in there, as much as possible.  Even outright scripts, when feasible.\n\nAn even-number release tag is usually made very shortly before an odd number tag,\nso if you're cautious about absorbing changes, you should update to the even number first,\nrun all your tests, and *then* upgrade to the odd number.\nUsually the step to the even number should go off without a hitch, but if you *do* get problems from advancing to an even number tag,\nA) you can be pretty sure it's a bug, and B) you didn't have to edit a bunch of code before finding that out.\n\n\n### Development branches\n\nThe following are norms you can expect of changes to this codebase, and the treatment of branches:\n\n- The `master` branch will not be force-pushed.\n    - (exceptional circumstances may exist, but such exceptions will only be considered valid for about as long after push as the \"$N-second-rule\" about dropped food).\n    - Therefore, commit hashes on master are gold to link against.\n- All other branches *can* be force-pushed.\n    - Therefore, commit hashes not reachable from the master branch are inadvisable to link against.\n- If it's on master, it's understood to be good, in as much as we can tell.\n    - Changes and features don't get merged until their tests pass!\n    - Packages of \"alpha\" developmental status may exist, and be more subject to change than other more finalized parts of the repo, but their self-tests will at least pass.\n- Development proceeds -- both starting from and ending on -- the `master` branch.\n    - There are no other long-running supported-but-not-master branches.\n    - The existence of tags at any particular commit do not indicate that we will consider starting a long running and supported diverged branch from that point, nor start doing backports, etc.\n"
  },
  {
    "path": "README_migrationGuide.md",
    "content": "A short guide to migrating to go-ipld-prime from other repos\n============================================================\n\nHere are some quick notes on APIs that you might've been using\nif you worked with IPLD in golang before go-ipld-prime,\nand a pointer to what you should check out for an equivalent\nin order to upgrade your code to use go-ipld-prime.\n\n(Let us know if there are more pointers we should add to this list to ease your journey,\nor someone else's future journey!)\n\n- Were you using [ipfs/go-datastore](https://pkg.go.dev/github.com/ipfs/go-datastore) APIs?\n\t- You can wrap those in `storage/dsadapter` and keep using them.\n\t  You can also plug that into `linking.LinkSystem` to get higher level IPLD operations.\n\t- Or if you were only using datastore because of some specific implementation of it, like, say `flatfs`?\n\t  Then check out the possibility of moving all the way directly to new implementations like `storage/fsstore`.\n- Were you using [ipfs/go-ipfs-blockstore](https://pkg.go.dev/github.com/ipfs/go-ipfs-blockstore) APIs?\n\t- You can wrap those in `storage/bsadapter` and keep using them.\n\t  You can also plug that into `linking.LinkSystem` to get higher level IPLD operations.\n\t  (This is almost exactly the same; we've just simplified in the interface, made it easier to implement, and cleaned up inconsistencies with the other interfaces in this migration guide which were already very very similar.)\n- Were you using [ipfs/go-blockservice](https://pkg.go.dev/github.com/ipfs/go-blockservice) APIs?\n\t- You can wrap those in `storage/bsrvadapter` and keep using them.\n\t  You can also plug that into `linking.LinkSystem` to get higher level IPLD operations.\n\t\t- Be judicious about whether you actually want to do this.\n\t\t  Plugging in the potential to experience unknown network latencies into code that's expecting predictable local lookup speeds\n\t\t  may have undesirable performance outcomes.  (But if you want to do it, go ahead...)\n- Were you using [ipfs/go-ipld-format.DAGService](https://pkg.go.dev/github.com/ipfs/go-ipld-format#DAGService)?\n\t- If you're using the `Add` and `Get` methods: those are now on `linking.LinkSystem`, as `Store` and `Load`.\n\t- If you're using the `*Many` methods: those don't have direct replacements;\n\t  we don't use APIs that force that style of future-aggregation anymore, because it's bad for pipelining.\n\t  Just use `Store` and `Load`.\n- Were you using [ipfs/go-ipld-format.Node](https://pkg.go.dev/github.com/ipfs/go-ipld-format#Node)?\n\t- That's actually a semantic doozy -- we use the word \"node\" _much_ differently now.\n\t  See https://ipld.io/glossary/#node for an introduction.\n\t  (Long story short: the old \"node\" was often more like a whole block, and the new \"node\" is more like an AST node: there's lots of \"node\" in a \"block\" now.)\n\t- There's an `datamodel.Node` interface -- it's probably what you want.\n\t  (You just might have to update how you think about it -- see above bullet point about semantics shift.)\n\t  It's also aliased as the `ipld.Node` interface here right in the root package, because it's such an important and central interface that you'll be using it all the time.\n\t- Are you specifically looking for how to get a list of links out of a block?\n\t  That's a `LinkSystem.Load` followed by applying `traversal.SelectLinks` on the node it gives you: now you've got the list of links from that node (and its children, recursively, as long as they came from the same block of raw data), tada!\n- Are you looking for the equivalent of [ipfs/go-ipld-format.Link](https://pkg.go.dev/github.com/ipfs/go-ipld-format#Link)?\n\t- That's actually a feature specific to dag-pb, and arguably even specific to unixfsv1.\n\t  There is no equivalent in go-ipld-prime as a result.\n\t  But you'll find it in other libraries that are modern and go-ipld-prime based: see below.\n- Were you using some feature specific to dag-pb?\n\t- There's an updated dag-pb codec found in https://github.com/ipld/go-codec-dagpb -- it should have what you need.\n\t- Does it turn out you actually meant you're using some feature specific to unixfsv1?\n\t  (Yeah -- that comes up a lot.  It's one of the reasons we're deprecating so many of the old libraries -- they make it _really_ easy to confuse this.)\n\t  Then hang on for the next bullet point, which is for you! :)\n- Were you using some features of unixfsv1?\n\t- Check out the https://github.com/ipfs/go-unixfsnode library -- it should have what you need.\n\t\t- Pathing, like what used to be found in ipfs/go-path?  That's here now.\n\t\t- Sharding?  That's here now too.\n\t\t- You probably don't need incentives if you're here already, but can we quickly mention that... you can use Selectors over these?  Neat!\n\nIf you're encountering more questions about how to migrate some code,\nplease jump in to the ipld chat via either [matrix](https://matrix.to/#/#ipld:ipfs.io) or discord (or any other bridge)\nand ask!\nWe want to grow this list of pointers to be as encompassing and helpful as possible.\n"
  },
  {
    "path": "adl/interface.go",
    "content": "package adl\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// ADL is an interface denoting an Advanced Data Layout,\n// which is something that supports all the datamodel.Node operations,\n// but may be doing so using some custom internal logic.\n//\n// For more details, see the docs at\n// https://ipld.io/docs/advanced-data-layouts/ .\n//\n// This interface doesn't specify much new behavior, but it does include\n// the requirement of a way to tell an examiner about your \"substrate\",\n// since this concept does seem to be present in all ADLs.\ntype ADL interface {\n\tdatamodel.Node\n\n\t// Substrate returns the underlying Data Model node, which can be used\n\t// to encode an ADL's raw layout.\n\t//\n\t// Note that the substrate of an ADL can contain other ADLs!\n\tSubstrate() datamodel.Node\n}\n"
  },
  {
    "path": "adl/rot13adl/example_test.go",
    "content": "package rot13adl_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/ipfs/go-cid\"\n\n\t\"github.com/ipld/go-ipld-prime/adl/rot13adl\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/storage/memstore\"\n)\n\nfunc ExampleReify_unmarshallingToADL() {\n\t// Create a NodeBuilder for the ADL's substrate.\n\t//  Unmarshalling into this memory structure is optimal,\n\t//   because it immediately puts data into the right memory layout for the ADL code to work on,\n\t//  but you could use any other kind of NodeBuilder just as well and still get correct results.\n\tnb := rot13adl.Prototype.SubstrateRoot.NewBuilder()\n\n\t// Unmarshal -- using the substrate's nodebuilder just like you'd unmarshal with any other nodebuilder.\n\terr := dagjson.Decode(nb, strings.NewReader(`\"n pbby fgevat\"`))\n\tfmt.Printf(\"unmarshal error: %v\\n\", err)\n\n\t// Use `Reify` to get the synthetic high-level view of the ADL data.\n\tsubstrateNode := nb.Build()\n\tsyntheticView, err := rot13adl.Reify(substrateNode)\n\tfmt.Printf(\"reify error: %v\\n\", err)\n\n\t// We can inspect the synthetic ADL node like any other node!\n\tfmt.Printf(\"adl node kind: %v\\n\", syntheticView.Kind())\n\tfmt.Printf(\"adl view value: %q\\n\", must.String(syntheticView))\n\n\t// Output:\n\t// unmarshal error: <nil>\n\t// reify error: <nil>\n\t// adl node kind: string\n\t// adl view value: \"a cool string\"\n}\nfunc ExampleReify_loadingToADL() {\n\n\t// Create a NodeBuilder for the ADL's substrate.\n\t//  Unmarshalling into this memory structure is optimal,\n\t//   because it immediately puts data into the right memory layout for the ADL code to work on,\n\t//  but you could use any other kind of NodeBuilder just as well and still get correct results.\n\tnb := rot13adl.Prototype.SubstrateRoot.NewBuilder()\n\n\t// Unmarshal -- using the substrate's nodebuilder just like you'd unmarshal with any other nodebuilder.\n\terr := dagjson.Decode(nb, strings.NewReader(`\"n pbby fgevat\"`))\n\tfmt.Printf(\"unmarshal error: %v\\n\", err)\n\n\tsubstrateNode := nb.Build()\n\t// now save the node to storage\n\tlp := cidlink.LinkPrototype{Prefix: cid.Prefix{\n\t\tVersion:  1,\n\t\tCodec:    0x129,\n\t\tMhType:   0x13,\n\t\tMhLength: 4,\n\t}}\n\tlinkSystem := cidlink.DefaultLinkSystem()\n\tstorage := &memstore.Store{}\n\tlinkSystem.SetReadStorage(storage)\n\tlinkSystem.SetWriteStorage(storage)\n\tlinkSystem.NodeReifier = func(_ linking.LinkContext, nd datamodel.Node, _ *linking.LinkSystem) (datamodel.Node, error) {\n\t\treturn rot13adl.Reify(nd)\n\t}\n\tlnk, err := linkSystem.Store(linking.LinkContext{Ctx: context.Background()}, lp, substrateNode)\n\tfmt.Printf(\"storage error: %v\\n\", err)\n\n\t// reload from storage, but this time the NodeReifier function should give us the ADL\n\tsyntheticView, err := linkSystem.Load(linking.LinkContext{Ctx: context.Background()}, lnk, rot13adl.Prototype.SubstrateRoot)\n\tfmt.Printf(\"load error: %v\\n\", err)\n\n\t// We can inspect the synthetic ADL node like any other node!\n\tfmt.Printf(\"adl node kind: %v\\n\", syntheticView.Kind())\n\tfmt.Printf(\"adl view value: %q\\n\", must.String(syntheticView))\n\n\t// Output:\n\t// unmarshal error: <nil>\n\t// storage error: <nil>\n\t// load error: <nil>\n\t// adl node kind: string\n\t// adl view value: \"a cool string\"\n}\nfunc ExampleR13String_creatingViaADL() {\n\t// Create a NodeBuilder for the ADL -- the high-level synthesized thing (not the substrate).\n\tnb := rot13adl.Prototype.Node.NewBuilder()\n\n\t// Create a ADL node via its builder.  This is just like creating any other node in IPLD.\n\tnb.AssignString(\"woohoo\")\n\tn := nb.Build()\n\n\t// We can inspect the synthetic ADL node like any other node!\n\tfmt.Printf(\"adl node kind: %v\\n\", n.Kind())\n\tfmt.Printf(\"adl view value: %q\\n\", must.String(n))\n\n\t// We can get the substrate view and examine that as a node too.\n\t// (This requires a cast to see that we have an ADL, though.  Not all IPLD nodes have a 'Substrate' property.)\n\tsubstrateNode := n.(rot13adl.R13String).Substrate()\n\tfmt.Printf(\"substrate node kind: %v\\n\", substrateNode.Kind())\n\tfmt.Printf(\"substrate value: %q\\n\", must.String(substrateNode))\n\n\t// To marshal the ADL, just use marshal methods on its substrate as normal:\n\tvar marshalBuffer bytes.Buffer\n\terr := dagjson.Encode(substrateNode, &marshalBuffer)\n\tfmt.Printf(\"marshalled: %v\\n\", marshalBuffer.String())\n\tfmt.Printf(\"marshal error: %v\\n\", err)\n\n\t// Output:\n\t// adl node kind: string\n\t// adl view value: \"woohoo\"\n\t// substrate node kind: string\n\t// substrate value: \"jbbubb\"\n\t// marshalled: \"jbbubb\"\n\t// marshal error: <nil>\n}\n\n// It's worth noting that the builders for an ADL substrate node still return the substrate.\n// (This is interesting in contrast to Schemas, where codegenerated representation-level builders\n// yield the type-level node values (and not the representation level node).)\n//\n// To convert the substrate node to the high level synthesized view of the ADL,\n// use Reify as normal -- it's the same whether you've used the substrate type\n// or if you've used any other node implementation to hold the data.\n//\n\n// Future work: unmarshalling which can invoke an ADL mid-structure,\n// and automatically places the reified ADL in place in the larger structure.\n//\n// There will be several ways to do this (it hinges around \"the signalling problem\",\n// discussed in https://github.com/ipld/specs/issues/130 ):\n//\n// The first way is to use IPLD Schemas, which provide a signalling mechanism\n// by leaning on the schema, and the matching of shape of surrounding data to the schema,\n// as a way to determine where an ADL is expected to appear.\n//\n// A second mechanism could involve new unmarshal function contracts\n// which would ake a (fairly complex) argument that says what NodePrototype to use in certain positions.\n// This could be accomplished by use of Selectors.\n// (This would also have many other potential purposes -- implementing this in terms of NodePrototype selection is very multi-purpose,\n// and could be used for efficiency and misc tuning purposes,\n// for expecting a *schema* thing part way through, and so forth.)\n//\n"
  },
  {
    "path": "adl/rot13adl/rot13logic.go",
    "content": "package rot13adl\n\nimport (\n\t\"strings\"\n)\n\nvar replaceTable = []string{\n\t\"A\", \"N\",\n\t\"B\", \"O\",\n\t\"C\", \"P\",\n\t\"D\", \"Q\",\n\t\"E\", \"R\",\n\t\"F\", \"S\",\n\t\"G\", \"T\",\n\t\"H\", \"U\",\n\t\"I\", \"V\",\n\t\"J\", \"W\",\n\t\"K\", \"X\",\n\t\"L\", \"Y\",\n\t\"M\", \"Z\",\n\t\"N\", \"A\",\n\t\"O\", \"B\",\n\t\"P\", \"C\",\n\t\"Q\", \"D\",\n\t\"R\", \"E\",\n\t\"S\", \"F\",\n\t\"T\", \"G\",\n\t\"U\", \"H\",\n\t\"V\", \"I\",\n\t\"W\", \"J\",\n\t\"X\", \"K\",\n\t\"Y\", \"L\",\n\t\"Z\", \"M\",\n\t\"a\", \"n\",\n\t\"b\", \"o\",\n\t\"c\", \"p\",\n\t\"d\", \"q\",\n\t\"e\", \"r\",\n\t\"f\", \"s\",\n\t\"g\", \"t\",\n\t\"h\", \"u\",\n\t\"i\", \"v\",\n\t\"j\", \"w\",\n\t\"k\", \"x\",\n\t\"l\", \"y\",\n\t\"m\", \"z\",\n\t\"n\", \"a\",\n\t\"o\", \"b\",\n\t\"p\", \"c\",\n\t\"q\", \"d\",\n\t\"r\", \"e\",\n\t\"s\", \"f\",\n\t\"t\", \"g\",\n\t\"u\", \"h\",\n\t\"v\", \"i\",\n\t\"w\", \"j\",\n\t\"x\", \"k\",\n\t\"y\", \"l\",\n\t\"z\", \"m\",\n}\nvar unreplaceTable = func() []string {\n\tv := make([]string, len(replaceTable))\n\tfor i := 0; i < len(replaceTable); i += 2 {\n\t\tv[i] = replaceTable[i+1]\n\t\tv[i+1] = replaceTable[i]\n\t}\n\treturn v\n}()\n\n// rotate transforms from the logical content to the raw content.\nfunc rotate(s string) string {\n\treturn strings.NewReplacer(replaceTable...).Replace(s)\n}\n\n// unrotate transforms from the raw content to the logical content.\nfunc unrotate(s string) string {\n\treturn strings.NewReplacer(unreplaceTable...).Replace(s)\n}\n"
  },
  {
    "path": "adl/rot13adl/rot13node.go",
    "content": "/*\nrot13adl is a demo ADL -- its purpose is to show what an ADL and its public interface can look like.\nIt implements a \"rot13\" string: when creating data through the ADL, the user gives it a regular string;\nthe ADL will create aninternal representation of it which has the characters altered in a reversible way.\n\nIt provides reference and example materal, but it's very unlikely you want to use it in real situations ;)\n\nThere are several ways to move data in and out of the ADL:\n\n  - treat it like a regular IPLD map:\n  - using the exported NodePrototype can be used to get a NodeBuilder which can accept keys and values;\n  - using the resulting Node and doing lookup operations on it like a regular map;\n  - load up raw substrate data and `Reify()` it into the synthesized form, and *then* treat it like a regular map:\n  - this is handy if the raw data already parsed into Nodes.\n  - optionally, use `SubstrateRootPrototype` as the prototype for loading the raw substrate data;\n    any kind of Node is a valid input to Reify, but this one will generally have optimal performance.\n  - take the synthesized form and inspect its substrate data:\n  - the `Substrate()` method will return another datamodel.Node which is the root of the raw substrate data,\n    and can be walked normally like any other datamodel.Node.\n*/\npackage rot13adl\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/mixins\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// -- Node -->\n\nvar _ datamodel.Node = (R13String)(nil)\n\ntype R13String = *_R13String\n\ntype _R13String struct {\n\traw         string // the raw content, before our ADL lens is applied to it.\n\tsynthesized string // the content that the ADL presents.  calculated proactively from the original, in this implementation (though you could imagine implementing it lazily, in either direction, too).\n}\n\nfunc (*_R13String) Kind() datamodel.Kind {\n\treturn datamodel.Kind_String\n}\nfunc (*_R13String) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"rot13adl.R13String\"}.LookupByString(\"\")\n}\nfunc (*_R13String) LookupByNode(datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"rot13adl.R13String\"}.LookupByNode(nil)\n}\nfunc (*_R13String) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"rot13adl.R13String\"}.LookupByIndex(0)\n}\nfunc (*_R13String) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"rot13adl.R13String\"}.LookupBySegment(seg)\n}\nfunc (*_R13String) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (*_R13String) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (*_R13String) Length() int64 {\n\treturn -1\n}\nfunc (*_R13String) IsAbsent() bool {\n\treturn false\n}\nfunc (*_R13String) IsNull() bool {\n\treturn false\n}\nfunc (*_R13String) AsBool() (bool, error) {\n\treturn mixins.String{TypeName: \"rot13adl.R13String\"}.AsBool()\n}\nfunc (*_R13String) AsInt() (int64, error) {\n\treturn mixins.String{TypeName: \"rot13adl.R13String\"}.AsInt()\n}\nfunc (*_R13String) AsFloat() (float64, error) {\n\treturn mixins.String{TypeName: \"rot13adl.R13String\"}.AsFloat()\n}\nfunc (n *_R13String) AsString() (string, error) {\n\treturn n.synthesized, nil\n}\nfunc (*_R13String) AsBytes() ([]byte, error) {\n\treturn mixins.String{TypeName: \"rot13adl.R13String\"}.AsBytes()\n}\nfunc (*_R13String) AsLink() (datamodel.Link, error) {\n\treturn mixins.String{TypeName: \"rot13adl.R13String\"}.AsLink()\n}\nfunc (*_R13String) Prototype() datamodel.NodePrototype {\n\treturn _R13String__Prototype{}\n}\n\n// -- NodePrototype -->\n\nvar _ datamodel.NodePrototype = _R13String__Prototype{}\n\ntype _R13String__Prototype struct {\n\t// There's no configuration to this ADL.\n\n\t// A more complex ADL might have some kind of parameters here.\n\t//\n\t// The general contract of a NodePrototype is supposed to be that:\n\t// when you get one from an existing Node,\n\t//  it should have enough information to create a new Node that\n\t//   could \"replace\" the previous one in whatever context it's in.\n\t// For ADLs, that means it should carry most of the configuration.\n\t//\n\t// An ADL that does multi-block stuff might also need functions like a LinkLoader passed in through here.\n}\n\nfunc (np _R13String__Prototype) NewBuilder() datamodel.NodeBuilder {\n\treturn &_R13String__Builder{}\n}\n\n// -- NodeBuilder -->\n\nvar _ datamodel.NodeBuilder = (*_R13String__Builder)(nil)\n\ntype _R13String__Builder struct {\n\t_R13String__Assembler\n}\n\nfunc (nb *_R13String__Builder) Build() datamodel.Node {\n\tif nb.m != schema.Maybe_Value {\n\t\tpanic(\"invalid state: cannot call Build on an assembler that's not finished\")\n\t}\n\treturn nb.w\n}\nfunc (nb *_R13String__Builder) Reset() {\n\t*nb = _R13String__Builder{}\n}\n\n// -- NodeAssembler -->\n\nvar _ datamodel.NodeAssembler = (*_R13String__Assembler)(nil)\n\ntype _R13String__Assembler struct {\n\tw *_R13String\n\tm schema.Maybe // REVIEW: if the package where this Maybe enum lives is maybe not the right home for it after all.  Or should this line use something different?  We're only using some of its values after all.\n}\n\nfunc (_R13String__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.R13String\"}.BeginMap(0)\n}\nfunc (_R13String__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.R13String\"}.BeginList(0)\n}\nfunc (na *_R13String__Assembler) AssignNull() error {\n\t// REVIEW: unclear how this might compose with some other context (like a schema) which does allow nulls.  Probably a wrapper type?\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.R13String\"}.AssignNull()\n}\nfunc (_R13String__Assembler) AssignBool(bool) error {\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.R13String\"}.AssignBool(false)\n}\nfunc (_R13String__Assembler) AssignInt(int64) error {\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.R13String\"}.AssignInt(0)\n}\nfunc (_R13String__Assembler) AssignFloat(float64) error {\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.R13String\"}.AssignFloat(0)\n}\nfunc (na *_R13String__Assembler) AssignString(v string) error {\n\tswitch na.m {\n\tcase schema.Maybe_Value:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t}\n\tna.w = &_R13String{\n\t\traw:         rotate(v),\n\t\tsynthesized: v,\n\t}\n\tna.m = schema.Maybe_Value\n\treturn nil\n}\nfunc (_R13String__Assembler) AssignBytes([]byte) error {\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.R13String\"}.AssignBytes(nil)\n}\nfunc (_R13String__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.R13String\"}.AssignLink(nil)\n}\nfunc (na *_R13String__Assembler) AssignNode(v datamodel.Node) error {\n\tif v.IsNull() {\n\t\treturn na.AssignNull()\n\t}\n\tif v2, ok := v.(*_R13String); ok {\n\t\tswitch na.m {\n\t\tcase schema.Maybe_Value:\n\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t}\n\t\tna.w = v2\n\t\tna.m = schema.Maybe_Value\n\t\treturn nil\n\t}\n\tif v2, err := v.AsString(); err != nil {\n\t\treturn err\n\t} else {\n\t\treturn na.AssignString(v2)\n\t}\n}\nfunc (_R13String__Assembler) Prototype() datamodel.NodePrototype {\n\treturn _R13String__Prototype{}\n}\n"
  },
  {
    "path": "adl/rot13adl/rot13node_test.go",
    "content": "package rot13adl\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestLogicalNodeRoundtrip(t *testing.T) {\n\t// Build high level node.\n\tnb := Prototype.Node.NewBuilder()\n\terr := nb.AssignString(\"abcd\")\n\tqt.Assert(t, err, qt.IsNil)\n\tn := nb.Build()\n\t// Inspect the high level node.\n\ts, err := n.AsString()\n\tqt.Check(t, err, qt.IsNil)\n\tqt.Check(t, s, qt.Equals, \"abcd\")\n}\n\nfunc TestNodeInternal(t *testing.T) {\n\t// Build high level node.\n\tnb := Prototype.Node.NewBuilder()\n\terr := nb.AssignString(\"abcd\")\n\tqt.Assert(t, err, qt.IsNil)\n\tn := nb.Build()\n\t// Poke its insides directly to see that the transformation occurred.\n\tqt.Check(t, n.(*_R13String).synthesized, qt.Equals, \"abcd\")\n\tqt.Check(t, n.(*_R13String).raw, qt.Equals, \"nopq\")\n}\n\nfunc TestReify(t *testing.T) {\n\tt.Run(\"using unspecialized raw node\", func(t *testing.T) {\n\t\t// Build substrate-shaped data using basicnode.\n\t\tsn := basicnode.NewString(\"nopq\")\n\t\t// Reify it.\n\t\tsynth, err := Reify(sn)\n\t\t// Inspect the resulting high level node.\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, synth.Kind(), qt.Equals, datamodel.Kind_String)\n\t\ts, err := synth.AsString()\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, s, qt.Equals, \"abcd\")\n\t})\n\tt.Run(\"using substrate node\", func(t *testing.T) {\n\t\t// Build substrate-shaped data, in the substrate type right from the start.\n\t\tsnb := Prototype.SubstrateRoot.NewBuilder()\n\t\tsnb.AssignString(\"nopq\")\n\t\tsn := snb.Build()\n\t\t// Reify it.\n\t\tsynth, err := Reify(sn)\n\t\t// Inspect the resulting high level node.\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, synth.Kind(), qt.Equals, datamodel.Kind_String)\n\t\ts, err := synth.AsString()\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, s, qt.Equals, \"abcd\")\n\t})\n}\n\nfunc TestInspectingSubstrate(t *testing.T) {\n\t// Build high level node.\n\tnb := Prototype.Node.NewBuilder()\n\terr := nb.AssignString(\"abcd\")\n\tqt.Assert(t, err, qt.IsNil)\n\tn := nb.Build()\n\t// Ask it about its substrate, and inspect that.\n\tsn := n.(R13String).Substrate()\n\t// TODO: It's unfortunate this is only available as a concrete type cast: we should probably make a standard feature detection interface with `Substrate()`.\n\t//  Is it reasonable to make this part of a standard feature detection pattern,\n\t//   and make that interface reside in the main IPLD package?  Or in an `adl` package that contains such standard interfaces?\n\tss, err := sn.AsString()\n\tqt.Check(t, err, qt.IsNil)\n\tqt.Check(t, ss, qt.Equals, \"nopq\")\n}\n"
  },
  {
    "path": "adl/rot13adl/rot13prototypes.go",
    "content": "package rot13adl\n\n// Prototype embeds a NodePrototype for every kind of Node implementation in this package.\n// This includes both the synthesized node as well as the substrate root node\n// (other substrate interior node prototypes are not exported here;\n// it's unlikely they'll be useful outside of the scope of the ADL's implementation package.)\n//\n// You can use it like this:\n//\n//\trot13adl.Prototype.Node.NewBuilder() //...\n//\n// and:\n//\n//\trot13adl.Prototype.SubstrateRoot.NewBuilder() // ...\nvar Prototype prototype\n\n// This may seem a tad mundane, but we do it for consistency with the way\n// other Node implementation packages (like basicnode) do this:\n// it's a convention for \"pkgname.Prototype.SpecificThing.NewBuilder()\" to be defined.\n\ntype prototype struct {\n\tNode          _R13String__Prototype\n\tSubstrateRoot _Substrate__Prototype\n}\n\n// REVIEW: In ADLs that use codegenerated substrate types defined by an IPLD Schema, the `Prototype.SubstrateRoot` field...\n// should it be a `_SubstrateRoot__Prototype`, or a `_SubstrateRoot__ReprPrototype`?\n//  Probably the latter, because the only thing an external user of this package should be interested in is how to read data into memory in an optimal path.\n// But does this answer all questions?  Codegen ReprPrototypes currently still return the type-level node from their Build method!\n//  This probably would functionally work -- we could make the Reify methods check for either the type-level or repr-level types -- but would it be weird/surprising/hard-to-use?\n"
  },
  {
    "path": "adl/rot13adl/rot13reification.go",
    "content": "package rot13adl\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// Reify examines data in a Node to see if it matches the shape for valid substrate data for this ADL,\n// and if so, synthesizes and returns the high-level view of the ADL.\n// If it succeeds in recognizing the raw data as this ADL,\n// Reify returns a new Node which exhibits the logical behaviors of the ADL;\n// otherwise, it returns an error.\n//\n// The input data can be any implementation of ipld.Node;\n// it will be considered purely through that interface.\n//\n// If your application is expecting ADL data, this pipeline can be optimized\n// by using the SubstratePrototype right from the start when unmarshalling;\n// then, Reify can detect if the rawRoot parameter is of that implementation,\n// and it can save some processing work internally that can be known to already be done.\n//\n// Reification will generally operate on the data in a single block\n// (e.g. this function will not do any additional block loads and unmarshalling).\n// This is important because some ADLs handle data so large that loading it all\n// eagerly would be impractical (and in some cases outright impossible).\n// However, it also necessarily implies that invalid data may lie beyond\n// one of those lazy loads, and it won't be discovered at the time of Reify.\n//\n// In this demo ADL, we don't have multi-block content at all,\n// so of course we don't have any additional block loads!\n// However, ADL implementations may vary in their approaches to lazy vs eager loading.\n// All ADLs should document their exact semantics regarding this --\n// especially if it has any implications for boundaries of data validity checking.\n//\n// REVIEW: this function is currently not conforming to any particular interface;\n// if we evolve the contract for ADLs to include an interface for reficiation functions,\n// might we need to add context and link loader systems as parameters to it?\n// Not all implementations might need it, as per previous paragraph; but some might.\n// Reification for multiblock ADLs might also need link loader systems as a parameter here\n// so they can capture them as config and hold them for use in future operations that do lazy loading.\nfunc Reify(maybeSubstrateRoot datamodel.Node) (datamodel.Node, error) {\n\t// Reify is often very easy to implement,\n\t//  especially if you have an IPLD Schema that specifies the shape of the substrate data:\n\t// We can just check if the data in maybeSubstrateRoot happens to already be exactly the right type,\n\t//  and if so, take very direct shortcuts because we already know its been validated in shape;\n\t// otherwise, we create a new piece of memory for our native substrate memory layout,\n\t//  and assign into it from the raw node, validating in the process,\n\t//   which again just leans directly on the shape validation logic already given to us by the schema logic on that type.\n\t// (Checking the concrete type of maybeSubstrateRoot in search of a shortcut is seemingly a tad redundant,\n\t//  because the AssignNode path later also has such a check!\n\t//  However, doing it earlier allows us to avoid an allocation;\n\t//   the AssignNode path doesn't become available until after NewBuilder is invoked, and NewBuilder is where allocations happen.)\n\n\t// Check if we can recognize the maybeSubstrateRoot as being our own substrate types;\n\t//  if it is, we can shortcut pretty drastically.\n\tif x, ok := maybeSubstrateRoot.(*_Substrate); ok {\n\t\t// In this ADL implementation, the high level node has the exact same memory layout as the substrate root,\n\t\t//  and so our only remaining processing here is just to cast them, so that\n\t\t//   the node we return has the correct methodset exposed.\n\t\treturn (*_R13String)(x), nil\n\t}\n\n\t// Shortcut didn't work.  Process via the data model.\n\t//  The AssignNode method on the substrate type already contains all the logic necessary for this, so we use that.\n\tnb := Prototype.SubstrateRoot.NewBuilder()\n\tif err := nb.AssignNode(maybeSubstrateRoot); err != nil {\n\t\treturn nil, fmt.Errorf(\"rot13adl.Reify failed: data does not match expected shape for substrate: %w\", err)\n\t}\n\treturn (*_R13String)(nb.Build().(*_Substrate)), nil\n}\n"
  },
  {
    "path": "adl/rot13adl/rot13substrate.go",
    "content": "package rot13adl\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/mixins\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// Substrate returns the root node of the raw internal data form of the ADL's content.\nfunc (n *_R13String) Substrate() datamodel.Node {\n\t// This is a very minor twist in the case of the rot13 ADL.\n\t//  However, for larger ADLs (especially those relating to multi-block collections),\n\t//   this could be quite a bit more involved, and would almost certainly be the root node of a larger tree.\n\treturn (*_Substrate)(n)\n}\n\n// -- Node -->\n\nvar _ datamodel.Node = (*_Substrate)(nil)\n\n// Somewhat unusually for an ADL, there's only one substrate node type,\n// and we actually made it have the same in-memory structure as the synthesized view node.\n//\n// When implementing other more complex ADLs, it will probably be more common to have\n// the synthesized high-level node type either embed or have a pointer to the substrate root node.\ntype _Substrate _R13String\n\n// REVIEW: what on earth we think the \"TypeName\" strings in error messages and other references to this node should be.\n//  At the moment, it shares a prefix with the synthesized node, which is potentially confusing (?),\n//  and I'm not sure what, if any, suffix actually makes meaningful sense to a user either.\n//  I added the segment \".internal.\" to the middle of the name mangle; does this seem helpful?\n\nfunc (*_Substrate) Kind() datamodel.Kind {\n\treturn datamodel.Kind_String\n}\nfunc (*_Substrate) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"rot13adl.internal.Substrate\"}.LookupByString(\"\")\n}\nfunc (*_Substrate) LookupByNode(datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"rot13adl.internal.Substrate\"}.LookupByNode(nil)\n}\nfunc (*_Substrate) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"rot13adl.internal.Substrate\"}.LookupByIndex(0)\n}\nfunc (*_Substrate) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"rot13adl.internal.Substrate\"}.LookupBySegment(seg)\n}\nfunc (*_Substrate) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (*_Substrate) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (*_Substrate) Length() int64 {\n\treturn -1\n}\nfunc (*_Substrate) IsAbsent() bool {\n\treturn false\n}\nfunc (*_Substrate) IsNull() bool {\n\treturn false\n}\nfunc (*_Substrate) AsBool() (bool, error) {\n\treturn mixins.String{TypeName: \"rot13adl.internal.Substrate\"}.AsBool()\n}\nfunc (*_Substrate) AsInt() (int64, error) {\n\treturn mixins.String{TypeName: \"rot13adl.internal.Substrate\"}.AsInt()\n}\nfunc (*_Substrate) AsFloat() (float64, error) {\n\treturn mixins.String{TypeName: \"rot13adl.internal.Substrate\"}.AsFloat()\n}\nfunc (n *_Substrate) AsString() (string, error) {\n\treturn n.raw, nil\n}\nfunc (*_Substrate) AsBytes() ([]byte, error) {\n\treturn mixins.String{TypeName: \"rot13adl.internal.Substrate\"}.AsBytes()\n}\nfunc (*_Substrate) AsLink() (datamodel.Link, error) {\n\treturn mixins.String{TypeName: \"rot13adl.internal.Substrate\"}.AsLink()\n}\nfunc (*_Substrate) Prototype() datamodel.NodePrototype {\n\treturn _Substrate__Prototype{}\n}\n\n// -- NodePrototype -->\n\nvar _ datamodel.NodePrototype = _Substrate__Prototype{}\n\ntype _Substrate__Prototype struct {\n\t// There's no configuration to this ADL.\n}\n\nfunc (np _Substrate__Prototype) NewBuilder() datamodel.NodeBuilder {\n\treturn &_Substrate__Builder{}\n}\n\n// -- NodeBuilder -->\n\nvar _ datamodel.NodeBuilder = (*_Substrate__Builder)(nil)\n\ntype _Substrate__Builder struct {\n\t_Substrate__Assembler\n}\n\nfunc (nb *_Substrate__Builder) Build() datamodel.Node {\n\tif nb.m != schema.Maybe_Value {\n\t\tpanic(\"invalid state: cannot call Build on an assembler that's not finished\")\n\t}\n\treturn nb.w\n}\nfunc (nb *_Substrate__Builder) Reset() {\n\t*nb = _Substrate__Builder{}\n}\n\n// -- NodeAssembler -->\n\nvar _ datamodel.NodeAssembler = (*_Substrate__Assembler)(nil)\n\ntype _Substrate__Assembler struct {\n\tw *_Substrate\n\tm schema.Maybe // REVIEW: if the package where this Maybe enum lives is maybe not the right home for it after all.  Or should this line use something different?  We're only using some of its values after all.\n}\n\nfunc (_Substrate__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.internal.Substrate\"}.BeginMap(0)\n}\nfunc (_Substrate__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.internal.Substrate\"}.BeginList(0)\n}\nfunc (na *_Substrate__Assembler) AssignNull() error {\n\t// REVIEW: unclear how this might compose with some other context (like a schema) which does allow nulls.  Probably a wrapper type?\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.internal.Substrate\"}.AssignNull()\n}\nfunc (_Substrate__Assembler) AssignBool(bool) error {\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.internal.Substrate\"}.AssignBool(false)\n}\nfunc (_Substrate__Assembler) AssignInt(int64) error {\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.internal.Substrate\"}.AssignInt(0)\n}\nfunc (_Substrate__Assembler) AssignFloat(float64) error {\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.internal.Substrate\"}.AssignFloat(0)\n}\nfunc (na *_Substrate__Assembler) AssignString(v string) error {\n\tswitch na.m {\n\tcase schema.Maybe_Value:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t}\n\tna.w = &_Substrate{\n\t\traw:         v,\n\t\tsynthesized: unrotate(v),\n\t}\n\tna.m = schema.Maybe_Value\n\treturn nil\n}\nfunc (_Substrate__Assembler) AssignBytes([]byte) error {\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.internal.Substrate\"}.AssignBytes(nil)\n}\nfunc (_Substrate__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.StringAssembler{TypeName: \"rot13adl.internal.Substrate\"}.AssignLink(nil)\n}\nfunc (na *_Substrate__Assembler) AssignNode(v datamodel.Node) error {\n\tif v.IsNull() {\n\t\treturn na.AssignNull()\n\t}\n\tif v2, ok := v.(*_Substrate); ok {\n\t\tswitch na.m {\n\t\tcase schema.Maybe_Value:\n\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t}\n\t\tna.w = v2\n\t\tna.m = schema.Maybe_Value\n\t\treturn nil\n\t}\n\tif v2, err := v.AsString(); err != nil {\n\t\treturn err\n\t} else {\n\t\treturn na.AssignString(v2)\n\t}\n}\nfunc (_Substrate__Assembler) Prototype() datamodel.NodePrototype {\n\treturn _Substrate__Prototype{}\n}\n"
  },
  {
    "path": "adl.go",
    "content": "package ipld\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/adl\"\n)\n\ntype ADL = adl.ADL\n"
  },
  {
    "path": "codec/README.md",
    "content": "Codecs\n======\n\nThe `go-ipld-prime/codec` package is a grouping package.\nThe subpackages contains some codecs which reside in this repo.\n\nThe codecs included here are our \"batteries included\" codecs,\nbut they are not otherwise special.\n\nIt is not necessary for a codec to be a subpackage here to be a valid codec to use with go-ipld;\nanything that implements the `codec.Encoder` and `codec.Decoder` interfaces is fine.\n\n\nTerminology\n-----------\n\nWe generally refer to \"codecs\" as having an \"encode\" function and \"decode\" function.\n\nWe consider \"encoding\" to be the process of going from {Data Model} to {serial data},\nand \"decoding\" to be the process of going from {serial data} to {Data Model}.\n\n### Codec vs Multicodec\n\nA \"codec\" is _any_ function that goes from {Data Model} to {serial data}, or vice versa.\n\nA \"multicodec\" is a function which does that and is _also_ specifically recognized and described in\nthe tables in https://github.com/multiformats/multicodec/ .\n\nMulticodecs generally leave no further room for customization and configuration,\nbecause their entire behavior is supposed to be specified by a multicodec indicator code number.\n\nOur codecs, in the child packages of this one, usually offer configuration options.\nThey also usually offer exactly one function, which does *not* allow configuration,\nwhich is supplying a multicodec-compatible behavior.\nYou'll see this marked in the docs on those functions.\n\n### Marshal vs Encode\n\nIt's common to see the terms \"marshal\" and \"unmarshal\" used in golang.\n\nThose terms are usually describing when structured data is transformed into linearized, tokenized data\n(and then, perhaps, all the way to serially encoded data), or vice versa.\n\nWe would use the words the same way... except we don't end up using them,\nbecause that feature doesn't really come up in our codec layer.\n\nIn IPLD, we would describe mapping some typed data into Data Model as \"marshalling\".\n(It's one step shy of tokenizing, but barely: Data Model does already have defined ordering for every element of data.)\nAnd we do have systems that do this:\n`bindnode` and our codegen systems both do this, implicitly, when they give you an `ipld.Node` of the representation of some data.\n\nWe just don't end up talking about it as \"marshalling\" because of how it's done implicitly by those systems.\nAs a result, all of our features relating to codecs only end up speaking about \"encoding\" and \"decoding\".\n\n### Legacy code\n\nThere are some appearances of the words \"marshal\" and \"unmarshal\" in some of our subpackages here.\n\nThat verbiage is generally on the way out.\nFor functions and structures with those names, you'll notice their docs marking them as deprecated.\n\n\nWhy have \"batteries-included\" codecs?\n-------------------------------------\n\nThese codecs live in this repo because they're commonly used, highly supported,\nand general-purpose codecs that we recommend for widespread usage in new developments.\n\nAlso, it's just plain nice to have something in-repo for development purposes.\nIt makes sure that if we try to make any API changes, we immediately see if they'd make codecs harder to implement.\nWe also use the batteries-included codecs for debugging, for test fixtures, and for benchmarking.\n\nFurther yet, the batteries-included codecs let us offer getting-started APIs.\nFor example, we offer some helper APIs which use codecs like e.g. JSON to give consumers of the libraries\none-step helper methods that \"do the right thing\" with zero config... so long as they happen to use that codec.\nEven for consumers who don't use those codecs, such functions then serve as natural documentation\nand examples for what to do to put their codec of choice to work.\n"
  },
  {
    "path": "codec/api.go",
    "content": "package codec\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// The following two types define the two directions of transform that a codec can be expected to perform:\n// from Node to serial stream (aka \"encoding\", sometimes also described as \"marshalling\"),\n// and from serial stream to Node (via a NodeAssembler) (aka \"decoding\", sometimes also described as \"unmarshalling\").\n//\n// You'll find a couple of implementations matching this shape in subpackages of 'codec'.\n// (These are the handful of encoders and decoders we ship as \"batteries included\".)\n// Other encoder and decoder implementations can be found in other repositories/modules.\n// It should also be easy to implement encodecs and decoders of your own!\n//\n// Encoder and Decoder functions can be used on their own, but are also often used via the `ipld/linking.LinkSystem` construction,\n// which handles all the other related operations necessary for a content-addressed storage system at once.\n//\n// Encoder and Decoder functions can be registered in the multicodec table in the `ipld/multicodec` package\n// if they're providing functionality that matches the expectations for a multicodec identifier.\n// This table will be used by some common EncoderChooser and DecoderChooser implementations\n// (namely, the ones in LinkSystems produced by the `linking/cid` package).\n// It's not strictly necessary to register functions there, though; you can also just use them directly.\n//\n// There are furthermore several conventions that codec packages are recommended to follow, but are only conventions:\n//\n// Most codec packages should have a ReusableEncoder and ResuableDecoder type,\n// which contain any working memory needed by the implementation, as well as any configuration options,\n// and those types should have an Encode and Decode function respectively which match these function types.\n// They may alternatively have EncoderConfig and DecoderConfig types, which have similar purpose,\n// but aren't promising memory reuse if kept around.\n//\n// By convention, a codec package that expects to fulfill a multicodec contract will also have\n// a package-scope exported function called Encode or Decode which also matches this interface,\n// and is the equivalent of creating a zero-value ReusableEncoder or ReusableDecoder (aka, default config)\n// and using its Encode or Decode methods.\n// This package-scope function may also internally use a sync.Pool\n// to keep some ReusableEncoder values on hand to avoid unnecessary allocations.\n//\n// Note that an EncoderConfig or DecoderConfig type that supports configuration options\n// does not functionally expose those options when invoked by the multicodec system --\n// multicodec indicator codes do not provide room for extended configuration info.\n// Codecs that expose configuration options are doing so for library users to enjoy;\n// it does not mean those non-default configurations will necessarily be available\n// in all scenarios that use codecs indirectly.\n// There is also no standard interface for such configurations: by nature,\n// if they exist at all, they tend to vary per codec.\ntype (\n\t// Encoder defines the shape of a function which traverses a Node tree\n\t// and emits its data in a serialized form into an io.Writer.\n\t//\n\t// The dual of Encoder is a Decoder, which takes a NodeAssembler\n\t// and fills it with deserialized data consumed from an io.Reader.\n\t// Typically, Decoder and Encoder functions will be found in pairs,\n\t// and will be expected to be able to round-trip each other's data.\n\t//\n\t// Encoder functions can be used directly.\n\t// Encoder functions are also often used via a LinkSystem when working with content-addressed storage.\n\t// LinkSystem methods will helpfully handle the entire process of traversing a Node tree,\n\t// encoding this data, hashing it, streaming it to the writer, and committing it -- all as one step.\n\t//\n\t// An Encoder works with Nodes.\n\t// If you have a native golang structure, and want to serialize it using an Encoder,\n\t// you'll need to figure out how to transform that golang structure into an ipld.Node tree first.\n\t//\n\t// It may be useful to understand \"multicodecs\" when working with Encoders.\n\t// In IPLD, a system called \"multicodecs\" is typically used to describe encoding foramts.\n\t// A \"multicodec indicator\" is a number which describes an encoding;\n\t// the Link implementations used in IPLD (CIDs) store a multicodec indicator in the Link;\n\t// and in this library, a multicodec registry exists in the `codec` package,\n\t// and can be used to associate a multicodec indicator number with an Encoder function.\n\t// The default EncoderChooser in a LinkSystem will use this multicodec registry to select Encoder functions.\n\t// However, you can construct a LinkSystem that uses any EncoderChooser you want.\n\t// It is also possible to have and use Encoder functions that aren't registered as a multicodec at all...\n\t// we just recommend being cautious of this, because it may make your data less recognizable\n\t// when working with other systems that use multicodec indicators as part of their communication.\n\tEncoder func(datamodel.Node, io.Writer) error\n\n\t// Decoder defines the shape of a function which produces a Node tree\n\t// by reading serialized data from an io.Reader.\n\t// (Decoder doesn't itself return a Node directly, but rather takes a NodeAssembler as an argument,\n\t// because this allows the caller more control over the Node implementation,\n\t// as well as some control over allocations.)\n\t//\n\t// The dual of Decoder is an Encoder, which takes a Node and\n\t// emits its data in a serialized form into an io.Writer.\n\t// Typically, Decoder and Encoder functions will be found in pairs,\n\t// and will be expected to be able to round-trip each other's data.\n\t//\n\t// Decoder functions can be used directly.\n\t// Decoder functions are also often used via a LinkSystem when working with content-addressed storage.\n\t// LinkSystem methods will helpfully handle the entire process of opening block readers,\n\t// verifying the hash of the data stream, and applying a Decoder to build Nodes -- all as one step.\n\t//\n\t// A Decoder works with Nodes.\n\t// If you have a native golang structure, and want to populate it with data using a Decoder,\n\t// you'll need to either get a NodeAssembler which proxies data into that structure directly,\n\t// or assemble a Node as intermediate storage and copy the data to the native structure as a separate step.\n\t//\n\t// It may be useful to understand \"multicodecs\" when working with Decoders.\n\t// See the documentation on the Encoder function interface for more discussion of multicodecs,\n\t// the multicodec table, and how this is typically connected to linking.\n\tDecoder func(datamodel.NodeAssembler, io.Reader) error\n)\n\n// -------------------\n//  Errors\n//\n\ntype ErrBudgetExhausted struct{}\n\nfunc (e ErrBudgetExhausted) Error() string {\n\treturn \"decoder resource budget exhausted (message too long or too complex)\"\n}\n\n// ---------------------\n//  Other valuable and reused constants\n//\n\ntype MapSortMode uint8\n\nconst (\n\tMapSortMode_None MapSortMode = iota\n\tMapSortMode_Lexical\n\tMapSortMode_RFC7049\n)\n"
  },
  {
    "path": "codec/cbor/multicodec.go",
    "content": "package cbor\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/codec\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagcbor\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/multicodec\"\n)\n\nvar (\n\t_ codec.Decoder = Decode\n\t_ codec.Encoder = Encode\n)\n\nfunc init() {\n\tmulticodec.RegisterEncoder(0x51, Encode)\n\tmulticodec.RegisterDecoder(0x51, Decode)\n}\n\n// Decode deserializes data from the given io.Reader and feeds it into the given datamodel.NodeAssembler.\n// Decode fits the codec.Decoder function interface.\n//\n// This is the function that will be registered in the default multicodec registry during package init time.\nfunc Decode(na datamodel.NodeAssembler, r io.Reader) error {\n\treturn dagcbor.DecodeOptions{\n\t\tAllowLinks: false,\n\t}.Decode(na, r)\n}\n\n// Encode walks the given datamodel.Node and serializes it to the given io.Writer.\n// Encode fits the codec.Encoder function interface.\n//\n// This is the function that will be registered in the default multicodec registry during package init time.\nfunc Encode(n datamodel.Node, w io.Writer) error {\n\treturn dagcbor.EncodeOptions{\n\t\tAllowLinks: false,\n\t}.Encode(n, w)\n}\n"
  },
  {
    "path": "codec/cbor/roundtrip_test.go",
    "content": "package cbor\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\tnodetests \"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nvar n = fluent.MustBuildMap(basicnode.Prototype.Map, 4, func(na fluent.MapAssembler) {\n\tna.AssembleEntry(\"plain\").AssignString(\"olde string\")\n\tna.AssembleEntry(\"map\").CreateMap(2, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"one\").AssignInt(1)\n\t\tna.AssembleEntry(\"two\").AssignInt(2)\n\t})\n\tna.AssembleEntry(\"list\").CreateList(2, func(na fluent.ListAssembler) {\n\t\tna.AssembleValue().AssignString(\"three\")\n\t\tna.AssembleValue().AssignString(\"four\")\n\t})\n\tna.AssembleEntry(\"nested\").CreateMap(1, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"deeper\").CreateList(1, func(na fluent.ListAssembler) {\n\t\t\tna.AssembleValue().AssignString(\"things\")\n\t\t})\n\t})\n})\n\nvar serial = \"\\xa4eplainkolde stringcmap\\xa2cone\\x01ctwo\\x02dlist\\x82ethreedfourfnested\\xa1fdeeper\\x81fthings\"\n\nfunc TestRoundtrip(t *testing.T) {\n\tt.Run(\"encoding\", func(t *testing.T) {\n\t\tvar buf bytes.Buffer\n\t\terr := Encode(n, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, buf.String(), qt.Equals, serial)\n\t})\n\tt.Run(\"decoding\", func(t *testing.T) {\n\t\tbuf := strings.NewReader(serial)\n\t\tnb := basicnode.Prototype.Map.NewBuilder()\n\t\terr := Decode(nb, buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, nb.Build(), nodetests.NodeContentEquals, n)\n\t})\n}\n\nfunc TestRoundtripScalar(t *testing.T) {\n\tnb := basicnode.Prototype__String{}.NewBuilder()\n\tnb.AssignString(\"applesauce\")\n\tsimple := nb.Build()\n\tt.Run(\"encoding\", func(t *testing.T) {\n\t\tvar buf bytes.Buffer\n\t\terr := Encode(simple, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, buf.String(), qt.Equals, `japplesauce`)\n\t})\n\tt.Run(\"decoding\", func(t *testing.T) {\n\t\tbuf := strings.NewReader(`japplesauce`)\n\t\tnb := basicnode.Prototype__String{}.NewBuilder()\n\t\terr := Decode(nb, buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, nb.Build(), nodetests.NodeContentEquals, simple)\n\t})\n}\n"
  },
  {
    "path": "codec/dagcbor/common.go",
    "content": "package dagcbor\n\nconst linkTag = 42\n"
  },
  {
    "path": "codec/dagcbor/doc.go",
    "content": "/*\nThe dagcbor package provides a DAG-CBOR codec implementation.\n\nThe Encode and Decode functions match the codec.Encoder and codec.Decoder function interfaces,\nand can be registered with the go-ipld-prime/multicodec package for easy usage with systems such as CIDs.\n\nImporting this package will automatically have the side-effect of registering Encode and Decode\nwith the go-ipld-prime/multicodec registry, associating them with the standard multicodec indicator numbers for DAG-CBOR.\n\nThis implementation follows most of the rules of DAG-CBOR, namely:\n\n- by and large, it does emit and parse CBOR!\n\n- only explicit-length maps and lists will be emitted by Encode;\n\n- only tag 42 is accepted, and it must parse as a CID;\n\n- only 64 bit floats will be emitted by Encode.\n\nThis implementation is also not strict about certain rules:\n\n- Encode is order-passthrough when emitting maps (it does not sort, nor abort in error if unsorted data is encountered).\nTo emit sorted data, the node should be sorted before applying the Encode function.\n\n- Decode is order-passthrough when parsing maps (it does not sort, nor abort in error if unsorted data is encountered).\nTo be strict about the ordering of data, additional validation must be applied to the result of the Decode function.\n\n- Decode will accept indeterminate length lists and maps without complaint.\n(These should not be allowed according to the DAG-CBOR spec, nor will the Encode function re-emit such values,\nso this behavior should almost certainly be seen as a bug.)\n\n- Decode does not consistently verify that ints and floats use the smallest representation possible (or, the 64-bit version, in the float case).\n(Only these numeric encodings should be allowed according to the DAG-CBOR spec, and the Encode function will not re-emit variations,\nso this behavior should almost certainly be seen as a bug.)\n\nA note for future contributors: some functions in this package expose references to packages from the refmt module, and/or use them internally.\nPlease avoid adding new code which expands the visibility of these references.\nIn future work, we'd like to reduce or break this relationship entirely\n(in part, to reduce dependency sprawl, and in part because several of\nthe imprecisions noted above stem from that library's lack of strictness).\n*/\npackage dagcbor\n"
  },
  {
    "path": "codec/dagcbor/marshal.go",
    "content": "package dagcbor\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"sort\"\n\n\t\"github.com/polydawn/refmt/cbor\"\n\t\"github.com/polydawn/refmt/shared\"\n\t\"github.com/polydawn/refmt/tok\"\n\n\t\"github.com/ipld/go-ipld-prime/codec\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n)\n\n// This file should be identical to the general feature in the parent package,\n// except for the `case datamodel.Kind_Link` block,\n// which is dag-cbor's special sauce for schemafree links.\n\n// EncodeOptions can be used to customize the behavior of an encoding function.\n// The Encode method on this struct fits the codec.Encoder function interface.\ntype EncodeOptions struct {\n\t// If true, allow encoding of Link nodes as CBOR tag(42);\n\t// otherwise, reject them as unencodable.\n\tAllowLinks bool\n\n\t// Control the sorting of map keys, using one of the `codec.MapSortMode_*` constants.\n\tMapSortMode codec.MapSortMode\n}\n\n// Encode walks the given datamodel.Node and serializes it to the given io.Writer.\n// Encode fits the codec.Encoder function interface.\n//\n// The behavior of the encoder can be customized by setting fields in the EncodeOptions struct before calling this method.\nfunc (cfg EncodeOptions) Encode(n datamodel.Node, w io.Writer) error {\n\t// Probe for a builtin fast path.  Shortcut to that if possible.\n\ttype detectFastPath interface {\n\t\tEncodeDagCbor(io.Writer) error\n\t}\n\tif n2, ok := n.(detectFastPath); ok {\n\t\treturn n2.EncodeDagCbor(w)\n\t}\n\t// Okay, generic inspection path.\n\treturn Marshal(n, cbor.NewEncoder(w), cfg)\n}\n\n// Future work: we would like to remove the Marshal function,\n// and in particular, stop seeing types from refmt (like shared.TokenSink) be visible.\n// Right now, some kinds of configuration (e.g. for whitespace and prettyprint) are only available through interacting with the refmt types;\n// we should improve our API so that this can be done with only our own types in this package.\n\n// Marshal is a deprecated function.\n// Please consider switching to EncodeOptions.Encode instead.\nfunc Marshal(n datamodel.Node, sink shared.TokenSink, options EncodeOptions) error {\n\tvar tk tok.Token\n\treturn marshal(n, &tk, sink, options)\n}\n\nfunc marshal(n datamodel.Node, tk *tok.Token, sink shared.TokenSink, options EncodeOptions) error {\n\tswitch n.Kind() {\n\tcase datamodel.Kind_Invalid:\n\t\treturn fmt.Errorf(\"cannot traverse a node that is absent\")\n\tcase datamodel.Kind_Null:\n\t\ttk.Type = tok.TNull\n\t\t_, err := sink.Step(tk)\n\t\treturn err\n\tcase datamodel.Kind_Map:\n\t\treturn marshalMap(n, tk, sink, options)\n\tcase datamodel.Kind_List:\n\t\t// Emit start of list.\n\t\ttk.Type = tok.TArrOpen\n\t\tl := n.Length()\n\t\ttk.Length = int(l) // TODO: overflow check\n\t\tif _, err := sink.Step(tk); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// Emit list contents (and recurse).\n\t\tfor i := int64(0); i < l; i++ {\n\t\t\tv, err := n.LookupByIndex(i)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := marshal(v, tk, sink, options); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\t// Emit list close.\n\t\ttk.Type = tok.TArrClose\n\t\t_, err := sink.Step(tk)\n\t\treturn err\n\tcase datamodel.Kind_Bool:\n\t\tv, err := n.AsBool()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttk.Type = tok.TBool\n\t\ttk.Bool = v\n\t\t_, err = sink.Step(tk)\n\t\treturn err\n\tcase datamodel.Kind_Int:\n\t\tif uin, ok := n.(datamodel.UintNode); ok {\n\t\t\tv, err := uin.AsUint()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\ttk.Type = tok.TUint\n\t\t\ttk.Uint = v\n\t\t} else {\n\t\t\tv, err := n.AsInt()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\ttk.Type = tok.TInt\n\t\t\ttk.Int = v\n\t\t}\n\t\t_, err := sink.Step(tk)\n\t\treturn err\n\tcase datamodel.Kind_Float:\n\t\tv, err := n.AsFloat()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttk.Type = tok.TFloat64\n\t\ttk.Float64 = v\n\t\t_, err = sink.Step(tk)\n\t\treturn err\n\tcase datamodel.Kind_String:\n\t\tv, err := n.AsString()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttk.Type = tok.TString\n\t\ttk.Str = v\n\t\t_, err = sink.Step(tk)\n\t\treturn err\n\tcase datamodel.Kind_Bytes:\n\t\tv, err := n.AsBytes()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttk.Type = tok.TBytes\n\t\ttk.Bytes = v\n\t\t_, err = sink.Step(tk)\n\t\treturn err\n\tcase datamodel.Kind_Link:\n\t\tif !options.AllowLinks {\n\t\t\treturn fmt.Errorf(\"cannot Marshal ipld links to CBOR\")\n\t\t}\n\t\tv, err := n.AsLink()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tswitch lnk := v.(type) {\n\t\tcase cidlink.Link:\n\t\t\tif !lnk.Cid.Defined() {\n\t\t\t\treturn fmt.Errorf(\"encoding undefined CIDs are not supported by this codec\")\n\t\t\t}\n\t\t\ttk.Type = tok.TBytes\n\t\t\ttk.Bytes = append([]byte{0}, lnk.Bytes()...)\n\t\t\ttk.Tagged = true\n\t\t\ttk.Tag = linkTag\n\t\t\t_, err = sink.Step(tk)\n\t\t\ttk.Tagged = false\n\t\t\treturn err\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"schemafree link emission only supported by this codec for CID type links\")\n\t\t}\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\n\nfunc marshalMap(n datamodel.Node, tk *tok.Token, sink shared.TokenSink, options EncodeOptions) error {\n\t// Emit start of map.\n\ttk.Type = tok.TMapOpen\n\texpectedLength := int(n.Length())\n\ttk.Length = expectedLength // TODO: overflow check\n\tif _, err := sink.Step(tk); err != nil {\n\t\treturn err\n\t}\n\tif options.MapSortMode != codec.MapSortMode_None {\n\t\t// Collect map entries, then sort by key\n\t\ttype entry struct {\n\t\t\tkey   string\n\t\t\tvalue datamodel.Node\n\t\t}\n\t\tentries := []entry{}\n\t\tfor itr := n.MapIterator(); !itr.Done(); {\n\t\t\tk, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tkeyStr, err := k.AsString()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tentries = append(entries, entry{keyStr, v})\n\t\t}\n\t\tif len(entries) != expectedLength {\n\t\t\treturn fmt.Errorf(\"map Length() does not match number of MapIterator() entries\")\n\t\t}\n\t\t// Apply the desired sort function.\n\t\tswitch options.MapSortMode {\n\t\tcase codec.MapSortMode_Lexical:\n\t\t\tsort.Slice(entries, func(i, j int) bool {\n\t\t\t\treturn entries[i].key < entries[j].key\n\t\t\t})\n\t\tcase codec.MapSortMode_RFC7049:\n\t\t\tsort.Slice(entries, func(i, j int) bool {\n\t\t\t\t// RFC7049 style sort as per DAG-CBOR spec\n\t\t\t\tli, lj := len(entries[i].key), len(entries[j].key)\n\t\t\t\tif li == lj {\n\t\t\t\t\treturn entries[i].key < entries[j].key\n\t\t\t\t}\n\t\t\t\treturn li < lj\n\t\t\t})\n\t\t}\n\t\t// Emit map contents (and recurse).\n\t\tfor _, e := range entries {\n\t\t\ttk.Type = tok.TString\n\t\t\ttk.Str = e.key\n\t\t\tif _, err := sink.Step(tk); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := marshal(e.value, tk, sink, options); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t} else { // no sorting\n\t\t// Emit map contents (and recurse).\n\t\tvar entryCount int\n\t\tfor itr := n.MapIterator(); !itr.Done(); {\n\t\t\tk, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tentryCount++\n\t\t\ttk.Type = tok.TString\n\t\t\ttk.Str, err = k.AsString()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif _, err := sink.Step(tk); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := marshal(v, tk, sink, options); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif entryCount != expectedLength {\n\t\t\treturn fmt.Errorf(\"map Length() does not match number of MapIterator() entries\")\n\t\t}\n\t}\n\t// Emit map close.\n\ttk.Type = tok.TMapClose\n\t_, err := sink.Step(tk)\n\treturn err\n}\n\n// EncodedLength will calculate the length in bytes that the encoded form of the\n// provided Node will occupy.\n//\n// Note that this function requires a full walk of the Node's graph, which may\n// not necessarily be a trivial cost and will incur some allocations. Using this\n// method to calculate buffers to pre-allocate may not result in performance\n// gains, but rather incur an overall cost. Use with care.\nfunc EncodedLength(n datamodel.Node) (int64, error) {\n\tswitch n.Kind() {\n\tcase datamodel.Kind_Invalid:\n\t\treturn 0, fmt.Errorf(\"cannot traverse a node that is absent\")\n\tcase datamodel.Kind_Null:\n\t\treturn 1, nil // 0xf6\n\tcase datamodel.Kind_Map:\n\t\tlength := uintLength(uint64(n.Length())) // length prefixed major 5\n\t\tfor itr := n.MapIterator(); !itr.Done(); {\n\t\t\tk, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\tkeyLength, err := EncodedLength(k)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\tlength += keyLength\n\t\t\tvalueLength, err := EncodedLength(v)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\tlength += valueLength\n\t\t}\n\t\treturn length, nil\n\tcase datamodel.Kind_List:\n\t\tnl := n.Length()\n\t\tlength := uintLength(uint64(nl)) // length prefixed major 4\n\t\tfor i := int64(0); i < nl; i++ {\n\t\t\tv, err := n.LookupByIndex(i)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\tinnerLength, err := EncodedLength(v)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\tlength += innerLength\n\t\t}\n\t\treturn length, nil\n\tcase datamodel.Kind_Bool:\n\t\treturn 1, nil // 0xf4 or 0xf5\n\tcase datamodel.Kind_Int:\n\t\tv, err := n.AsInt()\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tif v < 0 {\n\t\t\tv = -v - 1 // negint is stored as one less than actual\n\t\t}\n\t\treturn uintLength(uint64(v)), nil // major 0 or 1, as small as possible\n\tcase datamodel.Kind_Float:\n\t\treturn 9, nil // always major 7 and 64-bit float\n\tcase datamodel.Kind_String:\n\t\tv, err := n.AsString()\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\treturn uintLength(uint64(len(v))) + int64(len(v)), nil // length prefixed major 3\n\tcase datamodel.Kind_Bytes:\n\t\tv, err := n.AsBytes()\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\treturn uintLength(uint64(len(v))) + int64(len(v)), nil // length prefixed major 2\n\tcase datamodel.Kind_Link:\n\t\tv, err := n.AsLink()\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tswitch lnk := v.(type) {\n\t\tcase cidlink.Link:\n\t\t\tlength := int64(2)                    // tag,42: 0xd82a\n\t\t\tbl := int64(len(lnk.Bytes())) + 1     // additional 0x00 in front of the CID bytes\n\t\t\tlength += uintLength(uint64(bl)) + bl // length prefixed major 2\n\t\t\treturn length, err\n\t\tdefault:\n\t\t\treturn 0, fmt.Errorf(\"schemafree link emission only supported by this codec for CID type links\")\n\t\t}\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\n\n// Calculate how many bytes an integer, and therefore also the leading bytes of\n// a length-prefixed token. CBOR will pack it up into the smallest possible\n// uint representation, even merging it with the major if it's <=23.\n\ntype boundaryLength struct {\n\tupperBound uint64\n\tlength     int64\n}\n\nvar lengthBoundaries = []boundaryLength{\n\t{24, 1},         // packed major|minor\n\t{256, 2},        // major, 8-bit length\n\t{65536, 3},      // major, 16-bit length\n\t{4294967296, 5}, // major, 32-bit length\n\t{0, 9},          // major, 64-bit length\n}\n\nfunc uintLength(ii uint64) int64 {\n\tfor _, lb := range lengthBoundaries {\n\t\tif ii < lb.upperBound {\n\t\t\treturn lb.length\n\t\t}\n\t}\n\t// maximum number of bytes to pack this int\n\t// if this int is used as a length prefix for a map, list, string or bytes\n\t// then we likely have a very bad Node that shouldn't be encoded, but the\n\t// encoder may raise problems with that if the memory allocator doesn't first.\n\treturn lengthBoundaries[len(lengthBoundaries)-1].length\n}\n"
  },
  {
    "path": "codec/dagcbor/marshal_test.go",
    "content": "package dagcbor\n\nimport (\n\t\"bytes\"\n\t\"math/rand\"\n\t\"testing\"\n\t\"time\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent/qp\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\tbasicnode \"github.com/ipld/go-ipld-prime/node/basic\"\n\t\"github.com/ipld/go-ipld-prime/testutil/garbage\"\n)\n\nfunc calculateActualLength(t *testing.T, n datamodel.Node) int64 {\n\tvar buf bytes.Buffer\n\terr := Encode(n, &buf)\n\tqt.Assert(t, err, qt.IsNil)\n\treturn int64(buf.Len())\n}\n\nfunc verifyEstimatedSize(t *testing.T, n datamodel.Node) {\n\testimatedLength, err := EncodedLength(n)\n\tqt.Assert(t, err, qt.IsNil)\n\tactualLength := calculateActualLength(t, n)\n\tqt.Assert(t, estimatedLength, qt.Equals, actualLength)\n}\n\nfunc TestEncodedLength(t *testing.T) {\n\tt.Run(\"int boundaries\", func(t *testing.T) {\n\t\tfor ii := 0; ii < 4; ii++ {\n\t\t\tverifyEstimatedSize(t, basicnode.NewInt(int64(lengthBoundaries[ii].upperBound)))\n\t\t\tverifyEstimatedSize(t, basicnode.NewInt(int64(lengthBoundaries[ii].upperBound)-1))\n\t\t\tverifyEstimatedSize(t, basicnode.NewInt(int64(lengthBoundaries[ii].upperBound)+1))\n\t\t\tverifyEstimatedSize(t, basicnode.NewInt(-1*int64(lengthBoundaries[ii].upperBound)))\n\t\t\tverifyEstimatedSize(t, basicnode.NewInt(-1*int64(lengthBoundaries[ii].upperBound)-1))\n\t\t\tverifyEstimatedSize(t, basicnode.NewInt(-1*int64(lengthBoundaries[ii].upperBound)+1))\n\t\t}\n\t})\n\n\tt.Run(\"small garbage\", func(t *testing.T) {\n\t\tseed := time.Now().Unix()\n\t\tt.Logf(\"randomness seed: %v\\n\", seed)\n\t\trnd := rand.New(rand.NewSource(seed))\n\t\tfor i := 0; i < 1000; i++ {\n\t\t\tgbg := garbage.Generate(rnd, garbage.TargetBlockSize(1<<6))\n\t\t\tverifyEstimatedSize(t, gbg)\n\t\t}\n\t})\n\n\tt.Run(\"medium garbage\", func(t *testing.T) {\n\t\tseed := time.Now().Unix()\n\t\tt.Logf(\"randomness seed: %v\\n\", seed)\n\t\trnd := rand.New(rand.NewSource(seed))\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tgbg := garbage.Generate(rnd, garbage.TargetBlockSize(1<<16))\n\t\t\tverifyEstimatedSize(t, gbg)\n\t\t}\n\t})\n\n\tt.Run(\"large garbage\", func(t *testing.T) {\n\t\tseed := time.Now().Unix()\n\t\tt.Logf(\"randomness seed: %v\\n\", seed)\n\t\trnd := rand.New(rand.NewSource(seed))\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tgbg := garbage.Generate(rnd, garbage.TargetBlockSize(1<<20))\n\t\t\tverifyEstimatedSize(t, gbg)\n\t\t}\n\t})\n}\n\nfunc TestMarshalUndefCid(t *testing.T) {\n\tlink, err := cid.Decode(\"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\")\n\tqt.Assert(t, err, qt.IsNil)\n\tnode, err := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {\n\t\tqp.MapEntry(ma, \"UndefCid\", qp.Link(cidlink.Link{Cid: cid.Undef}))\n\t\tqp.MapEntry(ma, \"DefCid\", qp.Link(cidlink.Link{Cid: link}))\n\t})\n\tqt.Assert(t, err, qt.IsNil)\n\t_, err = ipld.Encode(node, Encode)\n\tqt.Assert(t, err, qt.ErrorMatches, \"encoding undefined CIDs are not supported by this codec\")\n}\n"
  },
  {
    "path": "codec/dagcbor/multicodec.go",
    "content": "package dagcbor\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/codec\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/multicodec\"\n)\n\nvar (\n\t_ codec.Decoder = Decode\n\t_ codec.Encoder = Encode\n)\n\nfunc init() {\n\tmulticodec.RegisterEncoder(0x71, Encode)\n\tmulticodec.RegisterDecoder(0x71, Decode)\n}\n\n// Decode deserializes data from the given io.Reader and feeds it into the given datamodel.NodeAssembler.\n// Decode fits the codec.Decoder function interface.\n//\n// A similar function is available on DecodeOptions type if you would like to customize any of the decoding details.\n// This function uses the defaults for the dag-cbor codec\n// (meaning: links (indicated by tag 42) are decoded).\n//\n// This is the function that will be registered in the default multicodec registry during package init time.\nfunc Decode(na datamodel.NodeAssembler, r io.Reader) error {\n\treturn DecodeOptions{\n\t\tAllowLinks: true,\n\t}.Decode(na, r)\n}\n\n// Encode walks the given datamodel.Node and serializes it to the given io.Writer.\n// Encode fits the codec.Encoder function interface.\n//\n// A similar function is available on EncodeOptions type if you would like to customize any of the encoding details.\n// This function uses the defaults for the dag-cbor codec\n// (meaning: links are encoded, and map keys are sorted (with RFC7049 ordering!) during encode).\n//\n// This is the function that will be registered in the default multicodec registry during package init time.\nfunc Encode(n datamodel.Node, w io.Writer) error {\n\treturn EncodeOptions{\n\t\tAllowLinks:  true,\n\t\tMapSortMode: codec.MapSortMode_RFC7049,\n\t}.Encode(n, w)\n}\n"
  },
  {
    "path": "codec/dagcbor/nongreedy_test.go",
    "content": "package dagcbor\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent/qp\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestNonGreedy(t *testing.T) {\n\t// same as JSON version of this test: {\"a\": 1}{\"b\": 2}\n\tbuf, err := hex.DecodeString(\"a1616101a1616202\")\n\tqt.Assert(t, err, qt.IsNil)\n\tr := bytes.NewReader(buf)\n\topts := DecodeOptions{\n\t\tDontParseBeyondEnd: true,\n\t}\n\n\t// first object\n\tnb1 := basicnode.Prototype.Map.NewBuilder()\n\terr = opts.Decode(nb1, r)\n\tqt.Assert(t, err, qt.IsNil)\n\texpected, err := qp.BuildMap(basicnode.Prototype.Any, 1, func(ma datamodel.MapAssembler) {\n\t\tqp.MapEntry(ma, \"a\", qp.Int(1))\n\t})\n\tqt.Assert(t, err, qt.IsNil)\n\tqt.Assert(t, ipld.DeepEqual(nb1.Build(), expected), qt.IsTrue)\n\n\t// second object\n\tnb2 := basicnode.Prototype.Map.NewBuilder()\n\terr = opts.Decode(nb2, r)\n\tqt.Assert(t, err, qt.IsNil)\n\texpected, err = qp.BuildMap(basicnode.Prototype.Any, 1, func(ma datamodel.MapAssembler) {\n\t\tqp.MapEntry(ma, \"b\", qp.Int(2))\n\t})\n\tqt.Assert(t, err, qt.IsNil)\n\tqt.Assert(t, ipld.DeepEqual(nb2.Build(), expected), qt.IsTrue)\n}\n"
  },
  {
    "path": "codec/dagcbor/roundtripCidlink_test.go",
    "content": "package dagcbor\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\tcid \"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\tnodetests \"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nfunc TestRoundtripCidlink(t *testing.T) {\n\tlp := cidlink.LinkPrototype{Prefix: cid.Prefix{\n\t\tVersion:  1,\n\t\tCodec:    0x71,\n\t\tMhType:   0x13,\n\t\tMhLength: 4,\n\t}}\n\tlsys := cidlink.DefaultLinkSystem()\n\n\tbuf := bytes.Buffer{}\n\tlsys.StorageWriteOpener = func(lnkCtx linking.LinkContext) (io.Writer, linking.BlockWriteCommitter, error) {\n\t\treturn &buf, func(lnk datamodel.Link) error { return nil }, nil\n\t}\n\tlsys.StorageReadOpener = func(lnkCtx linking.LinkContext, lnk datamodel.Link) (io.Reader, error) {\n\t\treturn bytes.NewReader(buf.Bytes()), nil\n\t}\n\n\tlnk, err := lsys.Store(linking.LinkContext{}, lp, n)\n\tqt.Assert(t, err, qt.IsNil)\n\n\tn2, err := lsys.Load(linking.LinkContext{}, lnk, basicnode.Prototype.Any)\n\tqt.Assert(t, err, qt.IsNil)\n\tqt.Check(t, n2, nodetests.NodeContentEquals, nSorted)\n}\n"
  },
  {
    "path": "codec/dagcbor/roundtrip_test.go",
    "content": "package dagcbor\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"math\"\n\t\"strings\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\tcid \"github.com/ipfs/go-cid\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\tnodetests \"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nvar n = fluent.MustBuildMap(basicnode.Prototype.Map, 4, func(na fluent.MapAssembler) {\n\tna.AssembleEntry(\"plain\").AssignString(\"olde string\")\n\tna.AssembleEntry(\"map\").CreateMap(2, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"one\").AssignInt(1)\n\t\tna.AssembleEntry(\"two\").AssignInt(2)\n\t})\n\tna.AssembleEntry(\"list\").CreateList(2, func(na fluent.ListAssembler) {\n\t\tna.AssembleValue().AssignString(\"three\")\n\t\tna.AssembleValue().AssignString(\"four\")\n\t})\n\tna.AssembleEntry(\"nested\").CreateMap(1, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"deeper\").CreateList(1, func(na fluent.ListAssembler) {\n\t\t\tna.AssembleValue().AssignString(\"things\")\n\t\t})\n\t})\n})\nvar nSorted = fluent.MustBuildMap(basicnode.Prototype.Map, 4, func(na fluent.MapAssembler) {\n\tna.AssembleEntry(\"map\").CreateMap(2, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"one\").AssignInt(1)\n\t\tna.AssembleEntry(\"two\").AssignInt(2)\n\t})\n\tna.AssembleEntry(\"list\").CreateList(2, func(na fluent.ListAssembler) {\n\t\tna.AssembleValue().AssignString(\"three\")\n\t\tna.AssembleValue().AssignString(\"four\")\n\t})\n\tna.AssembleEntry(\"plain\").AssignString(\"olde string\")\n\tna.AssembleEntry(\"nested\").CreateMap(1, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"deeper\").CreateList(1, func(na fluent.ListAssembler) {\n\t\t\tna.AssembleValue().AssignString(\"things\")\n\t\t})\n\t})\n})\nvar serial = \"\\xa4cmap\\xa2cone\\x01ctwo\\x02dlist\\x82ethreedfoureplainkolde stringfnested\\xa1fdeeper\\x81fthings\"\n\nfunc TestRoundtrip(t *testing.T) {\n\tt.Run(\"encoding\", func(t *testing.T) {\n\t\tvar buf bytes.Buffer\n\t\terr := Encode(n, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, buf.String(), qt.Equals, serial)\n\t})\n\tt.Run(\"length\", func(t *testing.T) {\n\t\tlength, err := EncodedLength(n)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, length, qt.Equals, int64(len(serial)))\n\t})\n\tt.Run(\"decoding\", func(t *testing.T) {\n\t\tbuf := strings.NewReader(serial)\n\t\tnb := basicnode.Prototype.Map.NewBuilder()\n\t\terr := Decode(nb, buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, nb.Build(), nodetests.NodeContentEquals, nSorted)\n\t})\n}\n\nfunc TestRoundtripScalar(t *testing.T) {\n\tnb := basicnode.Prototype__String{}.NewBuilder()\n\tnb.AssignString(\"applesauce\")\n\tsimple := nb.Build()\n\tt.Run(\"encoding\", func(t *testing.T) {\n\t\tvar buf bytes.Buffer\n\t\terr := Encode(simple, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, buf.String(), qt.Equals, `japplesauce`)\n\t})\n\tt.Run(\"decoding\", func(t *testing.T) {\n\t\tbuf := strings.NewReader(`japplesauce`)\n\t\tnb := basicnode.Prototype__String{}.NewBuilder()\n\t\terr := Decode(nb, buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, nb.Build(), nodetests.NodeContentEquals, simple)\n\t})\n}\n\nfunc TestRoundtripLinksAndBytes(t *testing.T) {\n\tlnk := cidlink.LinkPrototype{Prefix: cid.Prefix{\n\t\tVersion:  1,\n\t\tCodec:    0x71,\n\t\tMhType:   0x13,\n\t\tMhLength: 4,\n\t}}.BuildLink([]byte{1, 2, 3, 4}) // dummy value, content does not matter to this test.\n\n\tvar linkByteNode = fluent.MustBuildMap(basicnode.Prototype.Map, 4, func(na fluent.MapAssembler) {\n\t\tnva := na.AssembleEntry(\"Link\")\n\t\tnva.AssignLink(lnk)\n\t\tnva = na.AssembleEntry(\"Bytes\")\n\t\tbytes := make([]byte, 100)\n\t\t_, _ = rand.Read(bytes)\n\t\tnva.AssignBytes(bytes)\n\t})\n\n\tbuf := bytes.Buffer{}\n\terr := Encode(linkByteNode, &buf)\n\tqt.Assert(t, err, qt.IsNil)\n\tnb := basicnode.Prototype.Map.NewBuilder()\n\terr = Decode(nb, &buf)\n\tqt.Assert(t, err, qt.IsNil)\n\treconstructed := nb.Build()\n\tqt.Check(t, reconstructed, nodetests.NodeContentEquals, linkByteNode)\n}\n\nfunc TestInts(t *testing.T) {\n\tdata := []struct {\n\t\tname      string\n\t\thex       string\n\t\tvalue     uint64\n\t\tintValue  int64\n\t\tintErr    string\n\t\tdecodeErr string\n\t}{\n\t\t{\"max uint64\", \"1bffffffffffffffff\", math.MaxUint64, 0, \"unsigned integer out of range of int64 type\", \"\"},\n\t\t{\"max int64\", \"1b7fffffffffffffff\", math.MaxInt64, math.MaxInt64, \"\", \"\"},\n\t\t{\"1\", \"01\", 1, 1, \"\", \"\"},\n\t\t{\"0\", \"00\", 0, 0, \"\", \"\"},\n\t\t{\"-1\", \"20\", 0, -1, \"\", \"\"},\n\t\t{\"min int64\", \"3b7fffffffffffffff\", 0, math.MinInt64, \"\", \"\"},\n\t\t{\"~min uint64\", \"3bfffffffffffffffe\", 0, 0, \"\", \"cbor: negative integer out of rage of int64 type\"},\n\t\t// TODO: 3bffffffffffffffff isn't properly handled by refmt, it's coerced to zero\n\t\t// MaxUint64 gets overflowed here: https://github.com/polydawn/refmt/blob/30ac6d18308e584ca6a2e74ba81475559db94c5f/cbor/cborDecoderTerminals.go#L75\n\t}\n\n\tfor _, td := range data {\n\t\tt.Run(td.name, func(t *testing.T) {\n\t\t\tbuf, err := hex.DecodeString(td.hex) // max uint64\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\t\terr = Decode(nb, bytes.NewReader(buf))\n\t\t\tif td.decodeErr != \"\" {\n\t\t\t\tqt.Assert(t, err, qt.IsNotNil)\n\t\t\t\tqt.Assert(t, err.Error(), qt.Equals, td.decodeErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tn := nb.Build()\n\n\t\t\tii, err := n.AsInt()\n\t\t\tif td.intErr != \"\" {\n\t\t\t\tqt.Assert(t, err.Error(), qt.Equals, td.intErr)\n\t\t\t} else {\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t\tqt.Assert(t, ii, qt.Equals, int64(td.intValue))\n\t\t\t}\n\n\t\t\t// if the number is outside of the positive int64 range, we should be able\n\t\t\t// to access it as a UintNode and be able to access the full int64 range\n\t\t\tuin, ok := n.(datamodel.UintNode)\n\t\t\tif td.value <= math.MaxInt64 {\n\t\t\t\tqt.Assert(t, ok, qt.IsFalse)\n\t\t\t} else {\n\t\t\t\tqt.Assert(t, ok, qt.IsTrue)\n\t\t\t\tval, err := uin.AsUint()\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t\tqt.Assert(t, val, qt.Equals, uint64(td.value))\n\t\t\t}\n\n\t\t\tvar byts bytes.Buffer\n\t\t\terr = Encode(n, &byts)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tqt.Assert(t, hex.EncodeToString(byts.Bytes()), qt.Equals, td.hex)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "codec/dagcbor/unmarshal.go",
    "content": "package dagcbor\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\n\tcid \"github.com/ipfs/go-cid\"\n\t\"github.com/polydawn/refmt/cbor\"\n\t\"github.com/polydawn/refmt/shared\"\n\t\"github.com/polydawn/refmt/tok\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nvar (\n\tErrInvalidMultibase         = errors.New(\"invalid multibase on IPLD link\")\n\tErrAllocationBudgetExceeded = errors.New(\"message structure demanded too many resources to process\")\n\tErrDecodeDepthExceeded      = errors.New(\"message structure exceeded maximum nesting depth\")\n\tErrTrailingBytes            = errors.New(\"unexpected content after end of cbor object\")\n)\n\nconst (\n\tmapEntryCost  = 8\n\tlistEntryCost = 4\n)\n\n// This file should be identical to the general feature in the parent package,\n// except for the `case tok.TBytes` block,\n// which has dag-cbor's special sauce for detecting schemafree links.\n\n// DecodeOptions can be used to customize the behavior of a decoding function.\n// The Decode method on this struct fits the codec.Decoder function interface.\ntype DecodeOptions struct {\n\t// If true, parse DAG-CBOR tag(42) as Link nodes, otherwise reject them\n\tAllowLinks bool\n\n\t// TODO: ExperimentalDeterminism enforces map key order, but not the other parts\n\t// of the spec such as integers or floats. See the fuzz failures spotted in\n\t// https://github.com/ipld/go-ipld-prime/pull/389.\n\t// When we're done implementing strictness, deprecate the option in favor of\n\t// StrictDeterminism, but keep accepting both for backwards compatibility.\n\n\t// ExperimentalDeterminism requires decoded DAG-CBOR bytes to be canonical as per\n\t// the spec. For example, this means that integers and floats be encoded in\n\t// a particular way, and map keys be sorted.\n\t//\n\t// The decoder does not enforce this requirement by default, as the codec\n\t// was originally implemented without these rules. Because of that, there's\n\t// a significant amount of published data that isn't canonical but should\n\t// still decode with the default settings for backwards compatibility.\n\t//\n\t// Note that this option is experimental as it only implements partial strictness.\n\tExperimentalDeterminism bool\n\n\t// If true, the decoder stops reading from the stream at the end of a full,\n\t// valid CBOR object. This may be useful for parsing a stream of undelimited\n\t// CBOR objects.\n\t// As per standard IPLD behavior, in the default mode the parser considers the\n\t// entire block to be part of the CBOR object and will error if there is\n\t// extraneous data after the end of the object.\n\tDontParseBeyondEnd bool\n\n\t// AllocationBudget sets the maximum budget for the decoder. The budget is\n\t// decremented as the decoder allocates resources (nodes, map entries, list\n\t// elements, string/bytes content). If the budget is exhausted, the decoder\n\t// returns ErrAllocationBudgetExceeded.\n\t//\n\t// When zero, a default budget is used which is generous for typical IPLD\n\t// block sizes.\n\tAllocationBudget int64\n\n\t// MaxCollectionPrealloc sets the maximum size hint passed to\n\t// BeginMap/BeginList. CBOR headers declare collection sizes upfront;\n\t// this caps the initial allocation while collections grow dynamically\n\t// as entries are decoded.\n\t//\n\t// When zero, a default of 1024 is used.\n\tMaxCollectionPrealloc int64\n\n\t// MaxDepth sets the maximum nesting depth for decoded structures. If the\n\t// decoder encounters a map or list nested beyond this depth, it returns\n\t// ErrDecodeDepthExceeded.\n\t//\n\t// When zero, a default of 1024 is used.\n\tMaxDepth int64\n}\n\nconst (\n\tdefaultAllocationBudget      int64 = 1048576 * 10\n\tdefaultMaxCollectionPrealloc int64 = 1024\n\tdefaultMaxDepth              int64 = 1024\n)\n\n// Decode deserializes data from the given io.Reader and feeds it into the given datamodel.NodeAssembler.\n// Decode fits the codec.Decoder function interface.\n//\n// The behavior of the decoder can be customized by setting fields in the DecodeOptions struct before calling this method.\nfunc (cfg DecodeOptions) Decode(na datamodel.NodeAssembler, r io.Reader) error {\n\t// Probe for a builtin fast path.  Shortcut to that if possible.\n\t// Note: when an assembler implements this interface, it receives only the\n\t// reader and none of the fields set on cfg. Implementations are responsible\n\t// for enforcing their own equivalents of AllocationBudget,\n\t// MaxCollectionPrealloc, MaxDepth and the other DecodeOptions fields.\n\ttype detectFastPath interface {\n\t\tDecodeDagCbor(io.Reader) error\n\t}\n\tif na2, ok := na.(detectFastPath); ok {\n\t\treturn na2.DecodeDagCbor(r)\n\t}\n\t// Okay, generic builder path.\n\terr := Unmarshal(na, cbor.NewDecoder(cbor.DecodeOptions{\n\t\tCoerceUndefToNull: true,\n\t}, r), cfg)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif cfg.DontParseBeyondEnd {\n\t\treturn nil\n\t}\n\n\tvar buf [1]byte\n\t_, err = io.ReadFull(r, buf[:])\n\tswitch err {\n\tcase io.EOF:\n\t\treturn nil\n\tcase nil:\n\t\treturn ErrTrailingBytes\n\tdefault:\n\t\treturn err\n\t}\n}\n\n// Future work: we would like to remove the Unmarshal function,\n// and in particular, stop seeing types from refmt (like shared.TokenSource) be visible.\n// Right now, some kinds of configuration (e.g. for whitespace and prettyprint) are only available through interacting with the refmt types;\n// we should improve our API so that this can be done with only our own types in this package.\n\n// Unmarshal is a deprecated function.\n// Please consider switching to DecodeOptions.Decode instead.\nfunc Unmarshal(na datamodel.NodeAssembler, tokSrc shared.TokenSource, options DecodeOptions) error {\n\tbudget := options.AllocationBudget\n\tif budget == 0 {\n\t\tbudget = defaultAllocationBudget\n\t}\n\treturn unmarshal1(na, tokSrc, &budget, 0, options)\n}\n\nfunc (cfg DecodeOptions) maxPrealloc() int64 {\n\tif cfg.MaxCollectionPrealloc > 0 {\n\t\treturn cfg.MaxCollectionPrealloc\n\t}\n\treturn defaultMaxCollectionPrealloc\n}\n\nfunc (cfg DecodeOptions) maxDepth() int64 {\n\tif cfg.MaxDepth > 0 {\n\t\treturn cfg.MaxDepth\n\t}\n\treturn defaultMaxDepth\n}\n\nfunc unmarshal1(na datamodel.NodeAssembler, tokSrc shared.TokenSource, budget *int64, depth int64, options DecodeOptions) error {\n\tvar tk tok.Token\n\tdone, err := tokSrc.Step(&tk)\n\tif err == io.EOF {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\tif done && !tk.Type.IsValue() && tk.Type != tok.TNull {\n\t\treturn fmt.Errorf(\"unexpected eof\")\n\t}\n\treturn unmarshal2(na, tokSrc, &tk, budget, depth, options)\n}\n\n// starts with the first token already primed.  Necessary to get recursion\n//\n//\tto flow right without a peek+unpeek system.\nfunc unmarshal2(na datamodel.NodeAssembler, tokSrc shared.TokenSource, tk *tok.Token, budget *int64, depth int64, options DecodeOptions) error {\n\t// FUTURE: check for schema.TypedNodeBuilder that's going to parse a Link (they can slurp any token kind they want).\n\tswitch tk.Type {\n\tcase tok.TMapOpen:\n\t\tif depth >= options.maxDepth() {\n\t\t\treturn ErrDecodeDepthExceeded\n\t\t}\n\t\texpectLen := int64(tk.Length)\n\t\tallocLen := int64(tk.Length)\n\t\tif tk.Length == -1 {\n\t\t\texpectLen = math.MaxInt64\n\t\t\tallocLen = 0\n\t\t} else {\n\t\t\t*budget -= allocLen\n\t\t\tif *budget < 0 {\n\t\t\t\treturn ErrAllocationBudgetExceeded\n\t\t\t}\n\t\t\tif allocLen > options.maxPrealloc() {\n\t\t\t\tallocLen = options.maxPrealloc()\n\t\t\t}\n\t\t}\n\t\tma, err := na.BeginMap(allocLen)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tvar observedLen int64\n\t\tlastKey := \"\"\n\t\tfor {\n\t\t\t_, err := tokSrc.Step(tk)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tswitch tk.Type {\n\t\t\tcase tok.TMapClose:\n\t\t\t\tif expectLen != math.MaxInt64 && observedLen != expectLen {\n\t\t\t\t\treturn fmt.Errorf(\"unexpected mapClose before declared length\")\n\t\t\t\t}\n\t\t\t\treturn ma.Finish()\n\t\t\tcase tok.TString:\n\t\t\t\t*budget -= int64(len(tk.Str) + mapEntryCost)\n\t\t\t\tif *budget < 0 {\n\t\t\t\t\treturn ErrAllocationBudgetExceeded\n\t\t\t\t}\n\t\t\t\t// continue\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unexpected %s token while expecting map key\", tk.Type)\n\t\t\t}\n\t\t\tobservedLen++\n\t\t\tif observedLen > expectLen {\n\t\t\t\treturn fmt.Errorf(\"unexpected continuation of map elements beyond declared length\")\n\t\t\t}\n\t\t\tif observedLen > 1 && options.ExperimentalDeterminism {\n\t\t\t\tif len(lastKey) > len(tk.Str) || lastKey > tk.Str {\n\t\t\t\t\treturn fmt.Errorf(\"map key %q is not after %q as per RFC7049\", tk.Str, lastKey)\n\t\t\t\t}\n\t\t\t}\n\t\t\tlastKey = tk.Str\n\t\t\tmva, err := ma.AssembleEntry(tk.Str)\n\t\t\tif err != nil { // return in error if the key was rejected\n\t\t\t\treturn err\n\t\t\t}\n\t\t\terr = unmarshal1(mva, tokSrc, budget, depth+1, options)\n\t\t\tif err != nil { // return in error if some part of the recursion errored\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\tcase tok.TMapClose:\n\t\treturn fmt.Errorf(\"unexpected mapClose token\")\n\tcase tok.TArrOpen:\n\t\tif depth >= options.maxDepth() {\n\t\t\treturn ErrDecodeDepthExceeded\n\t\t}\n\t\texpectLen := int64(tk.Length)\n\t\tallocLen := int64(tk.Length)\n\t\tif tk.Length == -1 {\n\t\t\texpectLen = math.MaxInt64\n\t\t\tallocLen = 0\n\t\t} else {\n\t\t\t*budget -= allocLen\n\t\t\tif *budget < 0 {\n\t\t\t\treturn ErrAllocationBudgetExceeded\n\t\t\t}\n\t\t\tif allocLen > options.maxPrealloc() {\n\t\t\t\tallocLen = options.maxPrealloc()\n\t\t\t}\n\t\t}\n\t\tla, err := na.BeginList(allocLen)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tvar observedLen int64\n\t\tfor {\n\t\t\t_, err := tokSrc.Step(tk)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tswitch tk.Type {\n\t\t\tcase tok.TArrClose:\n\t\t\t\tif expectLen != math.MaxInt64 && observedLen != expectLen {\n\t\t\t\t\treturn fmt.Errorf(\"unexpected arrClose before declared length\")\n\t\t\t\t}\n\t\t\t\treturn la.Finish()\n\t\t\tdefault:\n\t\t\t\t*budget -= listEntryCost\n\t\t\t\tif *budget < 0 {\n\t\t\t\t\treturn ErrAllocationBudgetExceeded\n\t\t\t\t}\n\t\t\t\tobservedLen++\n\t\t\t\tif observedLen > expectLen {\n\t\t\t\t\treturn fmt.Errorf(\"unexpected continuation of array elements beyond declared length\")\n\t\t\t\t}\n\t\t\t\terr := unmarshal2(la.AssembleValue(), tokSrc, tk, budget, depth+1, options)\n\t\t\t\tif err != nil { // return in error if some part of the recursion errored\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase tok.TArrClose:\n\t\treturn fmt.Errorf(\"unexpected arrClose token\")\n\tcase tok.TNull:\n\t\treturn na.AssignNull()\n\tcase tok.TString:\n\t\t*budget -= int64(len(tk.Str))\n\t\tif *budget < 0 {\n\t\t\treturn ErrAllocationBudgetExceeded\n\t\t}\n\t\treturn na.AssignString(tk.Str)\n\tcase tok.TBytes:\n\t\t*budget -= int64(len(tk.Bytes))\n\t\tif *budget < 0 {\n\t\t\treturn ErrAllocationBudgetExceeded\n\t\t}\n\t\tif !tk.Tagged {\n\t\t\treturn na.AssignBytes(tk.Bytes)\n\t\t}\n\t\tswitch tk.Tag {\n\t\tcase linkTag:\n\t\t\tif !options.AllowLinks {\n\t\t\t\treturn fmt.Errorf(\"unhandled cbor tag %d\", tk.Tag)\n\t\t\t}\n\t\t\tif len(tk.Bytes) < 1 || tk.Bytes[0] != 0 {\n\t\t\t\treturn ErrInvalidMultibase\n\t\t\t}\n\t\t\telCid, err := cid.Cast(tk.Bytes[1:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn na.AssignLink(cidlink.Link{Cid: elCid})\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unhandled cbor tag %d\", tk.Tag)\n\t\t}\n\tcase tok.TBool:\n\t\t*budget -= 1\n\t\tif *budget < 0 {\n\t\t\treturn ErrAllocationBudgetExceeded\n\t\t}\n\t\treturn na.AssignBool(tk.Bool)\n\tcase tok.TInt:\n\t\t*budget -= 1\n\t\tif *budget < 0 {\n\t\t\treturn ErrAllocationBudgetExceeded\n\t\t}\n\t\treturn na.AssignInt(tk.Int)\n\tcase tok.TUint:\n\t\t*budget -= 1\n\t\tif *budget < 0 {\n\t\t\treturn ErrAllocationBudgetExceeded\n\t\t}\n\t\t// note that this pushes any overflow errors up the stack when AsInt() may\n\t\t// be called on a UintNode that is too large to cast to an int64\n\t\tif tk.Uint > math.MaxInt64 {\n\t\t\treturn na.AssignNode(basicnode.NewUint(tk.Uint))\n\t\t}\n\t\treturn na.AssignInt(int64(tk.Uint))\n\tcase tok.TFloat64:\n\t\t*budget -= 1\n\t\tif *budget < 0 {\n\t\t\treturn ErrAllocationBudgetExceeded\n\t\t}\n\t\treturn na.AssignFloat(tk.Float64)\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\n"
  },
  {
    "path": "codec/dagcbor/unmarshal_test.go",
    "content": "package dagcbor\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestFunBlocks(t *testing.T) {\n\tt.Run(\"zero length link\", func(t *testing.T) {\n\t\t// This fixture has a zero length link -- not even the multibase byte (which dag-cbor insists must be zero) is there.\n\t\tbuf := strings.NewReader(\"\\x8d\\x8d\\x97\\xd8*@\")\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, buf)\n\t\tqt.Assert(t, err, qt.Equals, ErrInvalidMultibase)\n\t})\n\tt.Run(\"fuzz001\", func(t *testing.T) {\n\t\t// This fixture might cause an overly large allocation if you aren't careful to have resource budgets.\n\t\tbuf := strings.NewReader(\"\\x9a\\xff000\")\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, buf)\n\t\tif runtime.GOARCH == \"386\" {\n\t\t\t// TODO: fix refmt to properly handle 64-bit ints on 32-bit runtime\n\t\t\tqt.Assert(t, err.Error(), qt.Equals, \"cbor: positive integer is out of length\")\n\t\t} else {\n\t\t\tqt.Assert(t, err, qt.Equals, ErrAllocationBudgetExceeded)\n\t\t}\n\t})\n\tt.Run(\"fuzz002\", func(t *testing.T) {\n\t\t// This fixture might cause an overly large allocation if you aren't careful to have resource budgets.\n\t\tbuf := strings.NewReader(\"\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9a\\xff000\")\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, buf)\n\t\tif runtime.GOARCH == \"386\" {\n\t\t\t// TODO: fix refmt to properly handle 64-bit ints on 32-bit\n\t\t\tqt.Assert(t, err.Error(), qt.Equals, \"cbor: positive integer is out of length\")\n\t\t} else {\n\t\t\tqt.Assert(t, err, qt.Equals, ErrAllocationBudgetExceeded)\n\t\t}\n\t})\n\tt.Run(\"fuzz003\", func(t *testing.T) {\n\t\t// This fixture might cause an overly large allocation if you aren't careful to have resource budgets.\n\t\tbuf := strings.NewReader(\"\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\x9f\\xbb00000000\")\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, buf)\n\t\tif runtime.GOARCH == \"386\" {\n\t\t\t// TODO: fix refmt to properly handle 64-bit ints on 32-bit\n\t\t\tqt.Assert(t, err.Error(), qt.Equals, \"cbor: positive integer is out of length\")\n\t\t} else {\n\t\t\tqt.Assert(t, err, qt.Equals, ErrAllocationBudgetExceeded)\n\t\t}\n\t})\n\tt.Run(\"undef\", func(t *testing.T) {\n\t\t// This fixture tests that we tolerate cbor's \"undefined\" token (even though it's noncanonical and you shouldn't use it),\n\t\t// and that it becomes a null in the data model level.\n\t\tbuf := strings.NewReader(\"\\xf7\")\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, nb.Build().Kind(), qt.Equals, datamodel.Kind_Null)\n\t})\n\tt.Run(\"extra bytes\", func(t *testing.T) {\n\t\tbuf := strings.NewReader(\"\\xa0\\x00\")\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, buf)\n\t\tqt.Assert(t, err, qt.Equals, ErrTrailingBytes)\n\t})\n}\n\nfunc cborMapHeader(length uint32) []byte {\n\tvar buf bytes.Buffer\n\tbuf.WriteByte(0xBA)\n\tbinary.Write(&buf, binary.BigEndian, length)\n\treturn buf.Bytes()\n}\n\nfunc cborArrayHeader(length uint32) []byte {\n\tvar buf bytes.Buffer\n\tbuf.WriteByte(0x9A)\n\tbinary.Write(&buf, binary.BigEndian, length)\n\treturn buf.Bytes()\n}\n\n// TestDecodeOptions_AllocationBudget verifies that the configurable allocation\n// budget is respected, both with defaults and custom values.\nfunc TestDecodeOptions_AllocationBudget(t *testing.T) {\n\tt.Run(\"default budget rejects oversized structure\", func(t *testing.T) {\n\t\t// A map header claiming more entries than the default budget allows\n\t\tpayload := cborMapHeader(20_000_000)\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, bytes.NewReader(payload))\n\t\tqt.Assert(t, err, qt.Equals, ErrAllocationBudgetExceeded)\n\t})\n\n\tt.Run(\"custom budget accepts within limit\", func(t *testing.T) {\n\t\t// Build a small valid map: {\"a\": 1}\n\t\tvar buf bytes.Buffer\n\t\tbuf.Write(cborMapHeader(1))\n\t\tbuf.WriteByte(0x61) // text(1)\n\t\tbuf.WriteByte('a')\n\t\tbuf.WriteByte(0x01) // uint(1)\n\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := DecodeOptions{AllowLinks: true, AllocationBudget: 100}.Decode(nb, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tnode := nb.Build()\n\t\tqt.Assert(t, node.Kind(), qt.Equals, datamodel.Kind_Map)\n\t})\n\n\tt.Run(\"custom budget rejects when exhausted\", func(t *testing.T) {\n\t\t// A map claiming 50 entries with a budget of only 10 should be rejected\n\t\tpayload := cborMapHeader(50)\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := DecodeOptions{AllowLinks: true, AllocationBudget: 10}.Decode(nb, bytes.NewReader(payload))\n\t\tqt.Assert(t, err, qt.Equals, ErrAllocationBudgetExceeded)\n\t})\n\n\tt.Run(\"budget accounts for declared collection sizes\", func(t *testing.T) {\n\t\t// A list claiming 1000 entries consumes budget even if no entries follow\n\t\tpayload := cborArrayHeader(1000)\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := DecodeOptions{AllowLinks: true, AllocationBudget: 500}.Decode(nb, bytes.NewReader(payload))\n\t\tqt.Assert(t, err, qt.Equals, ErrAllocationBudgetExceeded)\n\t})\n}\n\n// TestDecodeOptions_MaxCollectionPrealloc verifies that the preallocation cap\n// is respected and that large collections still decode correctly.\nfunc TestDecodeOptions_MaxCollectionPrealloc(t *testing.T) {\n\tt.Run(\"large map decodes correctly with default cap\", func(t *testing.T) {\n\t\tconst numEntries = 5_000\n\t\tvar buf bytes.Buffer\n\t\tbuf.Write(cborMapHeader(numEntries))\n\t\tfor i := 0; i < numEntries; i++ {\n\t\t\tkey := fmt.Sprintf(\"k%05d\", i)\n\t\t\tbuf.WriteByte(0x66) // text(6)\n\t\t\tbuf.WriteString(key)\n\t\t\tif i < 24 {\n\t\t\t\tbuf.WriteByte(byte(i))\n\t\t\t} else if i < 256 {\n\t\t\t\tbuf.WriteByte(0x18)\n\t\t\t\tbuf.WriteByte(byte(i))\n\t\t\t} else {\n\t\t\t\tbuf.WriteByte(0x19)\n\t\t\t\tbinary.Write(&buf, binary.BigEndian, uint16(i))\n\t\t\t}\n\t\t}\n\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tnode := nb.Build()\n\t\tqt.Assert(t, node.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\tqt.Assert(t, node.Length(), qt.Equals, int64(numEntries))\n\n\t\tv, err := node.LookupByString(\"k00000\")\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tvi, err := v.AsInt()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, vi, qt.Equals, int64(0))\n\n\t\tv, err = node.LookupByString(\"k04999\")\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tvi, err = v.AsInt()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, vi, qt.Equals, int64(4999))\n\t})\n\n\tt.Run(\"large list decodes correctly with default cap\", func(t *testing.T) {\n\t\tconst numEntries = 5_000\n\t\tvar buf bytes.Buffer\n\t\tbuf.Write(cborArrayHeader(numEntries))\n\t\tfor i := 0; i < numEntries; i++ {\n\t\t\tif i < 24 {\n\t\t\t\tbuf.WriteByte(byte(i))\n\t\t\t} else if i < 256 {\n\t\t\t\tbuf.WriteByte(0x18)\n\t\t\t\tbuf.WriteByte(byte(i))\n\t\t\t} else {\n\t\t\t\tbuf.WriteByte(0x19)\n\t\t\t\tbinary.Write(&buf, binary.BigEndian, uint16(i))\n\t\t\t}\n\t\t}\n\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tnode := nb.Build()\n\t\tqt.Assert(t, node.Kind(), qt.Equals, datamodel.Kind_List)\n\t\tqt.Assert(t, node.Length(), qt.Equals, int64(numEntries))\n\n\t\tv, err := node.LookupByIndex(0)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tvi, err := v.AsInt()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, vi, qt.Equals, int64(0))\n\n\t\tv, err = node.LookupByIndex(numEntries - 1)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tvi, err = v.AsInt()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, vi, qt.Equals, int64(numEntries-1))\n\t})\n\n\tt.Run(\"custom prealloc cap with valid data\", func(t *testing.T) {\n\t\t// 100-entry list with a prealloc cap of 10 should still decode fine\n\t\tconst numEntries = 100\n\t\tvar buf bytes.Buffer\n\t\tbuf.Write(cborArrayHeader(numEntries))\n\t\tfor i := 0; i < numEntries; i++ {\n\t\t\tbuf.WriteByte(byte(i % 24))\n\t\t}\n\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := DecodeOptions{AllowLinks: true, MaxCollectionPrealloc: 10}.Decode(nb, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tnode := nb.Build()\n\t\tqt.Assert(t, node.Length(), qt.Equals, int64(numEntries))\n\t})\n}\n\n// TestDecodeOptions_MaxDepth verifies that the configurable nesting-depth\n// limit is respected, both with defaults and custom values.\nfunc TestDecodeOptions_MaxDepth(t *testing.T) {\n\t// buildNestedArrays returns depth `0x81` bytes (array(1)) followed by a\n\t// single `0xF6` null, forming `depth` levels of nested single-element\n\t// arrays.\n\tbuildNestedArrays := func(depth int) []byte {\n\t\tbuf := make([]byte, 0, depth+1)\n\t\tfor i := 0; i < depth; i++ {\n\t\t\tbuf = append(buf, 0x81)\n\t\t}\n\t\tbuf = append(buf, 0xF6)\n\t\treturn buf\n\t}\n\n\tt.Run(\"default depth rejects deeply nested structure\", func(t *testing.T) {\n\t\tpayload := buildNestedArrays(2000)\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, bytes.NewReader(payload))\n\t\tqt.Assert(t, err, qt.Equals, ErrDecodeDepthExceeded)\n\t})\n\n\tt.Run(\"structure at default depth decodes\", func(t *testing.T) {\n\t\tpayload := buildNestedArrays(1024)\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, bytes.NewReader(payload))\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, nb.Build().Kind(), qt.Equals, datamodel.Kind_List)\n\t})\n\n\tt.Run(\"custom depth rejects when exceeded\", func(t *testing.T) {\n\t\tpayload := buildNestedArrays(10)\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := DecodeOptions{MaxDepth: 5}.Decode(nb, bytes.NewReader(payload))\n\t\tqt.Assert(t, err, qt.Equals, ErrDecodeDepthExceeded)\n\t})\n\n\tt.Run(\"custom depth accepts within limit\", func(t *testing.T) {\n\t\tpayload := buildNestedArrays(5)\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := DecodeOptions{MaxDepth: 10}.Decode(nb, bytes.NewReader(payload))\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, nb.Build().Kind(), qt.Equals, datamodel.Kind_List)\n\t})\n\n\tt.Run(\"nested maps also limited\", func(t *testing.T) {\n\t\t// Build N nested single-entry maps each with key \"x\" wrapping a null.\n\t\tconst depth = 2000\n\t\tbuf := make([]byte, 0, 3*depth+1)\n\t\tfor i := 0; i < depth; i++ {\n\t\t\tbuf = append(buf, 0xA1) // map(1)\n\t\t\tbuf = append(buf, 0x61) // text(1)\n\t\t\tbuf = append(buf, 'x')\n\t\t}\n\t\tbuf = append(buf, 0xF6) // null\n\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, bytes.NewReader(buf))\n\t\tqt.Assert(t, err, qt.Equals, ErrDecodeDepthExceeded)\n\t})\n\n\tt.Run(\"zero MaxDepth resolves to default\", func(t *testing.T) {\n\t\tpayload := buildNestedArrays(2000)\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := DecodeOptions{MaxDepth: 0}.Decode(nb, bytes.NewReader(payload))\n\t\tqt.Assert(t, err, qt.Equals, ErrDecodeDepthExceeded)\n\t})\n\n\tt.Run(\"indefinite-length collections also limited\", func(t *testing.T) {\n\t\t// Stream of 0x9F (indefinite list open) markers then a null, then\n\t\t// matching 0xFF break bytes. Exercises the indefinite-length branch\n\t\t// of the decoder which has a separate code path to the definite one.\n\t\tconst depth = 2000\n\t\tbuf := make([]byte, 0, 2*depth+1)\n\t\tfor i := 0; i < depth; i++ {\n\t\t\tbuf = append(buf, 0x9F)\n\t\t}\n\t\tbuf = append(buf, 0xF6)\n\t\tfor i := 0; i < depth; i++ {\n\t\t\tbuf = append(buf, 0xFF)\n\t\t}\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, bytes.NewReader(buf))\n\t\tqt.Assert(t, err, qt.Equals, ErrDecodeDepthExceeded)\n\t})\n}\n\n// TestDecoderBoundaries asserts that decoder-layer and tokenizer-layer limits\n// behave as expected for unusual or malformed inputs. These are sanity tests\n// around boundaries that callers sometimes need to reason about.\nfunc TestDecoderBoundaries(t *testing.T) {\n\tt.Run(\"oversized string declaration rejected by tokenizer\", func(t *testing.T) {\n\t\t// Text header declaring 1 TiB; no following bytes. The underlying\n\t\t// refmt tokenizer caps string/bytes length before attempting to read.\n\t\tvar buf bytes.Buffer\n\t\tbuf.WriteByte(0x7B) // text(uint64 length)\n\t\tbinary.Write(&buf, binary.BigEndian, uint64(1<<40))\n\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, bytes.NewReader(buf.Bytes()))\n\t\tqt.Assert(t, err, qt.Not(qt.IsNil))\n\t})\n\n\tt.Run(\"stacked CBOR tags rejected\", func(t *testing.T) {\n\t\t// CBOR permits tagging a value, but the tokenizer refuses to stack\n\t\t// multiple tags on a single item. Link handling relies on this.\n\t\tpayload := []byte{\n\t\t\t0xD8, 42, // tag(42)\n\t\t\t0xD8, 42, // tag(42)\n\t\t\t0x42, 0x00, 0x01,\n\t\t}\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := DecodeOptions{AllowLinks: true}.Decode(nb, bytes.NewReader(payload))\n\t\tqt.Assert(t, err, qt.Not(qt.IsNil))\n\t})\n\n\tt.Run(\"indefinite collection exceeding budget rejected\", func(t *testing.T) {\n\t\t// Indefinite-length arrays have no declared size, but per-entry\n\t\t// budget still applies as entries are read.\n\t\tconst entries = 3_000_000\n\t\tvar buf bytes.Buffer\n\t\tbuf.Grow(1 + entries + 1)\n\t\tbuf.WriteByte(0x9F)              // indefinite array\n\t\tbuf.Write(make([]byte, entries)) // entries zero-valued uints\n\t\tbuf.WriteByte(0xFF)              // break\n\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, bytes.NewReader(buf.Bytes()))\n\t\tqt.Assert(t, err, qt.Equals, ErrAllocationBudgetExceeded)\n\t})\n}\n"
  },
  {
    "path": "codec/dagjson/marshal.go",
    "content": "package dagjson\n\nimport (\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"io\"\n\t\"sort\"\n\n\t\"github.com/polydawn/refmt/json\"\n\t\"github.com/polydawn/refmt/shared\"\n\t\"github.com/polydawn/refmt/tok\"\n\n\t\"github.com/ipld/go-ipld-prime/codec\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n)\n\n// This should be identical to the general feature in the parent package,\n// except for the `case datamodel.Kind_Link` block,\n// which is dag-json's special sauce for schemafree links.\n\n// EncodeOptions can be used to customize the behavior of an encoding function.\n// The Encode method on this struct fits the codec.Encoder function interface.\ntype EncodeOptions struct {\n\t// If true, will encode nodes with a Link kind using the DAG-JSON\n\t// `{\"/\":\"cid string\"}` form.\n\tEncodeLinks bool\n\n\t// If true, will encode nodes with a Bytes kind using the DAG-JSON\n\t// `{\"/\":{\"bytes\":\"base64 bytes...\"}}` form.\n\tEncodeBytes bool\n\n\t// Control the sorting of map keys, using one of the `codec.MapSortMode_*` constants.\n\tMapSortMode codec.MapSortMode\n}\n\n// Encode walks the given datamodel.Node and serializes it to the given io.Writer.\n// Encode fits the codec.Encoder function interface.\n//\n// The behavior of the encoder can be customized by setting fields in the EncodeOptions struct before calling this method.\nfunc (cfg EncodeOptions) Encode(n datamodel.Node, w io.Writer) error {\n\treturn Marshal(n, json.NewEncoder(w, json.EncodeOptions{}), cfg)\n}\n\n// Future work: we would like to remove the Marshal function,\n// and in particular, stop seeing types from refmt (like shared.TokenSink) be visible.\n// Right now, some kinds of configuration (e.g. for whitespace and prettyprint) are only available through interacting with the refmt types;\n// we should improve our API so that this can be done with only our own types in this package.\n\n// Marshal is a deprecated function.\n// Please consider switching to EncodeOptions.Encode instead.\nfunc Marshal(n datamodel.Node, sink shared.TokenSink, options EncodeOptions) error {\n\tvar tk tok.Token\n\tswitch n.Kind() {\n\tcase datamodel.Kind_Invalid:\n\t\treturn fmt.Errorf(\"cannot traverse a node that is absent\")\n\tcase datamodel.Kind_Null:\n\t\ttk.Type = tok.TNull\n\t\t_, err := sink.Step(&tk)\n\t\treturn err\n\tcase datamodel.Kind_Map:\n\t\t// Emit start of map.\n\t\ttk.Type = tok.TMapOpen\n\t\texpectedLength := int(n.Length())\n\t\ttk.Length = expectedLength // TODO: overflow check\n\t\tif _, err := sink.Step(&tk); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif options.MapSortMode != codec.MapSortMode_None {\n\t\t\t// Collect map entries, then sort by key\n\t\t\ttype entry struct {\n\t\t\t\tkey   string\n\t\t\t\tvalue datamodel.Node\n\t\t\t}\n\t\t\tentries := []entry{}\n\t\t\tfor itr := n.MapIterator(); !itr.Done(); {\n\t\t\t\tk, v, err := itr.Next()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tkeyStr, err := k.AsString()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tentries = append(entries, entry{keyStr, v})\n\t\t\t}\n\t\t\tif len(entries) != expectedLength {\n\t\t\t\treturn fmt.Errorf(\"map Length() does not match number of MapIterator() entries\")\n\t\t\t}\n\t\t\t// Apply the desired sort function.\n\t\t\tswitch options.MapSortMode {\n\t\t\tcase codec.MapSortMode_Lexical:\n\t\t\t\tsort.Slice(entries, func(i, j int) bool {\n\t\t\t\t\treturn entries[i].key < entries[j].key\n\t\t\t\t})\n\t\t\tcase codec.MapSortMode_RFC7049:\n\t\t\t\tsort.Slice(entries, func(i, j int) bool {\n\t\t\t\t\t// RFC7049 style sort as per DAG-CBOR spec\n\t\t\t\t\tli, lj := len(entries[i].key), len(entries[j].key)\n\t\t\t\t\tif li == lj {\n\t\t\t\t\t\treturn entries[i].key < entries[j].key\n\t\t\t\t\t}\n\t\t\t\t\treturn li < lj\n\t\t\t\t})\n\t\t\t}\n\t\t\t// Emit map contents (and recurse).\n\t\t\tvar entryCount int\n\t\t\tfor _, e := range entries {\n\t\t\t\ttk.Type = tok.TString\n\t\t\t\ttk.Str = e.key\n\t\t\t\tentryCount++\n\t\t\t\tif _, err := sink.Step(&tk); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := Marshal(e.value, sink, options); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tif entryCount != expectedLength {\n\t\t\t\treturn fmt.Errorf(\"map Length() does not match number of MapIterator() entries\")\n\t\t\t}\n\t\t} else {\n\t\t\t// Don't sort map, emit map contents (and recurse).\n\t\t\tfor itr := n.MapIterator(); !itr.Done(); {\n\t\t\t\tk, v, err := itr.Next()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\ttk.Type = tok.TString\n\t\t\t\ttk.Str, err = k.AsString()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif _, err := sink.Step(&tk); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := Marshal(v, sink, options); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Emit map close.\n\t\ttk.Type = tok.TMapClose\n\t\t_, err := sink.Step(&tk)\n\t\treturn err\n\tcase datamodel.Kind_List:\n\t\t// Emit start of list.\n\t\ttk.Type = tok.TArrOpen\n\t\tl := n.Length()\n\t\ttk.Length = int(l) // TODO: overflow check\n\t\tif _, err := sink.Step(&tk); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// Emit list contents (and recurse).\n\t\tfor i := int64(0); i < l; i++ {\n\t\t\tv, err := n.LookupByIndex(i)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := Marshal(v, sink, options); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\t// Emit list close.\n\t\ttk.Type = tok.TArrClose\n\t\t_, err := sink.Step(&tk)\n\t\treturn err\n\tcase datamodel.Kind_Bool:\n\t\tv, err := n.AsBool()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttk.Type = tok.TBool\n\t\ttk.Bool = v\n\t\t_, err = sink.Step(&tk)\n\t\treturn err\n\tcase datamodel.Kind_Int:\n\t\tv, err := n.AsInt()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttk.Type = tok.TInt\n\t\ttk.Int = int64(v)\n\t\t_, err = sink.Step(&tk)\n\t\treturn err\n\tcase datamodel.Kind_Float:\n\t\tv, err := n.AsFloat()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttk.Type = tok.TFloat64\n\t\ttk.Float64 = v\n\t\t_, err = sink.Step(&tk)\n\t\treturn err\n\tcase datamodel.Kind_String:\n\t\tv, err := n.AsString()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttk.Type = tok.TString\n\t\ttk.Str = v\n\t\t_, err = sink.Step(&tk)\n\t\treturn err\n\tcase datamodel.Kind_Bytes:\n\t\tif !options.EncodeBytes {\n\t\t\treturn fmt.Errorf(\"cannot marshal IPLD bytes to this codec\")\n\t\t}\n\t\tv, err := n.AsBytes()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// Precisely seven tokens to emit:\n\t\ttk.Type = tok.TMapOpen\n\t\ttk.Length = 1\n\t\tif _, err = sink.Step(&tk); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttk.Type = tok.TString\n\t\ttk.Str = \"/\"\n\t\tif _, err = sink.Step(&tk); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttk.Type = tok.TMapOpen\n\t\ttk.Length = 1\n\t\tif _, err = sink.Step(&tk); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttk.Type = tok.TString\n\t\ttk.Str = \"bytes\"\n\t\tif _, err = sink.Step(&tk); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttk.Str = base64.RawStdEncoding.EncodeToString(v)\n\t\tif _, err = sink.Step(&tk); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttk.Type = tok.TMapClose\n\t\tif _, err = sink.Step(&tk); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttk.Type = tok.TMapClose\n\t\tif _, err = sink.Step(&tk); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\tcase datamodel.Kind_Link:\n\t\tif !options.EncodeLinks {\n\t\t\treturn fmt.Errorf(\"cannot marshal IPLD links to this codec\")\n\t\t}\n\t\tv, err := n.AsLink()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tswitch lnk := v.(type) {\n\t\tcase cidlink.Link:\n\t\t\tif !lnk.Cid.Defined() {\n\t\t\t\treturn fmt.Errorf(\"encoding undefined CIDs are not supported by this codec\")\n\t\t\t}\n\t\t\t// Precisely four tokens to emit:\n\t\t\ttk.Type = tok.TMapOpen\n\t\t\ttk.Length = 1\n\t\t\tif _, err = sink.Step(&tk); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\ttk.Type = tok.TString\n\t\t\ttk.Str = \"/\"\n\t\t\tif _, err = sink.Step(&tk); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\ttk.Str = lnk.Cid.String()\n\t\t\tif _, err = sink.Step(&tk); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\ttk.Type = tok.TMapClose\n\t\t\tif _, err = sink.Step(&tk); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn nil\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"schemafree link emission only supported by this codec for CID type links; got type %T\", lnk)\n\t\t}\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\n"
  },
  {
    "path": "codec/dagjson/marshal_test.go",
    "content": "package dagjson\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\tcid \"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent/qp\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nvar link = cid.MustParse(\"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\")\n\nfunc TestMarshalUndefCid(t *testing.T) {\n\tnode, err := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {\n\t\tqp.MapEntry(ma, \"UndefCid\", qp.Link(cidlink.Link{Cid: cid.Undef}))\n\t\tqp.MapEntry(ma, \"DefCid\", qp.Link(cidlink.Link{Cid: link}))\n\t})\n\tqt.Assert(t, err, qt.IsNil)\n\t_, err = ipld.Encode(node, Encode)\n\tqt.Assert(t, err, qt.ErrorMatches, \"encoding undefined CIDs are not supported by this codec\")\n}\n\n// mirrored in json but with errors\nfunc TestMarshalLinks(t *testing.T) {\n\tlinkNode := basicnode.NewLink(cidlink.Link{Cid: link})\n\tmapNode, err := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {\n\t\tqp.MapEntry(ma, \"Lnk\", qp.Node(linkNode))\n\t})\n\tqt.Assert(t, err, qt.IsNil)\n\n\tt.Run(\"link dag-json\", func(t *testing.T) {\n\t\tbyts, err := ipld.Encode(linkNode, Encode)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, string(byts), qt.Equals,\n\t\t\t`{\"/\":\"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\"}`)\n\t})\n\tt.Run(\"nested link dag-json\", func(t *testing.T) {\n\t\tbyts, err := ipld.Encode(mapNode, Encode)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, string(byts), qt.Equals,\n\t\t\t`{\"Lnk\":{\"/\":\"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\"}}`)\n\t})\n}\n\n// mirrored in json but with errors\nfunc TestMarshalBytes(t *testing.T) {\n\tbytsNode := basicnode.NewBytes([]byte(\"byte me\"))\n\tmapNode, err := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {\n\t\tqp.MapEntry(ma, \"Byts\", qp.Node(bytsNode))\n\t})\n\tqt.Assert(t, err, qt.IsNil)\n\n\tt.Run(\"bytes dag-json\", func(t *testing.T) {\n\t\tbyts, err := ipld.Encode(bytsNode, Encode)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, string(byts), qt.Equals,\n\t\t\t`{\"/\":{\"bytes\":\"Ynl0ZSBtZQ\"}}`)\n\t})\n\tt.Run(\"nested bytes dag-json\", func(t *testing.T) {\n\t\tbyts, err := ipld.Encode(mapNode, Encode)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, string(byts), qt.Equals,\n\t\t\t`{\"Byts\":{\"/\":{\"bytes\":\"Ynl0ZSBtZQ\"}}}`)\n\t})\n}\n"
  },
  {
    "path": "codec/dagjson/multicodec.go",
    "content": "package dagjson\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/codec\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/multicodec\"\n)\n\nvar (\n\t_ codec.Decoder = Decode\n\t_ codec.Encoder = Encode\n)\n\nfunc init() {\n\tmulticodec.RegisterEncoder(0x0129, Encode)\n\tmulticodec.RegisterDecoder(0x0129, Decode)\n}\n\n// Decode deserializes data from the given io.Reader and feeds it into the given datamodel.NodeAssembler.\n// Decode fits the codec.Decoder function interface.\n//\n// A similar function is available on DecodeOptions type if you would like to customize any of the decoding details.\n// This function uses the defaults for the dag-json codec\n// (meaning: links are decoded, and bytes are decoded).\n//\n// This is the function that will be registered in the default multicodec registry during package init time.\nfunc Decode(na datamodel.NodeAssembler, r io.Reader) error {\n\treturn DecodeOptions{\n\t\tParseLinks: true,\n\t\tParseBytes: true,\n\t}.Decode(na, r)\n}\n\n// Encode walks the given datamodel.Node and serializes it to the given io.Writer.\n// Encode fits the codec.Encoder function interface.\n//\n// A similar function is available on EncodeOptions type if you would like to customize any of the encoding details.\n// This function uses the defaults for the dag-json codec\n// (meaning: links are encoded, bytes are encoded, and map keys are sorted during encode).\n//\n// This is the function that will be registered in the default multicodec registry during package init time.\nfunc Encode(n datamodel.Node, w io.Writer) error {\n\treturn EncodeOptions{\n\t\tEncodeLinks: true,\n\t\tEncodeBytes: true,\n\t\tMapSortMode: codec.MapSortMode_Lexical,\n\t}.Encode(n, w)\n}\n"
  },
  {
    "path": "codec/dagjson/nongreedy_test.go",
    "content": "package dagjson\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestNonGreedy(t *testing.T) {\n\tbuf := bytes.NewBufferString(`{\"a\": 1}{\"b\": 2}`)\n\topts := DecodeOptions{\n\t\tParseLinks:         false,\n\t\tParseBytes:         false,\n\t\tDontParseBeyondEnd: true,\n\t}\n\tnb1 := basicnode.Prototype.Map.NewBuilder()\n\terr := opts.Decode(nb1, buf)\n\tif err != nil {\n\t\tt.Fatalf(\"first decode (%v)\", err)\n\t}\n\tn1 := nb1.Build()\n\tif n1.Kind() != datamodel.Kind_Map {\n\t\tt.Errorf(\"expecting a map\")\n\t}\n\tif _, err := n1.LookupByString(\"a\"); err != nil {\n\t\tt.Fatalf(\"missing fist key\")\n\t}\n\tnb2 := basicnode.Prototype.Map.NewBuilder()\n\terr = opts.Decode(nb2, buf)\n\tif err != nil {\n\t\tt.Fatalf(\"second decode (%v)\", err)\n\t}\n\tn2 := nb2.Build()\n\tif n2.Kind() != datamodel.Kind_Map {\n\t\tt.Errorf(\"expecting a map\")\n\t}\n\tif _, err := n2.LookupByString(\"b\"); err != nil {\n\t\tt.Fatalf(\"missing second key\")\n\t}\n}\n"
  },
  {
    "path": "codec/dagjson/options_test.go",
    "content": "package dagjson\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\n// TestDecodeOptions_MaxDepth verifies that the configurable nesting-depth\n// limit is respected, both with defaults and custom values.\nfunc TestDecodeOptions_MaxDepth(t *testing.T) {\n\tnested := func(depth int) []byte {\n\t\treturn []byte(strings.Repeat(\"[\", depth) + \"null\" + strings.Repeat(\"]\", depth))\n\t}\n\n\tt.Run(\"default depth rejects deeply nested structure\", func(t *testing.T) {\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, bytes.NewReader(nested(2000)))\n\t\tqt.Assert(t, err, qt.Equals, ErrDecodeDepthExceeded)\n\t})\n\n\tt.Run(\"structure at default depth decodes\", func(t *testing.T) {\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, bytes.NewReader(nested(1024)))\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, nb.Build().Kind(), qt.Equals, datamodel.Kind_List)\n\t})\n\n\tt.Run(\"custom depth rejects when exceeded\", func(t *testing.T) {\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := DecodeOptions{MaxDepth: 5}.Decode(nb, bytes.NewReader(nested(10)))\n\t\tqt.Assert(t, err, qt.Equals, ErrDecodeDepthExceeded)\n\t})\n\n\tt.Run(\"custom depth accepts within limit\", func(t *testing.T) {\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := DecodeOptions{MaxDepth: 10}.Decode(nb, bytes.NewReader(nested(5)))\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, nb.Build().Kind(), qt.Equals, datamodel.Kind_List)\n\t})\n\n\tt.Run(\"nested maps also limited\", func(t *testing.T) {\n\t\tconst depth = 2000\n\t\tbuf := strings.Repeat(`{\"x\":`, depth) + \"null\" + strings.Repeat(\"}\", depth)\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := Decode(nb, bytes.NewReader([]byte(buf)))\n\t\tqt.Assert(t, err, qt.Equals, ErrDecodeDepthExceeded)\n\t})\n\n\tt.Run(\"zero MaxDepth resolves to default\", func(t *testing.T) {\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := DecodeOptions{MaxDepth: 0}.Decode(nb, bytes.NewReader(nested(2000)))\n\t\tqt.Assert(t, err, qt.Equals, ErrDecodeDepthExceeded)\n\t})\n\n\tt.Run(\"ParseLinks lookahead does not bypass depth\", func(t *testing.T) {\n\t\t// A valid DAG-JSON link ({\"/\":\"...\"}) wrapped in deep list nesting.\n\t\t// The lookahead path for ParseLinks must still honour the depth limit.\n\t\tconst depth = 2000\n\t\tbuf := strings.Repeat(\"[\", depth) + `{\"/\":\"bafkqaaa\"}` + strings.Repeat(\"]\", depth)\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := DecodeOptions{ParseLinks: true}.Decode(nb, bytes.NewReader([]byte(buf)))\n\t\tqt.Assert(t, err, qt.Equals, ErrDecodeDepthExceeded)\n\t})\n\n\tt.Run(\"ParseBytes lookahead does not bypass depth\", func(t *testing.T) {\n\t\t// A valid DAG-JSON bytes object wrapped in deep list nesting.\n\t\tconst depth = 2000\n\t\tbuf := strings.Repeat(\"[\", depth) + `{\"/\":{\"bytes\":\"aGVsbG8\"}}` + strings.Repeat(\"]\", depth)\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := DecodeOptions{ParseBytes: true}.Decode(nb, bytes.NewReader([]byte(buf)))\n\t\tqt.Assert(t, err, qt.Equals, ErrDecodeDepthExceeded)\n\t})\n\n\tt.Run(\"ParseLinks within limit resolves link correctly\", func(t *testing.T) {\n\t\t// Depth 5 well within the default limit; ensure the lookahead path\n\t\t// still yields a Link node when not overflowing.\n\t\tbuf := strings.Repeat(\"[\", 5) + `{\"/\":\"bafkqaaa\"}` + strings.Repeat(\"]\", 5)\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr := DecodeOptions{ParseLinks: true}.Decode(nb, bytes.NewReader([]byte(buf)))\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tn := nb.Build()\n\t\tfor i := 0; i < 5; i++ {\n\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\tn, err = n.LookupByIndex(0)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t}\n\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Link)\n\t})\n}\n"
  },
  {
    "path": "codec/dagjson/roundtripBytes_test.go",
    "content": "package dagjson_test\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\tnodetests \"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nvar byteNode = fluent.MustBuildMap(basicnode.Prototype.Map, 4, func(na fluent.MapAssembler) {\n\tna.AssembleEntry(\"plain\").AssignString(\"olde string\")\n\tna.AssembleEntry(\"bytes\").AssignBytes([]byte(\"deadbeef\"))\n})\nvar byteNodeSorted = fluent.MustBuildMap(basicnode.Prototype.Map, 4, func(na fluent.MapAssembler) {\n\tna.AssembleEntry(\"bytes\").AssignBytes([]byte(\"deadbeef\"))\n\tna.AssembleEntry(\"plain\").AssignString(\"olde string\")\n})\nvar byteSerial = `{\"bytes\":{\"/\":{\"bytes\":\"ZGVhZGJlZWY\"}},\"plain\":\"olde string\"}`\n\nfunc TestRoundtripBytes(t *testing.T) {\n\tt.Run(\"encoding\", func(t *testing.T) {\n\t\tvar buf bytes.Buffer\n\t\terr := dagjson.Encode(byteNode, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, buf.String(), qt.Equals, byteSerial)\n\t})\n\tt.Run(\"decoding\", func(t *testing.T) {\n\t\tbuf := strings.NewReader(byteSerial)\n\t\tnb := basicnode.Prototype.Map.NewBuilder()\n\t\terr := dagjson.Decode(nb, buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, nb.Build(), nodetests.NodeContentEquals, byteNodeSorted)\n\t})\n}\n\nvar encapsulatedNode = fluent.MustBuildMap(basicnode.Prototype.Map, 1, func(na fluent.MapAssembler) {\n\tna.AssembleEntry(\"/\").CreateMap(1, func(sa fluent.MapAssembler) {\n\t\tsa.AssembleEntry(\"bytes\").AssignBytes([]byte(\"deadbeef\"))\n\t})\n})\nvar encapsulatedSerial = `{\"/\":{\"bytes\":{\"/\":{\"bytes\":\"ZGVhZGJlZWY\"}}}}`\n\nfunc TestEncapsulatedBytes(t *testing.T) {\n\tt.Run(\"encoding\", func(t *testing.T) {\n\t\tvar buf bytes.Buffer\n\t\terr := dagjson.Encode(encapsulatedNode, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, buf.String(), qt.Equals, encapsulatedSerial)\n\t})\n\tt.Run(\"decoding\", func(t *testing.T) {\n\t\tbuf := strings.NewReader(encapsulatedSerial)\n\t\tnb := basicnode.Prototype.Map.NewBuilder()\n\t\terr := dagjson.Decode(nb, buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, nb.Build(), nodetests.NodeContentEquals, encapsulatedNode)\n\t})\n}\n\nvar withPadding = `{\"/\": {\"bytes\": \"Bxrk96XO8cwr3hrcL4VeWtVdYudzHv47BbBl7CesWvmjRrRPOLZp9Ukg6sivn5Nqg4V5X2w43mk4Ppuzr+M+DA==\"}}`\n\nfunc TestPaddedBytes(t *testing.T) {\n\tt.Run(\"decoding\", func(t *testing.T) {\n\t\tbuf := strings.NewReader(withPadding)\n\t\tnb := basicnode.Prototype.Bytes.NewBuilder()\n\t\terr := dagjson.Decode(nb, buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t})\n}\n"
  },
  {
    "path": "codec/dagjson/roundtripCidlink_test.go",
    "content": "package dagjson_test\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\tcid \"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\tnodetests \"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nfunc TestRoundtripCidlink(t *testing.T) {\n\tlp := cidlink.LinkPrototype{Prefix: cid.Prefix{\n\t\tVersion:  1,\n\t\tCodec:    0x0129,\n\t\tMhType:   0x13,\n\t\tMhLength: 4,\n\t}}\n\tlsys := cidlink.DefaultLinkSystem()\n\n\tbuf := bytes.Buffer{}\n\tlsys.StorageWriteOpener = func(lnkCtx linking.LinkContext) (io.Writer, linking.BlockWriteCommitter, error) {\n\t\treturn &buf, func(lnk datamodel.Link) error { return nil }, nil\n\t}\n\tlsys.StorageReadOpener = func(lnkCtx linking.LinkContext, lnk datamodel.Link) (io.Reader, error) {\n\t\treturn bytes.NewReader(buf.Bytes()), nil\n\t}\n\n\tlnk, err := lsys.Store(linking.LinkContext{}, lp, n)\n\tqt.Assert(t, err, qt.IsNil)\n\n\tn2, err := lsys.Load(linking.LinkContext{}, lnk, basicnode.Prototype.Any)\n\tqt.Assert(t, err, qt.IsNil)\n\tqt.Check(t, n2, nodetests.NodeContentEquals, nSorted)\n}\n\n// Make sure that a map that *almost* looks like a link is handled safely.\n//\n// This is aiming very specifically at the corner case where a minimal number of\n// tokens have to be reprocessed before a recursion that find a real link appears.\nfunc TestUnmarshalTrickyMapContainingLink(t *testing.T) {\n\t// Create a link; don't particularly care about its contents.\n\tlnk := cidlink.LinkPrototype{Prefix: cid.Prefix{\n\t\tVersion:  1,\n\t\tCodec:    0x71,\n\t\tMhType:   0x13,\n\t\tMhLength: 4,\n\t}}.BuildLink([]byte{1, 2, 3, 4}) // dummy value, content does not matter to this test.\n\n\t// Compose the tricky corpus.  (lnk.String \"happens\" to work here, although this isn't recommended or correct in general.)\n\ttricky := `{\"/\":{\"/\":\"` + lnk.String() + `\"}}`\n\n\t// Unmarshal.  Hopefully we get a map with a link in it.\n\tnb := basicnode.Prototype.Any.NewBuilder()\n\terr := dagjson.Decode(nb, strings.NewReader(tricky))\n\tqt.Assert(t, err, qt.IsNil)\n\tn := nb.Build()\n\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\tn2, err := n.LookupByString(\"/\")\n\tqt.Assert(t, err, qt.IsNil)\n\tqt.Check(t, n2.Kind(), qt.Equals, datamodel.Kind_Link)\n}\n"
  },
  {
    "path": "codec/dagjson/roundtrip_test.go",
    "content": "package dagjson_test\n\nimport (\n\t\"bytes\"\n\t\"math/rand\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\tnodetests \"github.com/ipld/go-ipld-prime/node/tests\"\n\t\"github.com/ipld/go-ipld-prime/testutil/garbage\"\n)\n\nvar n = fluent.MustBuildMap(basicnode.Prototype.Map, 4, func(na fluent.MapAssembler) {\n\tna.AssembleEntry(\"plain\").AssignString(\"olde string\")\n\tna.AssembleEntry(\"map\").CreateMap(2, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"one\").AssignInt(1)\n\t\tna.AssembleEntry(\"two\").AssignInt(2)\n\t})\n\tna.AssembleEntry(\"list\").CreateList(2, func(na fluent.ListAssembler) {\n\t\tna.AssembleValue().AssignString(\"three\")\n\t\tna.AssembleValue().AssignString(\"four\")\n\t})\n\tna.AssembleEntry(\"nested\").CreateMap(1, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"deeper\").CreateList(1, func(na fluent.ListAssembler) {\n\t\t\tna.AssembleValue().AssignString(\"things\")\n\t\t})\n\t})\n})\nvar nSorted = fluent.MustBuildMap(basicnode.Prototype.Map, 4, func(na fluent.MapAssembler) {\n\tna.AssembleEntry(\"list\").CreateList(2, func(na fluent.ListAssembler) {\n\t\tna.AssembleValue().AssignString(\"three\")\n\t\tna.AssembleValue().AssignString(\"four\")\n\t})\n\tna.AssembleEntry(\"map\").CreateMap(2, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"one\").AssignInt(1)\n\t\tna.AssembleEntry(\"two\").AssignInt(2)\n\t})\n\tna.AssembleEntry(\"nested\").CreateMap(1, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"deeper\").CreateList(1, func(na fluent.ListAssembler) {\n\t\t\tna.AssembleValue().AssignString(\"things\")\n\t\t})\n\t})\n\tna.AssembleEntry(\"plain\").AssignString(\"olde string\")\n})\nvar serial = `{\"list\":[\"three\",\"four\"],\"map\":{\"one\":1,\"two\":2},\"nested\":{\"deeper\":[\"things\"]},\"plain\":\"olde string\"}`\n\nfunc TestRoundtrip(t *testing.T) {\n\tt.Run(\"encoding\", func(t *testing.T) {\n\t\tvar buf bytes.Buffer\n\t\terr := dagjson.Encode(n, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, buf.String(), qt.Equals, serial)\n\t})\n\tt.Run(\"decoding\", func(t *testing.T) {\n\t\tbuf := strings.NewReader(serial)\n\t\tnb := basicnode.Prototype.Map.NewBuilder()\n\t\terr := dagjson.Decode(nb, buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, nb.Build(), nodetests.NodeContentEquals, nSorted)\n\t})\n}\n\nfunc TestRoundtripScalar(t *testing.T) {\n\tnb := basicnode.Prototype__String{}.NewBuilder()\n\tnb.AssignString(\"applesauce\")\n\tsimple := nb.Build()\n\tt.Run(\"encoding\", func(t *testing.T) {\n\t\tvar buf bytes.Buffer\n\t\terr := dagjson.Encode(simple, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, buf.String(), qt.Equals, `\"applesauce\"`)\n\t})\n\tt.Run(\"decoding\", func(t *testing.T) {\n\t\tbuf := strings.NewReader(`\"applesauce\"`)\n\t\tnb := basicnode.Prototype__String{}.NewBuilder()\n\t\terr := dagjson.Decode(nb, buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, nb.Build(), nodetests.NodeContentEquals, simple)\n\t})\n}\n\nfunc TestGarbage(t *testing.T) {\n\tt.Run(\"small garbage\", func(t *testing.T) {\n\t\tseed := time.Now().Unix()\n\t\tt.Logf(\"randomness seed: %v\\n\", seed)\n\t\trnd := rand.New(rand.NewSource(seed))\n\t\tfor i := 0; i < 1000; i++ {\n\t\t\tgbg := garbage.Generate(rnd, garbage.TargetBlockSize(1<<6))\n\t\t\tvar buf bytes.Buffer\n\t\t\terr := dagjson.Encode(gbg, &buf)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\t\terr = dagjson.Decode(nb, bytes.NewReader(buf.Bytes()))\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tqt.Check(t, nb.Build(), nodetests.DeepNodeContentsEquals, gbg)\n\t\t}\n\t})\n\n\tt.Run(\"medium garbage\", func(t *testing.T) {\n\t\tseed := time.Now().Unix()\n\t\tt.Logf(\"randomness seed: %v\\n\", seed)\n\t\trnd := rand.New(rand.NewSource(seed))\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tgbg := garbage.Generate(rnd, garbage.TargetBlockSize(1<<16))\n\t\t\tvar buf bytes.Buffer\n\t\t\terr := dagjson.Encode(gbg, &buf)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\t\terr = dagjson.Decode(nb, bytes.NewReader(buf.Bytes()))\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tqt.Check(t, nb.Build(), nodetests.DeepNodeContentsEquals, gbg)\n\t\t}\n\t})\n\n\tt.Run(\"large garbage\", func(t *testing.T) {\n\t\tseed := time.Now().Unix()\n\t\tt.Logf(\"randomness seed: %v\\n\", seed)\n\t\trnd := rand.New(rand.NewSource(seed))\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tgbg := garbage.Generate(rnd, garbage.TargetBlockSize(1<<20))\n\t\t\tvar buf bytes.Buffer\n\t\t\terr := dagjson.Encode(gbg, &buf)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\t\terr = dagjson.Decode(nb, bytes.NewReader(buf.Bytes()))\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tqt.Check(t, nb.Build(), nodetests.DeepNodeContentsEquals, gbg)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "codec/dagjson/unmarshal.go",
    "content": "package dagjson\n\nimport (\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\tcid \"github.com/ipfs/go-cid\"\n\t\"github.com/polydawn/refmt/json\"\n\t\"github.com/polydawn/refmt/shared\"\n\t\"github.com/polydawn/refmt/tok\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n)\n\n// ErrDecodeDepthExceeded is returned when a decoded structure nests deeper\n// than the configured MaxDepth.\nvar ErrDecodeDepthExceeded = errors.New(\"message structure exceeded maximum nesting depth\")\n\nconst defaultMaxDepth int64 = 1024\n\n// This drifts pretty far from the general unmarshal in the parent package:\n//   - we know JSON never has length hints, so we ignore that field in tokens;\n//   - we know JSON never has tags, so we ignore that field as well;\n//   - we have dag-json's special sauce for detecting schemafree links\n//      (and this unfortunately turns out to *significantly* convolute the first\n//       several steps of handling maps, because it necessitates peeking several\n//        tokens before deciding what kind of value to create).\n\n// DecodeOptions can be used to customize the behavior of a decoding function.\n// The Decode method on this struct fits the codec.Decoder function interface.\ntype DecodeOptions struct {\n\t// If true, parse DAG-JSON `{\"/\":\"cid string\"}` as a Link kind node rather\n\t// than a plain map\n\tParseLinks bool\n\n\t// If true, parse DAG-JSON `{\"/\":{\"bytes\":\"base64 bytes...\"}}` as a Bytes kind\n\t// node rather than nested plain maps\n\tParseBytes bool\n\n\t// If true, the decoder stops reading from the stream at the end of the JSON structure.\n\t// i.e. it does not slurp remaining whitespaces and EOF.\n\t// As per standard IPLD behavior, the parser considers the entire block to be\n\t// part of the JSON structure and will error if there is extraneous\n\t// non-whitespace data.\n\tDontParseBeyondEnd bool\n\n\t// MaxDepth sets the maximum nesting depth for decoded structures. If the\n\t// decoder encounters a map or list nested beyond this depth, it returns\n\t// ErrDecodeDepthExceeded.\n\t//\n\t// When zero, a default of 1024 is used.\n\tMaxDepth int64\n}\n\nfunc (cfg DecodeOptions) maxDepth() int64 {\n\tif cfg.MaxDepth > 0 {\n\t\treturn cfg.MaxDepth\n\t}\n\treturn defaultMaxDepth\n}\n\n// Decode deserializes data from the given io.Reader and feeds it into the given datamodel.NodeAssembler.\n// Decode fits the codec.Decoder function interface.\n//\n// The behavior of the decoder can be customized by setting fields in the DecodeOptions struct before calling this method.\nfunc (cfg DecodeOptions) Decode(na datamodel.NodeAssembler, r io.Reader) error {\n\terr := Unmarshal(na, json.NewDecoder(r), cfg)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif cfg.DontParseBeyondEnd {\n\t\treturn nil\n\t}\n\t// Slurp any remaining whitespace.\n\t//  This behavior may be due for review.\n\t//  (This is relevant if our reader is tee'ing bytes to a hasher, and\n\t//   the json contained any trailing whitespace.)\n\t//  (We can't actually support multiple objects per reader from here;\n\t//   we can't unpeek if we find a non-whitespace token, so our only\n\t//    option is to error if this reader seems to contain more content.)\n\tvar buf [1]byte\n\tfor {\n\t\t_, err := r.Read(buf[:])\n\t\tswitch buf[0] {\n\t\tcase ' ', 0x0, '\\t', '\\r', '\\n': // continue\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unexpected content after end of json object\")\n\t\t}\n\t\tif err == nil {\n\t\t\tcontinue\n\t\t} else if err == io.EOF {\n\t\t\treturn nil\n\t\t} else {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// Future work: we would like to remove the Unmarshal function,\n// and in particular, stop seeing types from refmt (like shared.TokenSource) be visible.\n// Right now, some kinds of configuration (e.g. for whitespace and prettyprint) are only available through interacting with the refmt types;\n// we should improve our API so that this can be done with only our own types in this package.\n\n// Unmarshal is a deprecated function.\n// Please consider switching to DecodeOptions.Decode instead.\nfunc Unmarshal(na datamodel.NodeAssembler, tokSrc shared.TokenSource, options DecodeOptions) error {\n\tvar st unmarshalState\n\tst.options = options\n\tdone, err := tokSrc.Step(&st.tk[0])\n\tif err == io.EOF {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\tif done && !st.tk[0].Type.IsValue() && st.tk[0].Type != tok.TNull {\n\t\treturn fmt.Errorf(\"unexpected eof\")\n\t}\n\treturn st.unmarshal(na, tokSrc, 0)\n}\n\ntype unmarshalState struct {\n\ttk      [7]tok.Token // mostly, only 0'th is used... but [1:7] are used during lookahead for links.\n\tshift   int          // how many times to slide something out of tk[1:7] instead of getting a new token.\n\toptions DecodeOptions\n}\n\n// step leaves a \"new\" token in tk[0],\n// taking account of an shift left by linkLookahead.\n// It's only necessary to use this when handling maps,\n// since the situations resulting in nonzero shift are otherwise unreachable.\n//\n// At most, 'step' will be shifting buffered tokens for:\n//   - the first map key\n//   - the first map value (which will be a string)\n//   - the second map key\n//\n// and so (fortunately! whew!) we can do this in a fixed amount of memory,\n// since none of those states can reach a recursion.\nfunc (st *unmarshalState) step(tokSrc shared.TokenSource) error {\n\tswitch st.shift {\n\tcase 0:\n\t\t_, err := tokSrc.Step(&st.tk[0])\n\t\treturn err\n\tcase 1:\n\t\tst.tk[0] = st.tk[1]\n\t\tst.shift--\n\t\treturn nil\n\tcase 2:\n\t\tst.tk[0] = st.tk[1]\n\t\tst.tk[1] = st.tk[2]\n\t\tst.shift--\n\t\treturn nil\n\tcase 3:\n\t\tst.tk[0] = st.tk[1]\n\t\tst.tk[1] = st.tk[2]\n\t\tst.tk[2] = st.tk[3]\n\t\tst.shift--\n\t\treturn nil\n\tcase 4:\n\t\tst.tk[0] = st.tk[1]\n\t\tst.tk[1] = st.tk[2]\n\t\tst.tk[2] = st.tk[3]\n\t\tst.tk[3] = st.tk[4]\n\t\tst.shift--\n\t\treturn nil\n\tcase 5:\n\t\tst.tk[0] = st.tk[1]\n\t\tst.tk[1] = st.tk[2]\n\t\tst.tk[2] = st.tk[3]\n\t\tst.tk[3] = st.tk[4]\n\t\tst.tk[4] = st.tk[5]\n\t\tst.shift--\n\t\treturn nil\n\tcase 6:\n\t\tst.tk[0] = st.tk[1]\n\t\tst.tk[1] = st.tk[2]\n\t\tst.tk[2] = st.tk[3]\n\t\tst.tk[3] = st.tk[4]\n\t\tst.tk[4] = st.tk[5]\n\t\tst.tk[5] = st.tk[6]\n\t\tst.shift--\n\t\treturn nil\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\n\n// ensure checks that the token lookahead-ahead (tk[lookhead]) is loaded from the underlying source.\nfunc (st *unmarshalState) ensure(tokSrc shared.TokenSource, lookahead int) error {\n\tif st.shift < lookahead {\n\t\tif _, err := tokSrc.Step(&st.tk[lookahead]); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tst.shift = lookahead\n\t}\n\treturn nil\n}\n\n// linkLookahead is called after receiving a TMapOpen token;\n// when it returns, we will have either created a link, OR\n// it's not a link, and the caller should proceed to start a map\n// and while using st.step to ensure the peeked tokens are handled, OR\n// in case of error, the error should just rise.\n// If the bool return is true, we got a link, and you should not\n// continue to attempt to build a map.\nfunc (st *unmarshalState) linkLookahead(na datamodel.NodeAssembler, tokSrc shared.TokenSource) (bool, error) {\n\t// Peek next token.  If it's a \"/\" string, link is still a possibility\n\tif err := st.ensure(tokSrc, 1); err != nil {\n\t\treturn false, err\n\t}\n\tif st.tk[1].Type != tok.TString {\n\t\treturn false, nil\n\t}\n\tif st.tk[1].Str != \"/\" {\n\t\treturn false, nil\n\t}\n\t// Peek next token.  If it's a string, link is still a possibility.\n\t//  We won't try to parse it as a CID until we're sure it's the only thing in the map, though.\n\tif err := st.ensure(tokSrc, 2); err != nil {\n\t\treturn false, err\n\t}\n\tif st.tk[2].Type != tok.TString {\n\t\treturn false, nil\n\t}\n\t// Peek next token.  If it's map close, we've got a link!\n\t//  (Otherwise it had better be a string, because another map key is the\n\t//   only other valid transition here... but we'll leave that check to the caller.\n\tif err := st.ensure(tokSrc, 3); err != nil {\n\t\treturn false, err\n\t}\n\tif st.tk[3].Type != tok.TMapClose {\n\t\treturn false, nil\n\t}\n\t// Okay, we made it -- this looks like a link.  Parse it.\n\t//  If it *doesn't* parse as a CID, we treat this as an error.\n\telCid, err := cid.Decode(st.tk[2].Str)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tif err := na.AssignLink(cidlink.Link{Cid: elCid}); err != nil {\n\t\treturn false, err\n\t}\n\t// consume the look-ahead tokens\n\tst.shift = 0\n\treturn true, nil\n}\n\nfunc (st *unmarshalState) bytesLookahead(na datamodel.NodeAssembler, tokSrc shared.TokenSource) (bool, error) {\n\t// Peek next token.  If it's a \"/\" string, bytes is still a possibility\n\tif err := st.ensure(tokSrc, 1); err != nil {\n\t\treturn false, err\n\t}\n\tif st.tk[1].Type != tok.TString {\n\t\treturn false, nil\n\t}\n\tif st.tk[1].Str != \"/\" {\n\t\treturn false, nil\n\t}\n\t// Peek next token.  If it's a map, bytes is still a possibility.\n\tif err := st.ensure(tokSrc, 2); err != nil {\n\t\treturn false, err\n\t}\n\tif st.tk[2].Type != tok.TMapOpen {\n\t\treturn false, nil\n\t}\n\t// peek next token. If it's the string \"bytes\", we're on track.\n\tif err := st.ensure(tokSrc, 3); err != nil {\n\t\treturn false, err\n\t}\n\tif st.tk[3].Type != tok.TString {\n\t\treturn false, nil\n\t}\n\tif st.tk[3].Str != \"bytes\" {\n\t\treturn false, nil\n\t}\n\t// peek next token. if it's a string, we're on track.\n\tif err := st.ensure(tokSrc, 4); err != nil {\n\t\treturn false, err\n\t}\n\tif st.tk[4].Type != tok.TString {\n\t\treturn false, nil\n\t}\n\t// peek next token. if it's the first map close we're on track.\n\tif err := st.ensure(tokSrc, 5); err != nil {\n\t\treturn false, err\n\t}\n\tif st.tk[5].Type != tok.TMapClose {\n\t\treturn false, nil\n\t}\n\t// Peek next token.  If it's map close, we've got bytes!\n\tif err := st.ensure(tokSrc, 6); err != nil {\n\t\treturn false, err\n\t}\n\tif st.tk[6].Type != tok.TMapClose {\n\t\treturn false, nil\n\t}\n\t// Okay, we made it -- this looks like bytes.  Parse it.\n\telBytes, err := base64.RawStdEncoding.DecodeString(st.tk[4].Str)\n\tif err != nil {\n\t\tif _, isInput := err.(base64.CorruptInputError); isInput {\n\t\t\telBytes, err = base64.StdEncoding.DecodeString(st.tk[4].Str)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t}\n\tif err := na.AssignBytes(elBytes); err != nil {\n\t\treturn false, err\n\t}\n\t// consume the look-ahead tokens\n\tst.shift = 0\n\treturn true, nil\n}\n\n// starts with the first token already primed.  Necessary to get recursion\n//\n//\tto flow right without a peek+unpeek system.\nfunc (st *unmarshalState) unmarshal(na datamodel.NodeAssembler, tokSrc shared.TokenSource, depth int64) error {\n\t// FUTURE: check for schema.TypedNodeBuilder that's going to parse a Link (they can slurp any token kind they want).\n\tswitch st.tk[0].Type {\n\tcase tok.TMapOpen:\n\t\tif depth >= st.options.maxDepth() {\n\t\t\treturn ErrDecodeDepthExceeded\n\t\t}\n\t\t// dag-json has special needs: we pump a few tokens ahead to look for dag-json's \"link\" pattern.\n\t\t//  We can't actually call BeginMap until we're sure it's not gonna turn out to be a link.\n\t\tif st.options.ParseLinks {\n\t\t\tgotLink, err := st.linkLookahead(na, tokSrc)\n\t\t\tif err != nil { // return in error if any token peeks failed or if structure looked like a link but failed to parse as CID.\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif gotLink {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\tif st.options.ParseBytes {\n\t\t\tgotBytes, err := st.bytesLookahead(na, tokSrc)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif gotBytes {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\t// Okay, now back to regularly scheduled map logic.\n\t\tma, err := na.BeginMap(-1)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor {\n\t\t\terr := st.step(tokSrc) // shift next token into slot 0.\n\t\t\tif err != nil {        // return in error if next token unreadable\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tswitch st.tk[0].Type {\n\t\t\tcase tok.TMapClose:\n\t\t\t\treturn ma.Finish()\n\t\t\tcase tok.TString:\n\t\t\t\t// continue\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unexpected %s token while expecting map key\", st.tk[0].Type)\n\t\t\t}\n\t\t\tmva, err := ma.AssembleEntry(st.tk[0].Str)\n\t\t\tif err != nil { // return in error if the key was rejected\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t// Do another shift so the next token is primed before we recurse.\n\t\t\terr = st.step(tokSrc)\n\t\t\tif err != nil { // return in error if next token unreadable\n\t\t\t\treturn err\n\t\t\t}\n\t\t\terr = st.unmarshal(mva, tokSrc, depth+1)\n\t\t\tif err != nil { // return in error if some part of the recursion errored\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\tcase tok.TMapClose:\n\t\treturn fmt.Errorf(\"unexpected mapClose token\")\n\tcase tok.TArrOpen:\n\t\tif depth >= st.options.maxDepth() {\n\t\t\treturn ErrDecodeDepthExceeded\n\t\t}\n\t\tla, err := na.BeginList(-1)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor {\n\t\t\t_, err := tokSrc.Step(&st.tk[0])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tswitch st.tk[0].Type {\n\t\t\tcase tok.TArrClose:\n\t\t\t\treturn la.Finish()\n\t\t\tdefault:\n\t\t\t\terr := st.unmarshal(la.AssembleValue(), tokSrc, depth+1)\n\t\t\t\tif err != nil { // return in error if some part of the recursion errored\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase tok.TArrClose:\n\t\treturn fmt.Errorf(\"unexpected arrClose token\")\n\tcase tok.TNull:\n\t\treturn na.AssignNull()\n\tcase tok.TString:\n\t\treturn na.AssignString(st.tk[0].Str)\n\tcase tok.TBytes:\n\t\treturn na.AssignBytes(st.tk[0].Bytes)\n\tcase tok.TBool:\n\t\treturn na.AssignBool(st.tk[0].Bool)\n\tcase tok.TInt:\n\t\treturn na.AssignInt(st.tk[0].Int)\n\tcase tok.TUint:\n\t\treturn na.AssignInt(int64(st.tk[0].Uint)) // FIXME overflow check\n\tcase tok.TFloat64:\n\t\treturn na.AssignFloat(st.tk[0].Float64)\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\n"
  },
  {
    "path": "codec/decode_test.go",
    "content": "package codec_test\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\n\t_ \"github.com/ipld/go-ipld-prime/codec/cbor\"\n\t_ \"github.com/ipld/go-ipld-prime/codec/dagcbor\"\n\t_ \"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t_ \"github.com/ipld/go-ipld-prime/codec/json\"\n\tmcregistry \"github.com/ipld/go-ipld-prime/multicodec\"\n\tbasicnode \"github.com/ipld/go-ipld-prime/node/basic\"\n\t\"github.com/multiformats/go-multicodec\"\n)\n\nfunc TestDecodeZero(t *testing.T) {\n\tfor _, code := range []multicodec.Code{\n\t\tmulticodec.Cbor,\n\t\tmulticodec.DagCbor,\n\t\tmulticodec.Json,\n\t\tmulticodec.DagJson,\n\t} {\n\t\tt.Run(code.String(), func(t *testing.T) {\n\t\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\t\tdecode, err := mcregistry.LookupDecoder(uint64(code))\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\t\terr = decode(nb, strings.NewReader(\"\"))\n\t\t\tif !errors.Is(err, io.ErrUnexpectedEOF) {\n\t\t\t\tt.Fatalf(\"unexpected error: %v\", err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "codec/json/marshal_test.go",
    "content": "package json\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent/qp\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nvar link = cid.MustParse(\"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\")\n\n// mirrored in dag-json but without errors\nfunc TestMarshalLinks(t *testing.T) {\n\tlinkNode := basicnode.NewLink(cidlink.Link{Cid: link})\n\tmapNode, err := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {\n\t\tqp.MapEntry(ma, \"Lnk\", qp.Node(linkNode))\n\t})\n\tqt.Assert(t, err, qt.IsNil)\n\n\tt.Run(\"link json\", func(t *testing.T) {\n\t\t_, err := ipld.Encode(linkNode, Encode)\n\t\tqt.Assert(t, err, qt.ErrorMatches, \"cannot marshal IPLD links to this codec\")\n\t})\n\tt.Run(\"nested link json\", func(t *testing.T) {\n\t\t_, err := ipld.Encode(mapNode, Encode)\n\t\tqt.Assert(t, err, qt.ErrorMatches, \"cannot marshal IPLD links to this codec\")\n\t})\n}\n\n// mirrored in dag-json but without errors\nfunc TestMarshalBytes(t *testing.T) {\n\tbytsNode := basicnode.NewBytes([]byte(\"byte me\"))\n\tmapNode, err := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {\n\t\tqp.MapEntry(ma, \"Byts\", qp.Node(bytsNode))\n\t})\n\tqt.Assert(t, err, qt.IsNil)\n\n\tt.Run(\"bytes json\", func(t *testing.T) {\n\t\t_, err := ipld.Encode(bytsNode, Encode)\n\t\tqt.Assert(t, err, qt.ErrorMatches, \"cannot marshal IPLD bytes to this codec\")\n\t})\n\tt.Run(\"nested bytes json\", func(t *testing.T) {\n\t\t_, err := ipld.Encode(mapNode, Encode)\n\t\tqt.Assert(t, err, qt.ErrorMatches, \"cannot marshal IPLD bytes to this codec\")\n\t})\n}\n"
  },
  {
    "path": "codec/json/multicodec.go",
    "content": "package json\n\nimport (\n\t\"io\"\n\n\trfmtjson \"github.com/polydawn/refmt/json\"\n\n\t\"github.com/ipld/go-ipld-prime/codec\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/multicodec\"\n)\n\nvar (\n\t_ codec.Decoder = Decode\n\t_ codec.Encoder = Encode\n)\n\nfunc init() {\n\tmulticodec.RegisterEncoder(0x0200, Encode)\n\tmulticodec.RegisterDecoder(0x0200, Decode)\n}\n\n// Decode deserializes data from the given io.Reader and feeds it into the given datamodel.NodeAssembler.\n// Decode fits the codec.Decoder function interface.\n//\n// This is the function that will be registered in the default multicodec registry during package init time.\nfunc Decode(na datamodel.NodeAssembler, r io.Reader) error {\n\treturn dagjson.DecodeOptions{\n\t\tParseLinks: false,\n\t\tParseBytes: false,\n\t}.Decode(na, r)\n}\n\n// Encode walks the given datamodel.Node and serializes it to the given io.Writer.\n// Encode fits the codec.Encoder function interface.\n//\n// This is the function that will be registered in the default multicodec registry during package init time.\nfunc Encode(n datamodel.Node, w io.Writer) error {\n\t// Shell out directly to generic inspection path.\n\t//  (There's not really any fastpaths of note for json.)\n\t// Write another function if you need to tune encoding options about whitespace.\n\treturn dagjson.Marshal(n, rfmtjson.NewEncoder(w, rfmtjson.EncodeOptions{\n\t\tLine:   []byte{'\\n'},\n\t\tIndent: []byte{'\\t'},\n\t}), dagjson.EncodeOptions{\n\t\tEncodeLinks: false,\n\t\tEncodeBytes: false,\n\t\tMapSortMode: codec.MapSortMode_None,\n\t})\n}\n"
  },
  {
    "path": "codec/raw/codec.go",
    "content": "// Package raw implements IPLD's raw codec, which simply writes and reads a Node\n// which can be represented as bytes.\n//\n// The codec can be used with any node which supports AsBytes and AssignBytes.\n// In general, it only makes sense to use this codec on a plain \"bytes\" node\n// such as github.com/ipld/go-ipld-prime/node/basicnode.Prototype.Bytes.\npackage raw\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/codec\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/multicodec\"\n)\n\n// TODO(mvdan): make go-ipld use go-multicodec soon\nconst rawMulticodec = 0x55\n\nvar (\n\t_ codec.Decoder = Decode\n\t_ codec.Encoder = Encode\n)\n\nfunc init() {\n\tmulticodec.RegisterEncoder(rawMulticodec, Encode)\n\tmulticodec.RegisterDecoder(rawMulticodec, Decode)\n}\n\n// Decode implements decoding of a node with the raw codec.\n//\n// Note that if r has a Bytes method, such as is the case with *bytes.Buffer, we\n// will use those bytes directly to save having to allocate and copy them. The\n// Node interface is defined as immutable, so it is assumed that its bytes won't\n// be modified in-place. Similarly, we assume that the incoming buffer's bytes\n// won't get modified in-place later.\n//\n// To disable the shortcut above, hide the Bytes method by wrapping the buffer\n// with an io.Reader:\n//\n//\tDecode([...], struct{io.Reader}{buf})\nfunc Decode(am datamodel.NodeAssembler, r io.Reader) error {\n\tvar data []byte\n\tif buf, ok := r.(interface{ Bytes() []byte }); ok {\n\t\tdata = buf.Bytes()\n\t} else {\n\t\tvar err error\n\t\tdata, err = io.ReadAll(r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not decode raw node: %v\", err)\n\t\t}\n\t}\n\treturn am.AssignBytes(data)\n}\n\n// Encode implements encoding of a node with the raw codec.\n//\n// Note that Encode won't copy the node's bytes as returned by AsBytes, but the\n// call to Write will typically have to copy the bytes anyway.\nfunc Encode(node datamodel.Node, w io.Writer) error {\n\tdata, err := node.AsBytes()\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = w.Write(data)\n\treturn err\n}\n"
  },
  {
    "path": "codec/raw/codec_test.go",
    "content": "package raw\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\tnodetests \"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nvar tests = []struct {\n\tname string\n\tdata []byte\n}{\n\t{\"Empty\", nil},\n\t{\"Plaintext\", []byte(\"hello there\")},\n\t{\"JSON\", []byte(`{\"foo\": \"bar\"}`)},\n\t{\"NullBytes\", []byte(\"\\x00\\x00\")},\n}\n\nfunc TestRoundtrip(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tnb := basicnode.Prototype.Bytes.NewBuilder()\n\t\t\tr := bytes.NewBuffer(test.data)\n\n\t\t\terr := Decode(nb, r)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tnode := nb.Build()\n\n\t\t\tbuf := new(bytes.Buffer)\n\t\t\terr = Encode(node, buf)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\t\tqt.Assert(t, buf.Bytes(), qt.DeepEquals, test.data)\n\t\t})\n\t}\n}\n\nfunc TestRoundtripCidlink(t *testing.T) {\n\tt.Parallel()\n\n\tlp := cidlink.LinkPrototype{Prefix: cid.Prefix{\n\t\tVersion:  1,\n\t\tCodec:    rawMulticodec,\n\t\tMhType:   0x13,\n\t\tMhLength: 4,\n\t}}\n\tnode := basicnode.NewBytes([]byte(\"hello there\"))\n\n\tlsys := cidlink.DefaultLinkSystem()\n\n\tbuf := bytes.Buffer{}\n\tlsys.StorageWriteOpener = func(lnkCtx linking.LinkContext) (io.Writer, linking.BlockWriteCommitter, error) {\n\t\treturn &buf, func(lnk datamodel.Link) error { return nil }, nil\n\t}\n\tlsys.StorageReadOpener = func(lnkCtx linking.LinkContext, lnk datamodel.Link) (io.Reader, error) {\n\t\treturn bytes.NewReader(buf.Bytes()), nil\n\t}\n\tlnk, err := lsys.Store(linking.LinkContext{}, lp, node)\n\n\tqt.Assert(t, err, qt.IsNil)\n\n\tnewNode, err := lsys.Load(linking.LinkContext{}, lnk, basicnode.Prototype.Any)\n\tqt.Assert(t, err, qt.IsNil)\n\tqt.Assert(t, newNode, nodetests.NodeContentEquals, node)\n}\n\n// mustOnlyUseRead only exposes Read, hiding Bytes.\ntype mustOnlyUseRead struct {\n\tbuf *bytes.Buffer\n}\n\nfunc (r mustOnlyUseRead) Read(p []byte) (int, error) {\n\treturn r.buf.Read(p)\n}\n\n// mustNotUseRead exposes Bytes and makes Read always error.\ntype mustNotUseRead struct {\n\tbuf *bytes.Buffer\n}\n\nfunc (r mustNotUseRead) Read(p []byte) (int, error) {\n\treturn 0, fmt.Errorf(\"must not call Read\")\n}\n\nfunc (r mustNotUseRead) Bytes() []byte {\n\treturn r.buf.Bytes()\n}\n\nfunc TestDecodeBuffer(t *testing.T) {\n\tt.Parallel()\n\n\tvar err error\n\tbuf := bytes.NewBuffer([]byte(\"hello there\"))\n\n\terr = Decode(\n\t\tbasicnode.Prototype.Bytes.NewBuilder(),\n\t\tmustOnlyUseRead{buf},\n\t)\n\tqt.Assert(t, err, qt.IsNil)\n\n\terr = Decode(\n\t\tbasicnode.Prototype.Bytes.NewBuilder(),\n\t\tmustNotUseRead{buf},\n\t)\n\tqt.Assert(t, err, qt.IsNil)\n}\n"
  },
  {
    "path": "codec.go",
    "content": "package ipld\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/codec\"\n)\n\ntype (\n\tEncoder = codec.Encoder\n\tDecoder = codec.Decoder\n)\n"
  },
  {
    "path": "codecHelpers.go",
    "content": "package ipld\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"reflect\"\n\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// Encode serializes the given Node using the given Encoder function,\n// returning the serialized data or an error.\n//\n// The exact result data will depend the node content and on the encoder function,\n// but for example, using a json codec on a node with kind map will produce\n// a result starting in `{`, etc.\n//\n// Encode will automatically switch to encoding the representation form of the Node,\n// if it discovers the Node matches the schema.TypedNode interface.\n// This is probably what you want, in most cases;\n// if this is not desired, you can use the underlaying functions directly\n// (just look at the source of this function for an example of how!).\n//\n// If you would like this operation, but applied directly to a golang type instead of a Node,\n// look to the Marshal function.\nfunc Encode(n Node, encFn Encoder) ([]byte, error) {\n\tvar buf bytes.Buffer\n\terr := EncodeStreaming(&buf, n, encFn)\n\treturn buf.Bytes(), err\n}\n\n// EncodeStreaming is like Encode, but emits output to an io.Writer.\nfunc EncodeStreaming(wr io.Writer, n Node, encFn Encoder) error {\n\tif tn, ok := n.(schema.TypedNode); ok {\n\t\tn = tn.Representation()\n\t}\n\treturn encFn(n, wr)\n}\n\n// Decode parses the given bytes into a Node using the given Decoder function,\n// returning a new Node or an error.\n//\n// The new Node that is returned will be the implementation from the node/basicnode package.\n// This implementation of Node will work for storing any kind of data,\n// but note that because it is general, it is also not necessarily optimized.\n// If you want more control over what kind of Node implementation (and thus memory layout) is used,\n// or want to use features like IPLD Schemas (which can be engaged by using a schema.TypedPrototype),\n// then look to the DecodeUsingPrototype family of functions,\n// which accept more parameters in order to give you that kind of control.\n//\n// If you would like this operation, but applied directly to a golang type instead of a Node,\n// look to the Unmarshal function.\nfunc Decode(b []byte, decFn Decoder) (Node, error) {\n\treturn DecodeUsingPrototype(b, decFn, basicnode.Prototype.Any)\n}\n\n// DecodeStreaming is like Decode, but works on an io.Reader for input.\nfunc DecodeStreaming(r io.Reader, decFn Decoder) (Node, error) {\n\treturn DecodeStreamingUsingPrototype(r, decFn, basicnode.Prototype.Any)\n}\n\n// DecodeUsingPrototype is like Decode, but with a NodePrototype parameter,\n// which gives you control over the Node type you'll receive,\n// and thus control over the memory layout, and ability to use advanced features like schemas.\n// (Decode is simply this function, but hardcoded to use basicnode.Prototype.Any.)\n//\n// DecodeUsingPrototype internally creates a NodeBuilder, and throws it away when done.\n// If building a high performance system, and creating data of the same shape repeatedly,\n// you may wish to use NodeBuilder directly, so that you can control and avoid these allocations.\n//\n// For symmetry with the behavior of Encode, DecodeUsingPrototype will automatically\n// switch to using the representation form of the node for decoding\n// if it discovers the NodePrototype matches the schema.TypedPrototype interface.\n// This is probably what you want, in most cases;\n// if this is not desired, you can use the underlaying functions directly\n// (just look at the source of this function for an example of how!).\nfunc DecodeUsingPrototype(b []byte, decFn Decoder, np NodePrototype) (Node, error) {\n\treturn DecodeStreamingUsingPrototype(bytes.NewReader(b), decFn, np)\n}\n\n// DecodeStreamingUsingPrototype is like DecodeUsingPrototype, but works on an io.Reader for input.\nfunc DecodeStreamingUsingPrototype(r io.Reader, decFn Decoder, np NodePrototype) (Node, error) {\n\tif tnp, ok := np.(schema.TypedPrototype); ok {\n\t\tnp = tnp.Representation()\n\t}\n\tnb := np.NewBuilder()\n\tif err := decFn(nb, r); err != nil {\n\t\treturn nil, err\n\t}\n\treturn nb.Build(), nil\n}\n\n// Marshal accepts a pointer to a Go value and an IPLD schema type,\n// and encodes the representation form of that data (which may be configured with the schema!)\n// using the given Encoder function.\n//\n// Marshal uses the node/bindnode subsystem.\n// See the documentation in that package for more details about its workings.\n// Please note that this subsystem is relatively experimental at this time.\n//\n// The schema.Type parameter is optional, and can be nil.\n// If given, it controls what kind of schema.Type (and what kind of representation strategy!)\n// to use when processing the data.\n// If absent, a default schema.Type will be inferred based on the golang type\n// (so, a struct in go will be inferred to have a schema with a similar struct, and the default representation strategy (e.g. map), etc).\n// Note that not all features of IPLD Schemas can be inferred from golang types alone.\n// For example, to use union types, the schema parameter will be required.\n// Similarly, to use most kinds of non-default representation strategy, the schema parameter is needed in order to convey that intention.\nfunc Marshal(encFn Encoder, bind interface{}, typ schema.Type, opts ...bindnode.Option) ([]byte, error) {\n\tn := bindnode.Wrap(bind, typ, opts...)\n\treturn Encode(n.Representation(), encFn)\n}\n\n// MarshalStreaming is like Marshal, but emits output to an io.Writer.\nfunc MarshalStreaming(wr io.Writer, encFn Encoder, bind interface{}, typ schema.Type, opts ...bindnode.Option) error {\n\tn := bindnode.Wrap(bind, typ, opts...)\n\treturn EncodeStreaming(wr, n.Representation(), encFn)\n}\n\n// Unmarshal accepts a pointer to a Go value and an IPLD schema type,\n// and fills the value with data by decoding into it with the given Decoder function.\n//\n// Unmarshal uses the node/bindnode subsystem.\n// See the documentation in that package for more details about its workings.\n// Please note that this subsystem is relatively experimental at this time.\n//\n// The schema.Type parameter is optional, and can be nil.\n// If given, it controls what kind of schema.Type (and what kind of representation strategy!)\n// to use when processing the data.\n// If absent, a default schema.Type will be inferred based on the golang type\n// (so, a struct in go will be inferred to have a schema with a similar struct, and the default representation strategy (e.g. map), etc).\n// Note that not all features of IPLD Schemas can be inferred from golang types alone.\n// For example, to use union types, the schema parameter will be required.\n// Similarly, to use most kinds of non-default representation strategy, the schema parameter is needed in order to convey that intention.\n//\n// In contrast to some other unmarshal conventions common in golang,\n// notice that we also return a Node value.\n// This Node points to the same data as the value you handed in as the bind parameter,\n// while making it available to read and iterate and handle as a ipld datamodel.Node.\n// If you don't need that interface, or intend to re-bind it later, you can discard that value.\n//\n// The 'bind' parameter may be nil.\n// In that case, the type of the nil is still used to infer what kind of value to return,\n// and a Node will still be returned based on that type.\n// bindnode.Unwrap can be used on that Node and will still return something\n// of the same golang type as the typed nil that was given as the 'bind' parameter.\nfunc Unmarshal(b []byte, decFn Decoder, bind interface{}, typ schema.Type, opts ...bindnode.Option) (Node, error) {\n\treturn UnmarshalStreaming(bytes.NewReader(b), decFn, bind, typ, opts...)\n}\n\n// UnmarshalStreaming is like Unmarshal, but works on an io.Reader for input.\nfunc UnmarshalStreaming(r io.Reader, decFn Decoder, bind interface{}, typ schema.Type, opts ...bindnode.Option) (Node, error) {\n\t// Decode is fairly straightforward.\n\tnp := bindnode.Prototype(bind, typ, opts...)\n\tn, err := DecodeStreamingUsingPrototype(r, decFn, np.Representation())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// ... but our approach above allocated new memory, and we have to copy it back out.\n\t// In the future, the bindnode API could be improved to make this easier.\n\tif !reflect.ValueOf(bind).IsNil() {\n\t\treflect.ValueOf(bind).Elem().Set(reflect.ValueOf(bindnode.Unwrap(n)).Elem())\n\t}\n\t// ... and we also have to re-bind a new node to the 'bind' value,\n\t// because probably the user will be surprised if mutating 'bind' doesn't affect the Node later.\n\tn = bindnode.Wrap(bind, typ, opts...)\n\treturn n, err\n}\n"
  },
  {
    "path": "codecHelpers_test.go",
    "content": "package ipld_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/codec/json\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc Example_marshal() {\n\ttype Foobar struct {\n\t\tFoo string\n\t\tBar string\n\t}\n\tencoded, err := ipld.Marshal(json.Encode, &Foobar{\"wow\", \"whee\"}, nil)\n\tfmt.Printf(\"error: %v\\n\", err)\n\tfmt.Printf(\"data: %s\\n\", string(encoded))\n\n\t// Output:\n\t// error: <nil>\n\t// data: {\n\t// \t\"Foo\": \"wow\",\n\t// \t\"Bar\": \"whee\"\n\t// }\n}\n\n// TODO: Example_Unmarshal, which uses nil and infers a typesystem.  However, to match Example_Unmarshal_withSchema, that appears to need more features in bindnode.\n\nfunc Example_unmarshal_withSchema() {\n\ttypesys := schema.MustTypeSystem(\n\t\tschema.SpawnStruct(\"Foobar\",\n\t\t\t[]schema.StructField{\n\t\t\t\tschema.SpawnStructField(\"foo\", \"String\", false, false),\n\t\t\t\tschema.SpawnStructField(\"bar\", \"String\", false, false),\n\t\t\t},\n\t\t\tschema.SpawnStructRepresentationMap(nil),\n\t\t),\n\t\tschema.SpawnString(\"String\"),\n\t)\n\n\ttype Foobar struct {\n\t\tFoo string\n\t\tBar string\n\t}\n\tserial := []byte(`{\"foo\":\"wow\",\"bar\":\"whee\"}`)\n\tfoobar := Foobar{}\n\tn, err := ipld.Unmarshal(serial, json.Decode, &foobar, typesys.TypeByName(\"Foobar\"))\n\tfmt.Printf(\"error: %v\\n\", err)\n\tfmt.Printf(\"go struct: %v\\n\", foobar)\n\tfmt.Printf(\"node kind and length: %s, %d\\n\", n.Kind(), n.Length())\n\tfmt.Printf(\"node lookup 'foo': %q\\n\", must.String(must.Node(n.LookupByString(\"foo\"))))\n\n\t// Output:\n\t// error: <nil>\n\t// go struct: {wow whee}\n\t// node kind and length: map, 2\n\t// node lookup 'foo': \"wow\"\n}\n"
  },
  {
    "path": "datamodel/copy.go",
    "content": "package datamodel\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\n// Copy does an explicit shallow copy of a Node's data into a NodeAssembler.\n//\n// This can be used to flip data from one memory layout to another\n// (for example, from basicnode to using using bindnode,\n// or to codegenerated node implementations,\n// or to or from ADL nodes, etc).\n//\n// The copy is implemented by ranging over the contents if it's a recursive kind,\n// and for each of them, using `AssignNode` on the child values;\n// for scalars, it's just calling the appropriate `Assign*` method.\n//\n// Many NodeAssembler implementations use this as a fallback behavior in their\n// `AssignNode` method (that is, they call to this function after all other special\n// faster shortcuts they might prefer to employ, such as direct struct copying\n// if they share internal memory layouts, etc, have been tried already).\nfunc Copy(n Node, na NodeAssembler) error {\n\tif n == nil {\n\t\treturn errors.New(\"cannot copy a nil node\")\n\t}\n\tswitch n.Kind() {\n\tcase Kind_Null:\n\t\tif n.IsAbsent() {\n\t\t\treturn errors.New(\"copying an absent node makes no sense\")\n\t\t}\n\t\treturn na.AssignNull()\n\tcase Kind_Bool:\n\t\tv, err := n.AsBool()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"node violated contract: promised to be %v kind, but AsBool method returned %w\", n.Kind(), err)\n\t\t}\n\t\treturn na.AssignBool(v)\n\tcase Kind_Int:\n\t\tv, err := n.AsInt()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"node violated contract: promised to be %v kind, but AsInt method returned %w\", n.Kind(), err)\n\t\t}\n\t\treturn na.AssignInt(v)\n\tcase Kind_Float:\n\t\tv, err := n.AsFloat()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"node violated contract: promised to be %v kind, but AsFloat method returned %w\", n.Kind(), err)\n\t\t}\n\t\treturn na.AssignFloat(v)\n\tcase Kind_String:\n\t\tv, err := n.AsString()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"node violated contract: promised to be %v kind, but AsString method returned %w\", n.Kind(), err)\n\t\t}\n\t\treturn na.AssignString(v)\n\tcase Kind_Bytes:\n\t\tv, err := n.AsBytes()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"node violated contract: promised to be %v kind, but AsBytes method returned %w\", n.Kind(), err)\n\t\t}\n\t\treturn na.AssignBytes(v)\n\tcase Kind_Link:\n\t\tv, err := n.AsLink()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"node violated contract: promised to be %v kind, but AsLink method returned %w\", n.Kind(), err)\n\t\t}\n\t\treturn na.AssignLink(v)\n\tcase Kind_Map:\n\t\tma, err := na.BeginMap(n.Length())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\titr := n.MapIterator()\n\t\tfor !itr.Done() {\n\t\t\tk, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif v.IsAbsent() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif err := ma.AssembleKey().AssignNode(k); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := ma.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn ma.Finish()\n\tcase Kind_List:\n\t\tla, err := na.BeginList(n.Length())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\titr := n.ListIterator()\n\t\tfor !itr.Done() {\n\t\t\t_, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif v.IsAbsent() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif err := la.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn la.Finish()\n\tdefault:\n\t\treturn fmt.Errorf(\"node has invalid kind %v\", n.Kind())\n\t}\n}\n"
  },
  {
    "path": "datamodel/copy_test.go",
    "content": "package datamodel_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent/qp\"\n\tbasic \"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nvar copyTests = []struct {\n\tname string\n\tna   datamodel.NodeBuilder\n\tn    datamodel.Node\n\terr  string\n}{\n\t{name: \"Null / Any\", na: basic.Prototype.Any.NewBuilder(), n: datamodel.Null},\n\t{name: \"Int / Any\", na: basic.Prototype.Any.NewBuilder(), n: basic.NewInt(100)},\n\t{name: \"Int / Int\", na: basic.Prototype.Int.NewBuilder(), n: basic.NewInt(1000)},\n\t{name: \"Bool / Any\", na: basic.Prototype.Any.NewBuilder(), n: basic.NewBool(true)},\n\t{name: \"Bool / Bool\", na: basic.Prototype.Bool.NewBuilder(), n: basic.NewBool(false)},\n\t{name: \"Float / Any\", na: basic.Prototype.Any.NewBuilder(), n: basic.NewFloat(1.1)},\n\t{name: \"Float / Float\", na: basic.Prototype.Float.NewBuilder(), n: basic.NewFloat(1.2)},\n\t{name: \"String / Any\", na: basic.Prototype.Any.NewBuilder(), n: basic.NewString(\"mary had\")},\n\t{name: \"String / String\", na: basic.Prototype.String.NewBuilder(), n: basic.NewString(\"a little lamb\")},\n\t{name: \"Bytes / Any\", na: basic.Prototype.Any.NewBuilder(), n: basic.NewBytes([]byte(\"mary had\"))},\n\t{name: \"Bytes / Bytes\", na: basic.Prototype.Bytes.NewBuilder(), n: basic.NewBytes([]byte(\"a little lamb\"))},\n\t{name: \"Link / Any\", na: basic.Prototype.Any.NewBuilder(), n: basic.NewLink(globalLink)},\n\t{name: \"Link / Link\", na: basic.Prototype.Link.NewBuilder(), n: basic.NewLink(globalLink2)},\n\t{\n\t\tname: \"List / Any\",\n\t\tna:   basic.Prototype.Any.NewBuilder(),\n\t\tn: qpMust(qp.BuildList(basic.Prototype.Any, -1, func(am datamodel.ListAssembler) {\n\t\t\tqp.ListEntry(am, qp.Int(7))\n\t\t\tqp.ListEntry(am, qp.Int(8))\n\t\t})),\n\t},\n\t{\n\t\tname: \"List / List\",\n\t\tna:   basic.Prototype.List.NewBuilder(),\n\t\tn: qpMust(qp.BuildList(basic.Prototype.List, -1, func(am datamodel.ListAssembler) {\n\t\t\tqp.ListEntry(am, qp.String(\"yep\"))\n\t\t\tqp.ListEntry(am, qp.Int(8))\n\t\t\tqp.ListEntry(am, qp.String(\"nope\"))\n\t\t})),\n\t},\n\t{\n\t\tname: \"Map / Any\",\n\t\tna:   basic.Prototype.Any.NewBuilder(),\n\t\tn: qpMust(qp.BuildMap(basic.Prototype.Any, -1, func(am datamodel.MapAssembler) {\n\t\t\tqp.MapEntry(am, \"foo\", qp.Int(7))\n\t\t\tqp.MapEntry(am, \"bar\", qp.Int(8))\n\t\t})),\n\t},\n\t{\n\t\tname: \"Map / Map\",\n\t\tna:   basic.Prototype.Map.NewBuilder(),\n\t\tn: qpMust(qp.BuildMap(basic.Prototype.Map, -1, func(am datamodel.MapAssembler) {\n\t\t\tqp.MapEntry(am, \"foo\", qp.Int(7))\n\t\t\tqp.MapEntry(am, \"bar\", qp.Int(8))\n\t\t\tqp.MapEntry(am, \"bang\", qp.Link(globalLink))\n\t\t})),\n\t},\n\t{name: \"nil\", na: basic.Prototype.Any.NewBuilder(), n: nil, err: \"cannot copy a nil node\"},\n\t{name: \"absent\", na: basic.Prototype.Any.NewBuilder(), n: datamodel.Absent, err: \"copying an absent node makes no sense\"},\n}\n\nfunc TestCopy(t *testing.T) {\n\tfor _, tt := range copyTests {\n\t\ttt := tt\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\terr := datamodel.Copy(tt.n, tt.na)\n\t\t\tif err != nil {\n\t\t\t\tif tt.err != \"\" {\n\t\t\t\t\tif err.Error() != tt.err {\n\t\t\t\t\t\tt.Fatalf(\"expected error %q, got %q\", tt.err, err.Error())\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tt.Fatal(err)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t} else if tt.err != \"\" {\n\t\t\t\tt.Fatalf(\"expected error %q, got nil\", tt.err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tout := tt.na.Build()\n\t\t\tif !datamodel.DeepEqual(tt.n, out) {\n\t\t\t\tt.Fatalf(\"deep equal failed\")\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "datamodel/doc.go",
    "content": "// The datamodel package defines the most essential interfaces for describing IPLD Data --\n// such as Node, NodePrototype, NodeBuilder, Link, and Path.\n//\n// Note that since interfaces in this package are the core of the library,\n// choices made here maximize correctness and performance -- these choices\n// are *not* always the choices that would maximize ergonomics.\n// (Ergonomics can come on top; performance generally can't.)\n// You'll want to check out other packages for functions with more ergonomics;\n// for example, 'fluent' and its subpackages provide lots of ways to work with data;\n// 'traversal' provides some ergonomic features for walking around data graphs;\n// any use of schemas will provide a bunch of useful data validation options;\n// or you can make your own function decorators that do what *you* need.\npackage datamodel\n"
  },
  {
    "path": "datamodel/equal.go",
    "content": "package datamodel\n\n// DeepEqual reports whether x and y are \"deeply equal\" as IPLD nodes.\n// This is similar to reflect.DeepEqual, but based around the Node interface.\n//\n// Two nodes must have the same kind to be deeply equal.\n// If either node has the invalid kind, the nodes are not deeply equal.\n//\n// Two nodes of scalar kinds (null, bool, int, float, string, bytes, link)\n// are deeply equal if their Go values, as returned by AsKind methods, are equal as\n// per Go's == comparison operator.\n//\n// Note that Links are compared in a shallow way, without being followed.\n// This will generally be enough, as it's rare to have two different links to the\n// same IPLD data by using a different codec or multihash type.\n//\n// Two nodes of recursive kinds (map, list)\n// must have the same length to be deeply equal.\n// Their elements, as reported by iterators, must be deeply equal.\n// The elements are compared in the iterator's order,\n// meaning two maps sorting the same keys differently might not be equal.\n//\n// Note that this function panics if either Node returns an error.\n// We only call valid methods for each Kind,\n// so an error should only happen if a Node implementation breaks that contract.\n// It is generally not recommended to call DeepEqual on ADL nodes.\nfunc DeepEqual(x, y Node) bool {\n\tif x == nil || y == nil {\n\t\treturn x == y\n\t}\n\txk, yk := x.Kind(), y.Kind()\n\tif xk != yk {\n\t\treturn false\n\t}\n\n\tswitch xk {\n\n\t// Scalar kinds.\n\tcase Kind_Null:\n\t\treturn x.IsNull() == y.IsNull()\n\tcase Kind_Bool:\n\t\txv, err := x.AsBool()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tyv, err := y.AsBool()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn xv == yv\n\tcase Kind_Int:\n\t\txv, err := x.AsInt()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tyv, err := y.AsInt()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn xv == yv\n\tcase Kind_Float:\n\t\txv, err := x.AsFloat()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tyv, err := y.AsFloat()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn xv == yv\n\tcase Kind_String:\n\t\txv, err := x.AsString()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tyv, err := y.AsString()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn xv == yv\n\tcase Kind_Bytes:\n\t\txv, err := x.AsBytes()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tyv, err := y.AsBytes()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn string(xv) == string(yv)\n\tcase Kind_Link:\n\t\txv, err := x.AsLink()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tyv, err := y.AsLink()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\t// Links are just compared via ==.\n\t\t// This requires the types to exactly match,\n\t\t// and the values to be equal as per == too.\n\t\t// This will generally work,\n\t\t// as ipld-prime assumes link types to be consistent.\n\t\treturn xv == yv\n\n\t// Recursive kinds.\n\tcase Kind_Map:\n\t\tif x.Length() != y.Length() {\n\t\t\treturn false\n\t\t}\n\t\txitr := x.MapIterator()\n\t\tyitr := y.MapIterator()\n\t\tfor !xitr.Done() && !yitr.Done() {\n\t\t\txkey, xval, err := xitr.Next()\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tykey, yval, err := yitr.Next()\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tif !DeepEqual(xkey, ykey) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif !DeepEqual(xval, yval) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\tcase Kind_List:\n\t\tif x.Length() != y.Length() {\n\t\t\treturn false\n\t\t}\n\t\txitr := x.ListIterator()\n\t\tyitr := y.ListIterator()\n\t\tfor !xitr.Done() && !yitr.Done() {\n\t\t\t_, xval, err := xitr.Next()\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\t_, yval, err := yitr.Next()\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tif !DeepEqual(xval, yval) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\n\t// As per the docs, other kinds such as Invalid are not deeply equal.\n\tdefault:\n\t\treturn false\n\t}\n}\n"
  },
  {
    "path": "datamodel/equal_test.go",
    "content": "package datamodel_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent/qp\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\tbasic \"github.com/ipld/go-ipld-prime/node/basicnode\" // shorter name for the tests\n)\n\nvar (\n\tglobalNode = basic.NewString(\"global\")\n\tglobalLink = func() datamodel.Link {\n\t\tsomeCid, _ := cid.Cast([]byte{1, 85, 0, 5, 0, 1, 2, 3, 4})\n\t\treturn cidlink.Link{Cid: someCid}\n\t}()\n\tglobalLink2 = func() datamodel.Link {\n\t\tsomeCid, _ := cid.Cast([]byte{1, 85, 0, 5, 0, 5, 6, 7, 8})\n\t\treturn cidlink.Link{Cid: someCid}\n\t}()\n)\n\nfunc qpMust(node datamodel.Node, err error) datamodel.Node {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn node\n}\n\nvar deepEqualTests = []struct {\n\tname        string\n\tleft, right datamodel.Node\n\twant        bool\n}{\n\t{\"MismatchingKinds\", basic.NewBool(true), basic.NewInt(3), false},\n\n\t{\"SameNodeSamePointer\", globalNode, globalNode, true},\n\t// Repeated basicnode.New invocations might return different pointers.\n\t{\"SameNodeDiffPointer\", basic.NewString(\"same\"), basic.NewString(\"same\"), true},\n\n\t{\"NilVsNil\", nil, nil, true},\n\t{\"NilVsNull\", nil, datamodel.Null, false},\n\t{\"SameKindNull\", datamodel.Null, datamodel.Null, true},\n\t{\"DiffKindNull\", datamodel.Null, datamodel.Absent, false},\n\t{\"SameKindBool\", basic.NewBool(true), basic.NewBool(true), true},\n\t{\"DiffKindBool\", basic.NewBool(true), basic.NewBool(false), false},\n\t{\"SameKindInt\", basic.NewInt(12), basic.NewInt(12), true},\n\t{\"DiffKindInt\", basic.NewInt(12), basic.NewInt(15), false},\n\t{\"SameKindFloat\", basic.NewFloat(1.25), basic.NewFloat(1.25), true},\n\t{\"DiffKindFloat\", basic.NewFloat(1.25), basic.NewFloat(1.75), false},\n\t{\"SameKindString\", basic.NewString(\"foobar\"), basic.NewString(\"foobar\"), true},\n\t{\"DiffKindString\", basic.NewString(\"foobar\"), basic.NewString(\"baz\"), false},\n\t{\"SameKindBytes\", basic.NewBytes([]byte{5, 2, 3}), basic.NewBytes([]byte{5, 2, 3}), true},\n\t{\"DiffKindBytes\", basic.NewBytes([]byte{5, 2, 3}), basic.NewBytes([]byte{5, 8, 3}), false},\n\t{\"SameKindLink\", basic.NewLink(globalLink), basic.NewLink(globalLink), true},\n\t{\"DiffKindLink\", basic.NewLink(globalLink), basic.NewLink(globalLink2), false},\n\n\t{\n\t\t\"SameKindList\",\n\t\tqpMust(qp.BuildList(basic.Prototype.Any, -1, func(am datamodel.ListAssembler) {\n\t\t\tqp.ListEntry(am, qp.Int(7))\n\t\t\tqp.ListEntry(am, qp.Int(8))\n\t\t})),\n\t\tqpMust(qp.BuildList(basic.Prototype.Any, -1, func(am datamodel.ListAssembler) {\n\t\t\tqp.ListEntry(am, qp.Int(7))\n\t\t\tqp.ListEntry(am, qp.Int(8))\n\t\t})),\n\t\ttrue,\n\t},\n\t{\n\t\t\"DiffKindList_length\",\n\t\tqpMust(qp.BuildList(basic.Prototype.Any, -1, func(am datamodel.ListAssembler) {\n\t\t\tqp.ListEntry(am, qp.Int(7))\n\t\t\tqp.ListEntry(am, qp.Int(8))\n\t\t})),\n\t\tqpMust(qp.BuildList(basic.Prototype.Any, -1, func(am datamodel.ListAssembler) {\n\t\t\tqp.ListEntry(am, qp.Int(7))\n\t\t})),\n\t\tfalse,\n\t},\n\t{\n\t\t\"DiffKindList_elems\",\n\t\tqpMust(qp.BuildList(basic.Prototype.Any, -1, func(am datamodel.ListAssembler) {\n\t\t\tqp.ListEntry(am, qp.Int(7))\n\t\t\tqp.ListEntry(am, qp.Int(8))\n\t\t})),\n\t\tqpMust(qp.BuildList(basic.Prototype.Any, -1, func(am datamodel.ListAssembler) {\n\t\t\tqp.ListEntry(am, qp.Int(3))\n\t\t\tqp.ListEntry(am, qp.Int(2))\n\t\t})),\n\t\tfalse,\n\t},\n\n\t{\n\t\t\"SameKindMap\",\n\t\tqpMust(qp.BuildMap(basic.Prototype.Any, -1, func(am datamodel.MapAssembler) {\n\t\t\tqp.MapEntry(am, \"foo\", qp.Int(7))\n\t\t\tqp.MapEntry(am, \"bar\", qp.Int(8))\n\t\t})),\n\t\tqpMust(qp.BuildMap(basic.Prototype.Any, -1, func(am datamodel.MapAssembler) {\n\t\t\tqp.MapEntry(am, \"foo\", qp.Int(7))\n\t\t\tqp.MapEntry(am, \"bar\", qp.Int(8))\n\t\t})),\n\t\ttrue,\n\t},\n\t{\n\t\t\"DiffKindMap_length\",\n\t\tqpMust(qp.BuildMap(basic.Prototype.Any, -1, func(am datamodel.MapAssembler) {\n\t\t\tqp.MapEntry(am, \"foo\", qp.Int(7))\n\t\t\tqp.MapEntry(am, \"bar\", qp.Int(8))\n\t\t})),\n\t\tqpMust(qp.BuildMap(basic.Prototype.Any, -1, func(am datamodel.MapAssembler) {\n\t\t\tqp.MapEntry(am, \"foo\", qp.Int(7))\n\t\t})),\n\t\tfalse,\n\t},\n\t{\n\t\t\"DiffKindMap_elems\",\n\t\tqpMust(qp.BuildMap(basic.Prototype.Any, -1, func(am datamodel.MapAssembler) {\n\t\t\tqp.MapEntry(am, \"foo\", qp.Int(7))\n\t\t\tqp.MapEntry(am, \"bar\", qp.Int(8))\n\t\t})),\n\t\tqpMust(qp.BuildMap(basic.Prototype.Any, -1, func(am datamodel.MapAssembler) {\n\t\t\tqp.MapEntry(am, \"foo\", qp.Int(3))\n\t\t\tqp.MapEntry(am, \"baz\", qp.Int(8))\n\t\t})),\n\t\tfalse,\n\t},\n\n\t// TODO: tests involving different implementations, once bindnode is ready\n\n}\n\nfunc TestDeepEqual(t *testing.T) {\n\tt.Parallel()\n\tfor _, tc := range deepEqualTests {\n\t\ttc := tc // capture range variable\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgot := datamodel.DeepEqual(tc.left, tc.right)\n\t\t\tif got != tc.want {\n\t\t\t\tt.Fatalf(\"DeepEqual got %v, want %v\", got, tc.want)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "datamodel/errors.go",
    "content": "package datamodel\n\nimport (\n\t\"fmt\"\n)\n\n// ErrWrongKind may be returned from functions on the Node interface when\n// a method is invoked which doesn't make sense for the Kind that node\n// concretely contains.\n//\n// For example, calling AsString on a map will return ErrWrongKind.\n// Calling Lookup on an int will similarly return ErrWrongKind.\ntype ErrWrongKind struct {\n\t// TypeName may optionally indicate the named type of a node the function\n\t// was called on (if the node was typed!), or, may be the empty string.\n\tTypeName string\n\n\t// MethodName is literally the string for the operation attempted, e.g.\n\t// \"AsString\".\n\t//\n\t// For methods on nodebuilders, we say e.g. \"NodeBuilder.CreateMap\".\n\tMethodName string\n\n\t// ApprorpriateKind describes which Kinds the erroring method would\n\t// make sense for.\n\tAppropriateKind KindSet\n\n\t// ActualKind describes the Kind of the node the method was called on.\n\t//\n\t// In the case of typed nodes, this will typically refer to the 'natural'\n\t// data-model kind for such a type (e.g., structs will say 'map' here).\n\tActualKind Kind\n\n\t// TODO: it may be desirable for this error to be able to describe the schema typekind, too, if applicable.\n\t// Of course this presents certain package import graph problems.  Solution to this that maximizes user usability is unclear.\n}\n\nfunc (e ErrWrongKind) Error() string {\n\tif e.TypeName == \"\" {\n\t\treturn fmt.Sprintf(\"func called on wrong kind: %q called on a %s node, but only makes sense on %s\", e.MethodName, e.ActualKind, e.AppropriateKind)\n\t} else {\n\t\treturn fmt.Sprintf(\"func called on wrong kind: %q called on a %s node (kind: %s), but only makes sense on %s\", e.MethodName, e.TypeName, e.ActualKind, e.AppropriateKind)\n\t}\n}\n\n// TODO: revisit the claim below about ErrNoSuchField.  I think we moved back away from that, or want to.\n\n// ErrNotExists may be returned from the lookup functions of the Node interface\n// to indicate a missing value.\n//\n// Note that schema.ErrNoSuchField is another type of error which sometimes\n// occurs in similar places as ErrNotExists.  ErrNoSuchField is preferred\n// when handling data with constraints provided by a schema that mean that\n// a field can *never* exist (as differentiated from a map key which is\n// simply absent in some data).\ntype ErrNotExists struct {\n\tSegment PathSegment\n}\n\nfunc (e ErrNotExists) Error() string {\n\treturn fmt.Sprintf(\"key not found: %q\", e.Segment)\n}\n\n// ErrRepeatedMapKey is an error indicating that a key was inserted\n// into a map that already contains that key.\n//\n// This error may be returned by any methods that add data to a map --\n// any of the methods on a NodeAssembler that was yielded by MapAssembler.AssignKey(),\n// or from the MapAssembler.AssignDirectly() method.\ntype ErrRepeatedMapKey struct {\n\tKey Node\n}\n\nfunc (e ErrRepeatedMapKey) Error() string {\n\treturn fmt.Sprintf(\"cannot repeat map key %q\", e.Key)\n}\n\n// ErrInvalidSegmentForList is returned when using Node.LookupBySegment and the\n// given PathSegment can't be applied to a list because it's unparsable as a number.\ntype ErrInvalidSegmentForList struct {\n\t// TypeName may indicate the named type of a node the function was called on,\n\t// or be empty string if working on untyped data.\n\tTypeName string\n\n\t// TroubleSegment is the segment we couldn't use.\n\tTroubleSegment PathSegment\n\n\t// Reason may explain more about why the PathSegment couldn't be used;\n\t// in practice, it's probably a 'strconv.NumError'.\n\tReason error\n}\n\nfunc (e ErrInvalidSegmentForList) Error() string {\n\tv := \"invalid segment for lookup on a list\"\n\tif e.TypeName != \"\" {\n\t\tv += \" of type \" + e.TypeName\n\t}\n\treturn v + fmt.Sprintf(\": %q: %s\", e.TroubleSegment.s, e.Reason)\n}\n\n// ErrIteratorOverread is returned when calling 'Next' on a MapIterator or\n// ListIterator when it is already done.\ntype ErrIteratorOverread struct{}\n\nfunc (e ErrIteratorOverread) Error() string {\n\treturn \"iterator overread\"\n}\n"
  },
  {
    "path": "datamodel/kind.go",
    "content": "package datamodel\n\n// Kind represents the primitive kind in the IPLD data model.\n// All of these kinds map directly onto serializable data.\n//\n// Note that Kind contains the concept of \"map\", but not \"struct\"\n// or \"object\" -- those are a concepts that could be introduced in a\n// type system layers, but are *not* present in the data model layer,\n// and therefore they aren't included in the Kind enum.\ntype Kind uint8\n\nconst (\n\tKind_Invalid Kind = 0\n\tKind_Map     Kind = '{'\n\tKind_List    Kind = '['\n\tKind_Null    Kind = '0'\n\tKind_Bool    Kind = 'b'\n\tKind_Int     Kind = 'i'\n\tKind_Float   Kind = 'f'\n\tKind_String  Kind = 's'\n\tKind_Bytes   Kind = 'x'\n\tKind_Link    Kind = '/'\n)\n\nfunc (k Kind) String() string {\n\tswitch k {\n\tcase Kind_Invalid:\n\t\treturn \"INVALID\"\n\tcase Kind_Map:\n\t\treturn \"map\"\n\tcase Kind_List:\n\t\treturn \"list\"\n\tcase Kind_Null:\n\t\treturn \"null\"\n\tcase Kind_Bool:\n\t\treturn \"bool\"\n\tcase Kind_Int:\n\t\treturn \"int\"\n\tcase Kind_Float:\n\t\treturn \"float\"\n\tcase Kind_String:\n\t\treturn \"string\"\n\tcase Kind_Bytes:\n\t\treturn \"bytes\"\n\tcase Kind_Link:\n\t\treturn \"link\"\n\tdefault:\n\t\tpanic(\"invalid enumeration value!\")\n\t}\n}\n\n// KindSet is a type with a few enumerated consts that are commonly used\n// (mostly, in error messages).\ntype KindSet []Kind\n\nvar (\n\tKindSet_Recursive = KindSet{Kind_Map, Kind_List}\n\tKindSet_Scalar    = KindSet{Kind_Null, Kind_Bool, Kind_Int, Kind_Float, Kind_String, Kind_Bytes, Kind_Link}\n\n\tKindSet_JustMap    = KindSet{Kind_Map}\n\tKindSet_JustList   = KindSet{Kind_List}\n\tKindSet_JustNull   = KindSet{Kind_Null}\n\tKindSet_JustBool   = KindSet{Kind_Bool}\n\tKindSet_JustInt    = KindSet{Kind_Int}\n\tKindSet_JustFloat  = KindSet{Kind_Float}\n\tKindSet_JustString = KindSet{Kind_String}\n\tKindSet_JustBytes  = KindSet{Kind_Bytes}\n\tKindSet_JustLink   = KindSet{Kind_Link}\n)\n\nfunc (x KindSet) String() string {\n\tif len(x) == 0 {\n\t\treturn \"<empty KindSet>\"\n\t}\n\ts := \"\"\n\tfor i := 0; i < len(x)-1; i++ {\n\t\ts += x[i].String() + \" or \"\n\t}\n\ts += x[len(x)-1].String()\n\treturn s\n}\n\nfunc (x KindSet) Contains(e Kind) bool {\n\tfor _, v := range x {\n\t\tif v == e {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "datamodel/kind_test.go",
    "content": "package datamodel_test\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\nfunc TestErrWrongKind_String(t *testing.T) {\n\tqt.Check(t, datamodel.KindSet{}.String(), qt.Equals, `<empty KindSet>`)\n\tqt.Check(t, datamodel.ErrWrongKind{}.Error(), qt.Equals, `func called on wrong kind: \"\" called on a INVALID node, but only makes sense on <empty KindSet>`)\n}\n"
  },
  {
    "path": "datamodel/link.go",
    "content": "package datamodel\n\n// Link is a special kind of value in IPLD which can be \"loaded\" to access more nodes.\n//\n// Nodes can be a Link: \"link\" is one of the kinds in the IPLD Data Model;\n// and accordingly there is an `ipld.Kind_Link` enum value, and Node has an `AsLink` method.\n//\n// Links are considered a scalar value in the IPLD Data Model,\n// but when \"loaded\", the result can be any other IPLD kind:\n// maps, lists, strings, etc.\n//\n// Link is an interface in the go-ipld implementation,\n// but the most common instantiation of it comes from the `linking/cid` package,\n// and represents CIDs (see https://github.com/multiformats/cid).\n//\n// The Link interface says very little by itself; it's generally necessary to\n// use type assertions to unpack more specific forms of data.\n// The only real contract is that the Link must be able to return a LinkPrototype,\n// which must be able to produce new Link values of a similar form.\n// (In practice: if you're familiar with CIDs: Link.Prototype is analogous to cid.Prefix.)\n//\n// The traversal package contains powerful features for walking through large graphs of Nodes\n// while automatically loading and traversing links as the walk goes.\n//\n// Note that the Link interface should typically be inhabited by a struct or string, as opposed to a pointer.\n// This is because Link is often desirable to be able to use as a golang map key,\n// and in that context, pointers would not result in the desired behavior.\ntype Link interface {\n\t// Prototype should return a LinkPrototype which carries the information\n\t// to make more Link values similar to this one (but with different hashes).\n\tPrototype() LinkPrototype\n\n\t// String should return a reasonably human-readable debug-friendly representation the Link.\n\t// There is no contract that requires that the string be able to be parsed back into a Link value,\n\t// but the string should be unique (e.g. not elide any parts of the hash).\n\tString() string\n\n\t// Binary should return the densest possible encoding of the Link.\n\t// The value need not be printable or human-readable;\n\t// the golang string type is used for immutability and for ease of use as a map key.\n\t// As with the String method, the returned value may not elide any parts of the hash.\n\t//\n\t// Note that there is still no contract that the returned value should be parsable back into a Link value;\n\t// not even in the case of `lnk.Prototype().BuildLink(lnk.Binary()[:])`.\n\t// This is because the value returned by this method may contain data that the LinkPrototype would also restate.\n\t// (For a concrete example: if using CIDs, this method will return a binary string that includes\n\t// the cid version indicator, the multicodec and multihash indicators, etc, in addition to the hash itself --\n\t// whereas the LinkPrototype.BuildLink function still expects to receive only the hash itself alone.)\n\tBinary() string\n}\n\n// LinkPrototype encapsulates any implementation details and parameters\n// necessary for creating a Link, expect for the hash result itself.\n//\n// LinkPrototype, like Link, is an interface in go-ipld,\n// but the most common instantiation of it comes from the `linking/cid` package,\n// and represents CIDs (see https://github.com/multiformats/cid).\n// If using CIDs as an implementation, LinkPrototype will encapsulate information\n// like multihashType, multicodecType, and cidVersion, for example.\n// (LinkPrototype is analogous to cid.Prefix.)\ntype LinkPrototype interface {\n\t// BuildLink should return a new Link value based on the given hashsum.\n\t// The hashsum argument should typically be a value returned from a\n\t// https://golang.org/pkg/hash/#Hash.Sum call.\n\t//\n\t// The hashsum reference must not be retained (the caller is free to reuse it).\n\tBuildLink(hashsum []byte) Link\n}\n"
  },
  {
    "path": "datamodel/node.go",
    "content": "package datamodel\n\nimport \"io\"\n\n// Node represents a value in IPLD.  Any point in a tree of data is a node:\n// scalar values (like int64, string, etc) are nodes, and\n// so are recursive values (like map and list).\n//\n// Nodes and kinds are described in the IPLD specs at\n// https://github.com/ipld/specs/blob/master/data-model-layer/data-model.md .\n//\n// Methods on the Node interface cover the superset of all possible methods for\n// all possible kinds -- but some methods only make sense for particular kinds,\n// and thus will only make sense to call on values of the appropriate kind.\n// (For example, 'Length' on an integer doesn't make sense,\n// and 'AsInt' on a map certainly doesn't work either!)\n// Use the Kind method to find out the kind of value before\n// calling kind-specific methods.\n// Individual method documentation state which kinds the method is valid for.\n// (If you're familiar with the stdlib reflect package, you'll find\n// the design of the Node interface very comparable to 'reflect.Value'.)\n//\n// The Node interface is read-only.  All of the methods on the interface are\n// for examining values, and implementations should be immutable.\n// The companion interface, NodeBuilder, provides the matching writable\n// methods, and should be use to create a (thence immutable) Node.\n//\n// Keeping Node immutable and separating mutation into NodeBuilder makes\n// it possible to perform caching (or rather, memoization, since there's no\n// such thing as cache invalidation for immutable systems) of computed\n// properties of Node; use copy-on-write algorithms for memory efficiency;\n// and to generally build pleasant APIs.\n// Many library functions will rely on the immutability of Node (e.g.,\n// assuming that pointer-equal nodes do not change in value over time),\n// so any user-defined Node implementations should be careful to uphold\n// the immutability contract.)\n//\n// There are many different concrete types which implement Node.\n// The primary purpose of various node implementations is to organize\n// memory in the program in different ways -- some in-memory layouts may\n// be more optimal for some programs than others, and changing the Node\n// (and NodeBuilder) implementations lets the programmer choose.\n//\n// For concrete implementations of Node, check out the \"./node/\" folder,\n// and the packages within it.\n// \"node/basicnode\" should probably be your first start; the Node and NodeBuilder\n// implementations in that package work for any data.\n// Other packages are optimized for specific use-cases.\n// Codegen tools can also be used to produce concrete implementations of Node;\n// these may be specific to certain data, but still conform to the Node\n// interface for interoperability and to support higher-level functions.\n//\n// Nodes may also be *typed* -- see the 'schema' package and `schema.TypedNode`\n// interface, which extends the Node interface with additional methods.\n// Typed nodes have additional constraints and behaviors:\n// for example, they may be a \"struct\" and have a specific type/structure\n// to what data you can put inside them, but still behave as a regular Node\n// in all ways this interface specifies (so you can traverse typed nodes, etc,\n// without any additional special effort).\ntype Node interface {\n\t// Kind returns a value from the Kind enum describing what the\n\t// essential serializable kind of this node is (map, list, integer, etc).\n\t// Most other handling of a node requires first switching upon the kind.\n\tKind() Kind\n\n\t// LookupByString looks up a child object in this node and returns it.\n\t// The returned Node may be any of the Kind:\n\t// a primitive (string, int64, etc), a map, a list, or a link.\n\t//\n\t// If the Kind of this Node is not Kind_Map, a nil node and an error\n\t// will be returned.\n\t//\n\t// If the key does not exist, a nil node and an error will be returned.\n\tLookupByString(key string) (Node, error)\n\n\t// LookupByNode is the equivalent of LookupByString, but takes a reified Node\n\t// as a parameter instead of a plain string.\n\t// This mechanism is useful if working with typed maps (if the key types\n\t// have constraints, and you already have a reified `schema.TypedNode` value,\n\t// using that value can save parsing and validation costs);\n\t// and may simply be convenient if you already have a Node value in hand.\n\t//\n\t// (When writing generic functions over Node, a good rule of thumb is:\n\t// when handling a map, check for `schema.TypedNode`, and in this case prefer\n\t// the LookupByNode(Node) method; otherwise, favor LookupByString; typically\n\t// implementations will have their fastest paths thusly.)\n\tLookupByNode(key Node) (Node, error)\n\n\t// LookupByIndex is the equivalent of LookupByString but for indexing into a list.\n\t// As with LookupByString, the returned Node may be any of the Kind:\n\t// a primitive (string, int64, etc), a map, a list, or a link.\n\t//\n\t// If the Kind of this Node is not Kind_List, a nil node and an error\n\t// will be returned.\n\t//\n\t// If idx is out of range, a nil node and an error will be returned.\n\tLookupByIndex(idx int64) (Node, error)\n\n\t// LookupBySegment is will act as either LookupByString or LookupByIndex,\n\t// whichever is contextually appropriate.\n\t//\n\t// Using LookupBySegment may imply an \"atoi\" conversion if used on a list node,\n\t// or an \"itoa\" conversion if used on a map node.  If an \"itoa\" conversion\n\t// takes place, it may error, and this method may return that error.\n\tLookupBySegment(seg PathSegment) (Node, error)\n\n\t// Note that when using codegenerated types, there may be a fifth variant\n\t// of lookup method on maps: `Get($GeneratedTypeKey) $GeneratedTypeValue`!\n\n\t// MapIterator returns an iterator which yields key-value pairs\n\t// traversing the node.\n\t// If the node kind is anything other than a map, nil will be returned.\n\t//\n\t// The iterator will yield every entry in the map; that is, it\n\t// can be expected that itr.Next will be called node.Length times\n\t// before itr.Done becomes true.\n\tMapIterator() MapIterator\n\n\t// ListIterator returns an iterator which traverses the node and yields indicies and list entries.\n\t// If the node kind is anything other than a list, nil will be returned.\n\t//\n\t// The iterator will yield every entry in the list; that is, it\n\t// can be expected that itr.Next will be called node.Length times\n\t// before itr.Done becomes true.\n\t//\n\t// List iteration is ordered, and indices yielded during iteration will range from 0 to Node.Length-1.\n\t// (The IPLD Data Model definition of lists only defines that it is an ordered list of elements;\n\t// the definition does not include a concept of sparseness, so the indices are always sequential.)\n\tListIterator() ListIterator\n\n\t// Length returns the length of a list, or the number of entries in a map,\n\t// or -1 if the node is not of list nor map kind.\n\tLength() int64\n\n\t// Absent nodes are returned when traversing a struct field that is\n\t// defined by a schema but unset in the data.  (Absent nodes are not\n\t// possible otherwise; you'll only see them from `schema.TypedNode`.)\n\t// The absent flag is necessary so iterating over structs can\n\t// unambiguously make the distinction between values that are\n\t// present-and-null versus values that are absent.\n\t//\n\t// Absent nodes respond to `Kind()` as `ipld.Kind_Null`,\n\t// for lack of any better descriptive value; you should therefore\n\t// always check IsAbsent rather than just a switch on kind\n\t// when it may be important to handle absent values distinctly.\n\tIsAbsent() bool\n\n\tIsNull() bool\n\tAsBool() (bool, error)\n\tAsInt() (int64, error)\n\tAsFloat() (float64, error)\n\tAsString() (string, error)\n\tAsBytes() ([]byte, error)\n\tAsLink() (Link, error)\n\n\t// Prototype returns a NodePrototype which can describe some properties of this node's implementation,\n\t// and also be used to get a NodeBuilder,\n\t// which can be use to create new nodes with the same implementation as this one.\n\t//\n\t// For typed nodes, the NodePrototype will also implement schema.Type.\n\t//\n\t// For Advanced Data Layouts, the NodePrototype will encapsulate any additional\n\t// parameters and configuration of the ADL, and will also (usually)\n\t// implement NodePrototypeSupportingAmend.\n\t//\n\t// Calling this method should not cause an allocation.\n\tPrototype() NodePrototype\n}\n\n// UintNode is an optional interface that can be used to represent an Int node\n// that provides access to the full uint64 range.\n//\n// EXPERIMENTAL: this API is experimental and may be changed or removed in a\n// future use. A future iteration may replace this with a BigInt interface to\n// access a larger range of integers that may be enabled by alternative codecs.\ntype UintNode interface {\n\tNode\n\n\t// AsUint returns a uint64 representing the underlying integer if possible.\n\t// This may return an error if the Node represents a negative integer that\n\t// cannot be represented as a uint64.\n\tAsUint() (uint64, error)\n}\n\n// LargeBytesNode is an optional interface extending a Bytes node that allows its\n// contents to be accessed through an io.ReadSeeker instead of a []byte slice. Use of\n// an io.Reader is encouraged, as it allows for streaming large byte slices\n// without allocating a large slice in memory.\ntype LargeBytesNode interface {\n\tNode\n\t// AsLargeBytes returns an io.ReadSeeker that can be used to read the contents of the node.\n\t// Note that the presence of this method / interface does not imply that the node\n\t// can always return a valid io.ReadSeeker, and the error value must also be checked\n\t// for support.\n\t// It is not guaranteed that all implementations will implement the full semantics of\n\t// Seek, in particular, they may refuse to seek to the end of a large bytes node if\n\t// it is not possible to do so efficiently.\n\t// The io.ReadSeeker returned by AsLargeBytes must be a separate instance from subsequent\n\t// calls to AsLargeBytes. Calls to read or seek on one returned instance should NOT\n\t// affect the read position of other returned instances.\n\tAsLargeBytes() (io.ReadSeeker, error)\n}\n\n// NodePrototype describes a node implementation (all Node have a NodePrototype),\n// and a NodePrototype can always be used to get a NodeBuilder.\n//\n// A NodePrototype may also provide other information about implementation;\n// such information is specific to this library (\"prototype\" isn't a concept\n// you'll find in the IPLD Specifications), and is usually provided through\n// feature-detection interfaces (for example, see NodePrototypeSupportingAmend).\n//\n// Generic algorithms for working with IPLD Nodes make use of NodePrototype\n// to get builders for new nodes when creating data, and can also use the\n// feature-detection interfaces to help decide what kind of operations\n// will be optimal to use on a given node implementation.\n//\n// Note that NodePrototype is not the same as schema.Type.\n// NodePrototype is a (golang-specific!) way to reflect upon the implementation\n// and in-memory layout of some IPLD data.\n// schema.Type is information about how a group of nodes is related in a schema\n// (if they have one!) and the rules that the type mandates the node must follow.\n// (Every node must have a prototype; but schema types are an optional feature.)\ntype NodePrototype interface {\n\t// NewBuilder returns a NodeBuilder that can be used to create a new Node.\n\t//\n\t// Note that calling NewBuilder often performs an allocation\n\t// (while in contrast, getting a NodePrototype typically does not!) --\n\t// this may be consequential when writing high performance code.\n\tNewBuilder() NodeBuilder\n}\n\n// NodePrototypeSupportingAmend is a feature-detection interface that can be\n// used on a NodePrototype to see if it's possible to build new nodes of this style\n// while sharing some internal data in a copy-on-write way.\n//\n// For example, Nodes using an Advanced Data Layout will typically\n// support this behavior, and since ADLs are often used for handling large\n// volumes of data, detecting and using this feature can result in significant\n// performance savings.\ntype NodePrototypeSupportingAmend interface {\n\tAmendingBuilder(base Node) NodeBuilder\n\t// FUTURE: probably also needs a `AmendingWithout(base Node, filter func(k,v) bool) NodeBuilder`, or similar.\n\t//  (\"deletion\" based APIs are also possible but both more complicated in interfaces added, and prone to accidentally quadratic usage.)\n\t// FUTURE: there should be some stdlib `Copy` (?) methods that automatically look for this feature, and fallback if absent.\n\t//  Might include a wide range of point `Transform`, etc, methods.\n\t// FUTURE: consider putting this (and others like it) in a `feature` package, if there begin to be enough of them and docs get crowded.\n}\n\n// MapIterator is an interface for traversing map nodes.\n// Sequential calls to Next() will yield key-value pairs;\n// Done() describes whether iteration should continue.\n//\n// Iteration order is defined to be stable: two separate MapIterator\n// created to iterate the same Node will yield the same key-value pairs\n// in the same order.\n// The order itself may be defined by the Node implementation: some\n// Nodes may retain insertion order, and some may return iterators which\n// always yield data in sorted order, for example.\ntype MapIterator interface {\n\t// Next returns the next key-value pair.\n\t//\n\t// An error value can also be returned at any step: in the case of advanced\n\t// data structures with incremental loading, it's possible to encounter\n\t// cancellation or I/O errors at any point in iteration.\n\t// If an error will be returned by the next call to Next,\n\t// then the boolean returned by the Done method will be false\n\t// (meaning it's acceptable to check Done first and move on if it's true,\n\t// since that both means the iterator is complete and that there is no error).\n\t// If an error is returned, the key and value may be nil.\n\tNext() (key Node, value Node, err error)\n\n\t// Done returns false as long as there's at least one more entry to iterate.\n\t// When Done returns true, iteration can stop.\n\t//\n\t// Note when implementing iterators for advanced data layouts (e.g. more than\n\t// one chunk of backing data, which is loaded incrementally): if your\n\t// implementation does any I/O during the Done method, and it encounters\n\t// an error, it must return 'false', so that the following Next call\n\t// has an opportunity to return the error.\n\tDone() bool\n}\n\n// ListIterator is an interface for traversing list nodes.\n// Sequential calls to Next() will yield index-value pairs;\n// Done() describes whether iteration should continue.\n//\n// ListIterator's Next method returns an index for convenience,\n// but this number will always start at 0 and increment by 1 monotonically.\n// A loop which iterates from 0 to Node.Length while calling Node.LookupByIndex\n// is equivalent to using a ListIterator.\ntype ListIterator interface {\n\t// Next returns the next index and value.\n\t//\n\t// An error value can also be returned at any step: in the case of advanced\n\t// data structures with incremental loading, it's possible to encounter\n\t// cancellation or I/O errors at any point in iteration.\n\t// If an error will be returned by the next call to Next,\n\t// then the boolean returned by the Done method will be false\n\t// (meaning it's acceptable to check Done first and move on if it's true,\n\t// since that both means the iterator is complete and that there is no error).\n\t// If an error is returned, the key and value may be nil.\n\tNext() (idx int64, value Node, err error)\n\n\t// Done returns false as long as there's at least one more entry to iterate.\n\t// When Done returns false, iteration can stop.\n\t//\n\t// Note when implementing iterators for advanced data layouts (e.g. more than\n\t// one chunk of backing data, which is loaded incrementally): if your\n\t// implementation does any I/O during the Done method, and it encounters\n\t// an error, it must return 'false', so that the following Next call\n\t// has an opportunity to return the error.\n\tDone() bool\n}\n\n// REVIEW: immediate-mode AsBytes() method (as opposed to e.g. returning\n// an io.Reader instance) might be problematic, esp. if we introduce\n// AdvancedLayouts which support large bytes natively.\n//\n// Probable solution is having both immediate and iterator return methods.\n// Returning a reader for bytes when you know you want a slice already\n// is going to be high friction without purpose in many common uses.\n//\n// Unclear what SetByteStream() would look like for advanced layouts.\n// One could try to encapsulate the chunking entirely within the advlay\n// node impl... but would it be graceful?  Not sure.  Maybe.  Hopefully!\n// Yes?  The advlay impl would still tend to use SetBytes for the raw\n// data model layer nodes its composing, so overall, it shakes out nicely.\n"
  },
  {
    "path": "datamodel/nodeBuilder.go",
    "content": "package datamodel\n\n// NodeAssembler is the interface that describes all the ways we can set values\n// in a node that's under construction.\n//\n// A NodeAssembler is about filling in data.\n// To create a new Node, you should start with a NodeBuilder (which contains a\n// superset of the NodeAssembler methods, and can return the finished Node\n// from its `Build` method).\n// While continuing to build a recursive structure from there,\n// you'll see NodeAssembler for all the child values.\n//\n// For filling scalar data, there's a `Assign{Kind}` method for each kind;\n// after calling one of these methods, the data is filled in, and the assembler is done.\n// For recursives, there are `BeginMap` and `BeginList` methods,\n// which return an object that needs further manipulation to fill in the contents.\n//\n// There is also one special method: `AssignNode`.\n// `AssignNode` takes another `Node` as a parameter,\n// and should should internally call one of the other `Assign*` or `Begin*` (and subsequent) functions\n// as appropriate for the kind of the `Node` it is given.\n// This is roughly equivalent to using the `Copy` function (and is often implemented using it!), but\n// `AssignNode` may also try to take faster shortcuts in some implementations, when it detects they're possible.\n// (For example, for typed nodes, if they're the same type, lots of checking can be skipped.\n// For nodes implemented with pointers, lots of copying can be skipped.\n// For nodes that can detect the argument has the same memory layout, faster copy mechanisms can be used; etc.)\n//\n// Why do both this and the NodeBuilder interface exist?\n// In short: NodeBuilder is when you want to cause an allocation;\n// NodeAssembler can be used to just \"fill in\" memory.\n// (In the internal gritty details: separate interfaces, one of which lacks a\n// `Build` method, helps us write efficient library internals: avoiding the\n// requirement to be able to return a Node at any random point in the process\n// relieves internals from needing to implement 'freeze' features.\n// This is useful in turn because implementing those 'freeze' features in a\n// language without first-class/compile-time support for them (as golang is)\n// would tend to push complexity and costs to execution time; we'd rather not.)\ntype NodeAssembler interface {\n\tBeginMap(sizeHint int64) (MapAssembler, error)\n\tBeginList(sizeHint int64) (ListAssembler, error)\n\tAssignNull() error\n\tAssignBool(bool) error\n\tAssignInt(int64) error\n\tAssignFloat(float64) error\n\tAssignString(string) error\n\tAssignBytes([]byte) error\n\tAssignLink(Link) error\n\n\tAssignNode(Node) error // if you already have a completely constructed subtree, this method puts the whole thing in place at once.\n\n\t// Prototype returns a NodePrototype describing what kind of value we're assembling.\n\t//\n\t// You often don't need this (because you should be able to\n\t// just feed data and check errors), but it's here.\n\t//\n\t// Using `this.Prototype().NewBuilder()` to produce a new `Node`,\n\t// then giving that node to `this.AssignNode(n)` should always work.\n\t// (Note that this is not necessarily an _exclusive_ statement on what\n\t// sort of values will be accepted by `this.AssignNode(n)`.)\n\tPrototype() NodePrototype\n}\n\n// MapAssembler assembles a map node!  (You guessed it.)\n//\n// Methods on MapAssembler must be called in a valid order:\n// assemble a key, then assemble a value, then loop as long as desired;\n// when finished, call 'Finish'.\n//\n// Incorrect order invocations will panic.\n// Calling AssembleKey twice in a row will panic;\n// calling AssembleValue before finishing using the NodeAssembler from AssembleKey will panic;\n// calling AssembleValue twice in a row will panic;\n// etc.\n//\n// Note that the NodeAssembler yielded from AssembleKey has additional behavior:\n// if the node assembled there matches a key already present in the map,\n// that assembler will emit the error!\ntype MapAssembler interface {\n\tAssembleKey() NodeAssembler   // must be followed by call to AssembleValue.\n\tAssembleValue() NodeAssembler // must be called immediately after AssembleKey.\n\n\tAssembleEntry(k string) (NodeAssembler, error) // shortcut combining AssembleKey and AssembleValue into one step; valid when the key is a string kind.\n\n\tFinish() error\n\n\t// KeyPrototype returns a NodePrototype that knows how to build keys of a type this map uses.\n\t//\n\t// You often don't need this (because you should be able to\n\t// just feed data and check errors), but it's here.\n\t//\n\t// For all Data Model maps, this will answer with a basic concept of \"string\".\n\t// For Schema typed maps, this may answer with a more complex type\n\t// (potentially even a struct type or union type -- anything that can have a string representation).\n\tKeyPrototype() NodePrototype\n\n\t// ValuePrototype returns a NodePrototype that knows how to build values this map can contain.\n\t//\n\t// You often don't need this (because you should be able to\n\t// just feed data and check errors), but it's here.\n\t//\n\t// ValuePrototype requires a parameter describing the key in order to say what\n\t// NodePrototype will be acceptable as a value for that key, because when using\n\t// struct types (or union types) from the Schemas system, they behave as maps\n\t// but have different acceptable types for each field (or member, for unions).\n\t// For plain maps (that is, not structs or unions masquerading as maps),\n\t// the empty string can be used as a parameter, and the returned NodePrototype\n\t// can be assumed applicable for all values.\n\t// Using an empty string for a struct or union will return nil,\n\t// as will using any string which isn't a field or member of those types.\n\t//\n\t// (Design note: a string is sufficient for the parameter here rather than\n\t// a full Node, because the only cases where the value types vary are also\n\t// cases where the keys may not be complex.)\n\tValuePrototype(k string) NodePrototype\n}\n\ntype ListAssembler interface {\n\tAssembleValue() NodeAssembler\n\n\tFinish() error\n\n\t// ValuePrototype returns a NodePrototype that knows how to build values this map can contain.\n\t//\n\t// You often don't need this (because you should be able to\n\t// just feed data and check errors), but it's here.\n\t//\n\t// ValuePrototype, much like the matching method on the MapAssembler interface,\n\t// requires a parameter specifying the index in the list in order to say\n\t// what NodePrototype will be acceptable as a value at that position.\n\t// For many lists (and *all* lists which operate exclusively at the Data Model level),\n\t// this will return the same NodePrototype regardless of the value of 'idx';\n\t// the only time this value will vary is when operating with a Schema,\n\t// and handling the representation NodeAssembler for a struct type with\n\t// a representation of a list kind.\n\t// If you know you are operating in a situation that won't have varying\n\t// NodePrototypes, it is acceptable to call `ValuePrototype(0)` and use the\n\t// resulting NodePrototype for all reasoning.\n\tValuePrototype(idx int64) NodePrototype\n}\n\ntype NodeBuilder interface {\n\tNodeAssembler\n\n\t// Build returns the new value after all other assembly has been completed.\n\t//\n\t// A method on the NodeAssembler that finishes assembly of the data must\n\t// be called first (e.g., any of the \"Assign*\" methods, or \"Finish\" if\n\t// the assembly was for a map or a list); that finishing method still has\n\t// all responsibility for validating the assembled data and returning\n\t// any errors from that process.\n\t// (Correspondingly, there is no error return from this method.)\n\t//\n\t// Note that building via a representation-level NodePrototype or NodeBuilder\n\t// returns a node at the type level which implements schema.TypedNode.\n\t// To obtain the representation-level node, you can do:\n\t//\n\t//    // builder is at the representation level, so it returns typed nodes\n\t//    node := builder.Build().(schema.TypedNode)\n\t//    reprNode := node.Representation()\n\tBuild() Node\n\n\t// Resets the builder.  It can hereafter be used again.\n\t// Reusing a NodeBuilder can reduce allocations and improve performance.\n\t//\n\t// Only call this if you're going to reuse the builder.\n\t// (Otherwise, it's unnecessary, and may cause an unwanted allocation).\n\tReset()\n}\n"
  },
  {
    "path": "datamodel/path.go",
    "content": "package datamodel\n\nimport (\n\t\"strings\"\n)\n\n// Path describes a series of steps across a tree or DAG of Node,\n// where each segment in the path is a map key or list index\n// (literaly, Path is a slice of PathSegment values).\n// Path is used in describing progress in a traversal; and\n// can also be used as an instruction for traversing from one Node to another.\n// Path values will also often be encountered as part of error messages.\n//\n// (Note that Paths are useful as an instruction for traversing from\n// *one* Node to *one* other Node; to do a walk from one Node and visit\n// *several* Nodes based on some sort of pattern, look to IPLD Selectors,\n// and the 'traversal/selector' package in this project.)\n//\n// Path values are always relative.\n// Observe how 'traversal.Focus' requires both a Node and a Path argument --\n// where to start, and where to go, respectively.\n// Similarly, error values which include a Path will be speaking in reference\n// to the \"starting Node\" in whatever context they arose from.\n//\n// The canonical form of a Path is as a list of PathSegment.\n// Each PathSegment is a string; by convention, the string should be\n// in UTF-8 encoding and use NFC normalization, but all operations\n// will regard the string as its constituent eight-bit bytes.\n//\n// There are no illegal or magical characters in IPLD Paths\n// (in particular, do not mistake them for UNIX system paths).\n// IPLD Paths can only go down: that is, each segment must traverse one node.\n// There is no \"..\" which means \"go up\";\n// and there is no \".\" which means \"stay here\".\n// IPLD Paths have no magic behavior around characters such as \"~\".\n// IPLD Paths do not have a concept of \"globs\" nor behave specially\n// for a path segment string of \"*\" (but you may wish to see 'Selectors'\n// for globbing-like features that traverse over IPLD data).\n//\n// An empty string is a valid PathSegment.\n// (This leads to some unfortunate complications when wishing to represent\n// paths in a simple string format; however, consider that maps do exist\n// in serialized data in the wild where an empty string is used as the key:\n// it is important we be able to correctly describe and address this!)\n//\n// A string containing \"/\" (or even being simply \"/\"!) is a valid PathSegment.\n// (As with empty strings, this is unfortunate (in particular, because it\n// very much doesn't match up well with expectations popularized by UNIX-like\n// filesystems); but, as with empty strings, maps which contain such a key\n// certainly exist, and it is important that we be able to regard them!)\n//\n// A string starting, ending, or otherwise containing the NUL (\\x00) byte\n// is also a valid PathSegment.  This follows from the rule of \"a string is\n// regarded as its constituent eight-bit bytes\": an all-zero byte is not exceptional.\n// In golang, this doesn't pose particular difficulty, but note this would be\n// of marked concern for languages which have \"C-style nul-terminated strings\".\n//\n// For an IPLD Path to be represented as a string, an encoding system\n// including escaping is necessary.  At present, there is not a single\n// canonical specification for such an escaping; we expect to decide one\n// in the future, but this is not yet settled and done.\n// (This implementation has a 'String' method, but it contains caveats\n// and may be ambiguous for some content.  This may be fixed in the future.)\ntype Path struct {\n\tsegments []PathSegment\n}\n\n// EmptyPath is the Path with no segments.\nvar EmptyPath = Path{}\n\n// NewPath returns a Path composed of the given segments.\n//\n// This constructor function does a defensive copy,\n// in case your segments slice should mutate in the future.\n// (Use NewPathNocopy if this is a performance concern,\n// and you're sure you know what you're doing.)\nfunc NewPath(segments []PathSegment) Path {\n\tp := Path{make([]PathSegment, len(segments))}\n\tcopy(p.segments, segments)\n\treturn p\n}\n\n// NewPathNocopy is identical to NewPath but trusts that\n// the segments slice you provide will not be mutated.\nfunc NewPathNocopy(segments []PathSegment) Path {\n\treturn Path{segments}\n}\n\n// ParsePath converts a string to an IPLD Path, doing a basic parsing of the\n// string using \"/\" as a delimiter to produce a segmented Path.\n// This is a handy, but not a general-purpose nor spec-compliant (!),\n// way to create a Path: it cannot represent all valid paths.\n//\n// Multiple subsequent \"/\" characters will be silently collapsed.\n// E.g., `\"foo///bar\"` will be treated equivalently to `\"foo/bar\"`.\n// Prefixed and suffixed extraneous \"/\" characters are also discarded.\n// This makes this constructor incapable of handling some possible Path values\n// (specifically: paths with empty segments cannot be created with this constructor).\n//\n// There is no escaping mechanism used by this function.\n// This makes this constructor incapable of handling some possible Path values\n// (specifically, a path segment containing \"/\" cannot be created, because it\n// will always be interpreted as a segment separator).\n//\n// No other \"cleaning\" of the path occurs.  See the documentation of the Path struct;\n// in particular, note that \"..\" does not mean \"go up\", nor does \".\" mean \"stay here\" --\n// correspondingly, there isn't anything to \"clean\" in the same sense as\n// 'filepath.Clean' from the standard library filesystem path packages would.\n//\n// If the provided string contains unprintable characters, or non-UTF-8\n// or non-NFC-canonicalized bytes, no remark will be made about this,\n// and those bytes will remain part of the PathSegments in the resulting Path.\nfunc ParsePath(pth string) Path {\n\t// FUTURE: we should probably have some escaping mechanism which makes\n\t//  it possible to encode a slash in a segment.  Specification needed.\n\tss := strings.FieldsFunc(pth, func(r rune) bool { return r == '/' })\n\tssl := len(ss)\n\tp := Path{make([]PathSegment, ssl)}\n\tfor i := 0; i < ssl; i++ {\n\t\tp.segments[i] = PathSegmentOfString(ss[i])\n\t}\n\treturn p\n}\n\n// String representation of a Path is simply the join of each segment with '/'.\n// It does not include a leading nor trailing slash.\n//\n// This is a handy, but not a general-purpose nor spec-compliant (!),\n// way to reduce a Path to a string.\n// There is no escaping mechanism used by this function,\n// and as a result, not all possible valid Path values (such as those with\n// empty segments or with segments containing \"/\") can be encoded unambiguously.\n// For Path values containing these problematic segments, ParsePath applied\n// to the string returned from this function may return a nonequal Path value.\n//\n// No escaping for unprintable characters is provided.\n// No guarantee that the resulting string is UTF-8 nor NFC canonicalized\n// is provided unless all the constituent PathSegment had those properties.\nfunc (p Path) String() string {\n\tl := len(p.segments)\n\tif l == 0 {\n\t\treturn \"\"\n\t}\n\tsb := strings.Builder{}\n\tfor i := 0; i < l-1; i++ {\n\t\tsb.WriteString(p.segments[i].String())\n\t\tsb.WriteByte('/')\n\t}\n\tsb.WriteString(p.segments[l-1].String())\n\treturn sb.String()\n}\n\n// Segments returns a slice of the path segment strings.\n//\n// It is not lawful to mutate nor append the returned slice.\nfunc (p Path) Segments() []PathSegment {\n\treturn p.segments\n}\n\n// Len returns the number of segments in this path.\n//\n// Zero segments means the path refers to \"the current node\".\n// One segment means it refers to a child of the current node; etc.\nfunc (p Path) Len() int {\n\treturn len(p.segments)\n}\n\n// Join creates a new path composed of the concatenation of this and the given path's segments.\nfunc (p Path) Join(p2 Path) Path {\n\tcombinedSegments := make([]PathSegment, len(p.segments)+len(p2.segments))\n\tcopy(combinedSegments, p.segments)\n\tcopy(combinedSegments[len(p.segments):], p2.segments)\n\tp.segments = combinedSegments\n\treturn p\n}\n\n// AppendSegment is as per Join, but a shortcut when appending single segments.\nfunc (p Path) AppendSegment(ps PathSegment) Path {\n\tl := len(p.segments)\n\tcombinedSegments := make([]PathSegment, l+1)\n\tcopy(combinedSegments, p.segments)\n\tcombinedSegments[l] = ps\n\tp.segments = combinedSegments\n\treturn p\n}\n\n// AppendSegmentString is as per AppendSegment, but a shortcut when the segment is a string.\nfunc (p Path) AppendSegmentString(ps string) Path {\n\treturn p.AppendSegment(PathSegmentOfString(ps))\n}\n\n// AppendSegmentInt is as per AppendSegment, but a shortcut when the segment is an int.\nfunc (p Path) AppendSegmentInt(ps int64) Path {\n\treturn p.AppendSegment(PathSegmentOfInt(ps))\n}\n\n// Parent returns a path with the last of its segments popped off (or\n// the zero path if it's already empty).\nfunc (p Path) Parent() Path {\n\tif len(p.segments) == 0 {\n\t\treturn EmptyPath\n\t}\n\treturn Path{p.segments[0 : len(p.segments)-1]}\n}\n\n// Truncate returns a path with only as many segments remaining as requested.\nfunc (p Path) Truncate(i int) Path {\n\treturn Path{p.segments[0:i]}\n}\n\n// Last returns the trailing segment of the path. Path length should be checked before making use of this value.\n// If the path is empty, EmptyPathSegment is returned which may not be useful.\nfunc (p Path) Last() PathSegment {\n\tif len(p.segments) < 1 {\n\t\treturn EmptyPathSegment\n\t}\n\treturn p.segments[len(p.segments)-1]\n}\n\n// Pop returns a path with all segments except the last.\nfunc (p Path) Pop() Path {\n\tif len(p.segments) < 1 {\n\t\treturn EmptyPath\n\t}\n\treturn Path{p.segments[0 : len(p.segments)-1]}\n}\n\n// Shift returns the first segment of the path together with the remaining path after that first segment.\n// If you intend to use the resulting PathSegment, you should check its length before doing so.\n// If applied to a zero-length path, it returns EmptyPathSegment and the same zero-length path.\nfunc (p Path) Shift() (PathSegment, Path) {\n\tif len(p.segments) < 1 {\n\t\treturn EmptyPathSegment, EmptyPath\n\t}\n\treturn p.segments[0], Path{p.segments[1:]}\n}\n"
  },
  {
    "path": "datamodel/pathSegment.go",
    "content": "package datamodel\n\nimport (\n\t\"strconv\"\n)\n\n// PathSegment can describe either a key in a map, or an index in a list.\n//\n// Create a PathSegment via either ParsePathSegment, PathSegmentOfString,\n// or PathSegmentOfInt; or, via one of the constructors of Path,\n// which will implicitly create PathSegment internally.\n// Using PathSegment's natural zero value directly is discouraged\n// (it will act like ParsePathSegment(\"0\"), which likely not what you'd expect).\n//\n// Path segments are \"stringly typed\" -- they may be interpreted as either strings or ints depending on context.\n// A path segment of \"123\" will be used as a string when traversing a node of map kind;\n// and it will be converted to an integer when traversing a node of list kind.\n// (If a path segment string cannot be parsed to an int when traversing a node of list kind, then traversal will error.)\n// It is not possible to ask which kind (string or integer) a PathSegment is, because that is not defined -- this is *only* interpreted contextually.\n//\n// Internally, PathSegment will store either a string or an integer,\n// depending on how it was constructed,\n// and will automatically convert to the other on request.\n// (This means if two pieces of code communicate using PathSegment,\n// one producing ints and the other expecting ints,\n// then they will work together efficiently.)\n// PathSegment in a Path produced by ParsePath generally have all strings internally,\n// because there is no distinction possible when parsing a Path string\n// (and attempting to pre-parse all strings into ints \"just in case\" would waste time in almost all cases).\n//\n// Be cautious of attempting to use PathSegment as a map key!\n// Due to the implementation detail of internal storage, it's possible for\n// PathSegment values which are \"equal\" per PathSegment.Equal's definition\n// to still be unequal in the eyes of golang's native maps.\n// You should probably use the string values of the PathSegment as map keys.\n// (This has the additional bonus of hitting a special fastpath that the golang\n// built-in maps have specifically for plain string keys.)\ntype PathSegment struct {\n\t/*\n\t\tA quick implementation note about the Go compiler and \"union\" semantics:\n\n\t\tThere are roughly two ways to do \"union\" semantics in Go.\n\n\t\tThe first is to make a struct with each of the values.\n\n\t\tThe second is to make an interface and use an unexported method to keep it closed.\n\n\t\tThe second tactic provides somewhat nicer semantics to the programmer.\n\t\t(Namely, it's clearly impossible to have two inhabitants, which is... the point.)\n\t\tThe downside is... putting things in interfaces generally incurs an allocation\n\t\t(grep your assembly output for \"runtime.conv*\").\n\n\t\tThe first tactic looks kludgier, and would seem to waste memory\n\t\t(the struct reserves space for each possible value, even though the semantic is that only one may be non-zero).\n\t\tHowever, in most cases, more *bytes* are cheaper than more *allocs* --\n\t\tgarbage collection costs are domininated by alloc count, not alloc size.\n\n\t\tBecause PathSegment is something we expect to put in fairly \"hot\" paths,\n\t\twe're using the first tactic.\n\n\t\t(We also currently get away with having no extra discriminator bit\n\t\tbecause we use a signed int for indexes, and negative values aren't valid there,\n\t\tand thus we can use it as a sentinel value.\n\t\t(Fun note: Empty strings were originally used for this sentinel,\n\t\tbut it turns out empty strings are valid PathSegment themselves, so!))\n\t*/\n\n\ts string\n\ti int64\n}\n\n// EmptyPathSegment is the PathSegment with no value. This is not the same as\n// the zero value of PathSegment (PathSegment{}), which will be interpreted to\n// mean \"0\", as a list index. EmptyPathSegment is equivalent to\n// ParsePathSegment(\"\") or PathSegmentOfString(\"\").\nvar EmptyPathSegment = PathSegment{i: -1}\n\n// ParsePathSegment parses a string into a PathSegment,\n// handling any escaping if present.\n// (Note: there is currently no escaping specified for PathSegments,\n// so this is currently functionally equivalent to PathSegmentOfString.)\nfunc ParsePathSegment(s string) PathSegment {\n\treturn PathSegment{s: s, i: -1}\n}\n\n// PathSegmentOfString boxes a string into a PathSegment.\n// It does not attempt to parse any escaping; use ParsePathSegment for that.\nfunc PathSegmentOfString(s string) PathSegment {\n\treturn PathSegment{s: s, i: -1}\n}\n\n// PathSegmentOfString boxes an int into a PathSegment.\nfunc PathSegmentOfInt(i int64) PathSegment {\n\treturn PathSegment{i: i}\n}\n\n// containsString is unexported because we use it to see what our *storage* form is,\n// but this is considered an implementation detail that's non-semantic.\n// If it returns false, it implicitly means \"containsInt\", as these are the only options.\nfunc (ps PathSegment) containsString() bool {\n\treturn ps.i < 0\n}\n\n// String returns the PathSegment as a string.\nfunc (ps PathSegment) String() string {\n\tswitch ps.containsString() {\n\tcase true:\n\t\treturn ps.s\n\tcase false:\n\t\treturn strconv.FormatInt(ps.i, 10)\n\t}\n\tpanic(\"unreachable\")\n}\n\n// Index returns the PathSegment as an integer,\n// or returns an error if the segment is a string that can't be parsed as an int.\nfunc (ps PathSegment) Index() (int64, error) {\n\tswitch ps.containsString() {\n\tcase true:\n\t\treturn strconv.ParseInt(ps.s, 10, 64)\n\tcase false:\n\t\treturn ps.i, nil\n\t}\n\tpanic(\"unreachable\")\n}\n\n// Equals checks if two PathSegment values are equal.\n//\n// Because PathSegment is \"stringly typed\", this comparison does not\n// regard if one of the segments is stored as a string and one is stored as an int;\n// if string values of two segments are equal, they are \"equal\" overall.\n// In other words, `PathSegmentOfInt(2).Equals(PathSegmentOfString(\"2\")) == true`!\n// (You should still typically prefer this method over converting two segments\n// to string and comparing those, because even though that may be functionally\n// correct, this method will be faster if they're both ints internally.)\nfunc (x PathSegment) Equals(o PathSegment) bool {\n\tif !x.containsString() && !o.containsString() {\n\t\treturn x.i == o.i\n\t}\n\treturn x.String() == o.String()\n}\n"
  },
  {
    "path": "datamodel/path_test.go",
    "content": "package datamodel\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/google/go-cmp/cmp\"\n)\n\nfunc TestParsePath(t *testing.T) {\n\t// Allow equality checker to check all unexported fields in PathSegment.\n\tpathSegmentEquals := qt.CmpEquals(cmp.Exporter(func(reflect.Type) bool { return true }))\n\tt.Run(\"parsing one segment\", func(t *testing.T) {\n\t\tqt.Check(t, ParsePath(\"0\").segments, pathSegmentEquals, []PathSegment{{s: \"0\", i: -1}})\n\t})\n\tt.Run(\"parsing three segments\", func(t *testing.T) {\n\t\tqt.Check(t, ParsePath(\"0/foo/2\").segments, pathSegmentEquals, []PathSegment{{s: \"0\", i: -1}, {s: \"foo\", i: -1}, {s: \"2\", i: -1}})\n\t})\n\tt.Run(\"eliding leading slashes\", func(t *testing.T) {\n\t\tqt.Check(t, ParsePath(\"/0/2\").segments, pathSegmentEquals, []PathSegment{{s: \"0\", i: -1}, {s: \"2\", i: -1}})\n\t})\n\tt.Run(\"eliding trailing\", func(t *testing.T) {\n\t\tqt.Check(t, ParsePath(\"0/2/\").segments, pathSegmentEquals, []PathSegment{{s: \"0\", i: -1}, {s: \"2\", i: -1}})\n\t})\n\tt.Run(\"eliding empty segments\", func(t *testing.T) { // NOTE: a spec for string encoding might cause this to change in the future!\n\t\tqt.Check(t, ParsePath(\"0//2\").segments, pathSegmentEquals, []PathSegment{{s: \"0\", i: -1}, {s: \"2\", i: -1}})\n\t})\n\tt.Run(\"escaping segments\", func(t *testing.T) { // NOTE: a spec for string encoding might cause this to change in the future!\n\t\tqt.Check(t, ParsePath(`0/\\//2`).segments, pathSegmentEquals, []PathSegment{{s: \"0\", i: -1}, {s: `\\`, i: -1}, {s: \"2\", i: -1}})\n\t})\n}\n\nfunc TestPathSegmentZeroValue(t *testing.T) {\n\tqt.Check(t, PathSegment{}.String(), qt.Equals, \"0\")\n\ti, err := PathSegment{}.Index()\n\tqt.Check(t, err, qt.IsNil)\n\tqt.Check(t, i, qt.Equals, int64(0))\n\n\tqt.Check(t, EmptyPathSegment.String(), qt.Equals, \"\")\n\t_, err = EmptyPathSegment.Index()\n\tqt.Check(t, err, qt.IsNotNil)\n}\n"
  },
  {
    "path": "datamodel/unit.go",
    "content": "package datamodel\n\n// Null is the one kind of node we can have a true singleton implementation of.\n// This is that value.\n// The Null Node has Kind() == Kind_Null, returns IsNull() == true,\n// returns ErrWrongKind to most other inquiries (as you'd expect),\n// and returns a NodePrototype with a NewBuilder method that simply panics\n// (because why would you ever try to build a new \"null\"?).\nvar Null Node = nullNode{}\n\ntype nullNode struct{}\n\nfunc (nullNode) Kind() Kind {\n\treturn Kind_Null\n}\nfunc (nullNode) LookupByString(key string) (Node, error) {\n\treturn nil, ErrWrongKind{TypeName: \"null\", MethodName: \"LookupByString\", AppropriateKind: KindSet_JustMap, ActualKind: Kind_Null}\n}\nfunc (nullNode) LookupByNode(key Node) (Node, error) {\n\treturn nil, ErrWrongKind{TypeName: \"null\", MethodName: \"LookupByNode\", AppropriateKind: KindSet_JustMap, ActualKind: Kind_Null}\n}\nfunc (nullNode) LookupByIndex(idx int64) (Node, error) {\n\treturn nil, ErrWrongKind{TypeName: \"null\", MethodName: \"LookupByIndex\", AppropriateKind: KindSet_JustList, ActualKind: Kind_Null}\n}\nfunc (nullNode) LookupBySegment(seg PathSegment) (Node, error) {\n\treturn nil, ErrWrongKind{TypeName: \"null\", MethodName: \"LookupBySegment\", AppropriateKind: KindSet_Recursive, ActualKind: Kind_Null}\n}\nfunc (nullNode) MapIterator() MapIterator {\n\treturn nil\n}\nfunc (nullNode) ListIterator() ListIterator {\n\treturn nil\n}\nfunc (nullNode) Length() int64 {\n\treturn -1\n}\nfunc (nullNode) IsAbsent() bool {\n\treturn false\n}\nfunc (nullNode) IsNull() bool {\n\treturn true\n}\nfunc (nullNode) AsBool() (bool, error) {\n\treturn false, ErrWrongKind{TypeName: \"null\", MethodName: \"AsBool\", AppropriateKind: KindSet_JustBool, ActualKind: Kind_Null}\n}\nfunc (nullNode) AsInt() (int64, error) {\n\treturn 0, ErrWrongKind{TypeName: \"null\", MethodName: \"AsInt\", AppropriateKind: KindSet_JustInt, ActualKind: Kind_Null}\n}\nfunc (nullNode) AsFloat() (float64, error) {\n\treturn 0, ErrWrongKind{TypeName: \"null\", MethodName: \"AsFloat\", AppropriateKind: KindSet_JustFloat, ActualKind: Kind_Null}\n}\nfunc (nullNode) AsString() (string, error) {\n\treturn \"\", ErrWrongKind{TypeName: \"null\", MethodName: \"AsString\", AppropriateKind: KindSet_JustString, ActualKind: Kind_Null}\n}\nfunc (nullNode) AsBytes() ([]byte, error) {\n\treturn nil, ErrWrongKind{TypeName: \"null\", MethodName: \"AsBytes\", AppropriateKind: KindSet_JustBytes, ActualKind: Kind_Null}\n}\nfunc (nullNode) AsLink() (Link, error) {\n\treturn nil, ErrWrongKind{TypeName: \"null\", MethodName: \"AsLink\", AppropriateKind: KindSet_JustLink, ActualKind: Kind_Null}\n}\nfunc (nullNode) Prototype() NodePrototype {\n\treturn nullPrototype{}\n}\n\ntype nullPrototype struct{}\n\nfunc (nullPrototype) NewBuilder() NodeBuilder {\n\tpanic(\"cannot build null nodes\")\n}\n\n// Absent is the _other_ kind of node (besides Null) we can have a true singleton implementation of.\n// This is the singleton value for Absent.\n// The Absent Node has Kind() == Kind_Null, returns IsNull() == false (!),\n// returns IsAbsent() == true,\n// returns ErrWrongKind to most other inquiries (as you'd expect),\n// and returns a NodePrototype with a NewBuilder method that simply panics\n// (because why would you ever try to build a new \"nothing\"?).\n//\n// Despite its presence in the datamodel package, \"absent\" is not really a data model concept.\n// Absent should not really be seen in any datamodel Node implementations, for example.\n// Absent is seen used in the realm of schemas and typed data, because there,\n// there's a concept of data that has been described, and yet is not currently present;\n// it is this concept that \"absent\" is used to express.\n// Absent also sometimes shows up as a distinct case in codecs or other diagnostic printing,\n// and suchlike miscellaneous places; it is for these reasons that it's here in the datamodel package,\n// because it would end up imported somewhat universally for those diagnostic purposes anyway.\n// (This may be worth a design review at some point, but holds up well enough for now.)\nvar Absent Node = absentNode{}\n\ntype absentNode struct{}\n\nfunc (absentNode) Kind() Kind {\n\treturn Kind_Null\n}\nfunc (absentNode) LookupByString(key string) (Node, error) {\n\treturn nil, ErrWrongKind{TypeName: \"absent\", MethodName: \"LookupByString\", AppropriateKind: KindSet_JustMap, ActualKind: Kind_Null}\n}\nfunc (absentNode) LookupByNode(key Node) (Node, error) {\n\treturn nil, ErrWrongKind{TypeName: \"absent\", MethodName: \"LookupByNode\", AppropriateKind: KindSet_JustMap, ActualKind: Kind_Null}\n}\nfunc (absentNode) LookupByIndex(idx int64) (Node, error) {\n\treturn nil, ErrWrongKind{TypeName: \"absent\", MethodName: \"LookupByIndex\", AppropriateKind: KindSet_JustList, ActualKind: Kind_Null}\n}\nfunc (absentNode) LookupBySegment(seg PathSegment) (Node, error) {\n\treturn nil, ErrWrongKind{TypeName: \"absent\", MethodName: \"LookupBySegment\", AppropriateKind: KindSet_Recursive, ActualKind: Kind_Null}\n}\nfunc (absentNode) MapIterator() MapIterator {\n\treturn nil\n}\nfunc (absentNode) ListIterator() ListIterator {\n\treturn nil\n}\nfunc (absentNode) Length() int64 {\n\treturn -1\n}\nfunc (absentNode) IsAbsent() bool {\n\treturn true\n}\nfunc (absentNode) IsNull() bool {\n\treturn false\n}\nfunc (absentNode) AsBool() (bool, error) {\n\treturn false, ErrWrongKind{TypeName: \"absent\", MethodName: \"AsBool\", AppropriateKind: KindSet_JustBool, ActualKind: Kind_Null}\n}\nfunc (absentNode) AsInt() (int64, error) {\n\treturn 0, ErrWrongKind{TypeName: \"absent\", MethodName: \"AsInt\", AppropriateKind: KindSet_JustInt, ActualKind: Kind_Null}\n}\nfunc (absentNode) AsFloat() (float64, error) {\n\treturn 0, ErrWrongKind{TypeName: \"absent\", MethodName: \"AsFloat\", AppropriateKind: KindSet_JustFloat, ActualKind: Kind_Null}\n}\nfunc (absentNode) AsString() (string, error) {\n\treturn \"\", ErrWrongKind{TypeName: \"absent\", MethodName: \"AsString\", AppropriateKind: KindSet_JustString, ActualKind: Kind_Null}\n}\nfunc (absentNode) AsBytes() ([]byte, error) {\n\treturn nil, ErrWrongKind{TypeName: \"absent\", MethodName: \"AsBytes\", AppropriateKind: KindSet_JustBytes, ActualKind: Kind_Null}\n}\nfunc (absentNode) AsLink() (Link, error) {\n\treturn nil, ErrWrongKind{TypeName: \"absent\", MethodName: \"AsLink\", AppropriateKind: KindSet_JustLink, ActualKind: Kind_Null}\n}\nfunc (absentNode) Prototype() NodePrototype {\n\treturn absentPrototype{}\n}\n\ntype absentPrototype struct{}\n\nfunc (absentPrototype) NewBuilder() NodeBuilder {\n\tpanic(\"cannot build absent nodes\")\n}\n"
  },
  {
    "path": "datamodel.go",
    "content": "package ipld\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\ntype (\n\tKind          = datamodel.Kind\n\tNode          = datamodel.Node\n\tNodeAssembler = datamodel.NodeAssembler\n\tNodeBuilder   = datamodel.NodeBuilder\n\tNodePrototype = datamodel.NodePrototype\n\tMapIterator   = datamodel.MapIterator\n\tMapAssembler  = datamodel.MapAssembler\n\tListIterator  = datamodel.ListIterator\n\tListAssembler = datamodel.ListAssembler\n\n\tLink          = datamodel.Link\n\tLinkPrototype = datamodel.LinkPrototype\n\n\tPath        = datamodel.Path\n\tPathSegment = datamodel.PathSegment\n)\n\nvar (\n\tNull   = datamodel.Null\n\tAbsent = datamodel.Absent\n)\n\nconst (\n\tKind_Invalid = datamodel.Kind_Invalid\n\tKind_Map     = datamodel.Kind_Map\n\tKind_List    = datamodel.Kind_List\n\tKind_Null    = datamodel.Kind_Null\n\tKind_Bool    = datamodel.Kind_Bool\n\tKind_Int     = datamodel.Kind_Int\n\tKind_Float   = datamodel.Kind_Float\n\tKind_String  = datamodel.Kind_String\n\tKind_Bytes   = datamodel.Kind_Bytes\n\tKind_Link    = datamodel.Kind_Link\n)\n\n// Future: These aliases for the `KindSet_*` values may be dropped someday.\n// I don't think they're very important to have cluttering up namespace here.\n// They're included for a brief transitional period, largely for the sake of codegen things which have referred to them, but may disappear in the future.\nvar (\n\tKindSet_Recursive  = datamodel.KindSet_Recursive\n\tKindSet_Scalar     = datamodel.KindSet_Scalar\n\tKindSet_JustMap    = datamodel.KindSet_JustMap\n\tKindSet_JustList   = datamodel.KindSet_JustList\n\tKindSet_JustNull   = datamodel.KindSet_JustNull\n\tKindSet_JustBool   = datamodel.KindSet_JustBool\n\tKindSet_JustInt    = datamodel.KindSet_JustInt\n\tKindSet_JustFloat  = datamodel.KindSet_JustFloat\n\tKindSet_JustString = datamodel.KindSet_JustString\n\tKindSet_JustBytes  = datamodel.KindSet_JustBytes\n\tKindSet_JustLink   = datamodel.KindSet_JustLink\n)\n\n// Future: These error type aliases may be dropped someday.\n// Being able to see them as having more than one package name is not helpful to clarity.\n// They are left here for now for a brief transitional period, because it was relatively easy to do so.\ntype (\n\tErrWrongKind             = datamodel.ErrWrongKind\n\tErrNotExists             = datamodel.ErrNotExists\n\tErrRepeatedMapKey        = datamodel.ErrRepeatedMapKey\n\tErrInvalidSegmentForList = datamodel.ErrInvalidSegmentForList\n\tErrIteratorOverread      = datamodel.ErrIteratorOverread\n\tErrInvalidKey            = schema.ErrInvalidKey\n\tErrMissingRequiredField  = schema.ErrMissingRequiredField\n\tErrHashMismatch          = linking.ErrHashMismatch\n)\n\n// Future: a bunch of these alias methods for path creation may be dropped someday.\n// They don't hurt anything, but I don't think they add much clarity either, vs the amount of namespace noise they create;\n// many of the high level convenience functions we add here in the root package will probably refer to datamodel.Path, and that should be sufficient to create clarity for new users for where to look for more on pathing.\n// They are here for now for a transitional period, but may eventually be revisited and perhaps removed.\n\n// NewPath is an alias for datamodel.NewPath.\n//\n// Pathing is a concept defined in the data model layer of IPLD.\nfunc NewPath(segments []PathSegment) Path {\n\treturn datamodel.NewPath(segments)\n}\n\n// ParsePath is an alias for datamodel.ParsePath.\n//\n// Pathing is a concept defined in the data model layer of IPLD.\nfunc ParsePath(pth string) Path {\n\treturn datamodel.ParsePath(pth)\n}\n\n// ParsePathSegment is an alias for datamodel.ParsePathSegment.\n//\n// Pathing is a concept defined in the data model layer of IPLD.\nfunc ParsePathSegment(s string) PathSegment {\n\treturn datamodel.ParsePathSegment(s)\n}\n\n// PathSegmentOfString is an alias for datamodel.PathSegmentOfString.\n//\n// Pathing is a concept defined in the data model layer of IPLD.\nfunc PathSegmentOfString(s string) PathSegment {\n\treturn datamodel.PathSegmentOfString(s)\n}\n\n// PathSegmentOfInt is an alias for datamodel.PathSegmentOfInt.\n//\n// Pathing is a concept defined in the data model layer of IPLD.\nfunc PathSegmentOfInt(i int64) PathSegment {\n\treturn datamodel.PathSegmentOfInt(i)\n}\n"
  },
  {
    "path": "doc.go",
    "content": "// go-ipld-prime is a series of go interfaces for manipulating IPLD data.\n//\n// See https://ipld.io/ for more information about the basics\n// of \"What is IPLD?\".\n//\n// Here in the godoc, the first couple of types to look at should be:\n//\n//   - Node\n//   - NodeBuilder and NodeAssembler\n//   - NodePrototype.\n//\n// These types provide a generic description of the data model.\n//\n// A Node is a piece of IPLD data which can be inspected.\n// A NodeAssembler is used to create Nodes.\n// (A NodeBuilder is just like a NodeAssembler, but allocates memory\n// (whereas a NodeAssembler just fills up memory; using these carefully\n// allows construction of very efficient code.)\n//\n// Different NodePrototypes can be used to describe Nodes which follow certain logical rules\n// (e.g., we use these as part of implementing Schemas),\n// and can also be used so that programs can use different memory layouts for different data\n// (which can be useful for constructing efficient programs when data has known shape for\n// which we can use specific or compacted memory layouts).\n//\n// If working with linked data (data which is split into multiple\n// trees of Nodes, loaded separately, and connected by some kind of\n// \"link\" reference), the next types you should look at are:\n//\n//   - LinkSystem\n//   - ... and its fields.\n//\n// The most typical use of LinkSystem is to use the linking/cid package\n// to get a LinkSystem that works with CIDs:\n//\n//\tlsys := cidlink.DefaultLinkSystem()\n//\n// ... and then assign the StorageWriteOpener and StorageReadOpener fields\n// in order to control where data is stored to and read from.\n// Methods on the LinkSystem then provide the functions typically used\n// to get data in and out of Nodes so you can work with it.\n//\n// This root package gathers some of the most important ease-of-use functions\n// all in one place, but is mostly aliases out to features originally found\n// in other more specific sub-packages.  (If you're interested in keeping\n// your binary sizes small, and don't use some of the features of this library,\n// you'll probably want to look into using the relevant sub-packages directly.)\n//\n// Particularly interesting subpackages include:\n//\n//   - datamodel -- the most essential interfaces for describing data live here,\n//     describing Node, NodePrototype, NodeBuilder, Link, and Path.\n//   - node/* -- various Node + NodeBuilder implementations.\n//   - node/basicnode -- the first Node implementation you should try.\n//   - codec/* -- functions for serializing and deserializing Nodes.\n//   - linking -- the LinkSystem, which is a facade to all data loading and storing and hashing.\n//   - linking/* -- ways to bind concrete Link implementations (namely,\n//     the linking/cidlink package, which connects the go-cid library to our datamodel.Link interface).\n//   - traversal -- functions for walking Node graphs (including automatic link loading)\n//     and visiting them programmatically.\n//   - traversal/selector -- functions for working with IPLD Selectors,\n//     which are a language-agnostic declarative format for describing graph walks.\n//   - fluent/* -- various options for making datamodel Node and NodeBuilder easier to work with.\n//   - schema -- interfaces for working with IPLD Schemas, which can bring constraints\n//     and validation systems to otherwise schemaless and unstructured IPLD data.\n//   - adl/* -- examples of creating and using Advanced Data Layouts (in short, custom Node implementations)\n//     to do complex data structures transparently within the IPLD Data Model.\npackage ipld\n"
  },
  {
    "path": "examples_test.go",
    "content": "package ipld_test\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// Example_createDataAndMarshal shows how you can feed data into a NodeBuilder,\n// and also how to then hand that to an Encoder.\n//\n// Often you'll encoding implicitly through a LinkSystem.Store call instead,\n// but you can do it directly, too.\nfunc Example_createDataAndMarshal() {\n\tnp := basicnode.Prototype.Any // Pick a prototype: this is how we decide what implementation will store the in-memory data.\n\tnb := np.NewBuilder()         // Create a builder.\n\tma, _ := nb.BeginMap(2)       // Begin assembling a map.\n\tma.AssembleKey().AssignString(\"hey\")\n\tma.AssembleValue().AssignString(\"it works!\")\n\tma.AssembleKey().AssignString(\"yes\")\n\tma.AssembleValue().AssignBool(true)\n\tma.Finish()     // Call 'Finish' on the map assembly to let it know no more data is coming.\n\tn := nb.Build() // Call 'Build' to get the resulting Node.  (It's immutable!)\n\n\tdagjson.Encode(n, os.Stdout)\n\n\t// Output:\n\t// {\"hey\":\"it works!\",\"yes\":true}\n}\n\n// Example_unmarshalData shows how you can use a Decoder\n// and a NodeBuilder (or NodePrototype) together to do unmarshalling.\n//\n// Often you'll do this implicitly through a LinkSystem.Load call instead,\n// but you can do it directly, too.\nfunc Example_unmarshalData() {\n\tserial := strings.NewReader(`{\"hey\":\"it works!\",\"yes\": true}`)\n\n\tnp := basicnode.Prototype.Any // Pick a style for the in-memory data.\n\tnb := np.NewBuilder()         // Create a builder.\n\tdagjson.Decode(nb, serial)    // Hand the builder to decoding -- decoding will fill it in!\n\tn := nb.Build()               // Call 'Build' to get the resulting Node.  (It's immutable!)\n\n\tfmt.Printf(\"the data decoded was a %s kind\\n\", n.Kind())\n\tfmt.Printf(\"the length of the node is %d\\n\", n.Length())\n\n\t// Output:\n\t// the data decoded was a map kind\n\t// the length of the node is 2\n}\n\nfunc ExampleLoadSchema() {\n\tts, err := ipld.LoadSchema(\"sample.ipldsch\", strings.NewReader(`\n\t\ttype Root struct {\n\t\t\tfoo Int\n\t\t\tbar nullable String\n\t\t}\n\t\t`))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\ttypeRoot := ts.TypeByName(\"Root\").(*schema.TypeStruct)\n\tfor _, field := range typeRoot.Fields() {\n\t\tfmt.Printf(\"field name=%q nullable=%t type=%v\\n\",\n\t\t\tfield.Name(), field.IsNullable(), field.Type().Name())\n\t}\n\t// Output:\n\t// field name=\"foo\" nullable=false type=Int\n\t// field name=\"bar\" nullable=true type=String\n}\n\n// Example_goValueWithSchema shows how to combine a Go value with an IPLD\n// schema, which can then be used as an IPLD node.\n//\n// For more examples and documentation, see the node/bindnode package.\nfunc Example_goValueWithSchema() {\n\ttype Person struct {\n\t\tName    string\n\t\tAge     int\n\t\tFriends []string\n\t}\n\n\tts, err := ipld.LoadSchemaBytes([]byte(`\n\t\ttype Person struct {\n\t\t\tname    String\n\t\t\tage     Int\n\t\t\tfriends [String]\n\t\t} representation tuple\n\t`))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tschemaType := ts.TypeByName(\"Person\")\n\tperson := &Person{Name: \"Alice\", Age: 34, Friends: []string{\"Bob\"}}\n\tnode := bindnode.Wrap(person, schemaType)\n\n\tfmt.Printf(\"%#v\\n\", person)\n\tdagjson.Encode(node.Representation(), os.Stdout)\n\n\t// Output:\n\t// &ipld_test.Person{Name:\"Alice\", Age:34, Friends:[]string{\"Bob\"}}\n\t// [\"Alice\",34,[\"Bob\"]]\n}\n"
  },
  {
    "path": "fluent/bench_test.go",
    "content": "package fluent_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/fluent/qp\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc BenchmarkQp(b *testing.B) {\n\tb.ReportAllocs()\n\n\tf2 := func(na datamodel.NodeAssembler, a string, b string, c string, d []string) {\n\t\tqp.Map(4, func(ma datamodel.MapAssembler) {\n\t\t\tqp.MapEntry(ma, \"destination\", qp.String(a))\n\t\t\tqp.MapEntry(ma, \"type\", qp.String(b))\n\t\t\tqp.MapEntry(ma, \"source\", qp.String(c))\n\t\t\tqp.MapEntry(ma, \"options\", qp.List(int64(len(d)), func(la datamodel.ListAssembler) {\n\t\t\t\tfor _, s := range d {\n\t\t\t\t\tqp.ListEntry(la, qp.String(s))\n\t\t\t\t}\n\t\t\t}))\n\t\t})(na)\n\t}\n\tfor i := 0; i < b.N; i++ {\n\t\tn, err := qp.BuildList(basicnode.Prototype.Any, -1, func(la datamodel.ListAssembler) {\n\t\t\tf2(la.AssembleValue(), // TODO: forgot to check error?\n\t\t\t\t\"/\",\n\t\t\t\t\"overlay\",\n\t\t\t\t\"none\",\n\t\t\t\t[]string{\n\t\t\t\t\t\"lowerdir=\" + \"/\",\n\t\t\t\t\t\"upperdir=\" + \"/tmp/overlay-root/upper\",\n\t\t\t\t\t\"workdir=\" + \"/tmp/overlay-root/work\",\n\t\t\t\t},\n\t\t\t)\n\t\t})\n\t\tif err != nil {\n\t\t\tb.Fatal(err)\n\t\t}\n\t\t_ = n\n\t}\n}\n\nfunc BenchmarkUnmarshal(b *testing.B) {\n\tb.ReportAllocs()\n\n\tvar n datamodel.Node\n\tvar err error\n\tserial := `[{\n\t\t\"destination\": \"/\",\n\t\t\"type\": \"overlay\",\n\t\t\"source\": \"none\",\n\t\t\"options\": [\n\t\t\t\"lowerdir=/\",\n\t\t\t\"upperdir=/tmp/overlay-root/upper\",\n\t\t\t\"workdir=/tmp/overlay-root/work\"\n\t\t]\n\t}]`\n\tr := strings.NewReader(serial)\n\tfor i := 0; i < b.N; i++ {\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr = dagjson.Decode(nb, r)\n\t\tn = nb.Build()\n\t\tr.Reset(serial)\n\t}\n\t_ = n\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n}\n\nfunc BenchmarkFluent(b *testing.B) {\n\tb.ReportAllocs()\n\n\tvar n datamodel.Node\n\tvar err error\n\tfor i := 0; i < b.N; i++ {\n\t\tn, err = fluent.BuildList(basicnode.Prototype.Any, -1, func(la fluent.ListAssembler) {\n\t\t\tla.AssembleValue().CreateMap(4, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"destination\").AssignString(\"/\")\n\t\t\t\tma.AssembleEntry(\"type\").AssignString(\"overlay\")\n\t\t\t\tma.AssembleEntry(\"source\").AssignString(\"none\")\n\t\t\t\tma.AssembleEntry(\"options\").CreateList(-1, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"lowerdir=\" + \"/\")\n\t\t\t\t\tla.AssembleValue().AssignString(\"upperdir=\" + \"/tmp/overlay-root/upper\")\n\t\t\t\t\tla.AssembleValue().AssignString(\"workdir=\" + \"/tmp/overlay-root/work\")\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t}\n\t_ = n\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n}\n\nfunc BenchmarkReflect(b *testing.B) {\n\tb.ReportAllocs()\n\n\tvar n datamodel.Node\n\tvar err error\n\tval := []interface{}{\n\t\tmap[string]interface{}{\n\t\t\t\"destination\": \"/\",\n\t\t\t\"type\":        \"overlay\",\n\t\t\t\"source\":      \"none\",\n\t\t\t\"options\": []string{\n\t\t\t\t\"lowerdir=/\",\n\t\t\t\t\"upperdir=/tmp/overlay-root/upper\",\n\t\t\t\t\"workdir=/tmp/overlay-root/work\",\n\t\t\t},\n\t\t},\n\t}\n\tfor i := 0; i < b.N; i++ {\n\t\tn, err = fluent.Reflect(basicnode.Prototype.Any, val)\n\t}\n\t_ = n\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n}\n\nfunc BenchmarkReflectIncludingInitialization(b *testing.B) {\n\tb.ReportAllocs()\n\n\tvar n datamodel.Node\n\tvar err error\n\tfor i := 0; i < b.N; i++ {\n\t\tn, err = fluent.Reflect(basicnode.Prototype.Any, []interface{}{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"destination\": \"/\",\n\t\t\t\t\"type\":        \"overlay\",\n\t\t\t\t\"source\":      \"none\",\n\t\t\t\t\"options\": []string{\n\t\t\t\t\t\"lowerdir=/\",\n\t\t\t\t\t\"upperdir=/tmp/overlay-root/upper\",\n\t\t\t\t\t\"workdir=/tmp/overlay-root/work\",\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\t_ = n\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n}\n\nfunc BenchmarkAgonizinglyBare(b *testing.B) {\n\tb.ReportAllocs()\n\n\tvar n datamodel.Node\n\tvar err error\n\tfor i := 0; i < b.N; i++ {\n\t\tn, err = fab()\n\t}\n\t_ = n\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n}\n\nfunc fab() (datamodel.Node, error) {\n\tnb := basicnode.Prototype.Any.NewBuilder()\n\tla1, err := nb.BeginList(-1)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tma, err := la1.AssembleValue().BeginMap(4)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tva, err := ma.AssembleEntry(\"destination\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = va.AssignString(\"/\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tva, err = ma.AssembleEntry(\"type\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = va.AssignString(\"overlay\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tva, err = ma.AssembleEntry(\"source\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = va.AssignString(\"none\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tva, err = ma.AssembleEntry(\"options\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tla2, err := va.BeginList(-4)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = la2.AssembleValue().AssignString(\"lowerdir=\" + \"/\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = la2.AssembleValue().AssignString(\"upperdir=\" + \"/tmp/overlay-root/upper\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = la2.AssembleValue().AssignString(\"workdir=\" + \"/tmp/overlay-root/work\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = la2.Finish()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = ma.Finish()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = la1.Finish()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn nb.Build(), nil\n}\n"
  },
  {
    "path": "fluent/doc.go",
    "content": "/*\nThe fluent package offers helper utilities for using NodeAssembler\nmore tersely by providing an interface that handles all errors for you,\nand allows use of closures for any recursive assembly\nso that creating trees of data results in indentation for legibility.\n\nNote that the fluent package creates wrapper objects in order to provide\nthe API conveniences that it does, and this comes at some cost to performance.\nIf you're optimizing for performance, using some of the features of the\nfluent package may be inadvisable (and some moreso than others).\nHowever, as with any performance questions, benchmark before making decisions;\nits entirely possible that your performance bottlenecks will be elsewhere\nand there's no reason to deny yourself syntactic sugar if the costs don't\ndetectably affect the bottom line.\nVarious feature of the package will also attempt to document how costly they are in relative terms\n(e.g. the fluent.Reflect helper methods are very costly;\n*/\npackage fluent\n"
  },
  {
    "path": "fluent/fluentBuilder.go",
    "content": "package fluent\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\nfunc Build(np datamodel.NodePrototype, fn func(NodeAssembler)) (datamodel.Node, error) {\n\tnb := np.NewBuilder()\n\tfna := WrapAssembler(nb)\n\terr := Recover(func() {\n\t\tfn(fna)\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn nb.Build(), nil\n}\nfunc BuildMap(np datamodel.NodePrototype, sizeHint int64, fn func(MapAssembler)) (datamodel.Node, error) {\n\treturn Build(np, func(fna NodeAssembler) { fna.CreateMap(sizeHint, fn) })\n}\nfunc BuildList(np datamodel.NodePrototype, sizeHint int64, fn func(ListAssembler)) (datamodel.Node, error) {\n\treturn Build(np, func(fna NodeAssembler) { fna.CreateList(sizeHint, fn) })\n}\n\nfunc MustBuild(np datamodel.NodePrototype, fn func(NodeAssembler)) datamodel.Node {\n\tnb := np.NewBuilder()\n\tfn(WrapAssembler(nb))\n\treturn nb.Build()\n}\nfunc MustBuildMap(np datamodel.NodePrototype, sizeHint int64, fn func(MapAssembler)) datamodel.Node {\n\treturn MustBuild(np, func(fna NodeAssembler) { fna.CreateMap(sizeHint, fn) })\n}\nfunc MustBuildList(np datamodel.NodePrototype, sizeHint int64, fn func(ListAssembler)) datamodel.Node {\n\treturn MustBuild(np, func(fna NodeAssembler) { fna.CreateList(sizeHint, fn) })\n}\n\nfunc WrapAssembler(na datamodel.NodeAssembler) NodeAssembler {\n\treturn &nodeAssembler{na}\n}\n\n// NodeAssembler is the same as the interface in the core package, except:\n// instead of returning errors, any error will cause panic\n// (and you can collect these with `fluent.Recover`);\n// and all recursive operations take a function as a parameter,\n// within which you will receive another {Map,List,}NodeAssembler.\ntype NodeAssembler interface {\n\tCreateMap(sizeHint int64, fn func(MapAssembler))\n\tCreateList(sizeHint int64, fn func(ListAssembler))\n\tAssignNull()\n\tAssignBool(bool)\n\tAssignInt(int64)\n\tAssignFloat(float64)\n\tAssignString(string)\n\tAssignBytes([]byte)\n\tAssignLink(datamodel.Link)\n\tAssignNode(datamodel.Node)\n\n\tPrototype() datamodel.NodePrototype\n}\n\n// MapAssembler is the same as the interface in the core package, except:\n// instead of returning errors, any error will cause panic\n// (and you can collect these with `fluent.Recover`);\n// and all recursive operations take a function as a parameter,\n// within which you will receive another {Map,List,}NodeAssembler.\ntype MapAssembler interface {\n\tAssembleKey() NodeAssembler\n\tAssembleValue() NodeAssembler\n\n\tAssembleEntry(k string) NodeAssembler\n\n\tKeyPrototype() datamodel.NodePrototype\n\tValuePrototype(k string) datamodel.NodePrototype\n}\n\n// ListAssembler is the same as the interface in the core package, except:\n// instead of returning errors, any error will cause panic\n// (and you can collect these with `fluent.Recover`);\n// and all recursive operations take a function as a parameter,\n// within which you will receive another {Map,List,}NodeAssembler.\ntype ListAssembler interface {\n\tAssembleValue() NodeAssembler\n\n\tValuePrototype(idx int64) datamodel.NodePrototype\n}\n\ntype nodeAssembler struct {\n\tna datamodel.NodeAssembler\n}\n\nfunc (fna *nodeAssembler) CreateMap(sizeHint int64, fn func(MapAssembler)) {\n\tif ma, err := fna.na.BeginMap(sizeHint); err != nil {\n\t\tpanic(Error{err})\n\t} else {\n\t\tfn(&mapNodeAssembler{ma})\n\t\tif err := ma.Finish(); err != nil {\n\t\t\tpanic(Error{err})\n\t\t}\n\t}\n}\nfunc (fna *nodeAssembler) CreateList(sizeHint int64, fn func(ListAssembler)) {\n\tif la, err := fna.na.BeginList(sizeHint); err != nil {\n\t\tpanic(Error{err})\n\t} else {\n\t\tfn(&listNodeAssembler{la})\n\t\tif err := la.Finish(); err != nil {\n\t\t\tpanic(Error{err})\n\t\t}\n\t}\n}\nfunc (fna *nodeAssembler) AssignNull() {\n\tif err := fna.na.AssignNull(); err != nil {\n\t\tpanic(Error{err})\n\t}\n}\nfunc (fna *nodeAssembler) AssignBool(v bool) {\n\tif err := fna.na.AssignBool(v); err != nil {\n\t\tpanic(Error{err})\n\t}\n}\nfunc (fna *nodeAssembler) AssignInt(v int64) {\n\tif err := fna.na.AssignInt(v); err != nil {\n\t\tpanic(Error{err})\n\t}\n}\nfunc (fna *nodeAssembler) AssignFloat(v float64) {\n\tif err := fna.na.AssignFloat(v); err != nil {\n\t\tpanic(Error{err})\n\t}\n}\nfunc (fna *nodeAssembler) AssignString(v string) {\n\tif err := fna.na.AssignString(v); err != nil {\n\t\tpanic(Error{err})\n\t}\n}\nfunc (fna *nodeAssembler) AssignBytes(v []byte) {\n\tif err := fna.na.AssignBytes(v); err != nil {\n\t\tpanic(Error{err})\n\t}\n}\nfunc (fna *nodeAssembler) AssignLink(v datamodel.Link) {\n\tif err := fna.na.AssignLink(v); err != nil {\n\t\tpanic(Error{err})\n\t}\n}\nfunc (fna *nodeAssembler) AssignNode(v datamodel.Node) {\n\tif err := fna.na.AssignNode(v); err != nil {\n\t\tpanic(Error{err})\n\t}\n}\nfunc (fna *nodeAssembler) Prototype() datamodel.NodePrototype {\n\treturn fna.na.Prototype()\n}\n\ntype mapNodeAssembler struct {\n\tma datamodel.MapAssembler\n}\n\nfunc (fma *mapNodeAssembler) AssembleKey() NodeAssembler {\n\treturn &nodeAssembler{fma.ma.AssembleKey()}\n}\nfunc (fma *mapNodeAssembler) AssembleValue() NodeAssembler {\n\treturn &nodeAssembler{fma.ma.AssembleValue()}\n}\nfunc (fma *mapNodeAssembler) AssembleEntry(k string) NodeAssembler {\n\tva, err := fma.ma.AssembleEntry(k)\n\tif err != nil {\n\t\tpanic(Error{err})\n\t}\n\treturn &nodeAssembler{va}\n}\nfunc (fma *mapNodeAssembler) KeyPrototype() datamodel.NodePrototype {\n\treturn fma.ma.KeyPrototype()\n}\nfunc (fma *mapNodeAssembler) ValuePrototype(k string) datamodel.NodePrototype {\n\treturn fma.ma.ValuePrototype(k)\n}\n\ntype listNodeAssembler struct {\n\tla datamodel.ListAssembler\n}\n\nfunc (fla *listNodeAssembler) AssembleValue() NodeAssembler {\n\treturn &nodeAssembler{fla.la.AssembleValue()}\n}\nfunc (fla *listNodeAssembler) ValuePrototype(idx int64) datamodel.NodePrototype {\n\treturn fla.la.ValuePrototype(idx)\n}\n"
  },
  {
    "path": "fluent/fluentBuilder_test.go",
    "content": "package fluent_test\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestBuild(t *testing.T) {\n\tt.Run(\"scalar build should work\", func(t *testing.T) {\n\t\tn := fluent.MustBuild(basicnode.Prototype__String{}, func(fna fluent.NodeAssembler) {\n\t\t\tfna.AssignString(\"fine\")\n\t\t})\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_String)\n\t\tv2, err := n.AsString()\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, v2, qt.Equals, \"fine\")\n\t})\n\tt.Run(\"map build should work\", func(t *testing.T) {\n\t\tn := fluent.MustBuild(basicnode.Prototype.Map, func(fna fluent.NodeAssembler) {\n\t\t\tfna.CreateMap(3, func(fma fluent.MapAssembler) {\n\t\t\t\tfma.AssembleEntry(\"k1\").AssignString(\"fine\")\n\t\t\t\tfma.AssembleEntry(\"k2\").AssignString(\"super\")\n\t\t\t\tfma.AssembleEntry(\"k3\").CreateMap(3, func(fma fluent.MapAssembler) {\n\t\t\t\t\tfma.AssembleEntry(\"k31\").AssignString(\"thanks\")\n\t\t\t\t\tfma.AssembleEntry(\"k32\").AssignString(\"for\")\n\t\t\t\t\tfma.AssembleEntry(\"k33\").AssignString(\"asking\")\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\tqt.Check(t, n.Length(), qt.Equals, int64(3))\n\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"k1\"))), qt.Equals, \"fine\")\n\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"k2\"))), qt.Equals, \"super\")\n\t\tn = must.Node(n.LookupByString(\"k3\"))\n\t\tqt.Check(t, n.Length(), qt.Equals, int64(3))\n\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"k31\"))), qt.Equals, \"thanks\")\n\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"k32\"))), qt.Equals, \"for\")\n\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"k33\"))), qt.Equals, \"asking\")\n\t})\n\tt.Run(\"list build should work\", func(t *testing.T) {\n\t\tn := fluent.MustBuild(basicnode.Prototype.List, func(fna fluent.NodeAssembler) {\n\t\t\tfna.CreateList(1, func(fla fluent.ListAssembler) {\n\t\t\t\tfla.AssembleValue().CreateList(1, func(fla fluent.ListAssembler) {\n\t\t\t\t\tfla.AssembleValue().CreateList(1, func(fla fluent.ListAssembler) {\n\t\t\t\t\t\tfla.AssembleValue().CreateList(1, func(fla fluent.ListAssembler) {\n\t\t\t\t\t\t\tfla.AssembleValue().AssignInt(2)\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_List)\n\t\tqt.Check(t, n.Length(), qt.Equals, int64(1))\n\t\tn = must.Node(n.LookupByIndex(0))\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_List)\n\t\tqt.Check(t, n.Length(), qt.Equals, int64(1))\n\t\tn = must.Node(n.LookupByIndex(0))\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_List)\n\t\tqt.Check(t, n.Length(), qt.Equals, int64(1))\n\t\tn = must.Node(n.LookupByIndex(0))\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_List)\n\t\tqt.Check(t, n.Length(), qt.Equals, int64(1))\n\t\tn = must.Node(n.LookupByIndex(0))\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Int)\n\t\tqt.Check(t, must.Int(n), qt.Equals, int64(2))\n\t})\n}\n"
  },
  {
    "path": "fluent/fluentRecover.go",
    "content": "package fluent\n\ntype Error struct {\n\tErr error\n}\n\nfunc (e Error) Error() string {\n\treturn e.Err.Error()\n}\n\n// Recover invokes a function within a panic-recovering context, and returns\n// any raised fluent.Error values; any other values are re-panicked.\n//\n// This can be useful for writing large blocks of code using fluent nodes,\n// and handling any errors at once at the end.\nfunc Recover(fn func()) (err error) {\n\tdefer func() {\n\t\tei := recover()\n\t\tswitch e2 := ei.(type) {\n\t\tcase nil:\n\t\t\treturn\n\t\tcase Error:\n\t\t\terr = e2\n\t\tdefault:\n\t\t\tpanic(ei)\n\t\t}\n\t}()\n\tfn()\n\treturn\n}\n"
  },
  {
    "path": "fluent/fluentRecover_test.go",
    "content": "package fluent_test\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestRecover(t *testing.T) {\n\tt.Run(\"simple build error should capture\", func(t *testing.T) {\n\t\tqt.Check(t,\n\t\t\tfluent.Recover(func() {\n\t\t\t\tfluent.MustBuild(basicnode.Prototype__String{}, func(fna fluent.NodeAssembler) {\n\t\t\t\t\tfna.AssignInt(9)\n\t\t\t\t})\n\t\t\t\tt.Fatal(\"should not be reached\")\n\t\t\t}),\n\t\t\tqt.DeepEquals,\n\t\t\tfluent.Error{datamodel.ErrWrongKind{TypeName: \"string\", MethodName: \"AssignInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_String}},\n\t\t)\n\t})\n\tt.Run(\"correct build should return nil\", func(t *testing.T) {\n\t\tqt.Check(t,\n\t\t\tfluent.Recover(func() {\n\t\t\t\tfluent.MustBuild(basicnode.Prototype__String{}, func(fna fluent.NodeAssembler) {\n\t\t\t\t\tfna.AssignString(\"fine\")\n\t\t\t\t})\n\t\t\t}),\n\t\t\tqt.IsNil,\n\t\t)\n\t})\n\tt.Run(\"other panics should continue to rise\", func(t *testing.T) {\n\t\tqt.Check(t,\n\t\t\tfunc() (r interface{}) {\n\t\t\t\tdefer func() { r = recover() }()\n\t\t\t\tfluent.Recover(func() {\n\t\t\t\t\tpanic(\"fuqawds\")\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}(),\n\t\t\tqt.Equals,\n\t\t\t\"fuqawds\",\n\t\t)\n\t})\n}\n"
  },
  {
    "path": "fluent/qp/example_test.go",
    "content": "package qp_test\n\nimport (\n\t\"os\"\n\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent/qp\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\n// TODO: can we make ListEntry/MapEntry less verbose?\n\nfunc Example() {\n\tn, err := qp.BuildMap(basicnode.Prototype.Any, 4, func(ma datamodel.MapAssembler) {\n\t\tqp.MapEntry(ma, \"some key\", qp.String(\"some value\"))\n\t\tqp.MapEntry(ma, \"another key\", qp.String(\"another value\"))\n\t\tqp.MapEntry(ma, \"nested map\", qp.Map(2, func(ma datamodel.MapAssembler) {\n\t\t\tqp.MapEntry(ma, \"deeper entries\", qp.String(\"deeper values\"))\n\t\t\tqp.MapEntry(ma, \"more deeper entries\", qp.String(\"more deeper values\"))\n\t\t}))\n\t\tqp.MapEntry(ma, \"nested list\", qp.List(2, func(la datamodel.ListAssembler) {\n\t\t\tqp.ListEntry(la, qp.Int(1))\n\t\t\tqp.ListEntry(la, qp.Int(2))\n\t\t}))\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdagjson.Encode(n, os.Stdout)\n\n\t// Output:\n\t// {\"another key\":\"another value\",\"nested list\":[1,2],\"nested map\":{\"deeper entries\":\"deeper values\",\"more deeper entries\":\"more deeper values\"},\"some key\":\"some value\"}\n}\n"
  },
  {
    "path": "fluent/qp/qp.go",
    "content": "// qp helps to quickly build IPLD nodes.\n//\n// It contains top-level Build funcs, such as BuildMap and BuildList, which\n// return the final node as well as an error.\n//\n// Underneath, one can use a number of Assemble functions to construct basic\n// nodes, such as String or Int.\n//\n// Finally, functions like MapEntry and ListEntry allow inserting into maps and\n// lists.\n//\n// These all use the same IPLD datamodel interfaces such as NodePrototype and\n// NodeAssembler, but with some magic to reduce verbosity.\npackage qp\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\ntype Assemble = func(datamodel.NodeAssembler)\n\nfunc BuildMap(np datamodel.NodePrototype, sizeHint int64, fn func(datamodel.MapAssembler)) (_ datamodel.Node, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tif rerr, ok := r.(error); ok {\n\t\t\t\terr = rerr\n\t\t\t} else {\n\t\t\t\t// A reasonable fallback, for e.g. strings.\n\t\t\t\terr = fmt.Errorf(\"%v\", r)\n\t\t\t}\n\t\t}\n\t}()\n\tnb := np.NewBuilder()\n\tMap(sizeHint, fn)(nb)\n\treturn nb.Build(), nil\n}\n\ntype mapParams struct {\n\tsizeHint int64\n\tfn       func(datamodel.MapAssembler)\n}\n\nfunc (mp mapParams) Assemble(na datamodel.NodeAssembler) {\n\tma, err := na.BeginMap(mp.sizeHint)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tmp.fn(ma)\n\tif err := ma.Finish(); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc Map(sizeHint int64, fn func(datamodel.MapAssembler)) Assemble {\n\treturn mapParams{sizeHint, fn}.Assemble\n}\n\nfunc MapEntry(ma datamodel.MapAssembler, k string, fn Assemble) {\n\tna, err := ma.AssembleEntry(k)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfn(na)\n}\n\nfunc BuildList(np datamodel.NodePrototype, sizeHint int64, fn func(datamodel.ListAssembler)) (_ datamodel.Node, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tif rerr, ok := r.(error); ok {\n\t\t\t\terr = rerr\n\t\t\t} else {\n\t\t\t\t// A reasonable fallback, for e.g. strings.\n\t\t\t\terr = fmt.Errorf(\"%v\", r)\n\t\t\t}\n\t\t}\n\t}()\n\tnb := np.NewBuilder()\n\tList(sizeHint, fn)(nb)\n\treturn nb.Build(), nil\n}\n\ntype listParams struct {\n\tsizeHint int64\n\tfn       func(datamodel.ListAssembler)\n}\n\nfunc (lp listParams) Assemble(na datamodel.NodeAssembler) {\n\tla, err := na.BeginList(lp.sizeHint)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tlp.fn(la)\n\tif err := la.Finish(); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc List(sizeHint int64, fn func(datamodel.ListAssembler)) Assemble {\n\treturn listParams{sizeHint, fn}.Assemble\n}\n\nfunc ListEntry(la datamodel.ListAssembler, fn Assemble) {\n\tfn(la.AssembleValue())\n}\n\ntype nullParam struct{}\n\nfunc (s nullParam) Assemble(na datamodel.NodeAssembler) {\n\tif err := na.AssignNull(); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc Null() Assemble {\n\treturn nullParam{}.Assemble\n}\n\ntype boolParam bool\n\nfunc (s boolParam) Assemble(na datamodel.NodeAssembler) {\n\tif err := na.AssignBool(bool(s)); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc Bool(b bool) Assemble {\n\treturn boolParam(b).Assemble\n}\n\ntype intParam int64\n\nfunc (i intParam) Assemble(na datamodel.NodeAssembler) {\n\tif err := na.AssignInt(int64(i)); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc Int(i int64) Assemble {\n\treturn intParam(i).Assemble\n}\n\ntype floatParam float64\n\nfunc (f floatParam) Assemble(na datamodel.NodeAssembler) {\n\tif err := na.AssignFloat(float64(f)); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc Float(f float64) Assemble {\n\treturn floatParam(f).Assemble\n}\n\ntype stringParam string\n\nfunc (s stringParam) Assemble(na datamodel.NodeAssembler) {\n\tif err := na.AssignString(string(s)); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc String(s string) Assemble {\n\treturn stringParam(s).Assemble\n}\n\ntype bytesParam []byte\n\nfunc (p bytesParam) Assemble(na datamodel.NodeAssembler) {\n\tif err := na.AssignBytes([]byte(p)); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc Bytes(p []byte) Assemble {\n\treturn bytesParam(p).Assemble\n}\n\ntype linkParam struct {\n\tx datamodel.Link\n}\n\nfunc (l linkParam) Assemble(na datamodel.NodeAssembler) {\n\tif err := na.AssignLink(l.x); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc Link(l datamodel.Link) Assemble {\n\treturn linkParam{l}.Assemble\n}\n\ntype nodeParam struct {\n\tx datamodel.Node\n}\n\nfunc (n nodeParam) Assemble(na datamodel.NodeAssembler) {\n\tif err := na.AssignNode(n.x); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc Node(n datamodel.Node) Assemble {\n\treturn nodeParam{n}.Assemble\n}\n"
  },
  {
    "path": "fluent/reflect.go",
    "content": "package fluent\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"sort\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// Reflect creates a new Node by looking at a golang value with reflection\n// and converting it into IPLD Data Model.\n// This is a quick-and-dirty way to get data into the IPLD Data Model;\n// it's useful for rapid prototyping and demos,\n// but note that this feature is not intended to be suitable for \"production\" use\n// due to low performance and lack of configurability.\n//\n// The concrete type of the returned Node is determined by\n// the NodePrototype argument provided by the caller.\n//\n// No type information from the golang value will be observable in the result.\n//\n// The reflection will walk over any golang value, but is not configurable.\n// Golang maps become IPLD maps; golang slices and arrays become IPLD lists;\n// and golang structs become IPLD maps too.\n// When converting golang structs to IPLD maps, the field names will become the map keys.\n// Pointers and interfaces will be traversed transparently and are not visible in the output.\n//\n// An error will be returned if the process of assembling the Node returns any errors\n// (for example, if the NodePrototype is for a schema-constrained Node,\n// any validation errors from the schema will cause errors to be returned).\n//\n// A panic will be raised if there is any difficulty examining the golang value via reflection\n// (for example, if the value is a struct with unexported fields,\n// or if a non-data type like a channel or function is encountered).\n//\n// Some configuration (in particular, what to do about map ordering) is available via the Reflector struct.\n// That structure has a method of the same name and signiture as this one on it.\n// (This function is a shortcut for calling that method on a Reflector struct with default configuration.)\n//\n// Performance remarks: performance of this function will generally be poor.\n// In general, creating data in golang types and then *flipping* it to IPLD form\n// involves handling the data at least twice, and so will always be slower\n// than just creating the same data in IPLD form programmatically directly.\n// In particular, reflection is generally not fast, and this feature has\n// not been optimized for either speed nor allocation avoidance.\n// Other features in the fluent package will typically out-perform this,\n// and using NodeAssemblers directly (without any fluent tools) will be much faster.\n// Only use this function if performance is not of consequence.\nfunc Reflect(np datamodel.NodePrototype, i interface{}) (datamodel.Node, error) {\n\treturn defaultReflector.Reflect(np, i)\n}\n\n// MustReflect is a shortcut for Reflect but panics on any error.\n// It is useful if you need a single return value for function composition purposes.\nfunc MustReflect(np datamodel.NodePrototype, i interface{}) datamodel.Node {\n\tn, err := Reflect(np, i)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn n\n}\n\n// ReflectIntoAssembler is similar to Reflect, but takes a NodeAssembler parameter\n// instead of a Node Prototype.\n// This may be useful if you need more direct control over allocations,\n// or want to fill in only part of a larger node assembly process using the reflect tool.\n// Data is accumulated by the NodeAssembler parameter, so no Node is returned.\nfunc ReflectIntoAssembler(na datamodel.NodeAssembler, i interface{}) error {\n\treturn defaultReflector.ReflectIntoAssembler(na, i)\n}\n\nvar defaultReflector = Reflector{\n\tMapOrder: func(x, y string) bool {\n\t\treturn x < y\n\t},\n}\n\n// Reflector allows configuration of the Reflect family of functions\n// (`Reflect`, `ReflectIntoAssembler`, etc).\ntype Reflector struct {\n\t// MapOrder is used to decide a deterministic order for inserting entries to maps.\n\t// (This is used when converting golang maps, since their iteration order is randomized;\n\t// it is not used when converting other types such as structs, since those have a stable order.)\n\t// MapOrder should return x < y in the same way as sort.Interface.Less.\n\t//\n\t// If using a default Reflector (e.g. via the package-scope functions),\n\t// this function is a simple natural golang string sort: it performs `x < y` on the strings.\n\tMapOrder func(x, y string) bool\n}\n\n// Reflect is as per the package-scope function of the same name and signature,\n// but using the configuration in the Reflector struct.\n// See the package-scope function for documentation.\nfunc (rcfg Reflector) Reflect(np datamodel.NodePrototype, i interface{}) (datamodel.Node, error) {\n\tnb := np.NewBuilder()\n\tif err := rcfg.ReflectIntoAssembler(nb, i); err != nil {\n\t\treturn nil, err\n\t}\n\treturn nb.Build(), nil\n}\n\n// ReflectIntoAssembler is as per the package-scope function of the same name and signature,\n// but using the configuration in the Reflector struct.\n// See the package-scope function for documentation.\nfunc (rcfg Reflector) ReflectIntoAssembler(na datamodel.NodeAssembler, i interface{}) error {\n\t// Cover the most common values with a type-switch, as it's faster than reflection.\n\tswitch x := i.(type) {\n\tcase map[string]string:\n\t\tkeys := make([]string, 0, len(x))\n\t\tfor k := range x {\n\t\t\tkeys = append(keys, k)\n\t\t}\n\t\tsort.Sort(sortableStrings{keys, rcfg.MapOrder})\n\t\tma, err := na.BeginMap(int64(len(x)))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, k := range keys {\n\t\t\tva, err := ma.AssembleEntry(k)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := va.AssignString(x[k]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn ma.Finish()\n\tcase map[string]interface{}:\n\t\tkeys := make([]string, 0, len(x))\n\t\tfor k := range x {\n\t\t\tkeys = append(keys, k)\n\t\t}\n\t\tsort.Sort(sortableStrings{keys, rcfg.MapOrder})\n\t\tma, err := na.BeginMap(int64(len(x)))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, k := range keys {\n\t\t\tva, err := ma.AssembleEntry(k)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := rcfg.ReflectIntoAssembler(va, x[k]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn ma.Finish()\n\tcase []string:\n\t\tla, err := na.BeginList(int64(len(x)))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, v := range x {\n\t\t\tif err := la.AssembleValue().AssignString(v); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn la.Finish()\n\tcase []interface{}:\n\t\tla, err := na.BeginList(int64(len(x)))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, v := range x {\n\t\t\tif err := rcfg.ReflectIntoAssembler(la.AssembleValue(), v); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn la.Finish()\n\tcase string:\n\t\treturn na.AssignString(x)\n\tcase []byte:\n\t\treturn na.AssignBytes(x)\n\tcase int64:\n\t\treturn na.AssignInt(x)\n\tcase nil:\n\t\treturn na.AssignNull()\n\t}\n\t// That didn't fly?  Reflection time.\n\trv := reflect.ValueOf(i)\n\tswitch rv.Kind() {\n\tcase reflect.Bool:\n\t\treturn na.AssignBool(rv.Bool())\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\treturn na.AssignInt(rv.Int())\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\treturn na.AssignInt(int64(rv.Uint())) // TODO: check overflow\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn na.AssignFloat(rv.Float())\n\tcase reflect.String:\n\t\treturn na.AssignString(rv.String())\n\tcase reflect.Slice, reflect.Array:\n\t\tif rv.Type().Elem().Kind() == reflect.Uint8 { // byte slices are a special case\n\t\t\treturn na.AssignBytes(rv.Bytes())\n\t\t}\n\t\tl := rv.Len()\n\t\tla, err := na.BeginList(int64(l))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor i := 0; i < l; i++ {\n\t\t\tif err := rcfg.ReflectIntoAssembler(la.AssembleValue(), rv.Index(i).Interface()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn la.Finish()\n\tcase reflect.Map:\n\t\t// the keys slice for sorting keeps things in reflect.Value form, because unboxing is cheap,\n\t\t//  but re-boxing is not cheap, and the MapIndex method requires reflect.Value again later.\n\t\tkeys := make([]reflect.Value, 0, rv.Len())\n\t\titr := rv.MapRange()\n\t\tfor itr.Next() {\n\t\t\tk := itr.Key()\n\t\t\tif k.Kind() != reflect.String {\n\t\t\t\treturn fmt.Errorf(\"cannot convert a map with non-string keys (%T)\", i)\n\t\t\t}\n\t\t\tkeys = append(keys, k)\n\t\t}\n\t\tsort.Sort(sortableReflectStrings{keys, rcfg.MapOrder})\n\t\tma, err := na.BeginMap(int64(rv.Len()))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, k := range keys {\n\t\t\tva, err := ma.AssembleEntry(k.String())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := rcfg.ReflectIntoAssembler(va, rv.MapIndex(k).Interface()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn ma.Finish()\n\tcase reflect.Struct:\n\t\tl := rv.NumField()\n\t\tma, err := na.BeginMap(int64(l))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor i := 0; i < l; i++ {\n\t\t\tfn := rv.Type().Field(i).Name\n\t\t\tfv := rv.Field(i)\n\t\t\tva, err := ma.AssembleEntry(fn)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := rcfg.ReflectIntoAssembler(va, fv.Interface()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn ma.Finish()\n\tcase reflect.Ptr:\n\t\tif rv.IsNil() {\n\t\t\treturn na.AssignNull()\n\t\t}\n\t\treturn rcfg.ReflectIntoAssembler(na, rv.Elem())\n\tcase reflect.Interface:\n\t\treturn rcfg.ReflectIntoAssembler(na, rv.Elem())\n\t}\n\t// Some kints of values -- like Uintptr, Complex64/128, Channels, etc -- are not supported by this function.\n\treturn fmt.Errorf(\"fluent.Reflect: unsure how to handle type %T (kind: %v)\", i, rv.Kind())\n}\n\ntype sortableStrings struct {\n\ta    []string\n\tless func(x, y string) bool\n}\n\nfunc (a sortableStrings) Len() int           { return len(a.a) }\nfunc (a sortableStrings) Swap(i, j int)      { a.a[i], a.a[j] = a.a[j], a.a[i] }\nfunc (a sortableStrings) Less(i, j int) bool { return a.less(a.a[i], a.a[j]) }\n\ntype sortableReflectStrings struct {\n\ta    []reflect.Value\n\tless func(x, y string) bool\n}\n\nfunc (a sortableReflectStrings) Len() int           { return len(a.a) }\nfunc (a sortableReflectStrings) Swap(i, j int)      { a.a[i], a.a[j] = a.a[j], a.a[i] }\nfunc (a sortableReflectStrings) Less(i, j int) bool { return a.less(a.a[i].String(), a.a[j].String()) }\n"
  },
  {
    "path": "fluent/reflect_test.go",
    "content": "package fluent_test\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestReflect(t *testing.T) {\n\tt.Run(\"Map\", func(t *testing.T) {\n\t\tn, err := fluent.Reflect(basicnode.Prototype.Any, map[string]interface{}{\n\t\t\t\"k1\": \"fine\",\n\t\t\t\"k2\": \"super\",\n\t\t\t\"k3\": map[string]string{\n\t\t\t\t\"k31\": \"thanks\",\n\t\t\t\t\"k32\": \"for\",\n\t\t\t\t\"k33\": \"asking\",\n\t\t\t},\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\tt.Run(\"CorrectContents\", func(t *testing.T) {\n\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(3))\n\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"k1\"))), qt.Equals, \"fine\")\n\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"k2\"))), qt.Equals, \"super\")\n\t\t\tn := must.Node(n.LookupByString(\"k3\"))\n\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(3))\n\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"k31\"))), qt.Equals, \"thanks\")\n\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"k32\"))), qt.Equals, \"for\")\n\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"k33\"))), qt.Equals, \"asking\")\n\t\t})\n\t\tt.Run(\"CorrectOrder\", func(t *testing.T) {\n\t\t\titr := n.MapIterator()\n\t\t\tk, _, _ := itr.Next()\n\t\t\tqt.Check(t, must.String(k), qt.Equals, \"k1\")\n\t\t\tk, _, _ = itr.Next()\n\t\t\tqt.Check(t, must.String(k), qt.Equals, \"k2\")\n\t\t\tk, v, _ := itr.Next()\n\t\t\tqt.Check(t, must.String(k), qt.Equals, \"k3\")\n\t\t\titr = v.MapIterator()\n\t\t\tk, _, _ = itr.Next()\n\t\t\tqt.Check(t, must.String(k), qt.Equals, \"k31\")\n\t\t\tk, _, _ = itr.Next()\n\t\t\tqt.Check(t, must.String(k), qt.Equals, \"k32\")\n\t\t\tk, _, _ = itr.Next()\n\t\t\tqt.Check(t, must.String(k), qt.Equals, \"k33\")\n\t\t})\n\t})\n\tt.Run(\"Struct\", func(t *testing.T) {\n\t\ttype Woo struct {\n\t\t\tA string\n\t\t\tB string\n\t\t}\n\t\ttype Whee struct {\n\t\t\tX string\n\t\t\tZ string\n\t\t\tM Woo\n\t\t}\n\t\tn, err := fluent.Reflect(basicnode.Prototype.Any, Whee{\n\t\t\tX: \"fine\",\n\t\t\tZ: \"super\",\n\t\t\tM: Woo{\"thanks\", \"really\"},\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\tt.Run(\"CorrectContents\", func(t *testing.T) {\n\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(3))\n\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"X\"))), qt.Equals, \"fine\")\n\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"Z\"))), qt.Equals, \"super\")\n\t\t\tn := must.Node(n.LookupByString(\"M\"))\n\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(2))\n\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"A\"))), qt.Equals, \"thanks\")\n\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"B\"))), qt.Equals, \"really\")\n\t\t})\n\t\tt.Run(\"CorrectOrder\", func(t *testing.T) {\n\t\t\titr := n.MapIterator()\n\t\t\tk, _, _ := itr.Next()\n\t\t\tqt.Check(t, must.String(k), qt.Equals, \"X\")\n\t\t\tk, _, _ = itr.Next()\n\t\t\tqt.Check(t, must.String(k), qt.Equals, \"Z\")\n\t\t\tk, v, _ := itr.Next()\n\t\t\tqt.Check(t, must.String(k), qt.Equals, \"M\")\n\t\t\titr = v.MapIterator()\n\t\t\tk, _, _ = itr.Next()\n\t\t\tqt.Check(t, must.String(k), qt.Equals, \"A\")\n\t\t\tk, _, _ = itr.Next()\n\t\t\tqt.Check(t, must.String(k), qt.Equals, \"B\")\n\t\t})\n\t})\n\tt.Run(\"NamedString\", func(t *testing.T) {\n\t\ttype Foo string\n\t\ttype Bar struct {\n\t\t\tZ Foo\n\t\t}\n\t\tn, err := fluent.Reflect(basicnode.Prototype.Any, Bar{\"foo\"})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"Z\"))), qt.Equals, \"foo\")\n\t})\n\tt.Run(\"Interface\", func(t *testing.T) {\n\t\ttype Zaz struct {\n\t\t\tZ interface{}\n\t\t}\n\t\tn, err := fluent.Reflect(basicnode.Prototype.Any, Zaz{map[string]interface{}{\"wow\": \"wee\"}})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\tn, err = n.LookupByString(\"Z\")\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"wow\"))), qt.Equals, \"wee\")\n\t})\n\tt.Run(\"Bytes\", func(t *testing.T) {\n\t\tn, err := fluent.Reflect(basicnode.Prototype.Any, []byte{0x1, 0x2, 0x3})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Bytes)\n\t\tb, err := n.AsBytes()\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, b, qt.DeepEquals, []byte{0x1, 0x2, 0x3})\n\t})\n\tt.Run(\"NamedBytes\", func(t *testing.T) {\n\t\ttype Foo []byte\n\t\ttype Bar struct {\n\t\t\tZ Foo\n\t\t}\n\t\tn, err := fluent.Reflect(basicnode.Prototype.Any, Bar{[]byte{0x1, 0x2, 0x3}})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\tn, err = n.LookupByString(\"Z\")\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Bytes)\n\t\tb, err := n.AsBytes()\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, b, qt.DeepEquals, []byte{0x1, 0x2, 0x3})\n\t})\n\tt.Run(\"InterfaceContainingBytes\", func(t *testing.T) {\n\t\ttype Zaz struct {\n\t\t\tZ interface{}\n\t\t}\n\t\tn, err := fluent.Reflect(basicnode.Prototype.Any, Zaz{[]byte{0x1, 0x2, 0x3}})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\tn, err = n.LookupByString(\"Z\")\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Bytes)\n\t\tb, err := n.AsBytes()\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, b, qt.DeepEquals, []byte{0x1, 0x2, 0x3})\n\t})\n}\n"
  },
  {
    "path": "fluent/toInterfaceValue.go",
    "content": "package fluent\n\nimport (\n\t\"errors\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\nvar errInvalidKind = errors.New(\"invalid kind\")\nvar errUnknownKind = errors.New(\"unknown kind\")\n\n// ToInterface converts an IPLD node to its simplest equivalent Go value.\n//\n// Booleans, integers, floats, strings, bytes, and links are returned as themselves,\n// as per the node's AsT method. Note that nulls are returned as untyped nils.\n//\n// Lists and maps are returned as []interface{} and map[string]interface{}, respectively.\nfunc ToInterface(node datamodel.Node) (interface{}, error) {\n\tswitch k := node.Kind(); k {\n\tcase datamodel.Kind_Invalid:\n\t\treturn nil, errInvalidKind\n\tcase datamodel.Kind_Null:\n\t\treturn nil, nil\n\tcase datamodel.Kind_Bool:\n\t\treturn node.AsBool()\n\tcase datamodel.Kind_Int:\n\t\treturn node.AsInt()\n\tcase datamodel.Kind_Float:\n\t\treturn node.AsFloat()\n\tcase datamodel.Kind_String:\n\t\treturn node.AsString()\n\tcase datamodel.Kind_Bytes:\n\t\treturn node.AsBytes()\n\tcase datamodel.Kind_Link:\n\t\treturn node.AsLink()\n\tcase datamodel.Kind_Map:\n\t\toutMap := make(map[string]interface{}, node.Length())\n\t\tfor mi := node.MapIterator(); !mi.Done(); {\n\t\t\tk, v, err := mi.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tkVal, err := k.AsString()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tvVal, err := ToInterface(v)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\toutMap[kVal] = vVal\n\t\t}\n\t\treturn outMap, nil\n\tcase datamodel.Kind_List:\n\t\toutList := make([]interface{}, 0, node.Length())\n\t\tfor li := node.ListIterator(); !li.Done(); {\n\t\t\t_, v, err := li.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tvVal, err := ToInterface(v)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\toutList = append(outList, vVal)\n\t\t}\n\t\treturn outList, nil\n\tdefault:\n\t\treturn nil, errUnknownKind\n\t}\n}\n"
  },
  {
    "path": "fluent/toInterfaceValue_test.go",
    "content": "package fluent_test\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nvar roundTripTestCases = []struct {\n\tname  string\n\tvalue interface{}\n}{\n\t{name: \"Number\", value: int64(100)},\n\t{name: \"String\", value: \"hi\"},\n\t{name: \"Bool\", value: true},\n\t{name: \"Bytes\", value: []byte(\"hi\")},\n\t{name: \"Map\", value: map[string]interface{}{\"a\": \"1\", \"b\": int64(2), \"c\": 3.14, \"d\": true}},\n\t{name: \"Array\", value: []interface{}{\"a\", \"b\", \"c\"}},\n\t{name: \"Nil\", value: nil},\n}\n\nfunc TestRoundTrip(t *testing.T) {\n\tfor _, testCase := range roundTripTestCases {\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\tc := qt.New(t)\n\t\t\tn, err := fluent.Reflect(basicnode.Prototype.Any, testCase.value)\n\t\t\tc.Assert(err, qt.IsNil)\n\t\t\tout, err := fluent.ToInterface(n)\n\t\t\tc.Assert(err, qt.IsNil)\n\t\t\tc.Check(out, qt.DeepEquals, testCase.value)\n\t\t})\n\t}\n}\n\nfunc TestLink(t *testing.T) {\n\tc := qt.New(t)\n\tsomeCid, err := cid.Parse(\"bafybeihrqe2hmfauph5yfbd6ucv7njqpiy4tvbewlvhzjl4bhnyiu6h7pm\")\n\tc.Assert(err, qt.IsNil)\n\tlink := cidlink.Link{Cid: someCid}\n\tv, err := fluent.ToInterface(basicnode.NewLink(link))\n\tc.Assert(err, qt.IsNil)\n\tc.Assert(v.(cidlink.Link), qt.Equals, link)\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/ipld/go-ipld-prime\n\ngo 1.25.7\n\nrequire (\n\tgithub.com/frankban/quicktest v1.14.6\n\tgithub.com/google/go-cmp v0.7.0\n\tgithub.com/ipfs/go-cid v0.6.1\n\tgithub.com/multiformats/go-multicodec v0.10.0\n\tgithub.com/multiformats/go-multihash v0.2.3\n\tgithub.com/polydawn/refmt v0.89.1-0.20231129105047-37766d95467a\n\tgithub.com/warpfork/go-testmark v0.12.1\n\tgopkg.in/yaml.v2 v2.4.0\n)\n\nrequire (\n\tgithub.com/klauspost/cpuid/v2 v2.0.9 // indirect\n\tgithub.com/kr/pretty v0.3.1 // indirect\n\tgithub.com/kr/text v0.2.0 // indirect\n\tgithub.com/minio/sha256-simd v1.0.0 // indirect\n\tgithub.com/mr-tron/base58 v1.3.0 // indirect\n\tgithub.com/multiformats/go-base32 v0.1.0 // indirect\n\tgithub.com/multiformats/go-base36 v0.2.0 // indirect\n\tgithub.com/multiformats/go-multibase v0.3.0 // indirect\n\tgithub.com/multiformats/go-varint v0.1.0 // indirect\n\tgithub.com/rogpeppe/go-internal v1.9.0 // indirect\n\tgithub.com/spaolacci/murmur3 v1.1.0 // indirect\n\tgolang.org/x/crypto v0.50.0 // indirect\n\tgolang.org/x/sys v0.43.0 // indirect\n\tlukechampine.com/blake3 v1.1.6 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=\ncloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=\ncloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=\ncloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=\ncloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=\ncloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=\ncloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=\ncloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=\ncloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=\ncloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=\ncloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=\ncloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=\ncloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=\ncloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=\ncloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=\ncloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=\ncloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=\ncloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=\ncloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=\ngithub.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=\ngithub.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=\ngithub.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=\ngithub.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=\ngithub.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=\ngithub.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=\ngithub.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=\ngithub.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=\ngithub.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=\ngithub.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=\ngithub.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=\ngithub.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=\ngithub.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=\ngithub.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=\ngithub.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=\ngithub.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=\ngithub.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=\ngithub.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=\ngithub.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=\ngithub.com/ipfs/go-cid v0.6.1 h1:T5TnNb08+ueovG76Z5gx1L4Y7QOaGTXHg1F6raWFxIc=\ngithub.com/ipfs/go-cid v0.6.1/go.mod h1:zrY0SwOhjrrIdfPQ/kf+k1sXyJ0QE7cMxfCployLBs0=\ngithub.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=\ngithub.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=\ngithub.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=\ngithub.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=\ngithub.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=\ngithub.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=\ngithub.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=\ngithub.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=\ngithub.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=\ngithub.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=\ngithub.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/mr-tron/base58 v1.3.0 h1:K6Y13R2h+dku0wOqKtecgRnBUBPrZzLZy5aIj8lCcJI=\ngithub.com/mr-tron/base58 v1.3.0/go.mod h1:2BuubE67DCSWwVfx37JWNG8emOC0sHEU4/HpcYgCLX8=\ngithub.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=\ngithub.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=\ngithub.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=\ngithub.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=\ngithub.com/multiformats/go-multibase v0.3.0 h1:8helZD2+4Db7NNWFiktk2NePbF0boolBe6bDQvM4r68=\ngithub.com/multiformats/go-multibase v0.3.0/go.mod h1:MoBLQPCkRTOL3eveIPO81860j2AQY8JwcnNlRkGRUfI=\ngithub.com/multiformats/go-multicodec v0.10.0 h1:UpP223cig/Cx8J76jWt91njpK3GTAO1w02sdcjZDSuc=\ngithub.com/multiformats/go-multicodec v0.10.0/go.mod h1:wg88pM+s2kZJEQfRCKBNU+g32F5aWBEjyFHXvZLTcLI=\ngithub.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U=\ngithub.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=\ngithub.com/multiformats/go-varint v0.1.0 h1:i2wqFp4sdl3IcIxfAonHQV9qU5OsZ4Ts9IOoETFs5dI=\ngithub.com/multiformats/go-varint v0.1.0/go.mod h1:5KVAVXegtfmNQQm/lCY+ATvDzvJJhSkUlGQV9wgObdI=\ngithub.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=\ngithub.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=\ngithub.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=\ngithub.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/polydawn/refmt v0.89.1-0.20231129105047-37766d95467a h1:cgqrm0F3zwf9IPzca7xN4w+Zy6MC9ZkPvAC8QEWa/iQ=\ngithub.com/polydawn/refmt v0.89.1-0.20231129105047-37766d95467a/go.mod h1:ocZfO/tLSHqfScRDNTJbAJR1by4D1lewauX9OwTaPuY=\ngithub.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=\ngithub.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=\ngithub.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=\ngithub.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=\ngithub.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=\ngithub.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=\ngithub.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=\ngithub.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=\ngithub.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=\ngithub.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=\ngithub.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=\ngithub.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=\ngithub.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=\ngithub.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=\ngithub.com/warpfork/go-fsx v0.3.0/go.mod h1:oTACCMj+Zle+vgVa5SAhGAh7WksYpLgGUCKEAVc+xPg=\ngithub.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s=\ngithub.com/warpfork/go-testmark v0.12.1/go.mod h1:kHwy7wfvGSPh1rQJYKayD4AbtNaeyZdcGi9tNJTaa5Y=\ngithub.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=\ngithub.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=\ngithub.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngo.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=\ngo.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=\ngo.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=\ngo.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=\ngo.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=\ngo.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=\ngolang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=\ngolang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=\ngolang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=\ngolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=\ngolang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=\ngolang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=\ngolang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=\ngolang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=\ngolang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=\ngoogle.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=\ngoogle.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=\ngoogle.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=\ngoogle.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=\ngoogle.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=\ngoogle.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=\ngoogle.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=\ngoogle.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=\ngoogle.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=\ngoogle.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=\ngoogle.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=\ngoogle.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=\ngoogle.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhonnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nlukechampine.com/blake3 v1.1.6 h1:H3cROdztr7RCfoaTpGZFQsrqvweFLrqS73j7L7cmR5c=\nlukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\n"
  },
  {
    "path": "linking/cid/HACKME.md",
    "content": "Why does this package exist?\n----------------------------\n\nThe `linking/cid` package bends the `github.com/ipfs/go-cid` package into conforming to the `ipld.Link` interface.\n\nThe `linking/cid` package also contains factory functions for `ipld.LinkSystem`.\nThese LinkSystem will be constructed with `EncoderChooser`, `DecoderChooser`, and `HasherChooser` funcs\nwhich will use multicodec registries and multihash registries respectively.\n\n### Why not use go-cid directly?\n\nWe need a \"Link\" interface in the root `ipld` package or things just aren't definable.\nBut we don't want the root `ipld.Link` concept to directly map to `go-cid.Cid` for several reasons:\n\n1. We might want to revisit the go-cid library.  Possibly in the \"significantly breaking changes\" sense.\n\t- It's also not clear when we might do this -- and if we do, the transition period will be *long* because it's a highly-depended-upon library.\n\t- See below for some links to a gist that discusses why.\n2. We might want to extend the concept of linking to more than just plain CIDs.\n\t- This is hypothetical at present -- but an often-discussed example is \"what if CID+Path was also a Link?\"\n3. We might sometimes want to use IPLD libraries without using any CID implementation at all.\n\t- e.g. it's totally believable to want to use IPLD libraries for handling JSON and CBOR, even if you don't want IPLD linking.\n\t- if the CID packages were cheap enough, maybe this concern would fade -- but right now, they're **definitely** not; the transitive dependency tree of go-cid is *huge*.\n\n#### If go-cid is revisited, what might that look like?\n\nNo idea.  (At least, not in a committal way.)\n\nhttps://gist.github.com/warpfork/e871b7fee83cb814fb1f043089983bb3#existing-implementations\ngathers some reflections on the problems that would be nice to solve, though.\n\nhttps://gist.github.com/warpfork/e871b7fee83cb814fb1f043089983bb3#file-cid-go\ncontains a draft outline of what a revisited API could look like,\nbut note that at the time of writing, it is not strongly ratified nor in any way committed to.\n\nAt any rate, though, the operative question for this package is:\nif we do revisit go-cid, how are we going to make the transition manageable?\n\nIt seems unlikely we'd be able to make the transition manageable without some interface, somewhere.\nSo we might as well draw that line at `ipld.Link`.\n\n(I hypothesize that a transition story might involve two CID packages,\nwhich could grow towards a shared interface,\ndoing so in a way that's purely additive in the established `go-cid` package.\nWe'd need two separate go modules to do this, since the aim is reducing dependency bloat for those that use the new one.\nThe shared interface in this story could have more info than `ipld.Link` does now,\nbut would nonetheless still certainly be an interface in order to support the separation of modules.)\n\n### Why are LinkSystem factory functions here, instead of in the main IPLD package?\n\nSame reason as why we don't use go-cid directly.\n\nIf we put these LinkSystem defaults in the root `ipld` package,\nwe'd bring on all the transitive dependencies of `go-cid` onto an user of `ipld` unconditionally...\nand we don't want to do that.\n\nYou know that Weird Al song \"It's all about the pentiums\"?\nRetune that in your mind to \"It's all about dependencies\".\n"
  },
  {
    "path": "linking/cid/cidLink.go",
    "content": "package cidlink\n\nimport (\n\t\"fmt\"\n\n\tcid \"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\tmultihash \"github.com/multiformats/go-multihash\"\n)\n\nvar (\n\t_ datamodel.Link          = Link{}\n\t_ datamodel.LinkPrototype = LinkPrototype{}\n)\n\n// Link implements the datamodel.Link interface using a CID.\n// See https://github.com/ipfs/go-cid for more information about CIDs.\n//\n// When using this value, typically you'll use it as `Link`, and not `*Link`.\n// This includes when handling the value as an `datamodel.Link` interface -- the non-pointer form is typically preferable.\n// This is because the datamodel.Link interface is often desirable to be able to use as a golang map key,\n// and in that context, pointers would not result in the desired behavior.\ntype Link struct {\n\tcid.Cid\n}\n\nfunc (lnk Link) Prototype() datamodel.LinkPrototype {\n\treturn LinkPrototype{lnk.Cid.Prefix()}\n}\nfunc (lnk Link) String() string {\n\treturn lnk.Cid.String()\n}\nfunc (lnk Link) Binary() string {\n\treturn lnk.Cid.KeyString()\n}\n\ntype LinkPrototype struct {\n\tcid.Prefix\n}\n\nfunc (lp LinkPrototype) BuildLink(hashsum []byte) datamodel.Link {\n\t// Does this method body look surprisingly complex?  I agree.\n\t//  We actually have to do all this work.  The go-cid package doesn't expose a constructor that just lets us directly set the bytes and the prefix numbers next to each other.\n\t//  No, `cid.Prefix.Sum` is not the method you are looking for: that expects the whole data body.\n\t//  Most of the logic here is the same as the body of `cid.Prefix.Sum`; we just couldn't get at the relevant parts without copypasta.\n\t//  There is also some logic that's sort of folded in from the go-multihash module.  This is really a mess.\n\t//  The go-cid package needs review.  So does go-multihash.  Their responsibilies are not well compartmentalized and they don't play well with other stdlib golang interfaces.\n\tp := lp.Prefix\n\n\tlength := p.MhLength\n\tif p.MhType == multihash.IDENTITY {\n\t\tlength = -1\n\t}\n\tif p.Version == 0 && (p.MhType != multihash.SHA2_256 ||\n\t\t(p.MhLength != 32 && p.MhLength != -1)) {\n\t\tpanic(fmt.Errorf(\"invalid cid v0 prefix\"))\n\t}\n\n\tif length != -1 {\n\t\thashsum = hashsum[:p.MhLength]\n\t}\n\n\tmh, err := multihash.Encode(hashsum, p.MhType)\n\tif err != nil {\n\t\tpanic(err) // No longer possible, but multihash still returns an error for legacy reasons.\n\t}\n\n\tswitch lp.Prefix.Version {\n\tcase 0:\n\t\treturn Link{cid.NewCidV0(mh)}\n\tcase 1:\n\t\treturn Link{cid.NewCidV1(p.Codec, mh)}\n\tdefault:\n\t\tpanic(fmt.Errorf(\"invalid cid version\"))\n\t}\n}\n"
  },
  {
    "path": "linking/cid/linksystem.go",
    "content": "package cidlink\n\nimport (\n\t\"fmt\"\n\t\"hash\"\n\n\tmultihash \"github.com/multiformats/go-multihash/core\"\n\n\t\"github.com/ipld/go-ipld-prime/codec\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\t\"github.com/ipld/go-ipld-prime/multicodec\"\n)\n\n// DefaultLinkSystem returns a linking.LinkSystem which uses cidlink.Link for datamodel.Link.\n// During selection of encoders, decoders, and hashers, it examines the multicodec indicator numbers and multihash indicator numbers from the CID,\n// and uses the default global multicodec registry (see the go-ipld-prime/multicodec package) for resolving codec implementations,\n// and the default global multihash registry (see the go-multihash/core package) for resolving multihash implementations.\n//\n// No storage functions are present in the returned LinkSystem.\n// The caller can assign those themselves as desired.\nfunc DefaultLinkSystem() linking.LinkSystem {\n\treturn LinkSystemUsingMulticodecRegistry(multicodec.DefaultRegistry)\n}\n\n// LinkSystemUsingMulticodecRegistry is similar to DefaultLinkSystem, but accepts a multicodec.Registry as a parameter.\n//\n// This can help create a LinkSystem which uses different multicodec implementations than the global registry.\n// (Sometimes this can be desired if you want some parts of a program to support a more limited suite of codecs than other parts of the program,\n// or needed to use a different multicodec registry than the global one for synchronization purposes, or etc.)\nfunc LinkSystemUsingMulticodecRegistry(mcReg multicodec.Registry) linking.LinkSystem {\n\treturn linking.LinkSystem{\n\t\tEncoderChooser: func(lp datamodel.LinkPrototype) (codec.Encoder, error) {\n\t\t\tswitch lp2 := lp.(type) {\n\t\t\tcase LinkPrototype:\n\t\t\t\tfn, err := mcReg.LookupEncoder(lp2.GetCodec())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\treturn fn, nil\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"this encoderChooser can only handle cidlink.LinkPrototype; got %T\", lp)\n\t\t\t}\n\t\t},\n\t\tDecoderChooser: func(lnk datamodel.Link) (codec.Decoder, error) {\n\t\t\tlp := lnk.Prototype()\n\t\t\tswitch lp2 := lp.(type) {\n\t\t\tcase LinkPrototype:\n\t\t\t\tfn, err := mcReg.LookupDecoder(lp2.GetCodec())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\treturn fn, nil\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"this decoderChooser can only handle cidlink.LinkPrototype; got %T\", lp)\n\t\t\t}\n\t\t},\n\t\tHasherChooser: func(lp datamodel.LinkPrototype) (hash.Hash, error) {\n\t\t\tswitch lp2 := lp.(type) {\n\t\t\tcase LinkPrototype:\n\t\t\t\th, err := multihash.GetHasher(lp2.MhType)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"no hasher registered for multihash indicator 0x%x: %w\", lp2.MhType, err)\n\t\t\t\t}\n\t\t\t\treturn h, nil\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"this hasherChooser can only handle cidlink.LinkPrototype; got %T\", lp)\n\t\t\t}\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "linking/cid/memorystorage.go",
    "content": "package cidlink\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n)\n\n// Memory is a simple in-memory storage for cidlinks. It's the same as `storage.Memory`\n// but uses typical multihash semantics used when reading/writing cidlinks.\n//\n// Using multihash as the storage key rather than the whole CID will remove the\n// distinction between CIDv0 and their CIDv1 counterpart. It also removes the\n// distinction between CIDs where the multihash is the same but the codec is\n// different, e.g. `dag-cbor` and a `raw` version of the same data.\ntype Memory struct {\n\tBag map[string][]byte\n}\n\nfunc (store *Memory) beInitialized() {\n\tif store.Bag != nil {\n\t\treturn\n\t}\n\tstore.Bag = make(map[string][]byte)\n}\n\nfunc (store *Memory) OpenRead(lnkCtx linking.LinkContext, lnk datamodel.Link) (io.Reader, error) {\n\tstore.beInitialized()\n\tcl, ok := lnk.(Link)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"incompatible link type: %T\", lnk)\n\t}\n\tdata, exists := store.Bag[string(cl.Hash())]\n\tif !exists {\n\t\treturn nil, os.ErrNotExist\n\t}\n\treturn bytes.NewReader(data), nil\n}\n\nfunc (store *Memory) OpenWrite(lnkCtx linking.LinkContext) (io.Writer, linking.BlockWriteCommitter, error) {\n\tstore.beInitialized()\n\tbuf := bytes.Buffer{}\n\treturn &buf, func(lnk datamodel.Link) error {\n\t\tcl, ok := lnk.(Link)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"incompatible link type: %T\", lnk)\n\t\t}\n\n\t\tstore.Bag[string(cl.Hash())] = buf.Bytes()\n\t\treturn nil\n\t}, nil\n}\n"
  },
  {
    "path": "linking/errors.go",
    "content": "package linking\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// ErrLinkingSetup is returned by methods on LinkSystem when some part of the system is not set up correctly,\n// or when one of the components refuses to handle a Link or LinkPrototype given.\n// (It is not yielded for errors from the storage nor codec systems once they've started; those errors rise without interference.)\ntype ErrLinkingSetup struct {\n\tDetail string // Perhaps an enum here as well, which states which internal function was to blame?\n\tCause  error\n}\n\nfunc (e ErrLinkingSetup) Error() string { return fmt.Sprintf(\"%s: %v\", e.Detail, e.Cause) }\nfunc (e ErrLinkingSetup) Unwrap() error { return e.Cause }\n\n// ErrHashMismatch is the error returned when loading data and verifying its hash\n// and finding that the loaded data doesn't re-hash to the expected value.\n// It is typically seen returned by functions like LinkSystem.Load or LinkSystem.Fill.\ntype ErrHashMismatch struct {\n\tActual   datamodel.Link\n\tExpected datamodel.Link\n}\n\nfunc (e ErrHashMismatch) Error() string {\n\treturn fmt.Sprintf(\"hash mismatch!  %v (actual) != %v (expected)\", e.Actual, e.Expected)\n}\n"
  },
  {
    "path": "linking/functions.go",
    "content": "package linking\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// This file contains all the functions on LinkSystem.\n// These are the helpful, user-facing functions we expect folks to use \"most of the time\" when loading and storing data.\n\n// Variations:\n// - Load vs Store vs ComputeLink\n// - Load vs LoadPlusRaw\n// - With or without LinkContext?\n//   - Brevity would be nice but I can't think of what to name the functions, so: everything takes LinkContext.  Zero value is fine though.\n// - [for load direction only]: Prototype (and return Node|error) or Assembler (and just return error)?\n//   - naming: Load vs Fill.\n// - 'Must' variants.\n\n// Can we get as far as a `QuickLoad(lnk Link) (Node, error)` function, which doesn't even ask you for a NodePrototype?\n//  No, not quite.  (Alas.)  If we tried to do so, and make it use `basicnode.Prototype`, we'd have import cycles; ded.\n\n// Load looks up some data identified by a Link, and does everything necessary to turn it into usable data.\n// In detail, that means it:\n// brings that data into memory,\n// verifies the hash,\n// parses it into the Data Model using a codec,\n// and returns an IPLD Node.\n//\n// Where the data will be loaded from is determined by the configuration of the LinkSystem\n// (namely, the StorageReadOpener callback, which can either be set directly,\n// or configured via the SetReadStorage function).\n//\n// The in-memory form used for the returned Node is determined by the given NodePrototype parameter.\n// A new builder and a new node will be allocated, via NodePrototype.NewBuilder.\n// (If you'd like more control over memory allocation, you may wish to see the Fill function instead.)\n//\n// A schema may also be used, and apply additional data validation during loading,\n// by using a schema.TypedNodePrototype as the NodePrototype argument.\n//\n// The LinkContext parameter may be used to pass contextual information down to the loading layer.\n//\n// Which hashing function is used to validate the loaded data is determined by LinkSystem.HasherChooser.\n// Which codec is used to parse the loaded data into the Data Model is determined by LinkSystem.DecoderChooser.\n//\n// The LinkSystem.NodeReifier callback is also applied before returning the Node,\n// and so Load may also thereby return an ADL.\nfunc (lsys *LinkSystem) Load(lnkCtx LinkContext, lnk datamodel.Link, np datamodel.NodePrototype) (datamodel.Node, error) {\n\tnb := np.NewBuilder()\n\tif err := lsys.Fill(lnkCtx, lnk, nb); err != nil {\n\t\treturn nil, err\n\t}\n\tnd := nb.Build()\n\tif lsys.NodeReifier == nil {\n\t\treturn nd, nil\n\t}\n\treturn lsys.NodeReifier(lnkCtx, nd, lsys)\n}\n\n// MustLoad is identical to Load, but panics in the case of errors.\n//\n// This function is meant for convenience of use in test and demo code, but should otherwise probably be avoided.\nfunc (lsys *LinkSystem) MustLoad(lnkCtx LinkContext, lnk datamodel.Link, np datamodel.NodePrototype) datamodel.Node {\n\tif n, err := lsys.Load(lnkCtx, lnk, np); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\treturn n\n\t}\n}\n\n// LoadPlusRaw is similar to Load, but additionally retains and returns the byte slice of the raw data parsed.\n//\n// Be wary of using this with large data, since it will hold all data in memory at once.\n// For more control over streaming, you may want to construct a LinkSystem where you wrap the storage opener callbacks,\n// and thus can access the streams (and tee them, or whatever you need to do) as they're opened.\n// This function is meant for convenience when data sizes are small enough that fitting them into memory at once is not a problem.\nfunc (lsys *LinkSystem) LoadPlusRaw(lnkCtx LinkContext, lnk datamodel.Link, np datamodel.NodePrototype) (datamodel.Node, []byte, error) {\n\t// Choose all the parts.\n\tdecoder, err := lsys.DecoderChooser(lnk)\n\tif err != nil {\n\t\treturn nil, nil, ErrLinkingSetup{\"could not choose a decoder\", err}\n\t}\n\t// Use LoadRaw to get the data.\n\t//  If we're going to have everything in memory at once, we might as well do that first, and then give the codec and the hasher the whole thing at once.\n\tblock, err := lsys.LoadRaw(lnkCtx, lnk)\n\tif err != nil {\n\t\treturn nil, block, err\n\t}\n\t// Create a NodeBuilder.\n\t// Deploy the codec.\n\t// Build the node.\n\tnb := np.NewBuilder()\n\tif err := decoder(nb, bytes.NewBuffer(block)); err != nil {\n\t\treturn nil, block, err\n\t}\n\tnd := nb.Build()\n\t// Consider applying NodeReifier, if applicable.\n\tif lsys.NodeReifier == nil {\n\t\treturn nd, block, nil\n\t}\n\tnd, err = lsys.NodeReifier(lnkCtx, nd, lsys)\n\treturn nd, block, err\n}\n\n// LoadRaw looks up some data identified by a Link, brings that data into memory,\n// verifies the hash, and returns it directly as a byte slice.\n//\n// LoadRaw does not return a data model view of the data,\n// nor does it verify that a codec can parse the data at all!\n// Use this function at your own risk; it does not provide the same guarantees as the Load or Fill functions do.\nfunc (lsys *LinkSystem) LoadRaw(lnkCtx LinkContext, lnk datamodel.Link) ([]byte, error) {\n\tif lnkCtx.Ctx == nil {\n\t\tlnkCtx.Ctx = context.Background()\n\t}\n\t// Choose all the parts.\n\thasher, err := lsys.HasherChooser(lnk.Prototype())\n\tif err != nil {\n\t\treturn nil, ErrLinkingSetup{\"could not choose a hasher\", err}\n\t}\n\tif lsys.StorageReadOpener == nil {\n\t\treturn nil, ErrLinkingSetup{\"no storage configured for reading\", io.ErrClosedPipe} // REVIEW: better cause?\n\t}\n\t// Open storage: get the data.\n\t// FUTURE: this could probably use storage.ReadableStorage.Get instead of streaming and a buffer, if we refactored LinkSystem to carry that interface through.\n\treader, err := lsys.StorageReadOpener(lnkCtx, lnk)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif closer, ok := reader.(io.Closer); ok {\n\t\tdefer closer.Close()\n\t}\n\tvar buf bytes.Buffer\n\tif _, err := io.Copy(&buf, reader); err != nil {\n\t\treturn nil, err\n\t}\n\t// Compute the hash.\n\t// (Then do a bit of a jig to build a link out of it -- because that's what we do the actual hash equality check on.)\n\thasher.Write(buf.Bytes())\n\thash := hasher.Sum(nil)\n\tlnk2 := lnk.Prototype().BuildLink(hash)\n\tif lnk2.Binary() != lnk.Binary() {\n\t\treturn nil, ErrHashMismatch{Actual: lnk2, Expected: lnk}\n\t}\n\t// No codec to deploy; this is the raw load function.\n\t// So we're done.\n\treturn buf.Bytes(), nil\n}\n\n// Fill is similar to Load, but allows more control over memory allocations.\n// Instead of taking a NodePrototype parameter, Fill takes a NodeAssembler parameter:\n// this allows you to use your own NodeBuilder (and reset it, etc, thus controlling allocations),\n// or, to fill in some part of a larger structure.\n//\n// Note that Fill does not regard NodeReifier, even if one has been configured.\n// (This is in contrast to Load, which does regard a NodeReifier if one is configured, and thus may return an ADL node).\nfunc (lsys *LinkSystem) Fill(lnkCtx LinkContext, lnk datamodel.Link, na datamodel.NodeAssembler) error {\n\tif lnkCtx.Ctx == nil {\n\t\tlnkCtx.Ctx = context.Background()\n\t}\n\t// Choose all the parts.\n\tdecoder, err := lsys.DecoderChooser(lnk)\n\tif err != nil {\n\t\treturn ErrLinkingSetup{\"could not choose a decoder\", err}\n\t}\n\thasher, err := lsys.HasherChooser(lnk.Prototype())\n\tif err != nil {\n\t\treturn ErrLinkingSetup{\"could not choose a hasher\", err}\n\t}\n\tif lsys.StorageReadOpener == nil {\n\t\treturn ErrLinkingSetup{\"no storage configured for reading\", io.ErrClosedPipe} // REVIEW: better cause?\n\t}\n\t// Open storage; get a reader stream.\n\treader, err := lsys.StorageReadOpener(lnkCtx, lnk)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif closer, ok := reader.(io.Closer); ok {\n\t\tdefer closer.Close()\n\t}\n\t// TrustedStorage indicates the data coming out of this reader has already been hashed and verified earlier.\n\t// As a result, we can skip rehashing it\n\tif lsys.TrustedStorage {\n\t\treturn decoder(na, reader)\n\t}\n\t// Tee the stream so that the hasher is fed as the unmarshal progresses through the stream.\n\ttee := io.TeeReader(reader, hasher)\n\t// The actual read is then dragged forward by the codec.\n\tdecodeErr := decoder(na, tee)\n\tif decodeErr != nil {\n\t\t// It is important to security to check the hash before returning any other observation about the content,\n\t\t// so, if the decode process returns any error, we have several steps to take before potentially returning it.\n\t\t// First, we try to copy any data remaining that wasn't already pulled through the TeeReader by the decoder,\n\t\t// so that the hasher can reach the end of the stream.\n\t\t// If _that_ errors, return the I/O level error.\n\t\t// We hang onto decodeErr for a while: we can't return that until all the way after we check the hash equality.\n\t\t_, err := io.Copy(hasher, reader)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\t// Compute the hash.\n\t// (Then do a bit of a jig to build a link out of it -- because that's what we do the actual hash equality check on.)\n\thash := hasher.Sum(nil)\n\tlnk2 := lnk.Prototype().BuildLink(hash)\n\tif lnk2.Binary() != lnk.Binary() {\n\t\treturn ErrHashMismatch{Actual: lnk2, Expected: lnk}\n\t}\n\t// If we got all the way through IO and through the hash check:\n\t// now, finally, if we did get an error from the codec, we can admit to that.\n\tif decodeErr != nil {\n\t\treturn decodeErr\n\t}\n\treturn nil\n}\n\n// MustFill is identical to Fill, but panics in the case of errors.\n//\n// This function is meant for convenience of use in test and demo code, but should otherwise probably be avoided.\nfunc (lsys *LinkSystem) MustFill(lnkCtx LinkContext, lnk datamodel.Link, na datamodel.NodeAssembler) {\n\tif err := lsys.Fill(lnkCtx, lnk, na); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc (lsys *LinkSystem) Store(lnkCtx LinkContext, lp datamodel.LinkPrototype, n datamodel.Node) (datamodel.Link, error) {\n\tif lnkCtx.Ctx == nil {\n\t\tlnkCtx.Ctx = context.Background()\n\t}\n\t// Choose all the parts.\n\tencoder, err := lsys.EncoderChooser(lp)\n\tif err != nil {\n\t\treturn nil, ErrLinkingSetup{\"could not choose an encoder\", err}\n\t}\n\thasher, err := lsys.HasherChooser(lp)\n\tif err != nil {\n\t\treturn nil, ErrLinkingSetup{\"could not choose a hasher\", err}\n\t}\n\tif lsys.StorageWriteOpener == nil {\n\t\treturn nil, ErrLinkingSetup{\"no storage configured for writing\", io.ErrClosedPipe} // REVIEW: better cause?\n\t}\n\t// Open storage write stream, feed serial data to the storage and the hasher, and funnel the codec output into both.\n\twriter, commitFn, err := lsys.StorageWriteOpener(lnkCtx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttee := io.MultiWriter(writer, hasher)\n\terr = encoder(n, tee)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlnk := lp.BuildLink(hasher.Sum(nil))\n\treturn lnk, commitFn(lnk)\n}\n\nfunc (lsys *LinkSystem) MustStore(lnkCtx LinkContext, lp datamodel.LinkPrototype, n datamodel.Node) datamodel.Link {\n\tif lnk, err := lsys.Store(lnkCtx, lp, n); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\treturn lnk\n\t}\n}\n\n// ComputeLink returns a Link for the given data, but doesn't do anything else\n// (e.g. it doesn't try to store any of the serial-form data anywhere else).\nfunc (lsys *LinkSystem) ComputeLink(lp datamodel.LinkPrototype, n datamodel.Node) (datamodel.Link, error) {\n\tencoder, err := lsys.EncoderChooser(lp)\n\tif err != nil {\n\t\treturn nil, ErrLinkingSetup{\"could not choose an encoder\", err}\n\t}\n\thasher, err := lsys.HasherChooser(lp)\n\tif err != nil {\n\t\treturn nil, ErrLinkingSetup{\"could not choose a hasher\", err}\n\t}\n\terr = encoder(n, hasher)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn lp.BuildLink(hasher.Sum(nil)), nil\n}\n\nfunc (lsys *LinkSystem) MustComputeLink(lp datamodel.LinkPrototype, n datamodel.Node) datamodel.Link {\n\tif lnk, err := lsys.ComputeLink(lp, n); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\treturn lnk\n\t}\n}\n"
  },
  {
    "path": "linking/functions_test.go",
    "content": "package linking_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagcbor\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/storage/memstore\"\n\t\"github.com/multiformats/go-multicodec\"\n)\n\nfunc TestLinkSystem_LoadHashMismatch(t *testing.T) {\n\tsubject := cidlink.DefaultLinkSystem()\n\tstorage := &memstore.Store{}\n\tsubject.SetReadStorage(storage)\n\tsubject.SetWriteStorage(storage)\n\n\t// Construct some test IPLD node.\n\twantNode := fluent.MustBuildMap(basicnode.Prototype.Map, 1, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"fish\").AssignString(\"barreleye\")\n\t})\n\n\t// Encode as raw value to be used for testing LoadRaw\n\tvar buf bytes.Buffer\n\tqt.Check(t, dagcbor.Encode(wantNode, &buf), qt.IsNil)\n\twantNodeRaw := buf.Bytes()\n\n\t// Store the test IPLD node and get link back.\n\tlctx := ipld.LinkContext{Ctx: context.TODO()}\n\tgotLink, err := subject.Store(lctx, cidlink.LinkPrototype{\n\t\tPrefix: cid.Prefix{\n\t\t\tVersion:  1,\n\t\t\tCodec:    uint64(multicodec.DagCbor),\n\t\t\tMhType:   uint64(multicodec.Sha2_256),\n\t\t\tMhLength: -1,\n\t\t},\n\t}, wantNode)\n\tqt.Check(t, err, qt.IsNil)\n\tgotCidlink := gotLink.(cidlink.Link)\n\n\t// Assert all load variations return expected values for different link representations.\n\tfor _, test := range []struct {\n\t\tname string\n\t\tlink datamodel.Link\n\t}{\n\t\t{\"datamodel.Link\", gotLink},\n\t\t{\"cidlink.Link\", gotCidlink},\n\t\t{\"&cidlink.Link\", &gotCidlink},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tgotNode, err := subject.Load(lctx, test.link, basicnode.Prototype.Any)\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, ipld.DeepEqual(wantNode, gotNode), qt.IsTrue)\n\n\t\t\tgotNodeRaw, err := subject.LoadRaw(lctx, test.link)\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, bytes.Equal(wantNodeRaw, gotNodeRaw), qt.IsTrue)\n\n\t\t\tgotNode, gotNodeRaw, err = subject.LoadPlusRaw(lctx, test.link, basicnode.Prototype.Any)\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, ipld.DeepEqual(wantNode, gotNode), qt.IsTrue)\n\t\t\tqt.Check(t, bytes.Equal(wantNodeRaw, gotNodeRaw), qt.IsTrue)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "linking/linkingExamples_test.go",
    "content": "package linking_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipfs/go-cid\"\n\n\t_ \"github.com/ipld/go-ipld-prime/codec/dagcbor\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/storage/memstore\"\n)\n\n// storage is a map where we'll store serialized IPLD data.\n//\n// ExampleLinkSystem_Store will put data into this;\n// ExampleLinkSystem_Load will read out from it.\n//\n// In a real program, you'll probably make functions to load and store from disk,\n// or some network storage, or... whatever you want, really :)\nvar store = memstore.Store{}\n\n// TODO: These examples are really heavy on CIDs and the multicodec and multihash magic tables.\n// It would be good to have examples that create and use less magical LinkSystem constructions, too.\n\nfunc ExampleLinkSystem_Store() {\n\t// Creating a Link is done by choosing a concrete link implementation (typically, CID),\n\t//  getting a LinkSystem that knows how to work with that, and then using the LinkSystem methods.\n\n\t// Let's get a LinkSystem.  We're going to be working with CID links,\n\t//  so let's get the default LinkSystem that's ready to work with those.\n\tlsys := cidlink.DefaultLinkSystem()\n\n\t// We want to store the serialized data somewhere.\n\t//  We'll use an in-memory store for this.  (It's a package scoped variable.)\n\t//  You can use any kind of storage system here;\n\t//   or if you need even more control, you could also write a function that conforms to the linking.BlockWriteOpener interface.\n\tlsys.SetWriteStorage(&store)\n\n\t// To create any links, first we need a LinkPrototype.\n\t// This gathers together any parameters that might be needed when making a link.\n\t// (For CIDs, the version, the codec, and the multihash type are all parameters we'll need.)\n\t// Often, you can probably make this a constant for your whole application.\n\tlp := cidlink.LinkPrototype{Prefix: cid.Prefix{\n\t\tVersion:  1,    // Usually '1'.\n\t\tCodec:    0x71, // 0x71 means \"dag-cbor\" -- See the multicodecs table: https://github.com/multiformats/multicodec/\n\t\tMhType:   0x13, // 0x20 means \"sha2-512\" -- See the multicodecs table: https://github.com/multiformats/multicodec/\n\t\tMhLength: 64,   // sha2-512 hash has a 64-byte sum.\n\t}}\n\n\t// And we need some data to link to!  Here's a quick piece of example data:\n\tn := fluent.MustBuildMap(basicnode.Prototype.Map, 1, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"hello\").AssignString(\"world\")\n\t})\n\n\t// Before we use the LinkService, NOTE:\n\t//  There's a side-effecting import at the top of the file.  It's for the dag-cbor codec.\n\t//  The CID LinkSystem defaults use a global registry called the multicodec table;\n\t//  and the multicodec table is populated in part by the dag-cbor package when it's first imported.\n\t// You'll need that side-effecting import, too, to copy this example.\n\t//  It can happen anywhere in your program; once, in any package, is enough.\n\t//  If you don't have this import, the codec will not be registered in the multicodec registry,\n\t//  and when you use the LinkSystem we got from the cidlink package, it will return an error of type ErrLinkingSetup.\n\t// If you initialize a custom LinkSystem, you can control this more directly;\n\t//  these registry systems are only here as defaults.\n\n\t// Now: time to apply the LinkSystem, and do the actual store operation!\n\tlnk, err := lsys.Store(\n\t\tlinking.LinkContext{}, // The zero value is fine.  Configure it it you want cancellability or other features.\n\t\tlp,                    // The LinkPrototype says what codec and hashing to use.\n\t\tn,                     // And here's our data.\n\t)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t// That's it!  We got a link.\n\tfmt.Printf(\"link: %s\\n\", lnk)\n\tfmt.Printf(\"concrete type: `%T`\\n\", lnk)\n\n\t// Remember: the serialized data was also stored to the 'store' variable as a side-effect.\n\t//  (We set this up back when we customized the LinkSystem.)\n\t//  We'll pick this data back up again in the example for loading.\n\n\t// Output:\n\t// link: bafyrgqhai26anf3i7pips7q22coa4sz2fr4gk4q4sqdtymvvjyginfzaqewveaeqdh524nsktaq43j65v22xxrybrtertmcfxufdam3da3hbk\n\t// concrete type: `cidlink.Link`\n}\n\nfunc ExampleLinkSystem_Load() {\n\t// Let's say we want to load this link (it's the same one we created in ExampleLinkSystem_Store).\n\tcid, _ := cid.Decode(\"bafyrgqhai26anf3i7pips7q22coa4sz2fr4gk4q4sqdtymvvjyginfzaqewveaeqdh524nsktaq43j65v22xxrybrtertmcfxufdam3da3hbk\")\n\tlnk := cidlink.Link{Cid: cid}\n\n\t// Let's get a LinkSystem.  We're going to be working with CID links,\n\t//  so let's get the default LinkSystem that's ready to work with those.\n\t// (This is the same as we did in ExampleLinkSystem_Store.)\n\tlsys := cidlink.DefaultLinkSystem()\n\n\t// We need somewhere to go looking for any of the data we might want to load!\n\t//  We'll use an in-memory store for this.  (It's a package scoped variable.)\n\t//   (This particular memory store was filled with the data we'll load earlier, during ExampleLinkSystem_Store.)\n\t//  You can use any kind of storage system here;\n\t//   or if you need even more control, you could also write a function that conforms to the linking.BlockReadOpener interface.\n\tlsys.SetReadStorage(&store)\n\n\t// We'll need to decide what in-memory implementation of datamodel.Node we want to use.\n\t//  Here, we'll use the \"basicnode\" implementation.  This is a good getting-started choice.\n\t//   But you could also use other implementations, or even a code-generated type with special features!\n\tnp := basicnode.Prototype.Any\n\n\t// Before we use the LinkService, NOTE:\n\t//  There's a side-effecting import at the top of the file.  It's for the dag-cbor codec.\n\t//  See the comments in ExampleLinkSystem_Store for more discussion of this and why it's important.\n\n\t// Apply the LinkSystem, and ask it to load our link!\n\tn, err := lsys.Load(\n\t\tlinking.LinkContext{}, // The zero value is fine.  Configure it it you want cancellability or other features.\n\t\tlnk,                   // The Link we want to load!\n\t\tnp,                    // The NodePrototype says what kind of Node we want as a result.\n\t)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t// Tada!  We have the data as node that we can traverse and use as desired.\n\tfmt.Printf(\"we loaded a %s with %d entries\\n\", n.Kind(), n.Length())\n\n\t// Output:\n\t// we loaded a map with 1 entries\n}\n"
  },
  {
    "path": "linking/preload/preload.go",
    "content": "package preload\n\nimport (\n\t\"context\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// Loader is a function that will be called with a link discovered in a preload\n// pass of a traversal. A preload pass can be used to collect all links in each\n// block prior to traversal of that block, allowing for parallel (background)\n// loading of blocks in anticipation of eventual actual load during traversal.\ntype Loader func(PreloadContext, Link)\n\n// PreloadContext carries information about the current state of a traversal\n// where a set of links that may be preloaded were encountered.\ntype PreloadContext struct {\n\t// Ctx is the familiar golang Context pattern.\n\t// Use this for cancellation, or attaching additional info\n\t// (for example, perhaps to pass auth tokens through to the storage functions).\n\tCtx context.Context\n\n\t// Path where the link was encountered.  May be zero.\n\t//\n\t// Functions in the traversal package will set this automatically.\n\tBasePath datamodel.Path\n\n\t// Parent of the LinkNode.  May be zero.\n\t//\n\t// Functions in the traversal package will set this automatically.\n\tParentNode datamodel.Node\n}\n\n// Link provides the link encountered during a preload pass, the node it was\n// encountered on, and the segment of the path that led to the link.\ntype Link struct {\n\tSegment  datamodel.PathSegment\n\tLinkNode datamodel.Node\n\tLink     datamodel.Link\n}\n"
  },
  {
    "path": "linking/setup.go",
    "content": "package linking\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/storage\"\n)\n\n// SetReadStorage configures how the LinkSystem will look for information to load,\n// setting it to look at the given storage.ReadableStorage.\n//\n// This will overwrite the LinkSystem.StorageReadOpener field.\n//\n// This mechanism only supports setting exactly one ReadableStorage.\n// If you would like to make a more complex configuration\n// (for example, perhaps using information from a LinkContext to decide which storage area to use?)\n// then you should set LinkSystem.StorageReadOpener to a custom callback of your own creation instead.\nfunc (lsys *LinkSystem) SetReadStorage(store storage.ReadableStorage) {\n\tlsys.StorageReadOpener = func(lctx LinkContext, lnk datamodel.Link) (io.Reader, error) {\n\t\treturn storage.GetStream(lctx.Ctx, store, lnk.Binary())\n\t}\n}\n\n// SetWriteStorage configures how the LinkSystem will store information,\n// setting it to write into the given storage.WritableStorage.\n//\n// This will overwrite the LinkSystem.StorageWriteOpener field.\n//\n// This mechanism only supports setting exactly one WritableStorage.\n// If you would like to make a more complex configuration\n// (for example, perhaps using information from a LinkContext to decide which storage area to use?)\n// then you should set LinkSystem.StorageWriteOpener to a custom callback of your own creation instead.\nfunc (lsys *LinkSystem) SetWriteStorage(store storage.WritableStorage) {\n\tlsys.StorageWriteOpener = func(lctx LinkContext) (io.Writer, BlockWriteCommitter, error) {\n\t\twr, wrcommit, err := storage.PutStream(lctx.Ctx, store)\n\t\treturn wr, func(lnk datamodel.Link) error {\n\t\t\treturn wrcommit(lnk.Binary())\n\t\t}, err\n\t}\n}\n"
  },
  {
    "path": "linking/types.go",
    "content": "package linking\n\nimport (\n\t\"context\"\n\t\"hash\"\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/codec\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// LinkSystem is a struct that composes all the individual functions\n// needed to load and store content addressed data using IPLD --\n// encoding functions, hashing functions, and storage connections --\n// and then offers the operations a user wants -- Store and Load -- as methods.\n//\n// Typically, the functions which are fields of LinkSystem are not used\n// directly by users (except to set them, when creating the LinkSystem),\n// and it's the higher level operations such as Store and Load that user code then calls.\n//\n// The most typical way to get a LinkSystem is from the linking/cid package,\n// which has a factory function called DefaultLinkSystem.\n// The LinkSystem returned by that function will be based on CIDs,\n// and use the multicodec registry and multihash registry to select encodings and hashing mechanisms.\n// The BlockWriteOpener and BlockReadOpener must still be provided by the user;\n// otherwise, only the ComputeLink method will work.\n//\n// Some implementations of BlockWriteOpener and BlockReadOpener may be\n// found in the storage package.  Applications are also free to write their own.\n// Custom wrapping of BlockWriteOpener and BlockReadOpener are also common,\n// and may be reasonable if one wants to build application features that are block-aware.\ntype LinkSystem struct {\n\tEncoderChooser     func(datamodel.LinkPrototype) (codec.Encoder, error)\n\tDecoderChooser     func(datamodel.Link) (codec.Decoder, error)\n\tHasherChooser      func(datamodel.LinkPrototype) (hash.Hash, error)\n\tStorageWriteOpener BlockWriteOpener\n\tStorageReadOpener  BlockReadOpener\n\tTrustedStorage     bool\n\tNodeReifier        NodeReifier\n\tKnownReifiers      map[string]NodeReifier\n}\n\n// The following three types are the key functionality we need from a \"blockstore\".\n//\n// Some libraries might provide a \"blockstore\" object that has these as methods;\n// it may also have more methods (like enumeration features, GC features, etc),\n// but IPLD doesn't generally concern itself with those.\n// We just need these key things, so we can \"put\" and \"get\".\n//\n// The functions are a tad more complicated than \"put\" and \"get\" so that they have good mechanical sympathy.\n// In particular, the writing/\"put\" side is broken into two phases, so that the abstraction\n// makes it easy to begin to write data before the hash that will identify it is fully computed.\ntype (\n\t// BlockReadOpener defines the shape of a function used to\n\t// open a reader for a block of data.\n\t//\n\t// In a content-addressed system, the Link parameter should be only\n\t// determiner of what block body is returned.\n\t//\n\t// The LinkContext may be zero, or may be used to carry extra information:\n\t// it may be used to carry info which hints at different storage pools;\n\t// it may be used to carry authentication data; etc.\n\t// (Any such behaviors are something that a BlockReadOpener implementation\n\t// will needs to document at a higher detail level than this interface specifies.\n\t// In this interface, we can only note that it is possible to pass such information opaquely\n\t// via the LinkContext or by attachments to the general-purpose Context it contains.)\n\t// The LinkContext should not have effect on the block body returned, however;\n\t// at most should only affect data availability\n\t// (e.g. whether any block body is returned, versus an error).\n\t//\n\t// Reads are cancellable by cancelling the LinkContext.Context.\n\t//\n\t// Other parts of the IPLD library suite (such as the traversal package, and all its functions)\n\t// will typically take a Context as a parameter or piece of config from the caller,\n\t// and will pass that down through the LinkContext, meaning this can be used to\n\t// carry information as well as cancellation control all the way through the system.\n\t//\n\t// BlockReadOpener is typically not used directly, but is instead\n\t// composed in a LinkSystem and used via the methods of LinkSystem.\n\t// LinkSystem methods will helpfully handle the entire process of opening block readers,\n\t// verifying the hash of the data stream, and applying a Decoder to build Nodes -- all as one step.\n\t//\n\t// BlockReadOpener implementations are not required to validate that\n\t// the contents which will be streamed out of the reader actually match\n\t// and hash in the Link parameter before returning.\n\t// (This is something that the LinkSystem composition will handle if you're using it.)\n\t//\n\t// BlockReadOpener can also be created out of storage.ReadableStorage and attached to a LinkSystem\n\t// via the LinkSystem.SetReadStorage method.\n\t//\n\t// Users of a BlockReadOpener function should also check the io.Reader\n\t// for matching the io.Closer interface, and use the Close function as appropriate if present.\n\tBlockReadOpener func(LinkContext, datamodel.Link) (io.Reader, error)\n\n\t// BlockWriteOpener defines the shape of a function used to open a writer\n\t// into which data can be streamed, and which will eventually be \"commited\".\n\t// Committing is done using the BlockWriteCommitter returned by using the BlockWriteOpener,\n\t// and finishes the write along with requiring stating the Link which should identify this data for future reading.\n\t//\n\t// The LinkContext may be zero, or may be used to carry extra information:\n\t// it may be used to carry info which hints at different storage pools;\n\t// it may be used to carry authentication data; etc.\n\t//\n\t// Writes are cancellable by cancelling the LinkContext.Context.\n\t//\n\t// Other parts of the IPLD library suite (such as the traversal package, and all its functions)\n\t// will typically take a Context as a parameter or piece of config from the caller,\n\t// and will pass that down through the LinkContext, meaning this can be used to\n\t// carry information as well as cancellation control all the way through the system.\n\t//\n\t// BlockWriteOpener is typically not used directly, but is instead\n\t// composed in a LinkSystem and used via the methods of LinkSystem.\n\t// LinkSystem methods will helpfully handle the entire process of traversing a Node tree,\n\t// encoding this data, hashing it, streaming it to the writer, and committing it -- all as one step.\n\t//\n\t// BlockWriteOpener implementations are expected to start writing their content immediately,\n\t// and later, the returned BlockWriteCommitter should also be able to expect that\n\t// the Link which it is given is a reasonable hash of the content.\n\t// (To give an example of how this might be efficiently implemented:\n\t// One might imagine that if implementing a disk storage mechanism,\n\t// the io.Writer returned from a BlockWriteOpener will be writing a new tempfile,\n\t// and when the BlockWriteCommiter is called, it will flush the writes\n\t// and then use a rename operation to place the tempfile in a permanent path based the Link.)\n\t//\n\t// BlockWriteOpener can also be created out of storage.WritableStorage and attached to a LinkSystem\n\t// via the LinkSystem.SetWriteStorage method.\n\tBlockWriteOpener func(LinkContext) (io.Writer, BlockWriteCommitter, error)\n\n\t// BlockWriteCommitter defines the shape of a function which, together\n\t// with BlockWriteOpener, handles the writing and \"committing\" of a write\n\t// to a content-addressable storage system.\n\t//\n\t// BlockWriteCommitter is a function which is will be called at the end of a write process.\n\t// It should flush any buffers and close the io.Writer which was\n\t// made available earlier from the BlockWriteOpener call that also returned this BlockWriteCommitter.\n\t//\n\t// BlockWriteCommitter takes a Link parameter.\n\t// This Link is expected to be a reasonable hash of the content,\n\t// so that the BlockWriteCommitter can use this to commit the data to storage\n\t// in a content-addressable fashion.\n\t// See the documentation of BlockWriteOpener for more description of this\n\t// and an example of how this is likely to be reduced to practice.\n\tBlockWriteCommitter func(datamodel.Link) error\n\n\t// NodeReifier defines the shape of a function that given a node with no schema\n\t// or a basic schema, constructs Advanced Data Layout node\n\t//\n\t// The LinkSystem itself is passed to the NodeReifier along with a link context\n\t// because Node interface methods on an ADL may actually traverse links to other\n\t// pieces of context addressed data that need to be loaded with the Link system\n\t//\n\t// A NodeReifier return one of three things:\n\t// - original node, no error = no reification occurred, just use original node\n\t// - reified node, no error = the simple node was converted to an ADL\n\t// - nil, error = the simple node should have been converted to an ADL but something\n\t// went wrong when we tried to do so\n\t//\n\tNodeReifier func(LinkContext, datamodel.Node, *LinkSystem) (datamodel.Node, error)\n)\n\n// LinkContext is a structure carrying ancilary information that may be used\n// while loading or storing data -- see its usage in BlockReadOpener, BlockWriteOpener,\n// and in the methods on LinkSystem which handle loading and storing data.\n//\n// A zero value for LinkContext is generally acceptable in any functions that use it.\n// In this case, any operations that need a context.Context will quietly use Context.Background\n// (thus being uncancellable) and simply have no additional information to work with.\ntype LinkContext struct {\n\t// Ctx is the familiar golang Context pattern.\n\t// Use this for cancellation, or attaching additional info\n\t// (for example, perhaps to pass auth tokens through to the storage functions).\n\tCtx context.Context\n\n\t// Path where the link was encountered.  May be zero.\n\t//\n\t// Functions in the traversal package will set this automatically.\n\tLinkPath datamodel.Path\n\n\t// When traversing data or encoding: the Node containing the link --\n\t// it may have additional type info, etc, that can be accessed.\n\t// When building / decoding: not present.\n\t//\n\t// Functions in the traversal package will set this automatically.\n\tLinkNode datamodel.Node\n\n\t// When building data or decoding: the NodeAssembler that will be receiving the link --\n\t// it may have additional type info, etc, that can be accessed.\n\t// When traversing / encoding: not present.\n\t//\n\t// Functions in the traversal package will set this automatically.\n\tLinkNodeAssembler datamodel.NodeAssembler\n\n\t// Parent of the LinkNode.  May be zero.\n\t//\n\t// Functions in the traversal package will set this automatically.\n\tParentNode datamodel.Node\n\n\t// REVIEW: ParentNode in LinkContext -- so far, this has only ever been hypothetically useful.  Keep or drop?\n}\n"
  },
  {
    "path": "linking.go",
    "content": "package ipld\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/linking\"\n)\n\ntype (\n\tLinkSystem  = linking.LinkSystem\n\tLinkContext = linking.LinkContext\n)\n\ntype (\n\tBlockReadOpener     = linking.BlockReadOpener\n\tBlockWriteOpener    = linking.BlockWriteOpener\n\tBlockWriteCommitter = linking.BlockWriteCommitter\n\tNodeReifier         = linking.NodeReifier\n)\n"
  },
  {
    "path": "multicodec/defaultRegistry.go",
    "content": "package multicodec\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/codec\"\n)\n\n// DefaultRegistry is a multicodec.Registry instance which is global to the program,\n// and is used as a default set of codecs.\n//\n// Some systems (for example, cidlink.DefaultLinkSystem) will use this default registry,\n// which makes it easier to write programs that pass fewer explicit arguments around.\n// However, these are *only* for default behaviors;\n// variations of functions which allow explicit non-default options should always be available\n// (for example, cidlink also has other LinkSystem constructor functions which accept an explicit multicodec.Registry,\n// and the LookupEncoder and LookupDecoder functions in any LinkSystem can be replaced).\n//\n// Since this registry is global, mind that there are also some necessary tradeoffs and limitations:\n// It can be difficult to control exactly what's present in this global registry\n// (Libraries may register codecs in this registry as a side-effect of importing, so even transitive dependencies can affect its content!).\n// Also, this registry is only considered safe to modify at package init time.\n// If these are concerns for your program, you can create your own multicodec.Registry values,\n// and eschew using the global default.\nvar DefaultRegistry = Registry{}\n\n// RegisterEncoder updates the global DefaultRegistry to map a multicodec indicator number to the given codec.Encoder function.\n// The encoder functions registered can be subsequently looked up using LookupEncoder.\n// It is a shortcut to the RegisterEncoder method on the global DefaultRegistry.\n//\n// Packages which implement an IPLD codec and have a multicodec number associated with them\n// are encouraged to register themselves at package init time using this function.\n// (Doing this at package init time ensures the default global registry is populated\n// without causing race conditions for application code.)\n//\n// No effort is made to detect conflicting registrations in this map.\n// If your dependency tree is such that this becomes a problem,\n// there are two ways to address this:\n// If RegisterEncoder is called with the same indicator code more than once, the last call wins.\n// In practice, this means that if an application has a strong opinion about what implementation for a certain codec,\n// then this can be done by making a Register call with that effect at init time in the application's main package.\n// This should have the desired effect because the root of the import tree has its init time effect last.\n// Alternatively, one can just avoid use of this registry entirely:\n// do this by making a LinkSystem that uses a custom EncoderChooser function.\nfunc RegisterEncoder(indicator uint64, encodeFunc codec.Encoder) {\n\tDefaultRegistry.RegisterEncoder(indicator, encodeFunc)\n}\n\n// LookupEncoder yields a codec.Encoder function matching a multicodec indicator code number.\n// It is a shortcut to the LookupEncoder method on the global DefaultRegistry.\n//\n// To be available from this lookup function, an encoder must have been registered\n// for this indicator number by an earlier call to the RegisterEncoder function.\nfunc LookupEncoder(indicator uint64) (codec.Encoder, error) {\n\treturn DefaultRegistry.LookupEncoder(indicator)\n}\n\n// ListEncoders returns a list of multicodec indicators for which a codec.Encoder is registered.\n// The list is in no particular order.\n// It is a shortcut to the ListEncoders method on the global DefaultRegistry.\n//\n// Be judicious about trying to use this function outside of debugging.\n// Because the global default registry is global and easily modified,\n// and can be changed by any of the transitive dependencies of your program,\n// its contents are not particularly stable.\n// In particular, it is not recommended to make any behaviors of your program conditional\n// based on information returned by this function -- if your program needs conditional\n// behavior based on registered codecs, you may want to consider taking more explicit control\n// and using your own non-default registry.\nfunc ListEncoders() []uint64 {\n\treturn DefaultRegistry.ListEncoders()\n}\n\n// RegisterDecoder updates the global DefaultRegistry a map a multicodec indicator number to the given codec.Decoder function.\n// The decoder functions registered can be subsequently looked up using LookupDecoder.\n// It is a shortcut to the RegisterDecoder method on the global DefaultRegistry.\n//\n// Packages which implement an IPLD codec and have a multicodec number associated with them\n// are encouraged to register themselves in this map at package init time.\n// (Doing this at package init time ensures the default global registry is populated\n// without causing race conditions for application code.)\n//\n// No effort is made to detect conflicting registrations in this map.\n// If your dependency tree is such that this becomes a problem,\n// there are two ways to address this:\n// If RegisterDecoder is called with the same indicator code more than once, the last call wins.\n// In practice, this means that if an application has a strong opinion about what implementation for a certain codec,\n// then this can be done by making a Register call with that effect at init time in the application's main package.\n// This should have the desired effect because the root of the import tree has its init time effect last.\n// Alternatively, one can just avoid use of this registry entirely:\n// do this by making a LinkSystem that uses a custom DecoderChooser function.\nfunc RegisterDecoder(indicator uint64, decodeFunc codec.Decoder) {\n\tDefaultRegistry.RegisterDecoder(indicator, decodeFunc)\n}\n\n// LookupDecoder yields a codec.Decoder function matching a multicodec indicator code number.\n// It is a shortcut to the LookupDecoder method on the global DefaultRegistry.\n//\n// To be available from this lookup function, an decoder must have been registered\n// for this indicator number by an earlier call to the RegisterDecoder function.\nfunc LookupDecoder(indicator uint64) (codec.Decoder, error) {\n\treturn DefaultRegistry.LookupDecoder(indicator)\n}\n\n// ListDecoders returns a list of multicodec indicators for which a codec.Decoder is registered.\n// The list is in no particular order.\n// It is a shortcut to the ListDecoders method on the global DefaultRegistry.\n//\n// Be judicious about trying to use this function outside of debugging.\n// Because the global default registry is global and easily modified,\n// and can be changed by any of the transitive dependencies of your program,\n// its contents are not particularly stable.\n// In particular, it is not recommended to make any behaviors of your program conditional\n// based on information returned by this function -- if your program needs conditional\n// behavior based on registered codecs, you may want to consider taking more explicit control\n// and using your own non-default registry.\nfunc ListDecoders() []uint64 {\n\treturn DefaultRegistry.ListDecoders()\n}\n"
  },
  {
    "path": "multicodec/registry.go",
    "content": "package multicodec\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/codec\"\n)\n\n// Registry is a structure for storing mappings of multicodec indicator numbers to codec.Encoder and codec.Decoder functions.\n//\n// The most typical usage of this structure is in combination with a codec.LinkSystem.\n// For example, a linksystem using CIDs and a custom multicodec registry can be constructed\n// using cidlink.LinkSystemUsingMulticodecRegistry.\n//\n// Registry includes no mutexing.  If using Registry in a concurrent context, you must handle synchronization yourself.\n// (Typically, it is recommended to do initialization earlier in a program, before fanning out goroutines;\n// this avoids the need for mutexing overhead.)\n//\n// go-ipld also has a default registry, which has the same methods as this structure, but are at package scope.\n// Some systems, like cidlink.DefaultLinkSystem, will use this default registry.\n// However, this default registry is global to the entire program.\n// This Registry type is for helping if you wish to make your own registry which does not share that global state.\n//\n// Multicodec indicator numbers are specified in\n// https://github.com/multiformats/multicodec/blob/master/table.csv .\n// You should not use indicator numbers which are not specified in that table\n// (however, there is nothing in this implementation that will attempt to stop you, either; please behave).\ntype Registry struct {\n\tencoders map[uint64]codec.Encoder\n\tdecoders map[uint64]codec.Decoder\n}\n\nfunc (r *Registry) ensureInit() {\n\tif r.encoders != nil {\n\t\treturn\n\t}\n\tr.encoders = make(map[uint64]codec.Encoder)\n\tr.decoders = make(map[uint64]codec.Decoder)\n}\n\n// RegisterEncoder updates a simple map of multicodec indicator number to codec.Encoder function.\n// The encoder functions registered can be subsequently looked up using LookupEncoder.\nfunc (r *Registry) RegisterEncoder(indicator uint64, encodeFunc codec.Encoder) {\n\tr.ensureInit()\n\tif encodeFunc == nil {\n\t\tpanic(\"not sensible to attempt to register a nil function\")\n\t}\n\tr.encoders[indicator] = encodeFunc\n}\n\n// LookupEncoder yields a codec.Encoder function matching a multicodec indicator code number.\n//\n// To be available from this lookup function, an encoder must have been registered\n// for this indicator number by an earlier call to the RegisterEncoder function.\nfunc (r *Registry) LookupEncoder(indicator uint64) (codec.Encoder, error) {\n\tencodeFunc, exists := r.encoders[indicator]\n\tif !exists {\n\t\treturn nil, fmt.Errorf(\"no encoder registered for multicodec code %d (0x%x)\", indicator, indicator)\n\t}\n\treturn encodeFunc, nil\n}\n\n// ListEncoders returns a list of multicodec indicators for which a codec.Encoder is registered.\n// The list is in no particular order.\nfunc (r *Registry) ListEncoders() []uint64 {\n\tencoders := make([]uint64, 0, len(r.encoders))\n\tfor e := range r.encoders {\n\t\tencoders = append(encoders, e)\n\t}\n\treturn encoders\n}\n\n// TODO(mvdan): turn most of these uint64s into multicodec.Code\n\n// RegisterDecoder updates a simple map of multicodec indicator number to codec.Decoder function.\n// The decoder functions registered can be subsequently looked up using LookupDecoder.\nfunc (r *Registry) RegisterDecoder(indicator uint64, decodeFunc codec.Decoder) {\n\tr.ensureInit()\n\tif decodeFunc == nil {\n\t\tpanic(\"not sensible to attempt to register a nil function\")\n\t}\n\tr.decoders[indicator] = decodeFunc\n}\n\n// LookupDecoder yields a codec.Decoder function matching a multicodec indicator code number.\n//\n// To be available from this lookup function, an decoder must have been registered\n// for this indicator number by an earlier call to the RegisterDecoder function.\nfunc (r *Registry) LookupDecoder(indicator uint64) (codec.Decoder, error) {\n\tdecodeFunc, exists := r.decoders[indicator]\n\tif !exists {\n\t\treturn nil, fmt.Errorf(\"no decoder registered for multicodec code %d (0x%x)\", indicator, indicator)\n\t}\n\treturn decodeFunc, nil\n}\n\n// ListDecoders returns a list of multicodec indicators for which a codec.Decoder is registered.\n// The list is in no particular order.\nfunc (r *Registry) ListDecoders() []uint64 {\n\tdecoders := make([]uint64, 0, len(r.decoders))\n\tfor d := range r.decoders {\n\t\tdecoders = append(decoders, d)\n\t}\n\treturn decoders\n}\n"
  },
  {
    "path": "must/must.go",
    "content": "// Package 'must' provides another alternative to the 'fluent' package,\n// providing many helpful functions for wrapping methods with multiple returns\n// into a single return (converting errors into panics).\n//\n// It's useful especially for testing code and other situations where panics\n// are not problematic.\n//\n// Unlike the 'fluent' package, panics are not of any particular type.\n// There is no equivalent to the `fluent.Recover` feature in the 'must' package.\n//\n// Because golang supports implied destructuring of multiple-return functions\n// into arguments for another funtion of matching arity, most of the 'must'\n// functions can used smoothly in a pointfree/chainable form, like this:\n//\n//\tmust.Node(SomeNodeBuilder{}.CreateString(\"a\"))\npackage must\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// must.NotError simply panics if given an error.\n// It helps turn multi-line code into one-liner code in situations where\n// you simply don't care.\nfunc NotError(e error) {\n\tif e != nil {\n\t\tpanic(e)\n\t}\n}\n\n// must.Node helps write pointfree/chainable-style code\n// by taking a Node and an error and transforming any error into a panic.\n//\n// Because golang supports implied destructuring of multiple-return functions\n// into arguments for another funtion of matching arity, it can be used like this:\n//\n//\tmust.Node(SomeNodeBuilder{}.CreateString(\"a\"))\nfunc Node(n datamodel.Node, e error) datamodel.Node {\n\tif e != nil {\n\t\tpanic(e)\n\t}\n\treturn n\n}\n\n// must.TypedNode helps write pointfree/chainable-style code\n// by taking a Node and an error and transforming any error into a panic.\n// It will also cast the `datamodel.Node` to a `schema.TypedNode`, panicking if impossible.\n//\n// Because golang supports implied destructuring of multiple-return functions\n// into arguments for another funtion of matching arity, it can be used like this:\n//\n//\tmust.TypedNode(SomeNodeBuilder{}.CreateString(\"a\"))\nfunc TypedNode(n datamodel.Node, e error) schema.TypedNode {\n\tif e != nil {\n\t\tpanic(e)\n\t}\n\treturn n.(schema.TypedNode)\n}\n\n// must.True panics if the given bool is false.\nfunc True(v bool) {\n\tif !v {\n\t\tpanic(\"must.True\")\n\t}\n}\n\n// must.String unboxes the given Node via AsString,\n// panicking in the case that the Node isn't of string kind,\n// and otherwise returning the bare native string.\nfunc String(n datamodel.Node) string {\n\tif v, err := n.AsString(); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\treturn v\n\t}\n}\n\n// must.Int unboxes the given Node via AsInt,\n// panicking in the case that the Node isn't of int kind,\n// and otherwise returning the bare native int.\nfunc Int(n datamodel.Node) int64 {\n\tif v, err := n.AsInt(); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\treturn v\n\t}\n}\n"
  },
  {
    "path": "node/basic/deprecated.go",
    "content": "// This is a transitional package: please move your references to `node/basicnode`.\n// The new package is identical: we've renamed the import path only.\n//\n// All content in this package is a thin wrapper around `node/basicnode`.\n// Please update at your earliest convenience.\n//\n// This package will eventually be removed.\npackage basicnode\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nvar Prototype = basicnode.Prototype\n\nfunc Chooser(_ datamodel.Link, _ linking.LinkContext) (datamodel.NodePrototype, error) {\n\treturn basicnode.Chooser(nil, linking.LinkContext{})\n}\nfunc NewBool(value bool) datamodel.Node           { return basicnode.NewBool(value) }\nfunc NewBytes(value []byte) datamodel.Node        { return basicnode.NewBytes(value) }\nfunc NewFloat(value float64) datamodel.Node       { return basicnode.NewFloat(value) }\nfunc NewInt(value int64) datamodel.Node           { return basicnode.NewInt(value) }\nfunc NewLink(value datamodel.Link) datamodel.Node { return basicnode.NewLink(value) }\nfunc NewString(value string) datamodel.Node       { return basicnode.NewString(value) }\n\ntype Prototype__Any = basicnode.Prototype__Any\ntype Prototype__Bool = basicnode.Prototype__Bool\ntype Prototype__Bytes = basicnode.Prototype__Bytes\ntype Prototype__Float = basicnode.Prototype__Float\ntype Prototype__Int = basicnode.Prototype__Int\ntype Prototype__Link = basicnode.Prototype__Link\ntype Prototype__List = basicnode.Prototype__List\ntype Prototype__Map = basicnode.Prototype__Map\ntype Prototype__String = basicnode.Prototype__String\n"
  },
  {
    "path": "node/basicnode/HACKME.md",
    "content": "hackme\n======\n\nDesign rationale are documented here.\n\nThis doc is not necessary reading for users of this package,\nbut if you're considering submitting patches -- or just trying to understand\nwhy it was written this way, and check for reasoning that might be dated --\nthen it might be useful reading.\n\n### scalars are just typedefs\n\nThis is noteworthy because in codegen, this is typically *not* the case:\nin codegen, even scalar types are boxed in a struct, such that it prevents\ncasting values into those types.\n\nThis casting is not a concern for the node implementations in this package, because\n\n- A) we don't have any kind of validation rules to make such casting worrying; and\n- B) since our types are unexported, casting is still blocked by this anyway.\n\n### about builders for scalars\n\nThe assembler types for scalars (string, int, etc) are pretty funny-looking.\nYou might wish to make them work without any state at all!\n\nThe reason this doesn't fly is that we have to keep the \"wip\" value in hand\njust long enough to return it from the `NodeBuilder.Build` method -- the\n`NodeAssembler` contract for `Assign*` methods doesn't permit just returning\ntheir results immediately.\n\n(Another possible reason is if we expected to use these assemblers on\nslab-style allocations (say, `[]plainString`)...\nhowever, this is inapplicable at present, because\nA) we don't (except places that have special-case internal paths anyway); and\nB) the types aren't exported, so users can't either.)\n\nDoes this mean that using `NodeBuilder` for scalars has a completely\nunnecessary second allocation, which is laughably inefficient?  Yes.\nIt's unfortunate the interfaces constrain us to this.\n**But**: one typically doesn't actually use builders for scalars much;\nthey're just here for completeness.\nSo this is less of a problem in practice than it might at first seem.\n\nMore often, one will use the \"any\" builder (which is has a whole different set\nof design constraints and tradeoffs);\nor, if one is writing code and knows which scalar they need, the exported\ndirect constructor function for that kind\n(e.g., `String(\"foo\")` instead of `Prototype__String{}.NewBuilder().AssignString(\"foo\")`)\nwill do the right thing and do it in one allocation (and it's less to type, too).\n\n### maps and list keyAssembler and valueAssemblers have custom scalar handling\n\nRelated to the above heading.\n\nMaps and lists in this package do their own internal handling of scalars,\nusing unexported features inside the package, because they can more efficient.\n\n### when to invalidate the 'w' pointers\n\nThe 'w' pointer -- short for 'wip' node pointer -- has an interesting lifecycle.\n\nIn a NodeAssembler, the 'w' pointer should be intialized before the assembler is used.\nThis means either the matching NodeBuilder type does so; or,\nif we're inside recursive structure, the parent assembler did so.\n\nThe 'w' pointer is used throughout the life of the assembler.\n\nSetting the 'w' pointer to nil is one of two mechanisms used internally\nto mark that assembly has become \"finished\" (the other mechanism is using\nan internal state enum field).\nSetting the 'w' pointer to nil has two advantages:\none is that it makes it *impossible* to continue to mutate the target node;\nthe other is that we need no *additional* memory to track this state change.\nHowever, we can't use the strategy of nilling 'w' in all cases: in particular,\nwhen in the NodeBuilder at the root of some construction,\nwe need to continue to hold onto the node between when it becomes \"finished\"\nand when Build is called; otherwise we can't actually return the value!\nDifferent stratgies are therefore used in different parts of this package.\n\nMaps and lists use an internal state enum, because they already have one,\nand so they might as well; there's no additional cost to this.\nSince they can use this state to guard against additional mutations after \"finish\",\nthe map and list assemblers don't bother to nil their own 'w' at all.\n\nDuring recursion to assemble values _inside_ maps and lists, it's interesting:\nthe child assembler wrapper type takes reponsibility for nilling out\nthe 'w' pointer in the child assembler's state, doing this at the same time as\nit updates the parent's state machine to clear proceeding with the next entry.\n\nIn the case of scalars at the root of a build, we took a shortcut:\nwe actually don't fence against repeat mutations at all.\n*You can actually use the assign method more than once*.\nWe can do this without breaking safety contracts because the scalars\nall have a pass-by-value phase somewhere in their lifecycle\n(calling `nb.AssignString(\"x\")`, then `n := nb.Build()`, then `nb.AssignString(\"y\")`\nwon't error if `nb` is a freestanding builder for strings... but it also\nwon't result in mutating `n` to contain `\"y\"`, so overall, it's safe).\n\nWe could normalize the case with scalars at the root of a tree so that they\nerror more aggressively... but currently we haven't bothered, since this would\nrequire adding another piece of memory to the scalar builders; and meanwhile\nwe're not in trouble on compositional correctness.\n\nNote that these remarks are for the `basicnode` package, but may also\napply to other implementations too (e.g., our codegen output follows similar\noverall logic).\n\n### NodePrototypes are available through a singleton\n\nEvery NodePrototype available from this package is exposed as a field\nin a struct of which there's one public exported instance available,\ncalled 'Prototype'.\n\nThis means you can use it like this:\n\n```go\nnbm := basicnode.Prototype.Map.NewBuilder()\nnbs := basicnode.Prototype.String.NewBuilder()\nnba := basicnode.Prototype.Any.NewBuilder()\n// etc\n```\n\n(If you're interested in the performance of this: it's free!\nMethods called at the end of the chain are inlinable.\nSince all of the types of the structures on the way there are zero-member\nstructs, the compiler can effectively treat them as constants,\nand thus freely elide any memory dereferences that would\notherwise be necessary to get methods on such a value.)\n\n### NodePrototypes are (also) available as exported concrete types\n\nThe 'Prototype' singleton is one way to access the NodePrototype in this package;\ntheir exported types are another equivalent way.\n\n```go\nbasicnode.Prototype.Map = basicnode.Prototype.Map\n```\n\nIt is recommended to use the singleton style;\nthey compile to identical assembly, and the singleton is syntactically prettier.\n\nWe may make these concrete types unexported in the future.\nA decision on this is deferred until some time has passed and\nwe can accumulate reasonable certainty that there's no need for an exported type\n(such as type assertions, etc).\n"
  },
  {
    "path": "node/basicnode/any.go",
    "content": "package basicnode\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n)\n\nvar (\n\t//_ datamodel.Node          = &anyNode{}\n\t_ datamodel.NodePrototype = Prototype__Any{}\n\t_ datamodel.NodeBuilder   = &anyBuilder{}\n\t//_ datamodel.NodeAssembler = &anyAssembler{}\n)\n\n// Note that we don't use a \"var _\" declaration to assert that Chooser\n// implements traversal.LinkTargetNodePrototypeChooser, to keep basicnode's\n// dependencies fairly light.\n\n// Chooser implements traversal.LinkTargetNodePrototypeChooser.\n//\n// It can be used directly when loading links into the \"any\" prototype,\n// or with another chooser layer on top, such as:\n//\n//\tprototypeChooser := dagpb.AddSupportToChooser(basicnode.Chooser)\nfunc Chooser(_ datamodel.Link, _ linking.LinkContext) (datamodel.NodePrototype, error) {\n\treturn Prototype.Any, nil\n}\n\n// -- Node interface methods -->\n\n// Unimplemented at present -- see \"REVIEW\" comment on anyNode.\n\n// -- NodePrototype -->\n\ntype Prototype__Any struct{}\n\nfunc (Prototype__Any) NewBuilder() datamodel.NodeBuilder {\n\treturn &anyBuilder{}\n}\n\n// -- NodeBuilder -->\n\n// anyBuilder is a builder for any kind of node.\n//\n// anyBuilder is a little unusual in its internal workings:\n// unlike most builders, it doesn't embed the corresponding assembler,\n// nor will it end up using anyNode,\n// but instead embeds a builder for each of the kinds it might contain.\n// This is because we want a more granular return at the end:\n// if we used anyNode, and returned a pointer to just the relevant part of it,\n// we'd have all the extra bytes of anyNode still reachable in GC terms\n// for as long as that handle to the interior of it remains live.\ntype anyBuilder struct {\n\t// kind is set on first interaction, and used to select which builder to delegate 'Build' to!\n\t// As soon as it's been set to a value other than zero (being \"Invalid\"), all other Assign/Begin calls will fail since something is already in progress.\n\t// May also be set to the magic value '99', which means \"i dunno, I'm just carrying another node of unknown prototype\".\n\tkind datamodel.Kind\n\n\t// Only one of the following ends up being used...\n\t//  but we don't know in advance which one, so all are embeded here.\n\t//   This uses excessive space, but amortizes allocations, and all will be\n\t//    freed as soon as the builder is done.\n\t// Builders are only used for recursives;\n\t//  scalars are simple enough we just do them directly.\n\t// 'scalarNode' may also hold another Node of unknown prototype (possibly not even from this package),\n\t//  in which case this is indicated by 'kind==99'.\n\n\tmapBuilder  plainMap__Builder\n\tlistBuilder plainList__Builder\n\tscalarNode  datamodel.Node\n}\n\nfunc (nb *anyBuilder) Reset() {\n\t*nb = anyBuilder{}\n}\n\nfunc (nb *anyBuilder) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\tif nb.kind != datamodel.Kind_Invalid {\n\t\tpanic(\"misuse\")\n\t}\n\tnb.kind = datamodel.Kind_Map\n\tnb.mapBuilder.w = &plainMap{}\n\treturn nb.mapBuilder.BeginMap(sizeHint)\n}\nfunc (nb *anyBuilder) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\tif nb.kind != datamodel.Kind_Invalid {\n\t\tpanic(\"misuse\")\n\t}\n\tnb.kind = datamodel.Kind_List\n\tnb.listBuilder.w = &plainList{}\n\treturn nb.listBuilder.BeginList(sizeHint)\n}\nfunc (nb *anyBuilder) AssignNull() error {\n\tif nb.kind != datamodel.Kind_Invalid {\n\t\tpanic(\"misuse\")\n\t}\n\tnb.kind = datamodel.Kind_Null\n\treturn nil\n}\nfunc (nb *anyBuilder) AssignBool(v bool) error {\n\tif nb.kind != datamodel.Kind_Invalid {\n\t\tpanic(\"misuse\")\n\t}\n\tnb.kind = datamodel.Kind_Bool\n\tnb.scalarNode = NewBool(v)\n\treturn nil\n}\nfunc (nb *anyBuilder) AssignInt(v int64) error {\n\tif nb.kind != datamodel.Kind_Invalid {\n\t\tpanic(\"misuse\")\n\t}\n\tnb.kind = datamodel.Kind_Int\n\tnb.scalarNode = NewInt(v)\n\treturn nil\n}\nfunc (nb *anyBuilder) AssignFloat(v float64) error {\n\tif nb.kind != datamodel.Kind_Invalid {\n\t\tpanic(\"misuse\")\n\t}\n\tnb.kind = datamodel.Kind_Float\n\tnb.scalarNode = NewFloat(v)\n\treturn nil\n}\nfunc (nb *anyBuilder) AssignString(v string) error {\n\tif nb.kind != datamodel.Kind_Invalid {\n\t\tpanic(\"misuse\")\n\t}\n\tnb.kind = datamodel.Kind_String\n\tnb.scalarNode = NewString(v)\n\treturn nil\n}\nfunc (nb *anyBuilder) AssignBytes(v []byte) error {\n\tif nb.kind != datamodel.Kind_Invalid {\n\t\tpanic(\"misuse\")\n\t}\n\tnb.kind = datamodel.Kind_Bytes\n\tnb.scalarNode = NewBytes(v)\n\treturn nil\n}\nfunc (nb *anyBuilder) AssignLink(v datamodel.Link) error {\n\tif nb.kind != datamodel.Kind_Invalid {\n\t\tpanic(\"misuse\")\n\t}\n\tnb.kind = datamodel.Kind_Link\n\tnb.scalarNode = NewLink(v)\n\treturn nil\n}\nfunc (nb *anyBuilder) AssignNode(v datamodel.Node) error {\n\tif nb.kind != datamodel.Kind_Invalid {\n\t\tpanic(\"misuse\")\n\t}\n\tnb.kind = 99\n\tnb.scalarNode = v\n\treturn nil\n}\nfunc (anyBuilder) Prototype() datamodel.NodePrototype {\n\treturn Prototype.Any\n}\n\nfunc (nb *anyBuilder) Build() datamodel.Node {\n\tswitch nb.kind {\n\tcase datamodel.Kind_Invalid:\n\t\tpanic(\"misuse\")\n\tcase datamodel.Kind_Map:\n\t\treturn nb.mapBuilder.Build()\n\tcase datamodel.Kind_List:\n\t\treturn nb.listBuilder.Build()\n\tcase datamodel.Kind_Null:\n\t\treturn datamodel.Null\n\tcase datamodel.Kind_Bool:\n\t\treturn nb.scalarNode\n\tcase datamodel.Kind_Int:\n\t\treturn nb.scalarNode\n\tcase datamodel.Kind_Float:\n\t\treturn nb.scalarNode\n\tcase datamodel.Kind_String:\n\t\treturn nb.scalarNode\n\tcase datamodel.Kind_Bytes:\n\t\treturn nb.scalarNode\n\tcase datamodel.Kind_Link:\n\t\treturn nb.scalarNode\n\tcase 99:\n\t\treturn nb.scalarNode\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\n\n// -- NodeAssembler -->\n\n// ... oddly enough, we seem to be able to put off implementing this\n//  until we also implement something that goes full-hog on amortization\n//   and actually has a slab of `anyNode`.  Which so far, nothing does.\n//    See \"REVIEW\" comment on anyNode.\n// type anyAssembler struct {\n// \tw *anyNode\n// }\n"
  },
  {
    "path": "node/basicnode/any_test.go",
    "content": "package basicnode_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nfunc TestAnyBeingString(t *testing.T) {\n\ttests.SpecTestString(t, basicnode.Prototype.Any)\n}\n\nfunc TestAnyBeingMapStrInt(t *testing.T) {\n\ttests.SpecTestMapStrInt(t, basicnode.Prototype.Any)\n}\n\nfunc TestAnyBeingMapStrMapStrInt(t *testing.T) {\n\ttests.SpecTestMapStrMapStrInt(t, basicnode.Prototype.Any)\n}\n"
  },
  {
    "path": "node/basicnode/bench_test.go",
    "content": "package basicnode_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nfunc BenchmarkSpec_Walk_Map3StrInt(b *testing.B) {\n\ttests.BenchmarkSpec_Walk_Map3StrInt(b, basicnode.Prototype.Any)\n}\n\nfunc BenchmarkSpec_Walk_MapNStrMap3StrInt(b *testing.B) {\n\ttests.BenchmarkSpec_Walk_MapNStrMap3StrInt(b, basicnode.Prototype.Any)\n}\n"
  },
  {
    "path": "node/basicnode/bool.go",
    "content": "package basicnode\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/mixins\"\n)\n\nvar (\n\t_ datamodel.Node          = plainBool(false)\n\t_ datamodel.NodePrototype = Prototype__Bool{}\n\t_ datamodel.NodeBuilder   = &plainBool__Builder{}\n\t_ datamodel.NodeAssembler = &plainBool__Assembler{}\n)\n\nfunc NewBool(value bool) datamodel.Node {\n\tv := plainBool(value)\n\treturn &v\n}\n\n// plainBool is a simple boxed boolean that complies with datamodel.Node.\ntype plainBool bool\n\n// -- Node interface methods -->\n\nfunc (plainBool) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Bool\n}\nfunc (plainBool) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.Bool{TypeName: \"bool\"}.LookupByString(\"\")\n}\nfunc (plainBool) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.Bool{TypeName: \"bool\"}.LookupByNode(nil)\n}\nfunc (plainBool) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Bool{TypeName: \"bool\"}.LookupByIndex(0)\n}\nfunc (plainBool) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.Bool{TypeName: \"bool\"}.LookupBySegment(seg)\n}\nfunc (plainBool) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (plainBool) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (plainBool) Length() int64 {\n\treturn -1\n}\nfunc (plainBool) IsAbsent() bool {\n\treturn false\n}\nfunc (plainBool) IsNull() bool {\n\treturn false\n}\nfunc (n plainBool) AsBool() (bool, error) {\n\treturn bool(n), nil\n}\nfunc (plainBool) AsInt() (int64, error) {\n\treturn mixins.Bool{TypeName: \"bool\"}.AsInt()\n}\nfunc (plainBool) AsFloat() (float64, error) {\n\treturn mixins.Bool{TypeName: \"bool\"}.AsFloat()\n}\nfunc (plainBool) AsString() (string, error) {\n\treturn mixins.Bool{TypeName: \"bool\"}.AsString()\n}\nfunc (plainBool) AsBytes() ([]byte, error) {\n\treturn mixins.Bool{TypeName: \"bool\"}.AsBytes()\n}\nfunc (plainBool) AsLink() (datamodel.Link, error) {\n\treturn mixins.Bool{TypeName: \"bool\"}.AsLink()\n}\nfunc (plainBool) Prototype() datamodel.NodePrototype {\n\treturn Prototype__Bool{}\n}\n\n// -- NodePrototype -->\n\ntype Prototype__Bool struct{}\n\nfunc (Prototype__Bool) NewBuilder() datamodel.NodeBuilder {\n\tvar w plainBool\n\treturn &plainBool__Builder{plainBool__Assembler{w: &w}}\n}\n\n// -- NodeBuilder -->\n\ntype plainBool__Builder struct {\n\tplainBool__Assembler\n}\n\nfunc (nb *plainBool__Builder) Build() datamodel.Node {\n\treturn nb.w\n}\nfunc (nb *plainBool__Builder) Reset() {\n\tvar w plainBool\n\t*nb = plainBool__Builder{plainBool__Assembler{w: &w}}\n}\n\n// -- NodeAssembler -->\n\ntype plainBool__Assembler struct {\n\tw *plainBool\n}\n\nfunc (plainBool__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.BoolAssembler{TypeName: \"bool\"}.BeginMap(0)\n}\nfunc (plainBool__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.BoolAssembler{TypeName: \"bool\"}.BeginList(0)\n}\nfunc (plainBool__Assembler) AssignNull() error {\n\treturn mixins.BoolAssembler{TypeName: \"bool\"}.AssignNull()\n}\nfunc (na *plainBool__Assembler) AssignBool(v bool) error {\n\t*na.w = plainBool(v)\n\treturn nil\n}\nfunc (plainBool__Assembler) AssignInt(int64) error {\n\treturn mixins.BoolAssembler{TypeName: \"bool\"}.AssignInt(0)\n}\nfunc (plainBool__Assembler) AssignFloat(float64) error {\n\treturn mixins.BoolAssembler{TypeName: \"bool\"}.AssignFloat(0)\n}\nfunc (plainBool__Assembler) AssignString(string) error {\n\treturn mixins.BoolAssembler{TypeName: \"bool\"}.AssignString(\"\")\n}\nfunc (plainBool__Assembler) AssignBytes([]byte) error {\n\treturn mixins.BoolAssembler{TypeName: \"bool\"}.AssignBytes(nil)\n}\nfunc (plainBool__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.BoolAssembler{TypeName: \"bool\"}.AssignLink(nil)\n}\nfunc (na *plainBool__Assembler) AssignNode(v datamodel.Node) error {\n\tif v2, err := v.AsBool(); err != nil {\n\t\treturn err\n\t} else {\n\t\t*na.w = plainBool(v2)\n\t\treturn nil\n\t}\n}\nfunc (plainBool__Assembler) Prototype() datamodel.NodePrototype {\n\treturn Prototype__Bool{}\n}\n"
  },
  {
    "path": "node/basicnode/bytes.go",
    "content": "package basicnode\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/mixins\"\n)\n\nvar (\n\t_ datamodel.Node          = plainBytes(nil)\n\t_ datamodel.NodePrototype = Prototype__Bytes{}\n\t_ datamodel.NodeBuilder   = &plainBytes__Builder{}\n\t_ datamodel.NodeAssembler = &plainBytes__Assembler{}\n)\n\nfunc NewBytes(value []byte) datamodel.Node {\n\tv := plainBytes(value)\n\treturn &v\n}\n\n// plainBytes is a simple boxed byte slice that complies with datamodel.Node.\ntype plainBytes []byte\n\n// -- Node interface methods -->\n\nfunc (plainBytes) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Bytes\n}\nfunc (plainBytes) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.LookupByString(\"\")\n}\nfunc (plainBytes) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.LookupByNode(nil)\n}\nfunc (plainBytes) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.LookupByIndex(0)\n}\nfunc (plainBytes) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.LookupBySegment(seg)\n}\nfunc (plainBytes) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (plainBytes) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (plainBytes) Length() int64 {\n\treturn -1\n}\nfunc (plainBytes) IsAbsent() bool {\n\treturn false\n}\nfunc (plainBytes) IsNull() bool {\n\treturn false\n}\nfunc (plainBytes) AsBool() (bool, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsBool()\n}\nfunc (plainBytes) AsInt() (int64, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsInt()\n}\nfunc (plainBytes) AsFloat() (float64, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsFloat()\n}\nfunc (plainBytes) AsString() (string, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsString()\n}\nfunc (n plainBytes) AsBytes() ([]byte, error) {\n\treturn []byte(n), nil\n}\nfunc (plainBytes) AsLink() (datamodel.Link, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsLink()\n}\nfunc (plainBytes) Prototype() datamodel.NodePrototype {\n\treturn Prototype__Bytes{}\n}\nfunc (n plainBytes) AsLargeBytes() (io.ReadSeeker, error) {\n\treturn bytes.NewReader(n), nil\n}\n\n// -- NodePrototype -->\n\ntype Prototype__Bytes struct{}\n\nfunc (Prototype__Bytes) NewBuilder() datamodel.NodeBuilder {\n\tvar w plainBytes\n\treturn &plainBytes__Builder{plainBytes__Assembler{w: &w}}\n}\n\n// -- NodeBuilder -->\n\ntype plainBytes__Builder struct {\n\tplainBytes__Assembler\n}\n\nfunc (nb *plainBytes__Builder) Build() datamodel.Node {\n\treturn nb.w\n}\nfunc (nb *plainBytes__Builder) Reset() {\n\tvar w plainBytes\n\t*nb = plainBytes__Builder{plainBytes__Assembler{w: &w}}\n}\n\n// -- NodeAssembler -->\n\ntype plainBytes__Assembler struct {\n\tw datamodel.Node\n}\n\nfunc (plainBytes__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.BytesAssembler{TypeName: \"bytes\"}.BeginMap(0)\n}\nfunc (plainBytes__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.BytesAssembler{TypeName: \"bytes\"}.BeginList(0)\n}\nfunc (plainBytes__Assembler) AssignNull() error {\n\treturn mixins.BytesAssembler{TypeName: \"bytes\"}.AssignNull()\n}\nfunc (plainBytes__Assembler) AssignBool(bool) error {\n\treturn mixins.BytesAssembler{TypeName: \"bytes\"}.AssignBool(false)\n}\nfunc (plainBytes__Assembler) AssignInt(int64) error {\n\treturn mixins.BytesAssembler{TypeName: \"bytes\"}.AssignInt(0)\n}\nfunc (plainBytes__Assembler) AssignFloat(float64) error {\n\treturn mixins.BytesAssembler{TypeName: \"bytes\"}.AssignFloat(0)\n}\nfunc (plainBytes__Assembler) AssignString(string) error {\n\treturn mixins.BytesAssembler{TypeName: \"bytes\"}.AssignString(\"\")\n}\nfunc (na *plainBytes__Assembler) AssignBytes(v []byte) error {\n\tna.w = datamodel.Node(plainBytes(v))\n\treturn nil\n}\nfunc (plainBytes__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.BytesAssembler{TypeName: \"bytes\"}.AssignLink(nil)\n}\nfunc (na *plainBytes__Assembler) AssignNode(v datamodel.Node) error {\n\tif lb, ok := v.(datamodel.LargeBytesNode); ok {\n\t\tlbn, err := lb.AsLargeBytes()\n\t\tif err == nil {\n\t\t\tna.w = streamBytes{lbn}\n\t\t\treturn nil\n\t\t}\n\t}\n\tif v2, err := v.AsBytes(); err != nil {\n\t\treturn err\n\t} else {\n\t\tna.w = plainBytes(v2)\n\t\treturn nil\n\t}\n}\nfunc (plainBytes__Assembler) Prototype() datamodel.NodePrototype {\n\treturn Prototype__Bytes{}\n}\n"
  },
  {
    "path": "node/basicnode/bytes_stream.go",
    "content": "package basicnode\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/mixins\"\n)\n\nvar (\n\t_ datamodel.Node          = streamBytes{nil}\n\t_ datamodel.NodePrototype = Prototype__Bytes{}\n\t_ datamodel.NodeBuilder   = &plainBytes__Builder{}\n\t_ datamodel.NodeAssembler = &plainBytes__Assembler{}\n)\n\nfunc NewBytesFromReader(rs io.ReadSeeker) datamodel.Node {\n\treturn streamBytes{rs}\n}\n\n// streamBytes is a boxed reader that complies with datamodel.Node.\ntype streamBytes struct {\n\tio.ReadSeeker\n}\n\n// -- Node interface methods -->\n\nfunc (streamBytes) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Bytes\n}\nfunc (streamBytes) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.LookupByString(\"\")\n}\nfunc (streamBytes) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.LookupByNode(nil)\n}\nfunc (streamBytes) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.LookupByIndex(0)\n}\nfunc (streamBytes) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.LookupBySegment(seg)\n}\nfunc (streamBytes) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (streamBytes) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (streamBytes) Length() int64 {\n\treturn -1\n}\nfunc (streamBytes) IsAbsent() bool {\n\treturn false\n}\nfunc (streamBytes) IsNull() bool {\n\treturn false\n}\nfunc (streamBytes) AsBool() (bool, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsBool()\n}\nfunc (streamBytes) AsInt() (int64, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsInt()\n}\nfunc (streamBytes) AsFloat() (float64, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsFloat()\n}\nfunc (streamBytes) AsString() (string, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsString()\n}\nfunc (n streamBytes) AsBytes() ([]byte, error) {\n\treturn io.ReadAll(n)\n}\nfunc (streamBytes) AsLink() (datamodel.Link, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsLink()\n}\nfunc (streamBytes) Prototype() datamodel.NodePrototype {\n\treturn Prototype__Bytes{}\n}\nfunc (n streamBytes) AsLargeBytes() (io.ReadSeeker, error) {\n\treturn n.ReadSeeker, nil\n}\n"
  },
  {
    "path": "node/basicnode/bytes_test.go",
    "content": "package basicnode_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nfunc TestBytes(t *testing.T) {\n\ttests.SpecTestBytes(t, basicnode.Prototype__Bytes{})\n}\n"
  },
  {
    "path": "node/basicnode/float.go",
    "content": "package basicnode\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/mixins\"\n)\n\nvar (\n\t_ datamodel.Node          = plainFloat(0)\n\t_ datamodel.NodePrototype = Prototype__Float{}\n\t_ datamodel.NodeBuilder   = &plainFloat__Builder{}\n\t_ datamodel.NodeAssembler = &plainFloat__Assembler{}\n)\n\nfunc NewFloat(value float64) datamodel.Node {\n\tv := plainFloat(value)\n\treturn &v\n}\n\n// plainFloat is a simple boxed float that complies with datamodel.Node.\ntype plainFloat float64\n\n// -- Node interface methods -->\n\nfunc (plainFloat) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Float\n}\nfunc (plainFloat) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.Float{TypeName: \"float\"}.LookupByString(\"\")\n}\nfunc (plainFloat) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.Float{TypeName: \"float\"}.LookupByNode(nil)\n}\nfunc (plainFloat) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Float{TypeName: \"float\"}.LookupByIndex(0)\n}\nfunc (plainFloat) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.Float{TypeName: \"float\"}.LookupBySegment(seg)\n}\nfunc (plainFloat) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (plainFloat) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (plainFloat) Length() int64 {\n\treturn -1\n}\nfunc (plainFloat) IsAbsent() bool {\n\treturn false\n}\nfunc (plainFloat) IsNull() bool {\n\treturn false\n}\nfunc (plainFloat) AsBool() (bool, error) {\n\treturn mixins.Float{TypeName: \"float\"}.AsBool()\n}\nfunc (plainFloat) AsInt() (int64, error) {\n\treturn mixins.Float{TypeName: \"float\"}.AsInt()\n}\nfunc (n plainFloat) AsFloat() (float64, error) {\n\treturn float64(n), nil\n}\nfunc (plainFloat) AsString() (string, error) {\n\treturn mixins.Float{TypeName: \"float\"}.AsString()\n}\nfunc (plainFloat) AsBytes() ([]byte, error) {\n\treturn mixins.Float{TypeName: \"float\"}.AsBytes()\n}\nfunc (plainFloat) AsLink() (datamodel.Link, error) {\n\treturn mixins.Float{TypeName: \"float\"}.AsLink()\n}\nfunc (plainFloat) Prototype() datamodel.NodePrototype {\n\treturn Prototype__Float{}\n}\n\n// -- NodePrototype -->\n\ntype Prototype__Float struct{}\n\nfunc (Prototype__Float) NewBuilder() datamodel.NodeBuilder {\n\tvar w plainFloat\n\treturn &plainFloat__Builder{plainFloat__Assembler{w: &w}}\n}\n\n// -- NodeBuilder -->\n\ntype plainFloat__Builder struct {\n\tplainFloat__Assembler\n}\n\nfunc (nb *plainFloat__Builder) Build() datamodel.Node {\n\treturn nb.w\n}\nfunc (nb *plainFloat__Builder) Reset() {\n\tvar w plainFloat\n\t*nb = plainFloat__Builder{plainFloat__Assembler{w: &w}}\n}\n\n// -- NodeAssembler -->\n\ntype plainFloat__Assembler struct {\n\tw *plainFloat\n}\n\nfunc (plainFloat__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.FloatAssembler{TypeName: \"float\"}.BeginMap(0)\n}\nfunc (plainFloat__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.FloatAssembler{TypeName: \"float\"}.BeginList(0)\n}\nfunc (plainFloat__Assembler) AssignNull() error {\n\treturn mixins.FloatAssembler{TypeName: \"float\"}.AssignNull()\n}\nfunc (plainFloat__Assembler) AssignBool(bool) error {\n\treturn mixins.FloatAssembler{TypeName: \"float\"}.AssignBool(false)\n}\nfunc (plainFloat__Assembler) AssignInt(int64) error {\n\treturn mixins.FloatAssembler{TypeName: \"float\"}.AssignInt(0)\n}\nfunc (na *plainFloat__Assembler) AssignFloat(v float64) error {\n\t*na.w = plainFloat(v)\n\treturn nil\n}\nfunc (plainFloat__Assembler) AssignString(string) error {\n\treturn mixins.FloatAssembler{TypeName: \"float\"}.AssignString(\"\")\n}\nfunc (plainFloat__Assembler) AssignBytes([]byte) error {\n\treturn mixins.FloatAssembler{TypeName: \"float\"}.AssignBytes(nil)\n}\nfunc (plainFloat__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.FloatAssembler{TypeName: \"float\"}.AssignLink(nil)\n}\nfunc (na *plainFloat__Assembler) AssignNode(v datamodel.Node) error {\n\tif v2, err := v.AsFloat(); err != nil {\n\t\treturn err\n\t} else {\n\t\t*na.w = plainFloat(v2)\n\t\treturn nil\n\t}\n}\nfunc (plainFloat__Assembler) Prototype() datamodel.NodePrototype {\n\treturn Prototype__Float{}\n}\n"
  },
  {
    "path": "node/basicnode/int.go",
    "content": "package basicnode\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/mixins\"\n)\n\nvar (\n\t_ datamodel.Node          = plainInt(0)\n\t_ datamodel.Node          = plainUint(0)\n\t_ datamodel.UintNode      = plainUint(0)\n\t_ datamodel.NodePrototype = Prototype__Int{}\n\t_ datamodel.NodeBuilder   = &plainInt__Builder{}\n\t_ datamodel.NodeAssembler = &plainInt__Assembler{}\n)\n\nfunc NewInt(value int64) datamodel.Node {\n\tv := plainInt(value)\n\treturn &v\n}\n\n// NewUint creates a new uint64-backed Node which will behave as a plain Int\n// node but also conforms to the datamodel.UintNode interface which can access\n// the full uint64 range.\n//\n// EXPERIMENTAL: this API is experimental and may be changed or removed in a\n// future release.\nfunc NewUint(value uint64) datamodel.Node {\n\treturn plainUint(value)\n}\n\n// plainInt is a simple boxed int that complies with datamodel.Node.\ntype plainInt int64\n\n// -- Node interface methods for plainInt -->\n\nfunc (plainInt) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Int\n}\nfunc (plainInt) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupByString(\"\")\n}\nfunc (plainInt) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupByNode(nil)\n}\nfunc (plainInt) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupByIndex(0)\n}\nfunc (plainInt) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupBySegment(seg)\n}\nfunc (plainInt) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (plainInt) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (plainInt) Length() int64 {\n\treturn -1\n}\nfunc (plainInt) IsAbsent() bool {\n\treturn false\n}\nfunc (plainInt) IsNull() bool {\n\treturn false\n}\nfunc (plainInt) AsBool() (bool, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsBool()\n}\nfunc (n plainInt) AsInt() (int64, error) {\n\treturn int64(n), nil\n}\nfunc (plainInt) AsFloat() (float64, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsFloat()\n}\nfunc (plainInt) AsString() (string, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsString()\n}\nfunc (plainInt) AsBytes() ([]byte, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsBytes()\n}\nfunc (plainInt) AsLink() (datamodel.Link, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsLink()\n}\nfunc (plainInt) Prototype() datamodel.NodePrototype {\n\treturn Prototype__Int{}\n}\n\n// plainUint is a simple boxed uint64 that complies with datamodel.Node,\n// allowing representation of the uint64 range above the int64 maximum via the\n// UintNode interface\ntype plainUint uint64\n\n// -- Node interface methods for plainUint -->\n\nfunc (plainUint) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Int\n}\nfunc (plainUint) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupByString(\"\")\n}\nfunc (plainUint) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupByNode(nil)\n}\nfunc (plainUint) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupByIndex(0)\n}\nfunc (plainUint) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupBySegment(seg)\n}\nfunc (plainUint) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (plainUint) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (plainUint) Length() int64 {\n\treturn -1\n}\nfunc (plainUint) IsAbsent() bool {\n\treturn false\n}\nfunc (plainUint) IsNull() bool {\n\treturn false\n}\nfunc (plainUint) AsBool() (bool, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsBool()\n}\nfunc (n plainUint) AsInt() (int64, error) {\n\tif uint64(n) > uint64(math.MaxInt64) {\n\t\treturn -1, fmt.Errorf(\"unsigned integer out of range of int64 type\")\n\t}\n\treturn int64(n), nil\n}\nfunc (plainUint) AsFloat() (float64, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsFloat()\n}\nfunc (plainUint) AsString() (string, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsString()\n}\nfunc (plainUint) AsBytes() ([]byte, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsBytes()\n}\nfunc (plainUint) AsLink() (datamodel.Link, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsLink()\n}\nfunc (plainUint) Prototype() datamodel.NodePrototype {\n\treturn Prototype__Int{}\n}\n\n// allows plainUint to conform to the plainUint interface\n\nfunc (n plainUint) AsUint() (uint64, error) {\n\treturn uint64(n), nil\n}\n\n// -- NodePrototype -->\n\ntype Prototype__Int struct{}\n\nfunc (Prototype__Int) NewBuilder() datamodel.NodeBuilder {\n\tvar w plainInt\n\treturn &plainInt__Builder{plainInt__Assembler{w: &w}}\n}\n\n// -- NodeBuilder -->\n\ntype plainInt__Builder struct {\n\tplainInt__Assembler\n}\n\nfunc (nb *plainInt__Builder) Build() datamodel.Node {\n\treturn nb.w\n}\nfunc (nb *plainInt__Builder) Reset() {\n\tvar w plainInt\n\t*nb = plainInt__Builder{plainInt__Assembler{w: &w}}\n}\n\n// -- NodeAssembler -->\n\ntype plainInt__Assembler struct {\n\tw *plainInt\n}\n\nfunc (plainInt__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.IntAssembler{TypeName: \"int\"}.BeginMap(0)\n}\nfunc (plainInt__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.IntAssembler{TypeName: \"int\"}.BeginList(0)\n}\nfunc (plainInt__Assembler) AssignNull() error {\n\treturn mixins.IntAssembler{TypeName: \"int\"}.AssignNull()\n}\nfunc (plainInt__Assembler) AssignBool(bool) error {\n\treturn mixins.IntAssembler{TypeName: \"int\"}.AssignBool(false)\n}\nfunc (na *plainInt__Assembler) AssignInt(v int64) error {\n\t*na.w = plainInt(v)\n\treturn nil\n}\nfunc (plainInt__Assembler) AssignFloat(float64) error {\n\treturn mixins.IntAssembler{TypeName: \"int\"}.AssignFloat(0)\n}\nfunc (plainInt__Assembler) AssignString(string) error {\n\treturn mixins.IntAssembler{TypeName: \"int\"}.AssignString(\"\")\n}\nfunc (plainInt__Assembler) AssignBytes([]byte) error {\n\treturn mixins.IntAssembler{TypeName: \"int\"}.AssignBytes(nil)\n}\nfunc (plainInt__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.IntAssembler{TypeName: \"int\"}.AssignLink(nil)\n}\nfunc (na *plainInt__Assembler) AssignNode(v datamodel.Node) error {\n\tif v2, err := v.AsInt(); err != nil {\n\t\treturn err\n\t} else {\n\t\t*na.w = plainInt(v2)\n\t\treturn nil\n\t}\n}\nfunc (plainInt__Assembler) Prototype() datamodel.NodePrototype {\n\treturn Prototype__Int{}\n}\n"
  },
  {
    "path": "node/basicnode/int_test.go",
    "content": "package basicnode_test\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestBasicInt(t *testing.T) {\n\tm := basicnode.NewInt(3)\n\tb := m.Prototype().NewBuilder()\n\tb.AssignInt(4)\n\tn := b.Build()\n\tu := basicnode.NewUint(5)\n\tqt.Check(t, must.Int(m), qt.Equals, int64(3))\n\tqt.Check(t, must.Int(n), qt.Equals, int64(4))\n\tqt.Check(t, must.Int(u), qt.Equals, int64(5))\n}\n\nfunc TestIntErrors(t *testing.T) {\n\tx := basicnode.NewInt(3)\n\n\t_, err := x.LookupByIndex(0)\n\terrExpect := `func called on wrong kind: \"LookupByIndex\" called on a int node \\(kind: int\\), but only makes sense on list`\n\tqt.Check(t, err, qt.ErrorMatches, errExpect)\n\n\t_, err = x.LookupByString(\"n\")\n\terrExpect = `func called on wrong kind: \"LookupByString\" called on a int node \\(kind: int\\), but only makes sense on map`\n\tqt.Check(t, err, qt.ErrorMatches, errExpect)\n\n\t_, err = x.LookupByNode(x)\n\terrExpect = `func called on wrong kind: \"LookupByNode\" called on a int node \\(kind: int\\), but only makes sense on map`\n\tqt.Check(t, err, qt.ErrorMatches, errExpect)\n}\n"
  },
  {
    "path": "node/basicnode/link.go",
    "content": "package basicnode\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/mixins\"\n)\n\nvar (\n\t_ datamodel.Node          = &plainLink{}\n\t_ datamodel.NodePrototype = Prototype__Link{}\n\t_ datamodel.NodeBuilder   = &plainLink__Builder{}\n\t_ datamodel.NodeAssembler = &plainLink__Assembler{}\n)\n\nfunc NewLink(value datamodel.Link) datamodel.Node {\n\treturn &plainLink{value}\n}\n\n// plainLink is a simple box around a Link that complies with datamodel.Node.\ntype plainLink struct {\n\tx datamodel.Link\n}\n\n// -- Node interface methods -->\n\nfunc (plainLink) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Link\n}\nfunc (plainLink) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.Link{TypeName: \"link\"}.LookupByString(\"\")\n}\nfunc (plainLink) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.Link{TypeName: \"link\"}.LookupByNode(nil)\n}\nfunc (plainLink) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Link{TypeName: \"link\"}.LookupByIndex(0)\n}\nfunc (plainLink) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.Link{TypeName: \"link\"}.LookupBySegment(seg)\n}\nfunc (plainLink) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (plainLink) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (plainLink) Length() int64 {\n\treturn -1\n}\nfunc (plainLink) IsAbsent() bool {\n\treturn false\n}\nfunc (plainLink) IsNull() bool {\n\treturn false\n}\nfunc (plainLink) AsBool() (bool, error) {\n\treturn mixins.Link{TypeName: \"link\"}.AsBool()\n}\nfunc (plainLink) AsInt() (int64, error) {\n\treturn mixins.Link{TypeName: \"link\"}.AsInt()\n}\nfunc (plainLink) AsFloat() (float64, error) {\n\treturn mixins.Link{TypeName: \"link\"}.AsFloat()\n}\nfunc (plainLink) AsString() (string, error) {\n\treturn mixins.Link{TypeName: \"link\"}.AsString()\n}\nfunc (plainLink) AsBytes() ([]byte, error) {\n\treturn mixins.Link{TypeName: \"link\"}.AsBytes()\n}\nfunc (n *plainLink) AsLink() (datamodel.Link, error) {\n\treturn n.x, nil\n}\nfunc (plainLink) Prototype() datamodel.NodePrototype {\n\treturn Prototype__Link{}\n}\n\n// -- NodePrototype -->\n\ntype Prototype__Link struct{}\n\nfunc (Prototype__Link) NewBuilder() datamodel.NodeBuilder {\n\tvar w plainLink\n\treturn &plainLink__Builder{plainLink__Assembler{w: &w}}\n}\n\n// -- NodeBuilder -->\n\ntype plainLink__Builder struct {\n\tplainLink__Assembler\n}\n\nfunc (nb *plainLink__Builder) Build() datamodel.Node {\n\treturn nb.w\n}\nfunc (nb *plainLink__Builder) Reset() {\n\tvar w plainLink\n\t*nb = plainLink__Builder{plainLink__Assembler{w: &w}}\n}\n\n// -- NodeAssembler -->\n\ntype plainLink__Assembler struct {\n\tw *plainLink\n}\n\nfunc (plainLink__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.LinkAssembler{TypeName: \"link\"}.BeginMap(0)\n}\nfunc (plainLink__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.LinkAssembler{TypeName: \"link\"}.BeginList(0)\n}\nfunc (plainLink__Assembler) AssignNull() error {\n\treturn mixins.LinkAssembler{TypeName: \"link\"}.AssignNull()\n}\nfunc (plainLink__Assembler) AssignBool(bool) error {\n\treturn mixins.LinkAssembler{TypeName: \"link\"}.AssignBool(false)\n}\nfunc (plainLink__Assembler) AssignInt(int64) error {\n\treturn mixins.LinkAssembler{TypeName: \"link\"}.AssignInt(0)\n}\nfunc (plainLink__Assembler) AssignFloat(float64) error {\n\treturn mixins.LinkAssembler{TypeName: \"link\"}.AssignFloat(0)\n}\nfunc (plainLink__Assembler) AssignString(string) error {\n\treturn mixins.LinkAssembler{TypeName: \"link\"}.AssignString(\"\")\n}\nfunc (plainLink__Assembler) AssignBytes([]byte) error {\n\treturn mixins.LinkAssembler{TypeName: \"link\"}.AssignBytes(nil)\n}\nfunc (na *plainLink__Assembler) AssignLink(v datamodel.Link) error {\n\tna.w.x = v\n\treturn nil\n}\nfunc (na *plainLink__Assembler) AssignNode(v datamodel.Node) error {\n\tif v2, err := v.AsLink(); err != nil {\n\t\treturn err\n\t} else {\n\t\tna.w.x = v2\n\t\treturn nil\n\t}\n}\nfunc (plainLink__Assembler) Prototype() datamodel.NodePrototype {\n\treturn Prototype__Link{}\n}\n"
  },
  {
    "path": "node/basicnode/list.go",
    "content": "package basicnode\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/mixins\"\n)\n\nvar (\n\t_ datamodel.Node          = &plainList{}\n\t_ datamodel.NodePrototype = Prototype__List{}\n\t_ datamodel.NodeBuilder   = &plainList__Builder{}\n\t_ datamodel.NodeAssembler = &plainList__Assembler{}\n)\n\n// plainList is a concrete type that provides a list-kind datamodel.Node.\n// It can contain any kind of value.\n// plainList is also embedded in the 'any' struct and usable from there.\ntype plainList struct {\n\tx []datamodel.Node\n}\n\n// -- Node interface methods -->\n\nfunc (plainList) Kind() datamodel.Kind {\n\treturn datamodel.Kind_List\n}\nfunc (plainList) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.List{TypeName: \"list\"}.LookupByString(\"\")\n}\nfunc (plainList) LookupByNode(datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.List{TypeName: \"list\"}.LookupByNode(nil)\n}\nfunc (n *plainList) LookupByIndex(idx int64) (datamodel.Node, error) {\n\tif idx < 0 {\n\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfInt(idx)}\n\t}\n\tif n.Length() <= idx {\n\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfInt(idx)}\n\t}\n\treturn n.x[idx], nil\n}\nfunc (n *plainList) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\tidx, err := seg.Index()\n\tif err != nil {\n\t\treturn nil, datamodel.ErrInvalidSegmentForList{TroubleSegment: seg, Reason: err}\n\t}\n\treturn n.LookupByIndex(idx)\n}\nfunc (plainList) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (n *plainList) ListIterator() datamodel.ListIterator {\n\treturn &plainList_ListIterator{n, 0}\n}\nfunc (n *plainList) Length() int64 {\n\treturn int64(len(n.x))\n}\nfunc (plainList) IsAbsent() bool {\n\treturn false\n}\nfunc (plainList) IsNull() bool {\n\treturn false\n}\nfunc (plainList) AsBool() (bool, error) {\n\treturn mixins.List{TypeName: \"list\"}.AsBool()\n}\nfunc (plainList) AsInt() (int64, error) {\n\treturn mixins.List{TypeName: \"list\"}.AsInt()\n}\nfunc (plainList) AsFloat() (float64, error) {\n\treturn mixins.List{TypeName: \"list\"}.AsFloat()\n}\nfunc (plainList) AsString() (string, error) {\n\treturn mixins.List{TypeName: \"list\"}.AsString()\n}\nfunc (plainList) AsBytes() ([]byte, error) {\n\treturn mixins.List{TypeName: \"list\"}.AsBytes()\n}\nfunc (plainList) AsLink() (datamodel.Link, error) {\n\treturn mixins.List{TypeName: \"list\"}.AsLink()\n}\nfunc (plainList) Prototype() datamodel.NodePrototype {\n\treturn Prototype.List\n}\n\ntype plainList_ListIterator struct {\n\tn   *plainList\n\tidx int\n}\n\nfunc (itr *plainList_ListIterator) Next() (idx int64, v datamodel.Node, _ error) {\n\tif itr.Done() {\n\t\treturn -1, nil, datamodel.ErrIteratorOverread{}\n\t}\n\tv = itr.n.x[itr.idx]\n\tidx = int64(itr.idx)\n\titr.idx++\n\treturn\n}\nfunc (itr *plainList_ListIterator) Done() bool {\n\treturn itr.idx >= len(itr.n.x)\n}\n\n// -- NodePrototype -->\n\ntype Prototype__List struct{}\n\nfunc (Prototype__List) NewBuilder() datamodel.NodeBuilder {\n\treturn &plainList__Builder{plainList__Assembler{w: &plainList{}}}\n}\n\n// -- NodeBuilder -->\n\ntype plainList__Builder struct {\n\tplainList__Assembler\n}\n\nfunc (nb *plainList__Builder) Build() datamodel.Node {\n\tif nb.state != laState_finished {\n\t\tpanic(\"invalid state: assembler must be 'finished' before Build can be called!\")\n\t}\n\treturn nb.w\n}\nfunc (nb *plainList__Builder) Reset() {\n\t*nb = plainList__Builder{}\n\tnb.w = &plainList{}\n}\n\n// -- NodeAssembler -->\n\ntype plainList__Assembler struct {\n\tw *plainList\n\n\tva plainList__ValueAssembler\n\n\tstate laState\n}\ntype plainList__ValueAssembler struct {\n\tla *plainList__Assembler\n}\n\n// laState is an enum of the state machine for a list assembler.\n// (this might be something to export reusably, but it's also very much an impl detail that need not be seen, so, dubious.)\n// it's similar to maState for maps, but has fewer states because we never have keys to assemble.\ntype laState uint8\n\nconst (\n\tlaState_initial  laState = iota // also the 'expect value or finish' state\n\tlaState_midValue                // waiting for a 'finished' state in the ValueAssembler.\n\tlaState_finished                // 'w' will also be nil, but this is a politer statement\n)\n\nfunc (plainList__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.ListAssembler{TypeName: \"list\"}.BeginMap(0)\n}\nfunc (na *plainList__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\tif sizeHint < 0 {\n\t\tsizeHint = 0\n\t}\n\t// Allocate storage space.\n\tna.w.x = make([]datamodel.Node, 0, sizeHint)\n\t// That's it; return self as the ListAssembler.  We already have all the right methods on this structure.\n\treturn na, nil\n}\nfunc (plainList__Assembler) AssignNull() error {\n\treturn mixins.ListAssembler{TypeName: \"list\"}.AssignNull()\n}\nfunc (plainList__Assembler) AssignBool(bool) error {\n\treturn mixins.ListAssembler{TypeName: \"list\"}.AssignBool(false)\n}\nfunc (plainList__Assembler) AssignInt(int64) error {\n\treturn mixins.ListAssembler{TypeName: \"list\"}.AssignInt(0)\n}\nfunc (plainList__Assembler) AssignFloat(float64) error {\n\treturn mixins.ListAssembler{TypeName: \"list\"}.AssignFloat(0)\n}\nfunc (plainList__Assembler) AssignString(string) error {\n\treturn mixins.ListAssembler{TypeName: \"list\"}.AssignString(\"\")\n}\nfunc (plainList__Assembler) AssignBytes([]byte) error {\n\treturn mixins.ListAssembler{TypeName: \"list\"}.AssignBytes(nil)\n}\nfunc (plainList__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.ListAssembler{TypeName: \"list\"}.AssignLink(nil)\n}\nfunc (na *plainList__Assembler) AssignNode(v datamodel.Node) error {\n\t// Sanity check, then update, assembler state.\n\t//  Update of state to 'finished' comes later; where exactly depends on if shortcuts apply.\n\tif na.state != laState_initial {\n\t\tpanic(\"misuse\")\n\t}\n\t// Copy the content.\n\tif v2, ok := v.(*plainList); ok { // if our own type: shortcut.\n\t\t// Copy the structure by value.\n\t\t//  This means we'll have pointers into the same internal maps and slices;\n\t\t//   this is okay, because the Node type promises it's immutable, and we are going to instantly finish ourselves to also maintain that.\n\t\t// FIXME: the shortcut behaves differently than the long way: it discards any existing progress.  Doesn't violate immut, but is odd.\n\t\t*na.w = *v2\n\t\tna.state = laState_finished\n\t\treturn nil\n\t}\n\t// If the above shortcut didn't work, resort to a generic copy.\n\t//  We call AssignNode for all the child values, giving them a chance to hit shortcuts even if we didn't.\n\tif v.Kind() != datamodel.Kind_List {\n\t\treturn datamodel.ErrWrongKind{TypeName: \"list\", MethodName: \"AssignNode\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: v.Kind()}\n\t}\n\titr := v.ListIterator()\n\tfor !itr.Done() {\n\t\t_, v, err := itr.Next()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn na.Finish()\n}\nfunc (plainList__Assembler) Prototype() datamodel.NodePrototype {\n\treturn Prototype.List\n}\n\n// -- ListAssembler -->\n\n// AssembleValue is part of conforming to ListAssembler, which we do on\n// plainList__Assembler so that BeginList can just return a retyped pointer rather than new object.\nfunc (la *plainList__Assembler) AssembleValue() datamodel.NodeAssembler {\n\t// Sanity check, then update, assembler state.\n\tif la.state != laState_initial {\n\t\tpanic(\"misuse\")\n\t}\n\tla.state = laState_midValue\n\t// Make value assembler valid by giving it pointer back to whole 'la'; yield it.\n\tla.va.la = la\n\treturn &la.va\n}\n\n// Finish is part of conforming to ListAssembler, which we do on\n// plainList__Assembler so that BeginList can just return a retyped pointer rather than new object.\nfunc (la *plainList__Assembler) Finish() error {\n\t// Sanity check, then update, assembler state.\n\tif la.state != laState_initial {\n\t\tpanic(\"misuse\")\n\t}\n\tla.state = laState_finished\n\t// validators could run and report errors promptly, if this type had any.\n\treturn nil\n}\nfunc (plainList__Assembler) ValuePrototype(_ int64) datamodel.NodePrototype {\n\treturn Prototype.Any\n}\n\n// -- ListAssembler.ValueAssembler -->\n\nfunc (lva *plainList__ValueAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\tma := plainList__ValueAssemblerMap{}\n\tma.ca.w = &plainMap{}\n\tma.p = lva.la\n\t_, err := ma.ca.BeginMap(sizeHint)\n\treturn &ma, err\n}\nfunc (lva *plainList__ValueAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\tla := plainList__ValueAssemblerList{}\n\tla.ca.w = &plainList{}\n\tla.p = lva.la\n\t_, err := la.ca.BeginList(sizeHint)\n\treturn &la, err\n}\nfunc (lva *plainList__ValueAssembler) AssignNull() error {\n\treturn lva.AssignNode(datamodel.Null)\n}\nfunc (lva *plainList__ValueAssembler) AssignBool(v bool) error {\n\tvb := plainBool(v)\n\treturn lva.AssignNode(&vb)\n}\nfunc (lva *plainList__ValueAssembler) AssignInt(v int64) error {\n\tvb := plainInt(v)\n\treturn lva.AssignNode(&vb)\n}\nfunc (lva *plainList__ValueAssembler) AssignFloat(v float64) error {\n\tvb := plainFloat(v)\n\treturn lva.AssignNode(&vb)\n}\nfunc (lva *plainList__ValueAssembler) AssignString(v string) error {\n\tvb := plainString(v)\n\treturn lva.AssignNode(&vb)\n}\nfunc (lva *plainList__ValueAssembler) AssignBytes(v []byte) error {\n\tvb := plainBytes(v)\n\treturn lva.AssignNode(&vb)\n}\nfunc (lva *plainList__ValueAssembler) AssignLink(v datamodel.Link) error {\n\tvb := plainLink{v}\n\treturn lva.AssignNode(&vb)\n}\nfunc (lva *plainList__ValueAssembler) AssignNode(v datamodel.Node) error {\n\tlva.la.w.x = append(lva.la.w.x, v)\n\tlva.la.state = laState_initial\n\tlva.la = nil // invalidate self to prevent further incorrect use.\n\treturn nil\n}\nfunc (plainList__ValueAssembler) Prototype() datamodel.NodePrototype {\n\treturn Prototype.Any\n}\n\ntype plainList__ValueAssemblerMap struct {\n\tca plainMap__Assembler\n\tp  *plainList__Assembler // pointer back to parent, for final insert and state bump\n}\n\n// we briefly state only the methods we need to delegate here.\n// just embedding plainMap__Assembler also behaves correctly,\n//  but causes a lot of unnecessary autogenerated functions in the final binary.\n\nfunc (ma *plainList__ValueAssemblerMap) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\treturn ma.ca.AssembleEntry(k)\n}\nfunc (ma *plainList__ValueAssemblerMap) AssembleKey() datamodel.NodeAssembler {\n\treturn ma.ca.AssembleKey()\n}\nfunc (ma *plainList__ValueAssemblerMap) AssembleValue() datamodel.NodeAssembler {\n\treturn ma.ca.AssembleValue()\n}\nfunc (plainList__ValueAssemblerMap) KeyPrototype() datamodel.NodePrototype {\n\treturn Prototype__String{}\n}\nfunc (plainList__ValueAssemblerMap) ValuePrototype(_ string) datamodel.NodePrototype {\n\treturn Prototype.Any\n}\n\nfunc (ma *plainList__ValueAssemblerMap) Finish() error {\n\tif err := ma.ca.Finish(); err != nil {\n\t\treturn err\n\t}\n\tw := ma.ca.w\n\tma.ca.w = nil\n\treturn ma.p.va.AssignNode(w)\n}\n\ntype plainList__ValueAssemblerList struct {\n\tca plainList__Assembler\n\tp  *plainList__Assembler // pointer back to parent, for final insert and state bump\n}\n\n// we briefly state only the methods we need to delegate here.\n// just embedding plainList__Assembler also behaves correctly,\n//  but causes a lot of unnecessary autogenerated functions in the final binary.\n\nfunc (la *plainList__ValueAssemblerList) AssembleValue() datamodel.NodeAssembler {\n\treturn la.ca.AssembleValue()\n}\nfunc (plainList__ValueAssemblerList) ValuePrototype(_ int64) datamodel.NodePrototype {\n\treturn Prototype.Any\n}\n\nfunc (la *plainList__ValueAssemblerList) Finish() error {\n\tif err := la.ca.Finish(); err != nil {\n\t\treturn err\n\t}\n\tw := la.ca.w\n\tla.ca.w = nil\n\treturn la.p.va.AssignNode(w)\n}\n"
  },
  {
    "path": "node/basicnode/list_test.go",
    "content": "package basicnode_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nfunc TestList(t *testing.T) {\n\ttests.SpecTestListString(t, basicnode.Prototype.List)\n}\n"
  },
  {
    "path": "node/basicnode/map.go",
    "content": "package basicnode\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/mixins\"\n)\n\nvar (\n\t_ datamodel.Node          = &plainMap{}\n\t_ datamodel.NodePrototype = Prototype__Map{}\n\t_ datamodel.NodeBuilder   = &plainMap__Builder{}\n\t_ datamodel.NodeAssembler = &plainMap__Assembler{}\n)\n\n// plainMap is a concrete type that provides a map-kind datamodel.Node.\n// It can contain any kind of value.\n// plainMap is also embedded in the 'any' struct and usable from there.\ntype plainMap struct {\n\tm map[string]datamodel.Node // string key -- even if a runtime schema wrapper is using us for storage, we must have a comparable type here, and string is all we know.\n\tt []plainMap__Entry         // table for fast iteration, order keeping, and yielding pointers to enable alloc/conv amortization.\n}\n\ntype plainMap__Entry struct {\n\tk plainString    // address of this used when we return keys as nodes, such as in iterators.  Need in one place to amortize shifts to heap when ptr'ing for iface.\n\tv datamodel.Node // identical to map values.  keeping them here simplifies iteration.  (in codegen'd maps, this position is also part of amortization, but in this implementation, that's less useful.)\n\t// note on alternate implementations: 'v' could also use the 'any' type, and thus amortize value allocations.  the memory size trade would be large however, so we don't, here.\n}\n\n// -- Node interface methods -->\n\nfunc (plainMap) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Map\n}\nfunc (n *plainMap) LookupByString(key string) (datamodel.Node, error) {\n\tv, exists := n.m[key]\n\tif !exists {\n\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)}\n\t}\n\treturn v, nil\n}\nfunc (n *plainMap) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\tks, err := key.AsString()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn n.LookupByString(ks)\n}\nfunc (plainMap) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Map{TypeName: \"map\"}.LookupByIndex(0)\n}\nfunc (n *plainMap) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn n.LookupByString(seg.String())\n}\nfunc (n *plainMap) MapIterator() datamodel.MapIterator {\n\treturn &plainMap_MapIterator{n, 0}\n}\nfunc (plainMap) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (n *plainMap) Length() int64 {\n\treturn int64(len(n.t))\n}\nfunc (plainMap) IsAbsent() bool {\n\treturn false\n}\nfunc (plainMap) IsNull() bool {\n\treturn false\n}\nfunc (plainMap) AsBool() (bool, error) {\n\treturn mixins.Map{TypeName: \"map\"}.AsBool()\n}\nfunc (plainMap) AsInt() (int64, error) {\n\treturn mixins.Map{TypeName: \"map\"}.AsInt()\n}\nfunc (plainMap) AsFloat() (float64, error) {\n\treturn mixins.Map{TypeName: \"map\"}.AsFloat()\n}\nfunc (plainMap) AsString() (string, error) {\n\treturn mixins.Map{TypeName: \"map\"}.AsString()\n}\nfunc (plainMap) AsBytes() ([]byte, error) {\n\treturn mixins.Map{TypeName: \"map\"}.AsBytes()\n}\nfunc (plainMap) AsLink() (datamodel.Link, error) {\n\treturn mixins.Map{TypeName: \"map\"}.AsLink()\n}\nfunc (plainMap) Prototype() datamodel.NodePrototype {\n\treturn Prototype.Map\n}\n\ntype plainMap_MapIterator struct {\n\tn   *plainMap\n\tidx int\n}\n\nfunc (itr *plainMap_MapIterator) Next() (k datamodel.Node, v datamodel.Node, _ error) {\n\tif itr.Done() {\n\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t}\n\tk = &itr.n.t[itr.idx].k\n\tv = itr.n.t[itr.idx].v\n\titr.idx++\n\treturn\n}\nfunc (itr *plainMap_MapIterator) Done() bool {\n\treturn itr.idx >= len(itr.n.t)\n}\n\n// -- NodePrototype -->\n\ntype Prototype__Map struct{}\n\nfunc (Prototype__Map) NewBuilder() datamodel.NodeBuilder {\n\treturn &plainMap__Builder{plainMap__Assembler{w: &plainMap{}}}\n}\n\n// -- NodeBuilder -->\n\ntype plainMap__Builder struct {\n\tplainMap__Assembler\n}\n\nfunc (nb *plainMap__Builder) Build() datamodel.Node {\n\tif nb.state != maState_finished {\n\t\tpanic(\"invalid state: assembler must be 'finished' before Build can be called!\")\n\t}\n\treturn nb.w\n}\nfunc (nb *plainMap__Builder) Reset() {\n\t*nb = plainMap__Builder{}\n\tnb.w = &plainMap{}\n}\n\n// -- NodeAssembler -->\n\ntype plainMap__Assembler struct {\n\tw *plainMap\n\n\tka plainMap__KeyAssembler\n\tva plainMap__ValueAssembler\n\n\tstate maState\n}\ntype plainMap__KeyAssembler struct {\n\tma *plainMap__Assembler\n}\ntype plainMap__ValueAssembler struct {\n\tma *plainMap__Assembler\n}\n\n// maState is an enum of the state machine for a map assembler.\n// (this might be something to export reusably, but it's also very much an impl detail that need not be seen, so, dubious.)\ntype maState uint8\n\nconst (\n\tmaState_initial     maState = iota // also the 'expect key or finish' state\n\tmaState_midKey                     // waiting for a 'finished' state in the KeyAssembler.\n\tmaState_expectValue                // 'AssembleValue' is the only valid next step\n\tmaState_midValue                   // waiting for a 'finished' state in the ValueAssembler.\n\tmaState_finished                   // 'w' will also be nil, but this is a politer statement\n)\n\nfunc (na *plainMap__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\tif sizeHint < 0 {\n\t\tsizeHint = 0\n\t}\n\t// Allocate storage space.\n\tna.w.t = make([]plainMap__Entry, 0, sizeHint)\n\tna.w.m = make(map[string]datamodel.Node, sizeHint)\n\t// That's it; return self as the MapAssembler.  We already have all the right methods on this structure.\n\treturn na, nil\n}\nfunc (plainMap__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.MapAssembler{TypeName: \"map\"}.BeginList(0)\n}\nfunc (plainMap__Assembler) AssignNull() error {\n\treturn mixins.MapAssembler{TypeName: \"map\"}.AssignNull()\n}\nfunc (plainMap__Assembler) AssignBool(bool) error {\n\treturn mixins.MapAssembler{TypeName: \"map\"}.AssignBool(false)\n}\nfunc (plainMap__Assembler) AssignInt(int64) error {\n\treturn mixins.MapAssembler{TypeName: \"map\"}.AssignInt(0)\n}\nfunc (plainMap__Assembler) AssignFloat(float64) error {\n\treturn mixins.MapAssembler{TypeName: \"map\"}.AssignFloat(0)\n}\nfunc (plainMap__Assembler) AssignString(string) error {\n\treturn mixins.MapAssembler{TypeName: \"map\"}.AssignString(\"\")\n}\nfunc (plainMap__Assembler) AssignBytes([]byte) error {\n\treturn mixins.MapAssembler{TypeName: \"map\"}.AssignBytes(nil)\n}\nfunc (plainMap__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.MapAssembler{TypeName: \"map\"}.AssignLink(nil)\n}\nfunc (na *plainMap__Assembler) AssignNode(v datamodel.Node) error {\n\t// Sanity check assembler state.\n\t//  Update of state to 'finished' comes later; where exactly depends on if shortcuts apply.\n\tif na.state != maState_initial {\n\t\tpanic(\"misuse\")\n\t}\n\t// Copy the content.\n\tif v2, ok := v.(*plainMap); ok { // if our own type: shortcut.\n\t\t// Copy the structure by value.\n\t\t//  This means we'll have pointers into the same internal maps and slices;\n\t\t//   this is okay, because the Node type promises it's immutable, and we are going to instantly finish ourselves to also maintain that.\n\t\t// FIXME: the shortcut behaves differently than the long way: it discards any existing progress.  Doesn't violate immut, but is odd.\n\t\t*na.w = *v2\n\t\tna.state = maState_finished\n\t\treturn nil\n\t}\n\t// If the above shortcut didn't work, resort to a generic copy.\n\t//  We call AssignNode for all the child values, giving them a chance to hit shortcuts even if we didn't.\n\tif v.Kind() != datamodel.Kind_Map {\n\t\treturn datamodel.ErrWrongKind{TypeName: \"map\", MethodName: \"AssignNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: v.Kind()}\n\t}\n\titr := v.MapIterator()\n\tfor !itr.Done() {\n\t\tk, v, err := itr.Next()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := na.AssembleKey().AssignNode(k); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn na.Finish()\n}\nfunc (plainMap__Assembler) Prototype() datamodel.NodePrototype {\n\treturn Prototype.Map\n}\n\n// -- MapAssembler -->\n\n// AssembleEntry is part of conforming to MapAssembler, which we do on\n// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.\nfunc (ma *plainMap__Assembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\t// Sanity check assembler state.\n\t//  Update of state comes after possible key rejection.\n\tif ma.state != maState_initial {\n\t\tpanic(\"misuse\")\n\t}\n\t// Check for dup keys; error if so.\n\t_, exists := ma.w.m[k]\n\tif exists {\n\t\treturn nil, datamodel.ErrRepeatedMapKey{Key: plainString(k)}\n\t}\n\tma.state = maState_midValue\n\tma.w.t = append(ma.w.t, plainMap__Entry{k: plainString(k)})\n\t// Make value assembler valid by giving it pointer back to whole 'ma'; yield it.\n\tma.va.ma = ma\n\treturn &ma.va, nil\n}\n\n// AssembleKey is part of conforming to MapAssembler, which we do on\n// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.\nfunc (ma *plainMap__Assembler) AssembleKey() datamodel.NodeAssembler {\n\t// Sanity check, then update, assembler state.\n\tif ma.state != maState_initial {\n\t\tpanic(\"misuse\")\n\t}\n\tma.state = maState_midKey\n\t// Make key assembler valid by giving it pointer back to whole 'ma'; yield it.\n\tma.ka.ma = ma\n\treturn &ma.ka\n}\n\n// AssembleValue is part of conforming to MapAssembler, which we do on\n// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.\nfunc (ma *plainMap__Assembler) AssembleValue() datamodel.NodeAssembler {\n\t// Sanity check, then update, assembler state.\n\tif ma.state != maState_expectValue {\n\t\tpanic(\"misuse\")\n\t}\n\tma.state = maState_midValue\n\t// Make value assembler valid by giving it pointer back to whole 'ma'; yield it.\n\tma.va.ma = ma\n\treturn &ma.va\n}\n\n// Finish is part of conforming to MapAssembler, which we do on\n// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.\nfunc (ma *plainMap__Assembler) Finish() error {\n\t// Sanity check, then update, assembler state.\n\tif ma.state != maState_initial {\n\t\tpanic(\"misuse\")\n\t}\n\tma.state = maState_finished\n\t// validators could run and report errors promptly, if this type had any.\n\treturn nil\n}\nfunc (plainMap__Assembler) KeyPrototype() datamodel.NodePrototype {\n\treturn Prototype__String{}\n}\nfunc (plainMap__Assembler) ValuePrototype(_ string) datamodel.NodePrototype {\n\treturn Prototype.Any\n}\n\n// -- MapAssembler.KeyAssembler -->\n\nfunc (plainMap__KeyAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.BeginMap(0)\n}\nfunc (plainMap__KeyAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.BeginList(0)\n}\nfunc (plainMap__KeyAssembler) AssignNull() error {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.AssignNull()\n}\nfunc (plainMap__KeyAssembler) AssignBool(bool) error {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.AssignBool(false)\n}\nfunc (plainMap__KeyAssembler) AssignInt(int64) error {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.AssignInt(0)\n}\nfunc (plainMap__KeyAssembler) AssignFloat(float64) error {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.AssignFloat(0)\n}\nfunc (mka *plainMap__KeyAssembler) AssignString(v string) error {\n\t// Check for dup keys; error if so.\n\t//  (And, backtrack state to accepting keys again so we don't get eternally wedged here.)\n\t_, exists := mka.ma.w.m[v]\n\tif exists {\n\t\tmka.ma.state = maState_initial\n\t\tmka.ma = nil // invalidate self to prevent further incorrect use.\n\t\treturn datamodel.ErrRepeatedMapKey{Key: plainString(v)}\n\t}\n\t// Assign the key into the end of the entry table;\n\t//  we'll be doing map insertions after we get the value in hand.\n\t//  (There's no need to delegate to another assembler for the key type,\n\t//   because we're just at Data Model level here, which only regards plain strings.)\n\tmka.ma.w.t = append(mka.ma.w.t, plainMap__Entry{})\n\tmka.ma.w.t[len(mka.ma.w.t)-1].k = plainString(v)\n\t// Update parent assembler state: clear to proceed.\n\tmka.ma.state = maState_expectValue\n\tmka.ma = nil // invalidate self to prevent further incorrect use.\n\treturn nil\n}\nfunc (plainMap__KeyAssembler) AssignBytes([]byte) error {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.AssignBytes(nil)\n}\nfunc (plainMap__KeyAssembler) AssignLink(datamodel.Link) error {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.AssignLink(nil)\n}\nfunc (mka *plainMap__KeyAssembler) AssignNode(v datamodel.Node) error {\n\tvs, err := v.AsString()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot assign non-string node into map key assembler\") // FIXME:errors: this doesn't quite fit in ErrWrongKind cleanly; new error type?\n\t}\n\treturn mka.AssignString(vs)\n}\nfunc (plainMap__KeyAssembler) Prototype() datamodel.NodePrototype {\n\treturn Prototype__String{}\n}\n\n// -- MapAssembler.ValueAssembler -->\n\nfunc (mva *plainMap__ValueAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\tma := plainMap__ValueAssemblerMap{}\n\tma.ca.w = &plainMap{}\n\tma.p = mva.ma\n\t_, err := ma.ca.BeginMap(sizeHint)\n\treturn &ma, err\n}\nfunc (mva *plainMap__ValueAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\tla := plainMap__ValueAssemblerList{}\n\tla.ca.w = &plainList{}\n\tla.p = mva.ma\n\t_, err := la.ca.BeginList(sizeHint)\n\treturn &la, err\n}\nfunc (mva *plainMap__ValueAssembler) AssignNull() error {\n\treturn mva.AssignNode(datamodel.Null)\n}\nfunc (mva *plainMap__ValueAssembler) AssignBool(v bool) error {\n\tvb := plainBool(v)\n\treturn mva.AssignNode(&vb)\n}\nfunc (mva *plainMap__ValueAssembler) AssignInt(v int64) error {\n\tvb := plainInt(v)\n\treturn mva.AssignNode(&vb)\n}\nfunc (mva *plainMap__ValueAssembler) AssignFloat(v float64) error {\n\tvb := plainFloat(v)\n\treturn mva.AssignNode(&vb)\n}\nfunc (mva *plainMap__ValueAssembler) AssignString(v string) error {\n\tvb := plainString(v)\n\treturn mva.AssignNode(&vb)\n}\nfunc (mva *plainMap__ValueAssembler) AssignBytes(v []byte) error {\n\tvb := plainBytes(v)\n\treturn mva.AssignNode(&vb)\n}\nfunc (mva *plainMap__ValueAssembler) AssignLink(v datamodel.Link) error {\n\tvb := plainLink{v}\n\treturn mva.AssignNode(&vb)\n}\nfunc (mva *plainMap__ValueAssembler) AssignNode(v datamodel.Node) error {\n\tl := len(mva.ma.w.t) - 1\n\tmva.ma.w.t[l].v = v\n\tmva.ma.w.m[string(mva.ma.w.t[l].k)] = v\n\tmva.ma.state = maState_initial\n\tmva.ma = nil // invalidate self to prevent further incorrect use.\n\treturn nil\n}\nfunc (plainMap__ValueAssembler) Prototype() datamodel.NodePrototype {\n\treturn Prototype.Any\n}\n\ntype plainMap__ValueAssemblerMap struct {\n\tca plainMap__Assembler\n\tp  *plainMap__Assembler // pointer back to parent, for final insert and state bump\n}\n\n// we briefly state only the methods we need to delegate here.\n// just embedding plainMap__Assembler also behaves correctly,\n//  but causes a lot of unnecessary autogenerated functions in the final binary.\n\nfunc (ma *plainMap__ValueAssemblerMap) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\treturn ma.ca.AssembleEntry(k)\n}\nfunc (ma *plainMap__ValueAssemblerMap) AssembleKey() datamodel.NodeAssembler {\n\treturn ma.ca.AssembleKey()\n}\nfunc (ma *plainMap__ValueAssemblerMap) AssembleValue() datamodel.NodeAssembler {\n\treturn ma.ca.AssembleValue()\n}\nfunc (plainMap__ValueAssemblerMap) KeyPrototype() datamodel.NodePrototype {\n\treturn Prototype__String{}\n}\nfunc (plainMap__ValueAssemblerMap) ValuePrototype(_ string) datamodel.NodePrototype {\n\treturn Prototype.Any\n}\n\nfunc (ma *plainMap__ValueAssemblerMap) Finish() error {\n\tif err := ma.ca.Finish(); err != nil {\n\t\treturn err\n\t}\n\tw := ma.ca.w\n\tma.ca.w = nil\n\treturn ma.p.va.AssignNode(w)\n}\n\ntype plainMap__ValueAssemblerList struct {\n\tca plainList__Assembler\n\tp  *plainMap__Assembler // pointer back to parent, for final insert and state bump\n}\n\n// we briefly state only the methods we need to delegate here.\n// just embedding plainList__Assembler also behaves correctly,\n//  but causes a lot of unnecessary autogenerated functions in the final binary.\n\nfunc (la *plainMap__ValueAssemblerList) AssembleValue() datamodel.NodeAssembler {\n\treturn la.ca.AssembleValue()\n}\nfunc (plainMap__ValueAssemblerList) ValuePrototype(_ int64) datamodel.NodePrototype {\n\treturn Prototype.Any\n}\n\nfunc (la *plainMap__ValueAssemblerList) Finish() error {\n\tif err := la.ca.Finish(); err != nil {\n\t\treturn err\n\t}\n\tw := la.ca.w\n\tla.ca.w = nil\n\treturn la.p.va.AssignNode(w)\n}\n"
  },
  {
    "path": "node/basicnode/map_test.go",
    "content": "package basicnode_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n\t\"github.com/ipld/go-ipld-prime/printer\"\n)\n\nfunc TestMap(t *testing.T) {\n\ttests.SpecTestMapStrInt(t, basicnode.Prototype.Map)\n\ttests.SpecTestMapStrMapStrInt(t, basicnode.Prototype.Map)\n\ttests.SpecTestMapStrListStr(t, basicnode.Prototype.Map)\n}\n\nfunc BenchmarkMapStrInt_3n_AssembleStandard(b *testing.B) {\n\ttests.SpecBenchmarkMapStrInt_3n_AssembleStandard(b, basicnode.Prototype.Map)\n}\nfunc BenchmarkMapStrInt_3n_AssembleEntry(b *testing.B) {\n\ttests.SpecBenchmarkMapStrInt_3n_AssembleEntry(b, basicnode.Prototype.Map)\n}\nfunc BenchmarkMapStrInt_3n_Iteration(b *testing.B) {\n\ttests.SpecBenchmarkMapStrInt_3n_Iteration(b, basicnode.Prototype.Map)\n}\n\nfunc BenchmarkMapStrInt_25n_AssembleStandard(b *testing.B) {\n\ttests.SpecBenchmarkMapStrInt_25n_AssembleStandard(b, basicnode.Prototype.Map)\n}\nfunc BenchmarkMapStrInt_25n_AssembleEntry(b *testing.B) {\n\ttests.SpecBenchmarkMapStrInt_25n_AssembleEntry(b, basicnode.Prototype.Map)\n}\nfunc BenchmarkMapStrInt_25n_Iteration(b *testing.B) {\n\ttests.SpecBenchmarkMapStrInt_25n_Iteration(b, basicnode.Prototype.Map)\n}\n\nfunc BenchmarkSpec_Marshal_Map3StrInt(b *testing.B) {\n\ttests.BenchmarkSpec_Marshal_Map3StrInt(b, basicnode.Prototype.Map)\n}\nfunc BenchmarkSpec_Marshal_MapNStrMap3StrInt(b *testing.B) {\n\ttests.BenchmarkSpec_Marshal_MapNStrMap3StrInt(b, basicnode.Prototype.Map)\n}\n\nfunc BenchmarkSpec_Unmarshal_Map3StrInt(b *testing.B) {\n\ttests.BenchmarkSpec_Unmarshal_Map3StrInt(b, basicnode.Prototype.Map)\n}\nfunc BenchmarkSpec_Unmarshal_MapNStrMap3StrInt(b *testing.B) {\n\ttests.BenchmarkSpec_Unmarshal_MapNStrMap3StrInt(b, basicnode.Prototype.Map)\n}\n\n// Test that the map builder cannot be assigned arbitrary values, and trying to\n// will result in a sensible error\nfunc TestMapAssignError(t *testing.T) {\n\tb := basicnode.Prototype.Map.NewBuilder()\n\terr := b.AssignBool(true)\n\terrExpect := `func called on wrong kind: \"AssignBool\" called on a map node \\(kind: map\\), but only makes sense on bool`\n\tqt.Check(t, err, qt.ErrorMatches, errExpect)\n\n\terr = b.AssignInt(3)\n\terrExpect = `func called on wrong kind: \"AssignInt\" called on a map node \\(kind: map\\), but only makes sense on int`\n\tqt.Check(t, err, qt.ErrorMatches, errExpect)\n\n\terr = b.AssignFloat(5.7)\n\terrExpect = `func called on wrong kind: \"AssignFloat\" called on a map node \\(kind: map\\), but only makes sense on float`\n\tqt.Check(t, err, qt.ErrorMatches, errExpect)\n\n\terr = b.AssignString(\"hi\")\n\terrExpect = `func called on wrong kind: \"AssignString\" called on a map node \\(kind: map\\), but only makes sense on string`\n\tqt.Check(t, err, qt.ErrorMatches, errExpect)\n\n\terr = b.AssignNode(basicnode.NewInt(3))\n\terrExpect = `func called on wrong kind: \"AssignNode\" called on a map node \\(kind: int\\), but only makes sense on map`\n\tqt.Check(t, err, qt.ErrorMatches, errExpect)\n\n\t// TODO(dustmop): BeginList, AssignNull, AssignBytes, AssignLink\n}\n\n// Test that the map builder can create map nodes, and AssignNode will copy\n// such a node, and lookup methods on that node will work correctly\nfunc TestMapBuilder(t *testing.T) {\n\tb := basicnode.Prototype.Map.NewBuilder()\n\n\t// construct a map of three keys, using the MapBuilder\n\tma, err := b.BeginMap(3)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ta := ma.AssembleKey()\n\ta.AssignString(\"cat\")\n\ta = ma.AssembleValue()\n\ta.AssignString(\"meow\")\n\n\ta, err = ma.AssembleEntry(\"dog\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ta.AssignString(\"bark\")\n\n\ta = ma.AssembleKey()\n\ta.AssignString(\"eel\")\n\ta = ma.AssembleValue()\n\ta.AssignString(\"zap\")\n\n\terr = ma.Finish()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// test the builder's prototypes and its key and value prototypes, while we're here\n\tnp := b.Prototype()\n\tqt.Check(t, fmt.Sprintf(\"%T\", np), qt.Equals, \"basicnode.Prototype__Map\")\n\tnp = ma.KeyPrototype()\n\tqt.Check(t, fmt.Sprintf(\"%T\", np), qt.Equals, \"basicnode.Prototype__String\")\n\tnp = ma.ValuePrototype(\"\")\n\tqt.Check(t, fmt.Sprintf(\"%T\", np), qt.Equals, \"basicnode.Prototype__Any\")\n\n\t// compare the printed map\n\tmapNode := b.Build()\n\tactual := printer.Sprint(mapNode)\n\n\texpect := `map{\n\tstring{\"cat\"}: string{\"meow\"}\n\tstring{\"dog\"}: string{\"bark\"}\n\tstring{\"eel\"}: string{\"zap\"}\n}`\n\tqt.Check(t, expect, qt.Equals, actual)\n\n\t// copy the map using AssignNode\n\tc := basicnode.Prototype.Map.NewBuilder()\n\terr = c.AssignNode(mapNode)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tanotherNode := c.Build()\n\n\tactual = printer.Sprint(anotherNode)\n\tqt.Assert(t, expect, qt.Equals, actual)\n\n\t// access values of map, using string\n\tr, err := anotherNode.LookupByString(\"cat\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tqt.Check(t, \"meow\", qt.Equals, must.String(r))\n\n\t// access values of map, using node\n\tr, err = anotherNode.LookupByNode(basicnode.NewString(\"dog\"))\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tqt.Check(t, \"bark\", qt.Equals, must.String(r))\n\n\t// access values of map, using PathSegment\n\tr, err = anotherNode.LookupBySegment(datamodel.ParsePathSegment(\"eel\"))\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tqt.Check(t, \"zap\", qt.Equals, must.String(r))\n\n\t// validate the node's prototype\n\tnp = anotherNode.Prototype()\n\tqt.Check(t, fmt.Sprintf(\"%T\", np), qt.Equals, \"basicnode.Prototype__Map\")\n}\n\n// test that AssignNode will fail if called twice, it expects an empty\n// node to assign to\nfunc TestMapCantAssignNodeTwice(t *testing.T) {\n\tb := basicnode.Prototype.Map.NewBuilder()\n\n\t// construct a map of three keys, using the MapBuilder\n\tma, err := b.BeginMap(3)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ta := ma.AssembleKey()\n\ta.AssignString(\"cat\")\n\ta = ma.AssembleValue()\n\ta.AssignString(\"meow\")\n\n\ta, err = ma.AssembleEntry(\"dog\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ta.AssignString(\"bark\")\n\n\ta = ma.AssembleKey()\n\ta.AssignString(\"eel\")\n\ta = ma.AssembleValue()\n\ta.AssignString(\"zap\")\n\n\terr = ma.Finish()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tmapNode := b.Build()\n\n\t// copy the map using AssignNode, works the first time\n\tc := basicnode.Prototype.Map.NewBuilder()\n\terr = c.AssignNode(mapNode)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tqt.Assert(t,\n\t\tfunc() {\n\t\t\t_ = c.AssignNode(mapNode)\n\t\t},\n\t\tqt.PanicMatches,\n\t\t// TODO(dustmop): Error message here should be better\n\t\t`misuse`)\n}\n\nfunc TestMapLookupError(t *testing.T) {\n\tb := basicnode.Prototype.Map.NewBuilder()\n\n\t// construct a map of three keys, using the MapBuilder\n\tma, err := b.BeginMap(3)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ta := ma.AssembleKey()\n\ta.AssignString(\"cat\")\n\ta = ma.AssembleValue()\n\ta.AssignString(\"meow\")\n\n\ta, err = ma.AssembleEntry(\"dog\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ta.AssignString(\"bark\")\n\n\ta = ma.AssembleKey()\n\ta.AssignString(\"eel\")\n\ta = ma.AssembleValue()\n\ta.AssignString(\"zap\")\n\n\terr = ma.Finish()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tmapNode := b.Build()\n\n\t_, err = mapNode.LookupByString(\"frog\")\n\tqt.Check(t, err, qt.ErrorMatches, `key not found: \"frog\"`)\n\n\t_, err = mapNode.LookupByNode(basicnode.NewInt(3))\n\t// TODO(dustmop): This error message is not great. It's about how the\n\t// int node could not be converted when the real problem is that this\n\t// method should not accept ints as parameters\n\tqt.Check(t, err, qt.ErrorMatches, `func called on wrong kind: \"AsString\" called on a int node \\(kind: int\\), but only makes sense on string`)\n\n\t_, err = mapNode.LookupByIndex(0)\n\tqt.Check(t, err, qt.ErrorMatches, `func called on wrong kind: \"LookupByIndex\" called on a map node \\(kind: map\\), but only makes sense on list`)\n}\n\nfunc TestMapNewBuilderUsageError(t *testing.T) {\n\tqt.Assert(t,\n\t\tfunc() {\n\t\t\tb := basicnode.Prototype.Map.NewBuilder()\n\t\t\t_ = b.Build()\n\t\t},\n\t\tqt.PanicMatches,\n\t\t`invalid state: assembler must be 'finished' before Build can be called!`)\n\n\t// construct an empty map\n\tb := basicnode.Prototype.Map.NewBuilder()\n\tma, err := b.BeginMap(0)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\terr = ma.Finish()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tmapNode := b.Build()\n\tactual := printer.Sprint(mapNode)\n\n\texpect := `map{}`\n\tqt.Check(t, expect, qt.Equals, actual)\n\n\t// reset will return the state to 'initial', so Build will panic once again\n\tb.Reset()\n\tqt.Assert(t,\n\t\tfunc() {\n\t\t\t_ = b.Build()\n\t\t},\n\t\tqt.PanicMatches,\n\t\t`invalid state: assembler must be 'finished' before Build can be called!`)\n\n\t// assembling a key without a value will cause Finish to panic\n\tb.Reset()\n\tma, err = b.BeginMap(0)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ta := ma.AssembleKey()\n\ta.AssignString(\"cat\")\n\tqt.Assert(t,\n\t\tfunc() {\n\t\t\t_ = ma.Finish()\n\t\t},\n\t\tqt.PanicMatches,\n\t\t// TODO(dustmop): Error message here should be better\n\t\t`misuse`)\n}\n\nfunc TestMapDupKeyError(t *testing.T) {\n\tb := basicnode.Prototype.Map.NewBuilder()\n\n\t// construct a map with duplicate keys\n\tma, err := b.BeginMap(3)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ta := ma.AssembleKey()\n\ta.AssignString(\"cat\")\n\ta = ma.AssembleValue()\n\ta.AssignString(\"meow\")\n\ta = ma.AssembleKey()\n\terr = a.AssignString(\"cat\")\n\n\tqt.Check(t, err, qt.ErrorMatches, `cannot repeat map key \"cat\"`)\n}\n"
  },
  {
    "path": "node/basicnode/prototypes.go",
    "content": "package basicnode\n\n// Prototype embeds a NodePrototype for every kind of Node implementation in this package.\n// You can use it like this:\n//\n//\tbasicnode.Prototype.Map.NewBuilder().BeginMap() //...\n//\n// and:\n//\n//\tbasicnode.Prototype.String.NewBuilder().AssignString(\"x\") // ...\n//\n// Most of the prototypes are for one particular Kind of node (e.g. string, int, etc);\n// you can use the \"Any\" style if you want a builder that can accept any kind of data.\nvar Prototype prototype\n\ntype prototype struct {\n\tAny    Prototype__Any\n\tMap    Prototype__Map\n\tList   Prototype__List\n\tBool   Prototype__Bool\n\tInt    Prototype__Int\n\tFloat  Prototype__Float\n\tString Prototype__String\n\tBytes  Prototype__Bytes\n\tLink   Prototype__Link\n}\n"
  },
  {
    "path": "node/basicnode/string.go",
    "content": "package basicnode\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/mixins\"\n)\n\nvar (\n\t_ datamodel.Node          = plainString(\"\")\n\t_ datamodel.NodePrototype = Prototype__String{}\n\t_ datamodel.NodeBuilder   = &plainString__Builder{}\n\t_ datamodel.NodeAssembler = &plainString__Assembler{}\n)\n\nfunc NewString(value string) datamodel.Node {\n\tv := plainString(value)\n\treturn &v\n}\n\n// plainString is a simple boxed string that complies with datamodel.Node.\n// It's useful for many things, such as boxing map keys.\n//\n// The implementation is a simple typedef of a string;\n// handling it as a Node incurs 'runtime.convTstring',\n// which is about the best we can do.\ntype plainString string\n\n// -- Node interface methods -->\n\nfunc (plainString) Kind() datamodel.Kind {\n\treturn datamodel.Kind_String\n}\nfunc (plainString) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"string\"}.LookupByString(\"\")\n}\nfunc (plainString) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"string\"}.LookupByNode(nil)\n}\nfunc (plainString) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"string\"}.LookupByIndex(0)\n}\nfunc (plainString) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"string\"}.LookupBySegment(seg)\n}\nfunc (plainString) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (plainString) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (plainString) Length() int64 {\n\treturn -1\n}\nfunc (plainString) IsAbsent() bool {\n\treturn false\n}\nfunc (plainString) IsNull() bool {\n\treturn false\n}\nfunc (plainString) AsBool() (bool, error) {\n\treturn mixins.String{TypeName: \"string\"}.AsBool()\n}\nfunc (plainString) AsInt() (int64, error) {\n\treturn mixins.String{TypeName: \"string\"}.AsInt()\n}\nfunc (plainString) AsFloat() (float64, error) {\n\treturn mixins.String{TypeName: \"string\"}.AsFloat()\n}\nfunc (x plainString) AsString() (string, error) {\n\treturn string(x), nil\n}\nfunc (plainString) AsBytes() ([]byte, error) {\n\treturn mixins.String{TypeName: \"string\"}.AsBytes()\n}\nfunc (plainString) AsLink() (datamodel.Link, error) {\n\treturn mixins.String{TypeName: \"string\"}.AsLink()\n}\nfunc (plainString) Prototype() datamodel.NodePrototype {\n\treturn Prototype__String{}\n}\n\n// -- NodePrototype -->\n\ntype Prototype__String struct{}\n\nfunc (Prototype__String) NewBuilder() datamodel.NodeBuilder {\n\tvar w plainString\n\treturn &plainString__Builder{plainString__Assembler{w: &w}}\n}\n\n// -- NodeBuilder -->\n\ntype plainString__Builder struct {\n\tplainString__Assembler\n}\n\nfunc (nb *plainString__Builder) Build() datamodel.Node {\n\treturn nb.w\n}\nfunc (nb *plainString__Builder) Reset() {\n\tvar w plainString\n\t*nb = plainString__Builder{plainString__Assembler{w: &w}}\n}\n\n// -- NodeAssembler -->\n\ntype plainString__Assembler struct {\n\tw *plainString\n}\n\nfunc (plainString__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.BeginMap(0)\n}\nfunc (plainString__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.BeginList(0)\n}\nfunc (plainString__Assembler) AssignNull() error {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.AssignNull()\n}\nfunc (plainString__Assembler) AssignBool(bool) error {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.AssignBool(false)\n}\nfunc (plainString__Assembler) AssignInt(int64) error {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.AssignInt(0)\n}\nfunc (plainString__Assembler) AssignFloat(float64) error {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.AssignFloat(0)\n}\nfunc (na *plainString__Assembler) AssignString(v string) error {\n\t*na.w = plainString(v)\n\treturn nil\n}\nfunc (plainString__Assembler) AssignBytes([]byte) error {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.AssignBytes(nil)\n}\nfunc (plainString__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.StringAssembler{TypeName: \"string\"}.AssignLink(nil)\n}\nfunc (na *plainString__Assembler) AssignNode(v datamodel.Node) error {\n\tif v2, err := v.AsString(); err != nil {\n\t\treturn err\n\t} else {\n\t\t*na.w = plainString(v2)\n\t\treturn nil\n\t}\n}\nfunc (plainString__Assembler) Prototype() datamodel.NodePrototype {\n\treturn Prototype__String{}\n}\n"
  },
  {
    "path": "node/basicnode/string_test.go",
    "content": "package basicnode_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nfunc TestString(t *testing.T) {\n\ttests.SpecTestString(t, basicnode.Prototype__String{})\n}\n"
  },
  {
    "path": "node/bindnode/api.go",
    "content": "// Package bindnode provides a datamodel.Node implementation via Go reflection.\n//\n// This package is EXPERIMENTAL; its behavior and API might change as it's still\n// in development.\npackage bindnode\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// Prototype implements a schema.TypedPrototype given a Go pointer type and an\n// IPLD schema type. Note that the result is also a datamodel.NodePrototype.\n//\n// If both the Go type and schema type are supplied, it is assumed that they are\n// compatible with one another.\n//\n// If either the Go type or schema type are nil, we infer the missing type from\n// the other provided type. For example, we can infer an unnamed Go struct type\n// for a schema struct type, and we can infer a schema Int type for a Go int64\n// type. The inferring logic is still a work in progress and subject to change.\n// At this time, inferring IPLD Unions and Enums from Go types is not supported.\n//\n// When supplying a non-nil ptrType, Prototype only obtains the Go pointer type\n// from it, so its underlying value will typically be nil. For example:\n//\n//\tproto := bindnode.Prototype((*goType)(nil), schemaType)\nfunc Prototype(ptrType interface{}, schemaType schema.Type, options ...Option) schema.TypedPrototype {\n\tif ptrType == nil && schemaType == nil {\n\t\tpanic(\"bindnode: either ptrType or schemaType must not be nil\")\n\t}\n\n\tcfg := applyOptions(options...)\n\n\t// TODO: if both are supplied, verify that they are compatible\n\n\tvar goType reflect.Type\n\tif ptrType == nil {\n\t\tgoType = inferGoType(schemaType, make(map[schema.TypeName]inferredStatus), 0)\n\t} else {\n\t\tgoPtrType := reflect.TypeOf(ptrType)\n\t\tif goPtrType.Kind() != reflect.Ptr {\n\t\t\tpanic(\"bindnode: ptrType must be a pointer\")\n\t\t}\n\t\tgoType = goPtrType.Elem()\n\t\tif goType.Kind() == reflect.Ptr {\n\t\t\tpanic(\"bindnode: ptrType must not be a pointer to a pointer\")\n\t\t}\n\n\t\tif schemaType == nil {\n\t\t\tschemaType = inferSchema(goType, 0)\n\t\t} else {\n\t\t\tverifyCompatibility(cfg, make(map[seenEntry]bool), goType, schemaType)\n\t\t}\n\t}\n\n\treturn &_prototype{cfg: cfg, schemaType: schemaType, goType: goType}\n}\n\ntype converter struct {\n\tkind schema.TypeKind\n\n\tcustomFromBool func(bool) (interface{}, error)\n\tcustomToBool   func(interface{}) (bool, error)\n\n\tcustomFromInt func(int64) (interface{}, error)\n\tcustomToInt   func(interface{}) (int64, error)\n\n\tcustomFromFloat func(float64) (interface{}, error)\n\tcustomToFloat   func(interface{}) (float64, error)\n\n\tcustomFromString func(string) (interface{}, error)\n\tcustomToString   func(interface{}) (string, error)\n\n\tcustomFromBytes func([]byte) (interface{}, error)\n\tcustomToBytes   func(interface{}) ([]byte, error)\n\n\tcustomFromLink func(cid.Cid) (interface{}, error)\n\tcustomToLink   func(interface{}) (cid.Cid, error)\n\n\tcustomFromAny func(datamodel.Node) (interface{}, error)\n\tcustomToAny   func(interface{}) (datamodel.Node, error)\n}\n\ntype config struct {\n\tnamedConverters map[schema.TypeName]*converter\n\ttypeConverters  map[reflect.Type]*converter\n}\n\n// this mainly exists to short-circuit the nonPtrType() call; the `Type()` variant\n// exists for completeness\nfunc (c *config) converterFor(typeName schema.TypeName, val reflect.Value) *converter {\n\tif c == nil {\n\t\treturn nil\n\t}\n\n\tif namedConverter, ok := c.namedConverters[typeName]; ok {\n\t\treturn namedConverter\n\t}\n\n\treturn c.typeConverters[nonPtrType(val)]\n}\n\nfunc (c *config) converterForType(typeName schema.TypeName, typ reflect.Type) *converter {\n\tif c == nil {\n\t\treturn nil\n\t}\n\tif namedConverter, ok := c.namedConverters[typeName]; ok {\n\t\treturn namedConverter\n\t}\n\n\treturn c.typeConverters[typ]\n}\n\n// Option is able to apply custom options to the bindnode API\ntype Option func(*config)\n\n// TypedBoolConverter adds custom converter functions for a particular\n// type as identified by a pointer in the first argument.\n// The fromFunc is of the form: func(bool) (interface{}, error)\n// and toFunc is of the form: func(interface{}) (bool, error)\n// where interface{} is a pointer form of the type we are converting.\n//\n// TypedBoolConverter is an EXPERIMENTAL API and may be removed or\n// changed in a future release.\nfunc TypedBoolConverter(ptrVal interface{}, from func(bool) (interface{}, error), to func(interface{}) (bool, error)) Option {\n\tcustomType := nonPtrType(reflect.ValueOf(ptrVal))\n\tconverter := &converter{\n\t\tkind:           schema.TypeKind_Bool,\n\t\tcustomFromBool: from,\n\t\tcustomToBool:   to,\n\t}\n\treturn func(cfg *config) {\n\t\tcfg.typeConverters[customType] = converter\n\t}\n}\n\n// TypedIntConverter adds custom converter functions for a particular\n// type as identified by a pointer in the first argument.\n// The fromFunc is of the form: func(int64) (interface{}, error)\n// and toFunc is of the form: func(interface{}) (int64, error)\n// where interface{} is a pointer form of the type we are converting.\n//\n// TypedIntConverter is an EXPERIMENTAL API and may be removed or\n// changed in a future release.\nfunc TypedIntConverter(ptrVal interface{}, from func(int64) (interface{}, error), to func(interface{}) (int64, error)) Option {\n\tcustomType := nonPtrType(reflect.ValueOf(ptrVal))\n\tconverter := &converter{\n\t\tkind:          schema.TypeKind_Int,\n\t\tcustomFromInt: from,\n\t\tcustomToInt:   to,\n\t}\n\treturn func(cfg *config) {\n\t\tcfg.typeConverters[customType] = converter\n\t}\n}\n\n// TypedFloatConverter adds custom converter functions for a particular\n// type as identified by a pointer in the first argument.\n// The fromFunc is of the form: func(float64) (interface{}, error)\n// and toFunc is of the form: func(interface{}) (float64, error)\n// where interface{} is a pointer form of the type we are converting.\n//\n// TypedFloatConverter is an EXPERIMENTAL API and may be removed or\n// changed in a future release.\nfunc TypedFloatConverter(ptrVal interface{}, from func(float64) (interface{}, error), to func(interface{}) (float64, error)) Option {\n\tcustomType := nonPtrType(reflect.ValueOf(ptrVal))\n\tconverter := &converter{\n\t\tkind:            schema.TypeKind_Float,\n\t\tcustomFromFloat: from,\n\t\tcustomToFloat:   to,\n\t}\n\treturn func(cfg *config) {\n\t\tcfg.typeConverters[customType] = converter\n\t}\n}\n\n// TypedStringConverter adds custom converter functions for a particular\n// type as identified by a pointer in the first argument.\n// The fromFunc is of the form: func(string) (interface{}, error)\n// and toFunc is of the form: func(interface{}) (string, error)\n// where interface{} is a pointer form of the type we are converting.\n//\n// TypedStringConverter is an EXPERIMENTAL API and may be removed or\n// changed in a future release.\nfunc TypedStringConverter(ptrVal interface{}, from func(string) (interface{}, error), to func(interface{}) (string, error)) Option {\n\tcustomType := nonPtrType(reflect.ValueOf(ptrVal))\n\tconverter := &converter{\n\t\tkind:             schema.TypeKind_String,\n\t\tcustomFromString: from,\n\t\tcustomToString:   to,\n\t}\n\treturn func(cfg *config) {\n\t\tcfg.typeConverters[customType] = converter\n\t}\n}\n\n// TypedBytesConverter adds custom converter functions for a particular\n// type as identified by a pointer in the first argument.\n// The fromFunc is of the form: func([]byte) (interface{}, error)\n// and toFunc is of the form: func(interface{}) ([]byte, error)\n// where interface{} is a pointer form of the type we are converting.\n//\n// TypedBytesConverter is an EXPERIMENTAL API and may be removed or\n// changed in a future release.\nfunc TypedBytesConverter(ptrVal interface{}, from func([]byte) (interface{}, error), to func(interface{}) ([]byte, error)) Option {\n\tcustomType := nonPtrType(reflect.ValueOf(ptrVal))\n\tconverter := &converter{\n\t\tkind:            schema.TypeKind_Bytes,\n\t\tcustomFromBytes: from,\n\t\tcustomToBytes:   to,\n\t}\n\treturn func(cfg *config) {\n\t\tcfg.typeConverters[customType] = converter\n\t}\n}\n\n// TypedLinkConverter adds custom converter functions for a particular\n// type as identified by a pointer in the first argument.\n// The fromFunc is of the form: func([]byte) (interface{}, error)\n// and toFunc is of the form: func(interface{}) ([]byte, error)\n// where interface{} is a pointer form of the type we are converting.\n//\n// Beware that this API is only compatible with cidlink.Link types in the data\n// model and may result in errors if attempting to convert from other\n// datamodel.Link types.\n//\n// TypedLinkConverter is an EXPERIMENTAL API and may be removed or\n// changed in a future release.\nfunc TypedLinkConverter(ptrVal interface{}, from func(cid.Cid) (interface{}, error), to func(interface{}) (cid.Cid, error)) Option {\n\tcustomType := nonPtrType(reflect.ValueOf(ptrVal))\n\tconverter := &converter{\n\t\tkind:           schema.TypeKind_Link,\n\t\tcustomFromLink: from,\n\t\tcustomToLink:   to,\n\t}\n\treturn func(cfg *config) {\n\t\tcfg.typeConverters[customType] = converter\n\t}\n}\n\n// TypedAnyConverter adds custom converter functions for a particular\n// type as identified by a pointer in the first argument.\n// The fromFunc is of the form: func(datamodel.Node) (interface{}, error)\n// and toFunc is of the form: func(interface{}) (datamodel.Node, error)\n// where interface{} is a pointer form of the type we are converting.\n//\n// This method should be able to deal with all forms of Any and return an error\n// if the expected data forms don't match the expected.\n//\n// TypedAnyConverter is an EXPERIMENTAL API and may be removed or\n// changed in a future release.\nfunc TypedAnyConverter(ptrVal interface{}, from func(datamodel.Node) (interface{}, error), to func(interface{}) (datamodel.Node, error)) Option {\n\tcustomType := nonPtrType(reflect.ValueOf(ptrVal))\n\tconverter := &converter{\n\t\tkind:          schema.TypeKind_Any,\n\t\tcustomFromAny: from,\n\t\tcustomToAny:   to,\n\t}\n\treturn func(cfg *config) {\n\t\tcfg.typeConverters[customType] = converter\n\t}\n}\n\n// NamedBoolConverter adds custom converter functions for given\n// named schema type.\n// The fromFunc is of the form: func(bool) (interface{}, error)\n// and toFunc is of the form: func(interface{}) (bool, error)\n// where interface{} is a pointer form of the type we are converting.\n//\n// NamedBoolConverter is an EXPERIMENTAL API and may be removed or\n// changed in a future release.\nfunc NamedBoolConverter(typeName schema.TypeName, from func(bool) (interface{}, error), to func(interface{}) (bool, error)) Option {\n\tconverter := &converter{\n\t\tkind:           schema.TypeKind_Bool,\n\t\tcustomFromBool: from,\n\t\tcustomToBool:   to,\n\t}\n\treturn func(cfg *config) {\n\t\tcfg.namedConverters[typeName] = converter\n\t}\n}\n\n// NamedIntConverter adds custom converter functions for given\n// named schema type.\n// The fromFunc is of the form: func(int64) (interface{}, error)\n// and toFunc is of the form: func(interface{}) (int64, error)\n// where interface{} is a pointer form of the type we are converting.\n//\n// NamedIntConverter is an EXPERIMENTAL API and may be removed or\n// changed in a future release.\nfunc NamedIntConverter(typeName schema.TypeName, from func(int64) (interface{}, error), to func(interface{}) (int64, error)) Option {\n\tconverter := &converter{\n\t\tkind:          schema.TypeKind_Int,\n\t\tcustomFromInt: from,\n\t\tcustomToInt:   to,\n\t}\n\treturn func(cfg *config) {\n\t\tcfg.namedConverters[typeName] = converter\n\t}\n}\n\n// NamedFloatConverter adds custom converter functions for given\n// named schema type.\n// The fromFunc is of the form: func(float64) (interface{}, error)\n// and toFunc is of the form: func(interface{}) (float64, error)\n// where interface{} is a pointer form of the type we are converting.\n//\n// NamedFloatConverter is an EXPERIMENTAL API and may be removed or\n// changed in a future release.\nfunc NamedFloatConverter(typeName schema.TypeName, from func(float64) (interface{}, error), to func(interface{}) (float64, error)) Option {\n\tconverter := &converter{\n\t\tkind:            schema.TypeKind_Float,\n\t\tcustomFromFloat: from,\n\t\tcustomToFloat:   to,\n\t}\n\treturn func(cfg *config) {\n\t\tcfg.namedConverters[typeName] = converter\n\t}\n}\n\n// NamedStringConverter adds custom converter functions for given\n// named schema type.\n// The fromFunc is of the form: func(string) (interface{}, error)\n// and toFunc is of the form: func(interface{}) (string, error)\n// where interface{} is a pointer form of the type we are converting.\n//\n// NamedStringConverter is an EXPERIMENTAL API and may be removed or\n// changed in a future release.\nfunc NamedStringConverter(typeName schema.TypeName, from func(string) (interface{}, error), to func(interface{}) (string, error)) Option {\n\tconverter := &converter{\n\t\tkind:             schema.TypeKind_String,\n\t\tcustomFromString: from,\n\t\tcustomToString:   to,\n\t}\n\treturn func(cfg *config) {\n\t\tcfg.namedConverters[typeName] = converter\n\t}\n}\n\n// NamedBytesConverter adds custom converter functions for given\n// named schema type.\n// The fromFunc is of the form: func([]byte) (interface{}, error)\n// and toFunc is of the form: func(interface{}) ([]byte, error)\n// where interface{} is a pointer form of the type we are converting.\n//\n// NamedBytesConverter is an EXPERIMENTAL API and may be removed or\n// changed in a future release.\nfunc NamedBytesConverter(typeName schema.TypeName, from func([]byte) (interface{}, error), to func(interface{}) ([]byte, error)) Option {\n\tconverter := &converter{\n\t\tkind:            schema.TypeKind_Bytes,\n\t\tcustomFromBytes: from,\n\t\tcustomToBytes:   to,\n\t}\n\treturn func(cfg *config) {\n\t\tcfg.namedConverters[typeName] = converter\n\t}\n}\n\n// NamedLinkConverter adds custom converter functions for given\n// named schema type.\n// The fromFunc is of the form: func([]byte) (interface{}, error)\n// and toFunc is of the form: func(interface{}) ([]byte, error)\n// where interface{} is a pointer form of the type we are converting.\n//\n// Beware that this API is only compatible with cidlink.Link types in the data\n// model and may result in errors if attempting to convert from other\n// datamodel.Link types.\n//\n// NamedLinkConverter is an EXPERIMENTAL API and may be removed or\n// changed in a future release.\nfunc NamedLinkConverter(typeName schema.TypeName, from func(cid.Cid) (interface{}, error), to func(interface{}) (cid.Cid, error)) Option {\n\tconverter := &converter{\n\t\tkind:           schema.TypeKind_Link,\n\t\tcustomFromLink: from,\n\t\tcustomToLink:   to,\n\t}\n\treturn func(cfg *config) {\n\t\tcfg.namedConverters[typeName] = converter\n\t}\n}\n\n// NamedAnyConverter adds custom converter functions for given\n// named schema type.\n// The fromFunc is of the form: func(datamodel.Node) (interface{}, error)\n// and toFunc is of the form: func(interface{}) (datamodel.Node, error)\n// where interface{} is a pointer form of the type we are converting.\n//\n// This method should be able to deal with all forms of Any and return an error\n// if the expected data forms don't match the expected.\n//\n// NamedAnyConverter is an EXPERIMENTAL API and may be removed or\n// changed in a future release.\nfunc NamedAnyConverter(typeName schema.TypeName, from func(datamodel.Node) (interface{}, error), to func(interface{}) (datamodel.Node, error)) Option {\n\tconverter := &converter{\n\t\tkind:          schema.TypeKind_Any,\n\t\tcustomFromAny: from,\n\t\tcustomToAny:   to,\n\t}\n\treturn func(cfg *config) {\n\t\tcfg.namedConverters[typeName] = converter\n\t}\n}\n\nfunc applyOptions(opt ...Option) *config {\n\tif len(opt) == 0 {\n\t\t// no need to allocate, we access it via converterFor and converterForType\n\t\t// which are safe for nil maps\n\t\treturn nil\n\t}\n\tcfg := &config{\n\t\tnamedConverters: make(map[string]*converter),\n\t\ttypeConverters:  make(map[reflect.Type]*converter),\n\t}\n\n\tfor _, o := range opt {\n\t\to(cfg)\n\t}\n\treturn cfg\n}\n\n// Wrap implements a schema.TypedNode given a non-nil pointer to a Go value and an\n// IPLD schema type. Note that the result is also a datamodel.Node.\n//\n// Wrap is meant to be used when one already has a Go value with data.\n// As such, ptrVal must not be nil.\n//\n// Similar to Prototype, if schemaType is non-nil it is assumed to be compatible\n// with the Go type, and otherwise it's inferred from the Go type.\nfunc Wrap(ptrVal interface{}, schemaType schema.Type, options ...Option) schema.TypedNode {\n\tif ptrVal == nil {\n\t\tpanic(\"bindnode: ptrVal must not be nil\")\n\t}\n\tgoPtrVal := reflect.ValueOf(ptrVal)\n\tif goPtrVal.Kind() != reflect.Ptr {\n\t\tpanic(\"bindnode: ptrVal must be a pointer\")\n\t}\n\tif goPtrVal.IsNil() {\n\t\t// Note that this can happen if ptrVal was a typed nil.\n\t\tpanic(\"bindnode: ptrVal must not be nil\")\n\t}\n\tcfg := applyOptions(options...)\n\tgoVal := goPtrVal.Elem()\n\tif goVal.Kind() == reflect.Ptr {\n\t\tpanic(\"bindnode: ptrVal must not be a pointer to a pointer\")\n\t}\n\tif schemaType == nil {\n\t\tschemaType = inferSchema(goVal.Type(), 0)\n\t} else {\n\t\t// TODO(rvagg): explore ways to make this skippable by caching in the schema.Type\n\t\t// passed in to this function; e.g. if you call Prototype(), then you've gone through\n\t\t// this already, then calling .Type() on that could return a bindnode version of\n\t\t// schema.Type that has the config cached and can be assumed to have been checked or\n\t\t// inferred.\n\t\tverifyCompatibility(cfg, make(map[seenEntry]bool), goVal.Type(), schemaType)\n\t}\n\treturn newNode(cfg, schemaType, goVal)\n}\n\n// TODO: consider making our own Node interface, like:\n//\n// type WrappedNode interface {\n//     datamodel.Node\n//     Unwrap() (ptrVal interface)\n// }\n//\n// Pros: API is easier to understand, harder to mix up with other datamodel.Nodes.\n// Cons: One usually only has a datamodel.Node, and type assertions can be weird.\n\n// Unwrap takes a datamodel.Node implemented by Prototype or Wrap,\n// and returns a pointer to the inner Go value.\n//\n// Unwrap returns nil if the node isn't implemented by this package.\nfunc Unwrap(node datamodel.Node) (ptrVal interface{}) {\n\tvar val reflect.Value\n\tswitch node := node.(type) {\n\tcase *_node:\n\t\tval = node.val\n\tcase *_nodeRepr:\n\t\tval = node.val\n\tdefault:\n\t\treturn nil\n\t}\n\tif val.Kind() == reflect.Ptr {\n\t\tpanic(\"bindnode: didn't expect val to be a pointer\")\n\t}\n\treturn val.Addr().Interface()\n}\n"
  },
  {
    "path": "node/bindnode/api_test.go",
    "content": "package bindnode_test\n\nimport (\n\t\"encoding/hex\"\n\t\"math\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagcbor\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n)\n\nfunc TestEnumError(t *testing.T) {\n\ttype Action string\n\tconst (\n\t\tActionPresent = Action(\"p\")\n\t\tActionMissing = Action(\"m\")\n\t)\n\ttype S struct{ Action Action }\n\n\tschema := `\n\t\ttype S struct {\n\t\t\tAction Action\n\t\t} representation tuple\n\t\ttype Action enum {\n\t\t\t| Present             (\"p\")\n\t\t\t| Missing             (\"m\")\n\t\t} representation string\n \t`\n\n\ttypeSystem, err := ipld.LoadSchemaBytes([]byte(schema))\n\tqt.Assert(t, err, qt.IsNil)\n\tschemaType := typeSystem.TypeByName(\"S\")\n\n\tnode := bindnode.Wrap(&S{Action: ActionPresent}, schemaType).Representation()\n\t_, err = ipld.Encode(node, dagcbor.Encode)\n\tqt.Assert(t, err, qt.IsNotNil)\n\tqt.Assert(t, err.Error(), qt.Equals, `AsString: \"p\" is not a valid member of enum Action (bindnode works at the type level; did you mean \"Present\"?)`)\n}\n\nfunc TestSubNodeWalkAndUnwrap(t *testing.T) {\n\ttype F struct {\n\t\tF bool\n\t}\n\ttype B struct {\n\t\tB int\n\t}\n\ttype A struct {\n\t\tA string\n\t}\n\ttype S struct {\n\t\tF      F\n\t\tB      B\n\t\tA      *A\n\t\tAny    datamodel.Node\n\t\tBytes  []byte\n\t\tString string\n\t}\n\n\tschema := `\n\t\ttype F struct {\n\t\t\tF Bool\n\t\t} representation tuple\n\t\ttype B struct {\n\t\t\tB Int\n\t\t} representation tuple\n\t\ttype A struct {\n\t\t\tA String\n\t\t} representation tuple\n\t\ttype S struct {\n\t\t\tF F\n\t\t\tB B\n\t\t\tA optional A\n\t\t\tAny Any\n\t\t\tBytes Bytes\n\t\t\tString String\n\t\t} representation tuple\n\t`\n\n\tencodedHex := \"8681f581186581624141fb4069466666666666430102036f636f6e7374616e7420737472696e67\" // [[true],[101],[\"AA\"],202.2,[]byte{1,2,3},\"constant string\"]\n\tbyts := []byte{0, 1, 2, 3}\n\tconst constStr = \"constant string\"\n\n\texpected := S{\n\t\tF:      F{true},\n\t\tB:      B{101},\n\t\tA:      &A{\"AAA\"[1:]},\n\t\tAny:    basicnode.NewFloat(202.2),\n\t\tBytes:  byts[1:],\n\t\tString: constStr,\n\t}\n\n\ttypeSystem, err := ipld.LoadSchemaBytes([]byte(schema))\n\tqt.Assert(t, err, qt.IsNil)\n\tschemaType := typeSystem.TypeByName(\"S\")\n\n\tverifyMap := func(node datamodel.Node) {\n\t\tmi := node.MapIterator()\n\n\t\tkey, value, err := mi.Next()\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tstr, err := key.AsString()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, str, qt.Equals, \"F\")\n\n\t\ttyp := bindnode.Unwrap(value)\n\t\tinstF, ok := typ.(*F)\n\t\tqt.Assert(t, ok, qt.IsTrue)\n\t\tqt.Assert(t, *instF, qt.Equals, F{true})\n\n\t\tkey, value, err = mi.Next()\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tstr, err = key.AsString()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, str, qt.Equals, \"B\")\n\n\t\ttyp = bindnode.Unwrap(value)\n\t\tinstB, ok := typ.(*B)\n\t\tqt.Assert(t, ok, qt.IsTrue)\n\t\tqt.Assert(t, *instB, qt.Equals, B{101})\n\n\t\tkey, value, err = mi.Next()\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tstr, err = key.AsString()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, str, qt.Equals, \"A\")\n\n\t\ttyp = bindnode.Unwrap(value)\n\t\tinstA, ok := typ.(*A)\n\t\tqt.Assert(t, ok, qt.IsTrue)\n\t\tqt.Assert(t, *instA, qt.Equals, A{\"AA\"})\n\n\t\tkey, value, err = mi.Next()\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tstr, err = key.AsString()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, str, qt.Equals, \"Any\")\n\n\t\tqt.Assert(t, ipld.DeepEqual(basicnode.NewFloat(202.2), value), qt.IsTrue)\n\n\t\tkey, value, err = mi.Next()\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tstr, err = key.AsString()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, str, qt.Equals, \"Bytes\")\n\n\t\ttyp = bindnode.Unwrap(value)\n\t\tinstByts, ok := typ.(*[]byte)\n\t\tqt.Assert(t, ok, qt.IsTrue)\n\t\tqt.Assert(t, *instByts, qt.DeepEquals, []byte{1, 2, 3})\n\n\t\tkey, value, err = mi.Next()\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tstr, err = key.AsString()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Assert(t, str, qt.Equals, \"String\")\n\n\t\ttyp = bindnode.Unwrap(value)\n\t\tinstStr, ok := typ.(*string)\n\t\tqt.Assert(t, ok, qt.IsTrue)\n\t\tqt.Assert(t, *instStr, qt.DeepEquals, \"constant string\")\n\t}\n\n\tt.Run(\"decode\", func(t *testing.T) {\n\t\tencoded, _ := hex.DecodeString(encodedHex)\n\n\t\tproto := bindnode.Prototype(&S{}, schemaType)\n\n\t\tnode, err := ipld.DecodeUsingPrototype([]byte(encoded), dagcbor.Decode, proto)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\ttyp := bindnode.Unwrap(node)\n\t\tinstS, ok := typ.(*S)\n\t\tqt.Assert(t, ok, qt.IsTrue)\n\n\t\tqt.Assert(t, *instS, qt.DeepEquals, expected)\n\n\t\tverifyMap(node)\n\t})\n\n\tt.Run(\"encode\", func(t *testing.T) {\n\t\tnode := bindnode.Wrap(&expected, schemaType)\n\n\t\tbyts, err := ipld.Encode(node, dagcbor.Encode)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tqt.Assert(t, hex.EncodeToString(byts), qt.Equals, encodedHex)\n\n\t\tverifyMap(node)\n\t})\n}\n\nfunc TestUint64Struct(t *testing.T) {\n\tt.Run(\"in struct\", func(t *testing.T) {\n\t\ttype IntHolder struct {\n\t\t\tInt32  int32\n\t\t\tInt64  int64\n\t\t\tUint64 uint64\n\t\t}\n\t\tschema := `\n\t\t\ttype IntHolder struct {\n\t\t\t\tInt32 Int\n\t\t\t\tInt64 Int\n\t\t\t\tUint64 Int\n\t\t\t}\n\t\t`\n\n\t\tmaxExpectedHex := \"a365496e7433321a7fffffff65496e7436341b7fffffffffffffff6655696e7436341bffffffffffffffff\"\n\t\tmaxExpected, err := hex.DecodeString(maxExpectedHex)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\ttypeSystem, err := ipld.LoadSchemaBytes([]byte(schema))\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tschemaType := typeSystem.TypeByName(\"IntHolder\")\n\t\tproto := bindnode.Prototype(&IntHolder{}, schemaType)\n\n\t\tnode, err := ipld.DecodeUsingPrototype([]byte(maxExpected), dagcbor.Decode, proto)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\ttyp := bindnode.Unwrap(node)\n\t\tinst, ok := typ.(*IntHolder)\n\t\tqt.Assert(t, ok, qt.IsTrue)\n\n\t\tqt.Assert(t, *inst, qt.DeepEquals, IntHolder{\n\t\t\tInt32:  math.MaxInt32,\n\t\t\tInt64:  math.MaxInt64,\n\t\t\tUint64: math.MaxUint64,\n\t\t})\n\n\t\tnode = bindnode.Wrap(inst, schemaType).Representation()\n\t\tbyt, err := ipld.Encode(node, dagcbor.Encode)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tqt.Assert(t, hex.EncodeToString(byt), qt.Equals, maxExpectedHex)\n\t})\n\n\tt.Run(\"plain\", func(t *testing.T) {\n\t\ttype IntHolder uint64\n\t\tschema := `type IntHolder int`\n\n\t\tmaxExpectedHex := \"1bffffffffffffffff\"\n\t\tmaxExpected, err := hex.DecodeString(maxExpectedHex)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\ttypeSystem, err := ipld.LoadSchemaBytes([]byte(schema))\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tschemaType := typeSystem.TypeByName(\"IntHolder\")\n\t\tproto := bindnode.Prototype((*IntHolder)(nil), schemaType)\n\n\t\tnode, err := ipld.DecodeUsingPrototype([]byte(maxExpected), dagcbor.Decode, proto)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\ttyp := bindnode.Unwrap(node)\n\t\tinst, ok := typ.(*IntHolder)\n\t\tqt.Assert(t, ok, qt.IsTrue)\n\n\t\tqt.Assert(t, *inst, qt.Equals, IntHolder(math.MaxUint64))\n\n\t\tnode = bindnode.Wrap(inst, schemaType).Representation()\n\t\tbyt, err := ipld.Encode(node, dagcbor.Encode)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tqt.Assert(t, hex.EncodeToString(byt), qt.Equals, maxExpectedHex)\n\t})\n}\n"
  },
  {
    "path": "node/bindnode/custom_test.go",
    "content": "package bindnode_test\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagcbor\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent/qp\"\n\tbasicnode \"github.com/ipld/go-ipld-prime/node/basic\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/multiformats/go-multihash\"\n\n\tqt \"github.com/frankban/quicktest\"\n)\n\ntype BoolSubst int\n\nvar errorDefault = errors.New(\"something went wrong\")\n\nconst (\n\tBoolSubst_Yes = 100\n\tBoolSubst_No  = -100\n)\n\nfunc BoolSubstFromBool(b bool) (interface{}, error) {\n\tif b {\n\t\treturn BoolSubst_Yes, nil\n\t}\n\treturn BoolSubst_No, nil\n}\n\nfunc BoolSubstFromBoolError(b bool) (interface{}, error) {\n\treturn BoolSubst_No, errorDefault\n}\n\nfunc BoolToBoolSubst(b interface{}) (bool, error) {\n\tbp, ok := b.(*BoolSubst)\n\tif !ok {\n\t\treturn true, fmt.Errorf(\"expected *BoolSubst value\")\n\t}\n\tswitch *bp {\n\tcase BoolSubst_Yes:\n\t\treturn true, nil\n\tcase BoolSubst_No:\n\t\treturn false, nil\n\tdefault:\n\t\treturn true, fmt.Errorf(\"bad BoolSubst\")\n\t}\n}\nfunc BoolToBoolSubstError(b interface{}) (bool, error) {\n\treturn false, errorDefault\n}\n\ntype IntSubst string\n\nfunc IntSubstFromInt(i int64) (interface{}, error) {\n\tif i == 1000 {\n\t\treturn \"one thousand\", nil\n\t} else if i == 2000 {\n\t\treturn \"two thousand\", nil\n\t}\n\treturn nil, fmt.Errorf(\"unexpected value of IntSubst\")\n}\n\nfunc IntSubstFromIntError(i int64) (interface{}, error) {\n\treturn nil, errorDefault\n}\n\nfunc IntToIntSubst(i interface{}) (int64, error) {\n\tip, ok := i.(*IntSubst)\n\tif !ok {\n\t\treturn 0, fmt.Errorf(\"expected *IntSubst value\")\n\t}\n\tswitch *ip {\n\tcase \"one thousand\":\n\t\treturn 1000, nil\n\tcase \"two thousand\":\n\t\treturn 2000, nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"bad IntSubst\")\n\t}\n}\n\nfunc IntToIntSubstError(i interface{}) (int64, error) {\n\treturn 0, errorDefault\n}\n\ntype BigFloat struct{ *big.Float }\n\nfunc BigFloatFromFloat(f float64) (interface{}, error) {\n\tbf := big.NewFloat(f)\n\treturn &BigFloat{bf}, nil\n}\n\nfunc BigFloatFromFloatError(f float64) (interface{}, error) {\n\treturn nil, errorDefault\n}\n\nfunc FloatFromBigFloat(f interface{}) (float64, error) {\n\tfp, ok := f.(*BigFloat)\n\tif !ok {\n\t\treturn 0, fmt.Errorf(\"expected *BigFloat value\")\n\t}\n\tf64, _ := fp.Float64()\n\treturn f64, nil\n}\n\nfunc FloatFromBigFloatError(f interface{}) (float64, error) {\n\treturn 0, errorDefault\n}\n\ntype ByteArray [][]byte\n\nfunc ByteArrayFromString(s string) (interface{}, error) {\n\tsa := strings.Split(s, \"|\")\n\tba := make([][]byte, 0)\n\tfor _, a := range sa {\n\t\tba = append(ba, []byte(a))\n\t}\n\treturn ba, nil\n}\n\nfunc ByteArrayFromStringError(s string) (interface{}, error) {\n\treturn nil, errorDefault\n}\n\nfunc StringFromByteArray(b interface{}) (string, error) {\n\tbap, ok := b.(*ByteArray)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"expected *ByteArray value\")\n\t}\n\tsb := strings.Builder{}\n\tfor i, b := range *bap {\n\t\tsb.WriteString(string(b))\n\t\tif i != len(*bap)-1 {\n\t\t\tsb.WriteString(\"|\")\n\t\t}\n\t}\n\treturn sb.String(), nil\n}\n\nfunc StringFromByteArrayError(b interface{}) (string, error) {\n\treturn \"\", errorDefault\n}\n\n// similar to cid/Cid, go-address/Address, go-graphsync/RequestID\ntype Boop struct{ str string }\n\nfunc NewBoop(b []byte) *Boop {\n\treturn &Boop{string(b)}\n}\n\nfunc (b Boop) Bytes() []byte {\n\treturn []byte(b.str)\n}\n\nfunc (b Boop) String() string {\n\treturn b.str\n}\n\n// similar to go-state-types/big/Int\ntype Frop struct{ *big.Int }\n\nfunc NewFropFromString(str string) Frop {\n\tv, _ := big.NewInt(0).SetString(str, 10)\n\treturn Frop{v}\n}\n\nfunc NewFropFromBytes(buf []byte) *Frop {\n\tvar negative bool\n\tswitch buf[0] {\n\tcase 0:\n\t\tnegative = false\n\tcase 1:\n\t\tnegative = true\n\tdefault:\n\t\tpanic(\"can't handle this\")\n\t}\n\n\ti := big.NewInt(0).SetBytes(buf[1:])\n\tif negative {\n\t\ti.Neg(i)\n\t}\n\n\treturn &Frop{i}\n}\n\nfunc (b *Frop) Bytes() []byte {\n\tswitch {\n\tcase b.Sign() > 0:\n\t\treturn append([]byte{0}, b.Int.Bytes()...)\n\tcase b.Sign() < 0:\n\t\treturn append([]byte{1}, b.Int.Bytes()...)\n\tdefault:\n\t\treturn []byte{}\n\t}\n}\n\nfunc BoopFromBytes(b []byte) (interface{}, error) {\n\treturn NewBoop(b), nil\n}\n\nfunc BoopFromBytesError(b []byte) (interface{}, error) {\n\treturn nil, errorDefault\n}\n\nfunc BoopToBytes(iface interface{}) ([]byte, error) {\n\tif boop, ok := iface.(*Boop); ok {\n\t\treturn boop.Bytes(), nil\n\t}\n\treturn nil, fmt.Errorf(\"did not get expected type\")\n}\n\nfunc BoopToBytesError(iface interface{}) ([]byte, error) {\n\treturn nil, errorDefault\n}\n\nfunc FropFromBytes(b []byte) (interface{}, error) {\n\treturn NewFropFromBytes(b), nil\n}\n\nfunc FropFromBytesError(b []byte) (interface{}, error) {\n\treturn nil, errorDefault\n}\n\nfunc FropToBytes(iface interface{}) ([]byte, error) {\n\tif frop, ok := iface.(*Frop); ok {\n\t\treturn frop.Bytes(), nil\n\t}\n\treturn nil, fmt.Errorf(\"did not get expected type\")\n}\n\nfunc FropToBytesError(iface interface{}) ([]byte, error) {\n\treturn nil, errorDefault\n}\n\n// Bitcoin's version of \"links\" is a hex form of the dbl-sha2-256 digest reversed\ntype BtcId string\n\nfunc FromCidToBtcId(c cid.Cid) (interface{}, error) {\n\tif c.Prefix().Codec != cid.BitcoinBlock { // should be able to do BitcoinTx too .. but ..\n\t\treturn nil, fmt.Errorf(\"can only convert IDs for BitcoinBlock codecs\")\n\t}\n\t// and multihash must be dbl-sha2-256\n\tdig, err := multihash.Decode(c.Hash())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\thid := make([]byte, 0)\n\tfor i := len(dig.Digest) - 1; i >= 0; i-- {\n\t\thid = append(hid, dig.Digest[i])\n\t}\n\treturn BtcId(hex.EncodeToString(hid)), nil\n}\n\nfunc FromCidToBtcIdError(c cid.Cid) (interface{}, error) {\n\treturn BtcId(\"\"), errorDefault\n}\n\nfunc FromBtcIdToCid(iface interface{}) (cid.Cid, error) {\n\tbid, ok := iface.(*BtcId)\n\tif !ok {\n\t\treturn cid.Undef, fmt.Errorf(\"expected *BtcId value\")\n\t}\n\tdig := make([]byte, 0)\n\thid, err := hex.DecodeString(string(*bid))\n\tif err != nil {\n\t\treturn cid.Undef, err\n\t}\n\tfor i := len(hid) - 1; i >= 0; i-- {\n\t\tdig = append(dig, hid[i])\n\t}\n\tmh, err := multihash.Encode(dig, multihash.DBL_SHA2_256)\n\tif err != nil {\n\t\treturn cid.Undef, err\n\t}\n\treturn cid.NewCidV1(cid.BitcoinBlock, mh), nil\n}\n\nfunc FromBtcIdToCidError(iface interface{}) (cid.Cid, error) {\n\treturn cid.Undef, errorDefault\n}\n\ntype Boom struct {\n\tS    string\n\tSt   ByteArray\n\tB    Boop\n\tBo   BoolSubst\n\tBptr *Boop\n\tF    Frop\n\tFl   BigFloat\n\tI    int\n\tIn   IntSubst\n\tL    BtcId\n}\n\nconst boomSchema = `\ntype ByteArray string\ntype Boop bytes\ntype BoolSubst bool\ntype Frop bytes\ntype BigFloat float\ntype IntSubst int\ntype BtcId &Any\n\ntype Boom struct {\n\tS String\n\tSt   ByteArray\n\tB    Boop\n\tBo   BoolSubst\n\tBptr nullable Boop\n\tF    Frop\n\tFl   BigFloat\n\tI    Int\n\tIn   IntSubst\n\tL    BtcId\n} representation map\n`\n\nconst boomFixtureDagJson = `{\"B\":{\"/\":{\"bytes\":\"dGhlc2UgYXJlIGJ5dGVz\"}},\"Bo\":false,\"Bptr\":{\"/\":{\"bytes\":\"dGhlc2UgYXJlIHBvaW50ZXIgYnl0ZXM\"}},\"F\":{\"/\":{\"bytes\":\"AAH3fubjrGlwOMpClAkh/ro13L5Uls4/CtI\"}},\"Fl\":1.12,\"I\":10101,\"In\":2000,\"L\":{\"/\":\"bagyacvra2e6qt2fohajauxceox55t3gedsyqap2phmv7q2qaaaaaaaaaaaaa\"},\"S\":\"a string here\",\"St\":\"a|byte|array\"}`\n\nvar boomFixtureInstance = Boom{\n\tB:    *NewBoop([]byte(\"these are bytes\")),\n\tBo:   BoolSubst_No,\n\tBptr: NewBoop([]byte(\"these are pointer bytes\")),\n\tF:    NewFropFromString(\"12345678901234567891234567890123456789012345678901234567890\"),\n\tFl:   BigFloat{big.NewFloat(1.12)},\n\tI:    10101,\n\tIn:   IntSubst(\"two thousand\"),\n\tS:    \"a string here\",\n\tSt:   ByteArray([][]byte{[]byte(\"a\"), []byte(\"byte\"), []byte(\"array\")}),\n\tL:    BtcId(\"00000000000000006af82b3b4f3f00b11cc4ecd9fb75445c0a1238aee8093dd1\"),\n}\n\nfunc TestCustom(t *testing.T) {\n\topts := []bindnode.Option{\n\t\tbindnode.TypedBytesConverter(&Boop{}, BoopFromBytes, BoopToBytes),\n\t\tbindnode.TypedBytesConverter(&Frop{}, FropFromBytes, FropToBytes),\n\t\tbindnode.TypedBoolConverter(BoolSubst(0), BoolSubstFromBool, BoolToBoolSubst),\n\t\tbindnode.TypedIntConverter(IntSubst(\"\"), IntSubstFromInt, IntToIntSubst),\n\t\tbindnode.TypedFloatConverter(&BigFloat{}, BigFloatFromFloat, FloatFromBigFloat),\n\t\tbindnode.TypedStringConverter(&ByteArray{}, ByteArrayFromString, StringFromByteArray),\n\t\tbindnode.TypedLinkConverter(BtcId(\"\"), FromCidToBtcId, FromBtcIdToCid),\n\t}\n\n\ttypeSystem, err := ipld.LoadSchemaBytes([]byte(boomSchema))\n\tqt.Assert(t, err, qt.IsNil)\n\tschemaType := typeSystem.TypeByName(\"Boom\")\n\tproto := bindnode.Prototype(&Boom{}, schemaType, opts...)\n\n\tbuilder := proto.Representation().NewBuilder()\n\terr = dagjson.Decode(builder, bytes.NewReader([]byte(boomFixtureDagJson)))\n\tqt.Assert(t, err, qt.IsNil)\n\n\ttyp := bindnode.Unwrap(builder.Build())\n\tinst, ok := typ.(*Boom)\n\tqt.Assert(t, ok, qt.IsTrue)\n\n\tcmpr := qt.CmpEquals(\n\t\tcmp.Comparer(func(x, y Boop) bool { return x.String() == y.String() }),\n\t\tcmp.Comparer(func(x, y Frop) bool { return x.String() == y.String() }),\n\t\tcmp.Comparer(func(x, y BigFloat) bool { return x.String() == y.String() }),\n\t)\n\tqt.Assert(t, *inst, cmpr, boomFixtureInstance)\n\n\ttn := bindnode.Wrap(inst, schemaType, opts...)\n\tvar buf bytes.Buffer\n\terr = dagjson.Encode(tn.Representation(), &buf)\n\tqt.Assert(t, err, qt.IsNil)\n\n\tqt.Assert(t, buf.String(), qt.Equals, boomFixtureDagJson)\n}\n\nfunc TestCustomNamed(t *testing.T) {\n\topts := []bindnode.Option{\n\t\tbindnode.NamedBytesConverter(\"Boop\", BoopFromBytes, BoopToBytes),\n\t\tbindnode.NamedBytesConverter(\"Frop\", FropFromBytes, FropToBytes),\n\t\tbindnode.NamedBoolConverter(\"BoolSubst\", BoolSubstFromBool, BoolToBoolSubst),\n\t\tbindnode.NamedIntConverter(\"IntSubst\", IntSubstFromInt, IntToIntSubst),\n\t\tbindnode.NamedFloatConverter(\"BigFloat\", BigFloatFromFloat, FloatFromBigFloat),\n\t\tbindnode.NamedStringConverter(\"ByteArray\", ByteArrayFromString, StringFromByteArray),\n\t\tbindnode.NamedLinkConverter(\"BtcId\", FromCidToBtcId, FromBtcIdToCid),\n\t\t// these will error, but shouldn't get called cause the named converters take precedence\n\t\tbindnode.TypedBytesConverter(&Boop{}, BoopFromBytesError, BoopToBytesError),\n\t\tbindnode.TypedBytesConverter(&Frop{}, FropFromBytesError, FropToBytesError),\n\t\tbindnode.TypedBoolConverter(BoolSubst(0), BoolSubstFromBoolError, BoolToBoolSubstError),\n\t\tbindnode.TypedIntConverter(IntSubst(\"\"), IntSubstFromIntError, IntToIntSubstError),\n\t\tbindnode.TypedFloatConverter(&BigFloat{}, BigFloatFromFloatError, FloatFromBigFloatError),\n\t\tbindnode.TypedStringConverter(&ByteArray{}, ByteArrayFromStringError, StringFromByteArrayError),\n\t\tbindnode.TypedLinkConverter(BtcId(\"\"), FromCidToBtcIdError, FromBtcIdToCidError),\n\t}\n\n\ttypeSystem, err := ipld.LoadSchemaBytes([]byte(boomSchema))\n\tqt.Assert(t, err, qt.IsNil)\n\tschemaType := typeSystem.TypeByName(\"Boom\")\n\tproto := bindnode.Prototype(&Boom{}, schemaType, opts...)\n\n\tbuilder := proto.Representation().NewBuilder()\n\terr = dagjson.Decode(builder, bytes.NewReader([]byte(boomFixtureDagJson)))\n\tqt.Assert(t, err, qt.IsNil)\n\n\ttyp := bindnode.Unwrap(builder.Build())\n\tinst, ok := typ.(*Boom)\n\tqt.Assert(t, ok, qt.IsTrue)\n\n\tcmpr := qt.CmpEquals(\n\t\tcmp.Comparer(func(x, y Boop) bool { return x.String() == y.String() }),\n\t\tcmp.Comparer(func(x, y Frop) bool { return x.String() == y.String() }),\n\t\tcmp.Comparer(func(x, y BigFloat) bool { return x.String() == y.String() }),\n\t)\n\tqt.Assert(t, *inst, cmpr, boomFixtureInstance)\n\n\ttn := bindnode.Wrap(inst, schemaType, opts...)\n\tvar buf bytes.Buffer\n\terr = dagjson.Encode(tn.Representation(), &buf)\n\tqt.Assert(t, err, qt.IsNil)\n\n\tqt.Assert(t, buf.String(), qt.Equals, boomFixtureDagJson)\n}\n\ntype AnyExtend struct {\n\tName         string\n\tBlob         AnyExtendBlob\n\tCount        int\n\tNull         AnyCborEncoded\n\tNullPtr      *AnyCborEncoded\n\tNullableWith *AnyCborEncoded\n\tBool         AnyCborEncoded\n\tInt          AnyCborEncoded\n\tFloat        AnyCborEncoded\n\tString       AnyCborEncoded\n\tBytes        AnyCborEncoded\n\tLink         AnyCborEncoded\n\tMap          AnyCborEncoded\n\tList         AnyCborEncoded\n\tBoolPtr      *BoolSubst // included to test that a null entry won't call a non-Any converter\n\tXListAny     []AnyCborEncoded\n\tXMapAny      anyMap\n}\n\ntype anyMap struct {\n\tKeys   []string\n\tValues map[string]*AnyCborEncoded\n}\n\nconst anyExtendSchema = `\ntype AnyExtend struct {\n\tName String\n\tBlob Any\n\tCount Int\n\tNull nullable Any\n\tNullPtr nullable Any\n\tNullableWith nullable Any\n\tBool Any\n\tInt Any\n\tFloat Any\n\tString Any\n\tBytes Any\n\tLink Any\n\tMap Any\n\tList Any\n\tBoolPtr nullable Bool\n\tXListAny [Any]\n\tXMapAny {String:Any}\n}\n`\n\ntype AnyExtendBlob struct {\n\tf string\n\tx int64\n\ty int64\n\tz int64\n}\n\nfunc AnyExtendBlobFromNode(node datamodel.Node) (interface{}, error) {\n\tfoo, err := node.LookupByString(\"foo\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfooStr, err := foo.AsString()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbaz, err := node.LookupByString(\"baz\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx, err := baz.LookupByIndex(0)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\txi, err := x.AsInt()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ty, err := baz.LookupByIndex(1)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tyi, err := y.AsInt()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tz, err := baz.LookupByIndex(2)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tzi, err := z.AsInt()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &AnyExtendBlob{f: fooStr, x: xi, y: yi, z: zi}, nil\n}\n\nfunc (aeb AnyExtendBlob) ToNode() (datamodel.Node, error) {\n\treturn qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {\n\t\tqp.MapEntry(ma, \"foo\", qp.String(aeb.f))\n\t\tqp.MapEntry(ma, \"baz\", qp.List(-1, func(la datamodel.ListAssembler) {\n\t\t\tqp.ListEntry(la, qp.Int(aeb.x))\n\t\t\tqp.ListEntry(la, qp.Int(aeb.y))\n\t\t\tqp.ListEntry(la, qp.Int(aeb.z))\n\t\t}))\n\t})\n}\n\nfunc AnyExtendBlobToNode(ptr interface{}) (datamodel.Node, error) {\n\taeb, ok := ptr.(*AnyExtendBlob)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"expected *AnyExtendBlob type\")\n\t}\n\treturn aeb.ToNode()\n}\n\n// take a datamodel.Node, dag-cbor encode it and store it here, do the reverse\n// to get the datamodel.Node back\ntype AnyCborEncoded struct{ str []byte }\n\nfunc AnyCborEncodedFromNode(node datamodel.Node) (interface{}, error) {\n\tif tn, ok := node.(schema.TypedNode); ok {\n\t\tnode = tn.Representation()\n\t}\n\tvar buf bytes.Buffer\n\terr := dagcbor.Encode(node, &buf)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tacb := AnyCborEncoded{str: buf.Bytes()}\n\treturn &acb, nil\n}\n\nfunc AnyCborEncodedToNode(ptr interface{}) (datamodel.Node, error) {\n\tacb, ok := ptr.(*AnyCborEncoded)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"expected *AnyCborEncoded type\")\n\t}\n\tna := basicnode.Prototype.Any.NewBuilder()\n\terr := dagcbor.Decode(na, bytes.NewReader(acb.str))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn na.Build(), nil\n}\n\nconst anyExtendDagJson = `{\"Blob\":{\"baz\":[2,3,4],\"foo\":\"bar\"},\"Bool\":false,\"BoolPtr\":null,\"Bytes\":{\"/\":{\"bytes\":\"AgMEBQYHCA\"}},\"Count\":101,\"Float\":2.34,\"Int\":123456789,\"Link\":{\"/\":\"bagyacvra2e6qt2fohajauxceox55t3gedsyqap2phmv7q2qaaaaaaaaaaaaa\"},\"List\":[null,\"one\",\"two\",\"three\",1,2,3,true],\"Map\":{\"foo\":\"bar\",\"one\":1,\"three\":3,\"two\":2},\"Name\":\"Any extend test\",\"Null\":null,\"NullPtr\":null,\"NullableWith\":123456789,\"String\":\"this is a string\",\"XListAny\":[1,2,true,null,\"bop\"],\"XMapAny\":{\"a\":1,\"b\":2,\"c\":true,\"d\":null,\"e\":\"bop\"}}`\n\nvar anyExtendFixtureInstance = AnyExtend{\n\tName:         \"Any extend test\",\n\tCount:        101,\n\tBlob:         AnyExtendBlob{f: \"bar\", x: 2, y: 3, z: 4},\n\tNull:         AnyCborEncoded{mustFromHex(\"f6\")}, // normally these two fields would be `nil`, but we now get to decide whether it should be something concrete\n\tNullPtr:      &AnyCborEncoded{mustFromHex(\"f6\")},\n\tNullableWith: &AnyCborEncoded{mustFromHex(\"1a075bcd15\")},\n\tBool:         AnyCborEncoded{mustFromHex(\"f4\")},\n\tInt:          AnyCborEncoded{mustFromHex(\"1a075bcd15\")},                                                                           // 123456789\n\tFloat:        AnyCborEncoded{mustFromHex(\"fb4002b851eb851eb8\")},                                                                   // 2.34\n\tString:       AnyCborEncoded{mustFromHex(\"7074686973206973206120737472696e67\")},                                                   // \"this is a string\"\n\tBytes:        AnyCborEncoded{mustFromHex(\"4702030405060708\")},                                                                     // [2,3,4,5,6,7,8]\n\tLink:         AnyCborEncoded{mustFromHex(\"d82a58260001b0015620d13d09e8ae38120a5c4475fbd9ecc41cb1003f4f3b2bf86a0000000000000000\")}, // bagyacvra2e6qt2fohajauxceox55t3gedsyqap2phmv7q2qaaaaaaaaaaaaa\n\tMap:          AnyCborEncoded{mustFromHex(\"a463666f6f63626172636f6e65016374776f0265746872656503\")},                                 // {\"one\":1,\"two\":2,\"three\":3,\"foo\":\"bar\"}\n\tList:         AnyCborEncoded{mustFromHex(\"88f6636f6e656374776f657468726565010203f5\")},                                             // [null,'one','two','three',1,2,3,true]\n\tBoolPtr:      nil,\n\tXListAny:     []AnyCborEncoded{{mustFromHex(\"01\")}, {mustFromHex(\"02\")}, {mustFromHex(\"f5\")}, {mustFromHex(\"f6\")}, {mustFromHex(\"63626f70\")}}, // [1,2,true,null,\"bop\"]\n\tXMapAny: anyMap{\n\t\tKeys: []string{\"a\", \"b\", \"c\", \"d\", \"e\"},\n\t\tValues: map[string]*AnyCborEncoded{\n\t\t\t\"a\": {mustFromHex(\"01\")},\n\t\t\t\"b\": {mustFromHex(\"02\")},\n\t\t\t\"c\": {mustFromHex(\"f5\")},\n\t\t\t\"d\": {mustFromHex(\"f6\")},\n\t\t\t\"e\": {mustFromHex(\"63626f70\")}}}, // {\"a\":1,\"b\":2,\"c\":true,\"d\":null,\"e\":\"bop\"}\n}\n\nfunc TestCustomAny(t *testing.T) {\n\topts := []bindnode.Option{\n\t\tbindnode.TypedAnyConverter(&AnyExtendBlob{}, AnyExtendBlobFromNode, AnyExtendBlobToNode),\n\t\tbindnode.TypedAnyConverter(&AnyCborEncoded{}, AnyCborEncodedFromNode, AnyCborEncodedToNode),\n\t\tbindnode.TypedBoolConverter(BoolSubst(0), BoolSubstFromBool, BoolToBoolSubst),\n\t}\n\n\ttypeSystem, err := ipld.LoadSchemaBytes([]byte(anyExtendSchema))\n\tqt.Assert(t, err, qt.IsNil)\n\tschemaType := typeSystem.TypeByName(\"AnyExtend\")\n\tproto := bindnode.Prototype(&AnyExtend{}, schemaType, opts...)\n\n\tbuilder := proto.Representation().NewBuilder()\n\terr = dagjson.Decode(builder, bytes.NewReader([]byte(anyExtendDagJson)))\n\tqt.Assert(t, err, qt.IsNil)\n\n\ttyp := bindnode.Unwrap(builder.Build())\n\tinst, ok := typ.(*AnyExtend)\n\tqt.Assert(t, ok, qt.IsTrue)\n\n\tcmpr := qt.CmpEquals(\n\t\tcmp.Comparer(func(x, y AnyExtendBlob) bool {\n\t\t\treturn x.f == y.f && x.x == y.x && x.y == y.y && x.z == y.z\n\t\t}),\n\t\tcmp.Comparer(func(x, y AnyCborEncoded) bool {\n\t\t\treturn bytes.Equal(x.str, y.str)\n\t\t}),\n\t)\n\tqt.Assert(t, *inst, cmpr, anyExtendFixtureInstance)\n\n\ttn := bindnode.Wrap(inst, schemaType, opts...)\n\tvar buf bytes.Buffer\n\terr = dagjson.Encode(tn.Representation(), &buf)\n\tqt.Assert(t, err, qt.IsNil)\n\n\tqt.Assert(t, buf.String(), qt.Equals, anyExtendDagJson)\n}\n\nfunc mustFromHex(hexStr string) []byte {\n\tbyt, err := hex.DecodeString(hexStr)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn byt\n}\n\ntype ClosedUnion interface {\n\tisClosedUnion()\n}\n\ntype intUnion uint64\n\nfunc (intUnion) isClosedUnion() {}\n\ntype stringUnion string\n\nfunc (stringUnion) isClosedUnion() {}\n\nfunc ClosedUnionFromNode(node datamodel.Node) (interface{}, error) {\n\tasInt, err := node.AsInt()\n\tif err == nil {\n\t\treturn intUnion(asInt), nil\n\t}\n\tasString, err := node.AsString()\n\tif err == nil {\n\t\treturn stringUnion(asString), nil\n\t}\n\treturn nil, errors.New(\"unrecognized type\")\n}\n\nfunc ClosedUnionToNode(val interface{}) (datamodel.Node, error) {\n\tcu, ok := val.(*ClosedUnion)\n\tif !ok {\n\t\treturn nil, errors.New(\"should be a ClosedUnion\")\n\t}\n\tswitch concrete := (*cu).(type) {\n\tcase intUnion:\n\t\treturn basicnode.NewInt(int64(concrete)), nil\n\tcase stringUnion:\n\t\treturn basicnode.NewString(string(concrete)), nil\n\tdefault:\n\t\treturn nil, errors.New(\"unexpected union type\")\n\t}\n}\n\ntype StructWithUnion struct {\n\tCu ClosedUnion\n}\n\nconst closedUnionSchema = `\ntype ClosedUnion any\n\ntype StructWithUnion struct {\n  cu ClosedUnion\n}\n`\n\nconst closedUnionFixtureIntDagJson = `{\"cu\":8}`\nconst closedUnionFixtureStringDagJson = `{\"cu\":\"happy\"}`\n\nvar closedUnionIntInst = StructWithUnion{\n\tCu: intUnion(8),\n}\nvar closedUnionStringInst = StructWithUnion{\n\tCu: stringUnion(\"happy\"),\n}\n\nfunc TestCustomAnyWithInterface(t *testing.T) {\n\topts := []bindnode.Option{\n\t\tbindnode.NamedAnyConverter(\"ClosedUnion\", ClosedUnionFromNode, ClosedUnionToNode),\n\t}\n\n\ttypeSystem, err := ipld.LoadSchemaBytes([]byte(closedUnionSchema))\n\tqt.Assert(t, err, qt.IsNil)\n\tschemaType := typeSystem.TypeByName(\"StructWithUnion\")\n\tproto := bindnode.Prototype(&StructWithUnion{}, schemaType, opts...)\n\n\t// test one union variant\n\tbuilder := proto.Representation().NewBuilder()\n\terr = dagjson.Decode(builder, bytes.NewReader([]byte(closedUnionFixtureIntDagJson)))\n\tqt.Assert(t, err, qt.IsNil)\n\n\ttyp := bindnode.Unwrap(builder.Build())\n\tinst, ok := typ.(*StructWithUnion)\n\tqt.Assert(t, ok, qt.IsTrue)\n\n\tcmpr := qt.CmpEquals()\n\tqt.Assert(t, *inst, cmpr, closedUnionIntInst)\n\n\ttn := bindnode.Wrap(inst, schemaType, opts...)\n\tvar buf bytes.Buffer\n\terr = dagjson.Encode(tn.Representation(), &buf)\n\tqt.Assert(t, err, qt.IsNil)\n\n\tqt.Assert(t, buf.String(), qt.Equals, closedUnionFixtureIntDagJson)\n\n\t// test other union variant\n\tbuilder = proto.Representation().NewBuilder()\n\terr = dagjson.Decode(builder, bytes.NewReader([]byte(closedUnionFixtureStringDagJson)))\n\tqt.Assert(t, err, qt.IsNil)\n\n\ttyp = bindnode.Unwrap(builder.Build())\n\tinst, ok = typ.(*StructWithUnion)\n\tqt.Assert(t, ok, qt.IsTrue)\n\n\tcmpr = qt.CmpEquals()\n\tqt.Assert(t, *inst, cmpr, closedUnionStringInst)\n\n\ttn = bindnode.Wrap(inst, schemaType, opts...)\n\tbuf = bytes.Buffer{}\n\terr = dagjson.Encode(tn.Representation(), &buf)\n\tqt.Assert(t, err, qt.IsNil)\n\n\tqt.Assert(t, buf.String(), qt.Equals, closedUnionFixtureStringDagJson)\n}\n"
  },
  {
    "path": "node/bindnode/example_test.go",
    "content": "package bindnode_test\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent/qp\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc ExampleWrap_withSchema() {\n\tts, err := ipld.LoadSchemaBytes([]byte(`\n\t\ttype Person struct {\n\t\t\tName    String\n\t\t\tAge     optional Int\n\t\t\tFriends optional [String]\n\t\t}\n\t`))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tschemaType := ts.TypeByName(\"Person\")\n\n\ttype Person struct {\n\t\tName    string\n\t\tAge     *int64   // optional\n\t\tFriends []string // optional; no need for a pointer as slices are nilable\n\t}\n\tperson := &Person{\n\t\tName:    \"Michael\",\n\t\tFriends: []string{\"Sarah\", \"Alex\"},\n\t}\n\tnode := bindnode.Wrap(person, schemaType)\n\n\tnodeRepr := node.Representation()\n\tdagjson.Encode(nodeRepr, os.Stdout)\n\n\t// Output:\n\t// {\"Friends\":[\"Sarah\",\"Alex\"],\"Name\":\"Michael\"}\n}\n\nfunc ExampleWrap_noSchema() {\n\ttype Person struct {\n\t\tName    string\n\t\tAge     int64 // TODO: optional to match other examples\n\t\tFriends []string\n\t}\n\tperson := &Person{\n\t\tName:    \"Michael\",\n\t\tFriends: []string{\"Sarah\", \"Alex\"},\n\t}\n\tnode := bindnode.Wrap(person, nil)\n\n\tnodeRepr := node.Representation()\n\tdagjson.Encode(nodeRepr, os.Stdout)\n\n\t// Output:\n\t// {\"Age\":0,\"Friends\":[\"Sarah\",\"Alex\"],\"Name\":\"Michael\"}\n}\n\nfunc ExamplePrototype_onlySchema() {\n\tts, err := ipld.LoadSchemaBytes([]byte(`\n\t\ttype Person struct {\n\t\t\tName    String\n\t\t\tAge     optional Int\n\t\t\tFriends [String]\n\t\t}\n\t`))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tschemaType := ts.TypeByName(\"Person\")\n\tproto := bindnode.Prototype(nil, schemaType)\n\n\tnode, err := qp.BuildMap(proto, -1, func(ma datamodel.MapAssembler) {\n\t\tqp.MapEntry(ma, \"Name\", qp.String(\"Michael\"))\n\t\tqp.MapEntry(ma, \"Friends\", qp.List(-1, func(la datamodel.ListAssembler) {\n\t\t\tqp.ListEntry(la, qp.String(\"Sarah\"))\n\t\t\tqp.ListEntry(la, qp.String(\"Alex\"))\n\t\t}))\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tnodeRepr := node.(schema.TypedNode).Representation()\n\tdagjson.Encode(nodeRepr, os.Stdout)\n\n\t// Output:\n\t// {\"Friends\":[\"Sarah\",\"Alex\"],\"Name\":\"Michael\"}\n}\n\nfunc ExamplePrototype_union() {\n\tts, err := ipld.LoadSchemaBytes([]byte(`\n\t\ttype StringOrInt union {\n\t\t\t| String \"hasString\"\n\t\t\t| Int    \"hasInt\"\n\t\t} representation keyed\n\t`))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tschemaType := ts.TypeByName(\"StringOrInt\")\n\n\ttype CustomIntType int64\n\ttype StringOrInt struct {\n\t\tString *string\n\t\tInt    *CustomIntType // We can use custom types, too.\n\t}\n\n\tproto := bindnode.Prototype((*StringOrInt)(nil), schemaType)\n\n\tnode, err := qp.BuildMap(proto.Representation(), -1, func(ma datamodel.MapAssembler) {\n\t\tqp.MapEntry(ma, \"hasInt\", qp.Int(123))\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Print(\"Type level DAG-JSON: \")\n\tdagjson.Encode(node, os.Stdout)\n\tfmt.Println()\n\n\tfmt.Print(\"Representation level DAG-JSON: \")\n\tnodeRepr := node.(schema.TypedNode).Representation()\n\tdagjson.Encode(nodeRepr, os.Stdout)\n\tfmt.Println()\n\n\t// Inspect what the underlying Go value contains.\n\tunion := bindnode.Unwrap(node).(*StringOrInt)\n\tswitch {\n\tcase union.String != nil:\n\t\tfmt.Printf(\"Go StringOrInt.String: %v\\n\", *union.String)\n\tcase union.Int != nil:\n\t\tfmt.Printf(\"Go StringOrInt.Int: %v\\n\", *union.Int)\n\t}\n\n\t// Output:\n\t// Type level DAG-JSON: {\"Int\":123}\n\t// Representation level DAG-JSON: {\"hasInt\":123}\n\t// Go StringOrInt.Int: 123\n}\n"
  },
  {
    "path": "node/bindnode/fuzz_test.go",
    "content": "//go:build go1.18\n\npackage bindnode_test\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/codec/dagcbor\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\tschemadmt \"github.com/ipld/go-ipld-prime/schema/dmt\"\n\tschemadsl \"github.com/ipld/go-ipld-prime/schema/dsl\"\n)\n\nvar fuzzInputs = []struct {\n\tschemaDSL, nodeDagJSON string\n}{\n\t{\n\t\tschemaDSL:   `type Root bool`,\n\t\tnodeDagJSON: `true`,\n\t},\n\t{\n\t\tschemaDSL:   `type Root int`,\n\t\tnodeDagJSON: `123`,\n\t},\n\t{\n\t\tschemaDSL:   `type Root float`,\n\t\tnodeDagJSON: `45.67`,\n\t},\n\t{\n\t\tschemaDSL:   `type Root string`,\n\t\tnodeDagJSON: `\"foo\"`,\n\t},\n\t{\n\t\tschemaDSL:   `type Root bytes`,\n\t\tnodeDagJSON: `{\"/\":{\"bytes\":\"ZGVhZGJlZWY\"}}`,\n\t},\n\t{\n\t\tschemaDSL:   `type Root [Int]`,\n\t\tnodeDagJSON: `[3,2,1]`,\n\t},\n\t{\n\t\tschemaDSL:   `type Root [String]`,\n\t\tnodeDagJSON: `[\"x\",\"y\",\"z\"]`,\n\t},\n\t{\n\t\tschemaDSL:   `type Root {String:Int}`,\n\t\tnodeDagJSON: `{\"a\":20,\"b\":10}`,\n\t},\n\t{\n\t\tschemaDSL:   `type Root {String:Float}`,\n\t\tnodeDagJSON: `{\"a\":20.5,\"b\":10.2}`,\n\t},\n\t{\n\t\tschemaDSL: `type Root struct {\n\t\t\tF1 Bool\n\t\t\tF2 Bytes\n\t\t}`,\n\t\tnodeDagJSON: `{\"F1\":true,\"F2\":{\"/\":{\"bytes\":\"ZGVhZGJlZWY\"}}}`,\n\t},\n\t{\n\t\tschemaDSL: `type Root struct {\n\t\t\tF1 Int\n\t\t\tF2 Float\n\t\t} representation tuple`,\n\t\tnodeDagJSON: `[23,45.67]`,\n\t},\n\t{\n\t\tschemaDSL: `type Root enum {\n\t\t\t| aa (\"a\")\n\t\t\t| bb (\"b\")\n\t\t} representation string`,\n\t\tnodeDagJSON: `\"b\"`,\n\t},\n\t{\n\t\tschemaDSL: `type Root enum {\n\t\t\t| One (\"1\")\n\t\t\t| Two (\"2\")\n\t\t} representation int`,\n\t\tnodeDagJSON: `2`,\n\t},\n\t{\n\t\tschemaDSL: `type Root union {\n\t\t\t| Int    \"x\"\n\t\t\t| String \"y\"\n\t\t} representation keyed`,\n\t\tnodeDagJSON: `{\"y\":\"foo\"}`,\n\t},\n\t{\n\t\tschemaDSL: `type Root union {\n\t\t\t| Float  float\n\t\t\t| Bytes  bytes\n\t\t\t| Bool   bool\n\t\t\t| Nested map\n\t\t} representation kinded\n\t\ttype Nested struct {\n\t\t\tF1 Int\n\t\t}\n\t\t`,\n\t\tnodeDagJSON: `true`,\n\t},\n}\n\nfunc marshalDagCBOR(tb testing.TB, node datamodel.Node) []byte {\n\ttb.Helper()\n\tvar buf bytes.Buffer\n\tif err := dagcbor.Encode(node, &buf); err != nil {\n\t\ttb.Fatal(err)\n\t}\n\treturn buf.Bytes()\n}\n\nfunc marshalDagJSON(tb testing.TB, node datamodel.Node) []byte {\n\ttb.Helper()\n\tvar buf bytes.Buffer\n\tif err := dagjson.Encode(node, &buf); err != nil {\n\t\tswitch s := err.Error(); {\n\t\tcase strings.Contains(s, \"unsupported value: NaN\"),\n\t\t\tstrings.Contains(s, \"unsupported value: -Inf\"),\n\t\t\tstrings.Contains(s, \"unsupported value: +Inf\"):\n\t\t\ttb.Skipf(\"dagcbor does not support NaN/Inf\")\n\t\t}\n\t\ttb.Fatal(err)\n\t}\n\treturn buf.Bytes()\n}\n\n// TODO: consider allowing any codec multicode instead of hard-coding dagcbor\n\n// TODO: we always infer the Go type; it would be interesting to also support\n// inferring the IPLD schema, or to supply both.\n\n// TODO: encoding roundtrips via codecs are a good way to exercise bindnode's\n// Node implementation, but they do not call all the methods on the Node\n// interface. Consider other ways to call the rest of the methods, akin to how\n// infer_test.go has useNodeAsKind.\n\nfunc FuzzBindnodeViaDagCBOR(f *testing.F) {\n\tfor _, input := range fuzzInputs {\n\t\t// f.Logf(\"debug: %#v\\n\", input)\n\t\tschemaDMT, err := schemadsl.ParseBytes([]byte(input.schemaDSL))\n\t\tif err != nil {\n\t\t\tf.Fatal(err)\n\t\t}\n\t\tschemaNode := bindnode.Wrap(schemaDMT, schemadmt.Prototypes.Schema.Type())\n\t\tschemaDagCBOR := marshalDagCBOR(f, schemaNode.Representation())\n\n\t\tnodeBuilder := basicnode.Prototype.Any.NewBuilder()\n\t\tif err := dagjson.Decode(nodeBuilder, strings.NewReader(input.nodeDagJSON)); err != nil {\n\t\t\tf.Fatal(err)\n\t\t}\n\t\tnode := nodeBuilder.Build()\n\t\tnodeDagCBOR := marshalDagCBOR(f, node)\n\t\tf.Add(schemaDagCBOR, nodeDagCBOR)\n\n\t\t// Verify that nodeDagCBOR actually fits the schema.\n\t\t// Otherwise, if any of our fuzz inputs are wrong, we might not notice.\n\t\t{\n\t\t\tschemaDMT := bindnode.Unwrap(schemaNode).(*schemadmt.Schema)\n\t\t\tts := new(schema.TypeSystem)\n\t\t\tts.Init()\n\t\t\tif err := schemadmt.Compile(ts, schemaDMT); err != nil {\n\t\t\t\tf.Fatal(err)\n\t\t\t}\n\t\t\tschemaType := ts.TypeByName(\"Root\")\n\t\t\tproto := bindnode.Prototype(nil, schemaType)\n\t\t\tnodeBuilder := proto.Representation().NewBuilder()\n\t\t\tif err := dagcbor.Decode(nodeBuilder, bytes.NewReader(nodeDagCBOR)); err != nil {\n\t\t\t\tf.Fatal(err)\n\t\t\t}\n\t\t}\n\t}\n\tf.Fuzz(func(t *testing.T, schemaDagCBOR, nodeDagCBOR []byte) {\n\t\tschemaBuilder := schemadmt.Prototypes.Schema.Representation().NewBuilder()\n\n\t\tif err := dagcbor.Decode(schemaBuilder, bytes.NewReader(schemaDagCBOR)); err != nil {\n\t\t\tt.Skipf(\"invalid schema-schema dag-cbor: %v\", err)\n\t\t}\n\n\t\tschemaNode := schemaBuilder.Build().(schema.TypedNode)\n\t\tschemaDMT := bindnode.Unwrap(schemaNode).(*schemadmt.Schema)\n\n\t\t// Log the input schema and node we're fuzzing with, to help debugging.\n\t\t// We also use dag-json, as it's more human readable.\n\t\tt.Logf(\"schema in dag-cbor: %X\", schemaDagCBOR)\n\t\tt.Logf(\"node in dag-cbor: %X\", nodeDagCBOR)\n\t\tt.Logf(\"schema in dag-json: %s\", marshalDagJSON(t, schemaNode.Representation()))\n\t\t{\n\t\t\tnodeBuilder := basicnode.Prototype.Any.NewBuilder()\n\t\t\tif err := dagcbor.Decode(nodeBuilder, bytes.NewReader(nodeDagCBOR)); err != nil {\n\t\t\t\t// If some dag-cbor bytes don't decode into the Any prototype,\n\t\t\t\t// then they're just not valid dag-cbor at all.\n\t\t\t\tt.Skipf(\"invalid node dag-cbor: %v\", err)\n\t\t\t}\n\t\t\tnode := nodeBuilder.Build()\n\t\t\tt.Logf(\"node in dag-json: %s\", marshalDagJSON(t, node))\n\t\t}\n\n\t\t// Is nodeDagCBOR canonically encoded, i.e. strictly deterministic as\n\t\t// per the DAG-CBOR spec? This matters for the re-encode checks below.\n\t\t// Note that we want to use the non-strict decoder for fuzzing,\n\t\t// as that default is what the vast majority users will use.\n\t\tcanonicalNodeDagCBOR := true\n\t\tcanonicalDecoder := dagcbor.DecodeOptions{AllowLinks: true, ExperimentalDeterminism: true}\n\t\tif err := canonicalDecoder.Decode(basicnode.Prototype.Any.NewBuilder(), bytes.NewReader(nodeDagCBOR)); err != nil {\n\t\t\tcanonicalNodeDagCBOR = false\n\t\t\tt.Logf(\"note that this node dag-cbor isn't canonical!\")\n\t\t}\n\n\t\tts := new(schema.TypeSystem)\n\t\tts.Init()\n\t\t// For the time being, we're not interested in panics from\n\t\t// schemadmt.Compile or schema.TypeSystem. They are relatively prone to\n\t\t// panics at the moment, and right now we're mainly interested in bugs\n\t\t// in bindnode and dagcbor.\n\t\tfunc() {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tt.Skipf(\"invalid schema: %v\", r)\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif err := schemadmt.Compile(ts, schemaDMT); err != nil {\n\t\t\t\tt.Skipf(\"invalid schema: %v\", err)\n\t\t\t}\n\t\t}()\n\n\t\tschemaType := ts.TypeByName(\"Root\")\n\t\tif schemaType == nil {\n\t\t\tt.Skipf(\"schema has no Root type\")\n\t\t}\n\t\tvar proto schema.TypedPrototype\n\t\tfunc() {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tstr := fmt.Sprint(r)\n\t\t\t\t\tswitch {\n\t\t\t\t\tcase strings.Contains(str, \"bindnode: unexpected nil schema.Type\"):\n\t\t\t\t\tcase strings.Contains(str, \"is not a valid Go identifier\"):\n\t\t\t\t\tcase strings.Contains(str, \"bindnode: inferring Go types from cyclic schemas is not supported\"):\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tpanic(r)\n\t\t\t\t\t}\n\t\t\t\t\tt.Skipf(\"invalid schema: %v\", r)\n\t\t\t\t}\n\t\t\t}()\n\t\t\tproto = bindnode.Prototype(nil, schemaType)\n\t\t}()\n\n\t\tfor _, repr := range []bool{false, true} {\n\t\t\tt.Logf(\"decode and encode roundtrip with dag-cbor repr=%v\", repr)\n\t\t\tvar nodeBuilder datamodel.NodeBuilder\n\t\t\tif !repr {\n\t\t\t\tnodeBuilder = proto.NewBuilder()\n\t\t\t} else {\n\t\t\t\tnodeBuilder = proto.Representation().NewBuilder()\n\t\t\t}\n\t\t\tif err := dagcbor.Decode(nodeBuilder, bytes.NewReader(nodeDagCBOR)); err != nil {\n\t\t\t\t// The dag-cbor isn't valid for this node. Nothing else to do.\n\t\t\t\t// We don't use t.Skip, because a dag-cbor might only be valid\n\t\t\t\t// at the repr level, but not at the type level.\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tnode := nodeBuilder.Build()\n\t\t\tif repr {\n\t\t\t\tnode = node.(schema.TypedNode).Representation()\n\t\t\t}\n\t\t\t// Unwrap returns a pointer, and %#v prints pointers as hex,\n\t\t\t// so to get useful output, use reflect to dereference them.\n\t\t\tt.Logf(\"decode successful: %#v\", reflect.ValueOf(bindnode.Unwrap(node)).Elem().Interface())\n\t\t\treenc := marshalDagCBOR(t, node)\n\t\t\tswitch {\n\t\t\tcase canonicalNodeDagCBOR && !bytes.Equal(reenc, nodeDagCBOR):\n\t\t\t\tt.Errorf(\"node reencoded as %X rather than %X\", reenc, nodeDagCBOR)\n\t\t\tcase !canonicalNodeDagCBOR && bytes.Equal(reenc, nodeDagCBOR):\n\t\t\t\tt.Errorf(\"node reencoded as %X even though it's not canonical\", reenc)\n\t\t\tdefault:\n\t\t\t\tt.Logf(\"re-encode successful: %X\", reenc)\n\t\t\t}\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "node/bindnode/generate.go",
    "content": "package bindnode\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"go/format\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// TODO(mvdan): deduplicate with inferGoType once reflect supports creating named types\n\nfunc produceGoType(goTypes map[string]string, typ schema.Type) (name, src string) {\n\tif typ, ok := typ.(interface{ IsAnonymous() bool }); ok {\n\t\tif typ.IsAnonymous() {\n\t\t\tpanic(\"TODO: does this ever happen?\")\n\t\t}\n\t}\n\n\tname = string(typ.Name())\n\n\tswitch typ.(type) {\n\tcase *schema.TypeBool:\n\t\treturn goTypeBool.String(), \"\"\n\tcase *schema.TypeInt:\n\t\treturn goTypeInt.String(), \"\"\n\tcase *schema.TypeFloat:\n\t\treturn goTypeFloat.String(), \"\"\n\tcase *schema.TypeString:\n\t\treturn goTypeString.String(), \"\"\n\tcase *schema.TypeBytes:\n\t\treturn goTypeBytes.String(), \"\"\n\tcase *schema.TypeLink:\n\t\treturn goTypeLink.String(), \"\" // datamodel.Link\n\tcase *schema.TypeAny:\n\t\treturn goTypeNode.String(), \"\" // datamodel.Node\n\t}\n\n\t// Results are cached in goTypes.\n\tif src := goTypes[name]; src != \"\" {\n\t\treturn name, src\n\t}\n\n\tsrc = produceGoTypeInner(goTypes, name, typ)\n\tgoTypes[name] = src\n\treturn name, src\n}\n\nfunc produceGoTypeInner(goTypes map[string]string, name string, typ schema.Type) (src string) {\n\t// Avoid infinite cycles.\n\t// produceGoType will fill in the final type later.\n\tgoTypes[name] = \"WIP\"\n\n\tswitch typ := typ.(type) {\n\tcase *schema.TypeEnum:\n\t\t// TODO: also generate named constants for the members.\n\t\treturn goTypeString.String()\n\tcase *schema.TypeStruct:\n\t\tvar b strings.Builder\n\t\tfmt.Fprintf(&b, \"struct {\\n\")\n\t\tfields := typ.Fields()\n\t\tfor _, field := range fields {\n\t\t\tfmt.Fprintf(&b, \"%s \", fieldNameFromSchema(field.Name()))\n\t\t\tftypGo, _ := produceGoType(goTypes, field.Type())\n\t\t\tif field.IsNullable() {\n\t\t\t\tfmt.Fprintf(&b, \"*\")\n\t\t\t}\n\t\t\tif field.IsOptional() {\n\t\t\t\tfmt.Fprintf(&b, \"*\")\n\t\t\t}\n\t\t\tfmt.Fprintf(&b, \"%s\\n\", ftypGo)\n\t\t}\n\t\tfmt.Fprintf(&b, \"\\n}\")\n\t\treturn b.String()\n\tcase *schema.TypeMap:\n\t\tktyp, _ := produceGoType(goTypes, typ.KeyType())\n\t\tvtyp, _ := produceGoType(goTypes, typ.ValueType())\n\t\tif typ.ValueIsNullable() {\n\t\t\tvtyp = \"*\" + vtyp\n\t\t}\n\t\treturn fmt.Sprintf(`struct {\n\t\t\tKeys []%s\n\t\t\tValues map[%s]%s\n\t\t}`, ktyp, ktyp, vtyp)\n\tcase *schema.TypeList:\n\t\tetyp, _ := produceGoType(goTypes, typ.ValueType())\n\t\tif typ.ValueIsNullable() {\n\t\t\tetyp = \"*\" + etyp\n\t\t}\n\t\treturn fmt.Sprintf(\"[]%s\", etyp)\n\tcase *schema.TypeUnion:\n\t\tvar b strings.Builder\n\t\tfmt.Fprintf(&b, \"struct{\\n\")\n\t\tmembers := typ.Members()\n\t\tfor _, ftyp := range members {\n\t\t\tftypGo, _ := produceGoType(goTypes, ftyp)\n\t\t\tfmt.Fprintf(&b, \"%s \", fieldNameFromSchema(string(ftyp.Name())))\n\t\t\tfmt.Fprintf(&b, \"*%s\\n\", ftypGo)\n\t\t}\n\t\tfmt.Fprintf(&b, \"\\n}\")\n\t\treturn b.String()\n\t}\n\tpanic(fmt.Sprintf(\"%T\\n\", typ))\n}\n\n// ProduceGoTypes infers Go types from an IPLD schema in ts\n// and writes their Go source code type declarations to w.\n// Note that just the types are written,\n// without a package declaration nor any imports.\n//\n// This gives a good starting point when wanting to use bindnode with Go types,\n// but users will generally want to own and modify the types afterward,\n// so they can add documentation or tweak the types as needed.\nfunc ProduceGoTypes(w io.Writer, ts *schema.TypeSystem) error {\n\tgoTypes := make(map[string]string)\n\tvar buf bytes.Buffer\n\tfor _, name := range ts.Names() {\n\t\tschemaType := ts.TypeByName(string(name))\n\t\tif name != schemaType.Name() {\n\t\t\tpanic(fmt.Sprintf(\"%s vs %s\", name, schemaType.Name()))\n\t\t}\n\t\t_, src := produceGoType(goTypes, schemaType)\n\t\tif src == \"\" {\n\t\t\tcontinue // scalar type used directly\n\t\t}\n\t\tfmt.Fprintf(&buf, \"type %s %s\\n\", name, src)\n\t}\n\n\tsrc, err := format.Source(buf.Bytes())\n\tif err != nil {\n\t\treturn err\n\t}\n\tif _, err := w.Write(src); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "node/bindnode/infer.go",
    "content": "package bindnode\n\nimport (\n\t\"fmt\"\n\t\"go/token\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nvar (\n\tgoTypeBool    = reflect.TypeOf(false)\n\tgoTypeInt     = reflect.TypeOf(int(0))\n\tgoTypeFloat   = reflect.TypeOf(0.0)\n\tgoTypeString  = reflect.TypeOf(\"\")\n\tgoTypeBytes   = reflect.TypeOf([]byte{})\n\tgoTypeLink    = reflect.TypeOf((*datamodel.Link)(nil)).Elem()\n\tgoTypeNode    = reflect.TypeOf((*datamodel.Node)(nil)).Elem()\n\tgoTypeCidLink = reflect.TypeOf((*cidlink.Link)(nil)).Elem()\n\tgoTypeCid     = reflect.TypeOf((*cid.Cid)(nil)).Elem()\n\n\tschemaTypeBool   = schema.SpawnBool(\"Bool\")\n\tschemaTypeInt    = schema.SpawnInt(\"Int\")\n\tschemaTypeFloat  = schema.SpawnFloat(\"Float\")\n\tschemaTypeString = schema.SpawnString(\"String\")\n\tschemaTypeBytes  = schema.SpawnBytes(\"Bytes\")\n\tschemaTypeLink   = schema.SpawnLink(\"Link\")\n\tschemaTypeAny    = schema.SpawnAny(\"Any\")\n)\n\n// Consider exposing these APIs later, if they might be useful.\n\ntype seenEntry struct {\n\tgoType     reflect.Type\n\tschemaType schema.Type\n}\n\n// verifyCompatibility is the primary way we check that the schema type(s)\n// matches the Go type(s); so we do this before we can proceed operating on it.\n// verifyCompatibility doesn't return an error, it panics—the errors here are\n// not runtime errors, they're programmer errors because your schema doesn't\n// match your Go type\nfunc verifyCompatibility(cfg *config, seen map[seenEntry]bool, goType reflect.Type, schemaType schema.Type) {\n\t// TODO(mvdan): support **T as well?\n\tif goType.Kind() == reflect.Ptr {\n\t\tgoType = goType.Elem()\n\t}\n\n\t// Avoid endless loops.\n\t//\n\t// TODO(mvdan): this is easy but fairly allocation-happy.\n\t// Plus, one map per call means we don't reuse work.\n\tif seen[seenEntry{goType, schemaType}] {\n\t\treturn\n\t}\n\tseen[seenEntry{goType, schemaType}] = true\n\n\tdoPanic := func(format string, args ...interface{}) {\n\t\tpanicFormat := \"bindnode: schema type %s is not compatible with Go type %s\"\n\t\tpanicArgs := []interface{}{schemaType.Name(), goType.String()}\n\n\t\tif format != \"\" {\n\t\t\tpanicFormat += \": \" + format\n\t\t}\n\t\tpanicArgs = append(panicArgs, args...)\n\t\tpanic(fmt.Sprintf(panicFormat, panicArgs...))\n\t}\n\tswitch schemaType := schemaType.(type) {\n\tcase *schema.TypeBool:\n\t\tif customConverter := cfg.converterForType(schemaType.Name(), goType); customConverter != nil {\n\t\t\tif customConverter.kind != schema.TypeKind_Bool {\n\t\t\t\tdoPanic(\"kind mismatch; custom converter for type is not for Bool\")\n\t\t\t}\n\t\t} else if goType.Kind() != reflect.Bool {\n\t\t\tdoPanic(\"kind mismatch; need boolean\")\n\t\t}\n\tcase *schema.TypeInt:\n\t\tif customConverter := cfg.converterForType(schemaType.Name(), goType); customConverter != nil {\n\t\t\tif customConverter.kind != schema.TypeKind_Int {\n\t\t\t\tdoPanic(\"kind mismatch; custom converter for type is not for Int\")\n\t\t\t}\n\t\t} else if kind := goType.Kind(); !kindInt[kind] && !kindUint[kind] {\n\t\t\tdoPanic(\"kind mismatch; need integer\")\n\t\t}\n\tcase *schema.TypeFloat:\n\t\tif customConverter := cfg.converterForType(schemaType.Name(), goType); customConverter != nil {\n\t\t\tif customConverter.kind != schema.TypeKind_Float {\n\t\t\t\tdoPanic(\"kind mismatch; custom converter for type is not for Float\")\n\t\t\t}\n\t\t} else {\n\t\t\tswitch goType.Kind() {\n\t\t\tcase reflect.Float32, reflect.Float64:\n\t\t\tdefault:\n\t\t\t\tdoPanic(\"kind mismatch; need float\")\n\t\t\t}\n\t\t}\n\tcase *schema.TypeString:\n\t\t// TODO: allow []byte?\n\t\tif customConverter := cfg.converterForType(schemaType.Name(), goType); customConverter != nil {\n\t\t\tif customConverter.kind != schema.TypeKind_String {\n\t\t\t\tdoPanic(\"kind mismatch; custom converter for type is not for String\")\n\t\t\t}\n\t\t} else if goType.Kind() != reflect.String {\n\t\t\tdoPanic(\"kind mismatch; need string\")\n\t\t}\n\tcase *schema.TypeBytes:\n\t\t// TODO: allow string?\n\t\tif customConverter := cfg.converterForType(schemaType.Name(), goType); customConverter != nil {\n\t\t\tif customConverter.kind != schema.TypeKind_Bytes {\n\t\t\t\tdoPanic(\"kind mismatch; custom converter for type is not for Bytes\")\n\t\t\t}\n\t\t} else if goType.Kind() != reflect.Slice {\n\t\t\tdoPanic(\"kind mismatch; need slice of bytes\")\n\t\t} else if goType.Elem().Kind() != reflect.Uint8 {\n\t\t\tdoPanic(\"kind mismatch; need slice of bytes\")\n\t\t}\n\tcase *schema.TypeEnum:\n\t\tif _, ok := schemaType.RepresentationStrategy().(schema.EnumRepresentation_Int); ok {\n\t\t\tif kind := goType.Kind(); kind != reflect.String && !kindInt[kind] && !kindUint[kind] {\n\t\t\t\tdoPanic(\"kind mismatch; need string or integer\")\n\t\t\t}\n\t\t} else {\n\t\t\tif goType.Kind() != reflect.String {\n\t\t\t\tdoPanic(\"kind mismatch; need string\")\n\t\t\t}\n\t\t}\n\tcase *schema.TypeList:\n\t\tif goType.Kind() != reflect.Slice {\n\t\t\tdoPanic(\"kind mismatch; need slice\")\n\t\t}\n\t\tgoType = goType.Elem()\n\t\tif schemaType.ValueIsNullable() {\n\t\t\tif ptr, nilable := ptrOrNilable(goType.Kind()); !nilable {\n\t\t\t\tdoPanic(\"nullable types must be nilable\")\n\t\t\t} else if ptr {\n\t\t\t\tgoType = goType.Elem()\n\t\t\t}\n\t\t}\n\t\tverifyCompatibility(cfg, seen, goType, schemaType.ValueType())\n\tcase *schema.TypeMap:\n\t\t//\tstruct {\n\t\t//\t\tKeys   []K\n\t\t//\t\tValues map[K]V\n\t\t//\t}\n\t\tif goType.Kind() != reflect.Struct {\n\t\t\tdoPanic(\"kind mismatch; need struct{Keys []K; Values map[K]V}\")\n\t\t}\n\t\tif goType.NumField() != 2 {\n\t\t\tdoPanic(\"%d vs 2 fields\", goType.NumField())\n\t\t}\n\n\t\tfieldKeys := goType.Field(0)\n\t\tif fieldKeys.Type.Kind() != reflect.Slice {\n\t\t\tdoPanic(\"kind mismatch; need struct{Keys []K; Values map[K]V}\")\n\t\t}\n\t\tverifyCompatibility(cfg, seen, fieldKeys.Type.Elem(), schemaType.KeyType())\n\n\t\tfieldValues := goType.Field(1)\n\t\tif fieldValues.Type.Kind() != reflect.Map {\n\t\t\tdoPanic(\"kind mismatch; need struct{Keys []K; Values map[K]V}\")\n\t\t}\n\t\tkeyType := fieldValues.Type.Key()\n\t\tverifyCompatibility(cfg, seen, keyType, schemaType.KeyType())\n\n\t\telemType := fieldValues.Type.Elem()\n\t\tif schemaType.ValueIsNullable() {\n\t\t\tif ptr, nilable := ptrOrNilable(elemType.Kind()); !nilable {\n\t\t\t\tdoPanic(\"nullable types must be nilable\")\n\t\t\t} else if ptr {\n\t\t\t\telemType = elemType.Elem()\n\t\t\t}\n\t\t}\n\t\tverifyCompatibility(cfg, seen, elemType, schemaType.ValueType())\n\tcase *schema.TypeStruct:\n\t\tif goType.Kind() != reflect.Struct {\n\t\t\tdoPanic(\"kind mismatch; need struct\")\n\t\t}\n\n\t\tschemaFields := schemaType.Fields()\n\t\tif goType.NumField() != len(schemaFields) {\n\t\t\tdoPanic(\"%d vs %d fields\", goType.NumField(), len(schemaFields))\n\t\t}\n\t\tfor i, schemaField := range schemaFields {\n\t\t\tschemaType := schemaField.Type()\n\t\t\tgoType := goType.Field(i).Type\n\t\t\tswitch {\n\t\t\tcase schemaField.IsOptional() && schemaField.IsNullable():\n\t\t\t\t// TODO: https://github.com/ipld/go-ipld-prime/issues/340 will\n\t\t\t\t// help here, to avoid the double pointer. We can't use nilable\n\t\t\t\t// but non-pointer types because that's just one \"nil\" state.\n\t\t\t\t// TODO: deal with custom converters in this case\n\t\t\t\tif goType.Kind() != reflect.Ptr {\n\t\t\t\t\tdoPanic(\"optional and nullable fields must use double pointers (**)\")\n\t\t\t\t}\n\t\t\t\tgoType = goType.Elem()\n\t\t\t\tif goType.Kind() != reflect.Ptr {\n\t\t\t\t\tdoPanic(\"optional and nullable fields must use double pointers (**)\")\n\t\t\t\t}\n\t\t\t\tgoType = goType.Elem()\n\t\t\tcase schemaField.IsOptional():\n\t\t\t\tif ptr, nilable := ptrOrNilable(goType.Kind()); !nilable {\n\t\t\t\t\tdoPanic(\"optional fields must be nilable\")\n\t\t\t\t} else if ptr {\n\t\t\t\t\tgoType = goType.Elem()\n\t\t\t\t}\n\t\t\tcase schemaField.IsNullable():\n\t\t\t\tif ptr, nilable := ptrOrNilable(goType.Kind()); !nilable {\n\t\t\t\t\tif customConverter := cfg.converterForType(schemaType.Name(), goType); customConverter == nil {\n\t\t\t\t\t\tdoPanic(\"nullable fields must be nilable\")\n\t\t\t\t\t}\n\t\t\t\t} else if ptr {\n\t\t\t\t\tgoType = goType.Elem()\n\t\t\t\t}\n\t\t\t}\n\t\t\tverifyCompatibility(cfg, seen, goType, schemaType)\n\t\t}\n\tcase *schema.TypeUnion:\n\t\tif goType.Kind() != reflect.Struct {\n\t\t\tdoPanic(\"kind mismatch; need struct for an union\")\n\t\t}\n\n\t\tschemaMembers := schemaType.Members()\n\t\tif goType.NumField() != len(schemaMembers) {\n\t\t\tdoPanic(\"%d vs %d members\", goType.NumField(), len(schemaMembers))\n\t\t}\n\n\t\tfor i, schemaType := range schemaMembers {\n\t\t\tgoType := goType.Field(i).Type\n\t\t\tif ptr, nilable := ptrOrNilable(goType.Kind()); !nilable {\n\t\t\t\tdoPanic(\"union members must be nilable\")\n\t\t\t} else if ptr {\n\t\t\t\tgoType = goType.Elem()\n\t\t\t}\n\t\t\tverifyCompatibility(cfg, seen, goType, schemaType)\n\t\t}\n\tcase *schema.TypeLink:\n\t\tif customConverter := cfg.converterForType(schemaType.Name(), goType); customConverter != nil {\n\t\t\tif customConverter.kind != schema.TypeKind_Link {\n\t\t\t\tdoPanic(\"kind mismatch; custom converter for type is not for Link\")\n\t\t\t}\n\t\t} else if goType != goTypeLink && goType != goTypeCidLink && goType != goTypeCid {\n\t\t\tdoPanic(\"links in Go must be datamodel.Link, cidlink.Link, or cid.Cid\")\n\t\t}\n\tcase *schema.TypeAny:\n\t\tif customConverter := cfg.converterForType(schemaType.Name(), goType); customConverter != nil {\n\t\t\tif customConverter.kind != schema.TypeKind_Any {\n\t\t\t\tdoPanic(\"kind mismatch; custom converter for type is not for Any\")\n\t\t\t}\n\t\t} else if goType != goTypeNode {\n\t\t\tdoPanic(\"Any in Go must be datamodel.Node\")\n\t\t}\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"%T\", schemaType))\n\t}\n}\n\nfunc ptrOrNilable(kind reflect.Kind) (ptr, nilable bool) {\n\tswitch kind {\n\tcase reflect.Ptr:\n\t\treturn true, true\n\tcase reflect.Interface, reflect.Map, reflect.Slice:\n\t\treturn false, true\n\tdefault:\n\t\treturn false, false\n\t}\n}\n\n// If we recurse past a large number of levels, we're mostly stuck in a loop.\n// Prevent burning CPU or causing OOM crashes.\n// If a user really wrote an IPLD schema or Go type with such deep nesting,\n// it's likely they are trying to abuse the system as well.\nconst maxRecursionLevel = 1 << 10\n\ntype inferredStatus int\n\nconst (\n\t_ inferredStatus = iota\n\tinferringInProcess\n\tinferringDone\n)\n\n// inferGoType can build a Go type given a schema\nfunc inferGoType(typ schema.Type, status map[schema.TypeName]inferredStatus, level int) reflect.Type {\n\tif level > maxRecursionLevel {\n\t\tpanic(fmt.Sprintf(\"inferGoType: refusing to recurse past %d levels\", maxRecursionLevel))\n\t}\n\tname := typ.Name()\n\tif status[name] == inferringInProcess {\n\t\tpanic(\"bindnode: inferring Go types from cyclic schemas is not supported since Go reflection does not support creating named types\")\n\t}\n\tstatus[name] = inferringInProcess\n\tdefer func() { status[name] = inferringDone }()\n\tswitch typ := typ.(type) {\n\tcase *schema.TypeBool:\n\t\treturn goTypeBool\n\tcase *schema.TypeInt:\n\t\treturn goTypeInt\n\tcase *schema.TypeFloat:\n\t\treturn goTypeFloat\n\tcase *schema.TypeString:\n\t\treturn goTypeString\n\tcase *schema.TypeBytes:\n\t\treturn goTypeBytes\n\tcase *schema.TypeStruct:\n\t\tfields := typ.Fields()\n\t\tfieldsGo := make([]reflect.StructField, len(fields))\n\t\tfor i, field := range fields {\n\t\t\tftypGo := inferGoType(field.Type(), status, level+1)\n\t\t\tif field.IsNullable() {\n\t\t\t\tftypGo = reflect.PointerTo(ftypGo)\n\t\t\t}\n\t\t\tif field.IsOptional() {\n\t\t\t\tftypGo = reflect.PointerTo(ftypGo)\n\t\t\t}\n\t\t\tfieldsGo[i] = reflect.StructField{\n\t\t\t\tName: fieldNameFromSchema(field.Name()),\n\t\t\t\tType: ftypGo,\n\t\t\t}\n\t\t}\n\t\treturn reflect.StructOf(fieldsGo)\n\tcase *schema.TypeMap:\n\t\tktyp := inferGoType(typ.KeyType(), status, level+1)\n\t\tvtyp := inferGoType(typ.ValueType(), status, level+1)\n\t\tif typ.ValueIsNullable() {\n\t\t\tvtyp = reflect.PointerTo(vtyp)\n\t\t}\n\t\t// We need an extra field to keep the map ordered,\n\t\t// since IPLD maps must have stable iteration order.\n\t\t// We could sort when iterating, but that's expensive.\n\t\t// Keeping the insertion order is easy and intuitive.\n\t\t//\n\t\t//\tstruct {\n\t\t//\t\tKeys   []K\n\t\t//\t\tValues map[K]V\n\t\t//\t}\n\t\tfieldsGo := []reflect.StructField{\n\t\t\t{\n\t\t\t\tName: \"Keys\",\n\t\t\t\tType: reflect.SliceOf(ktyp),\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"Values\",\n\t\t\t\tType: reflect.MapOf(ktyp, vtyp),\n\t\t\t},\n\t\t}\n\t\treturn reflect.StructOf(fieldsGo)\n\tcase *schema.TypeList:\n\t\tetyp := inferGoType(typ.ValueType(), status, level+1)\n\t\tif typ.ValueIsNullable() {\n\t\t\tetyp = reflect.PointerTo(etyp)\n\t\t}\n\t\treturn reflect.SliceOf(etyp)\n\tcase *schema.TypeUnion:\n\t\t// type goUnion struct {\n\t\t// \tType1 *Type1\n\t\t// \tType2 *Type2\n\t\t// \t...\n\t\t// }\n\t\tmembers := typ.Members()\n\t\tfieldsGo := make([]reflect.StructField, len(members))\n\t\tfor i, ftyp := range members {\n\t\t\tftypGo := inferGoType(ftyp, status, level+1)\n\t\t\tfieldsGo[i] = reflect.StructField{\n\t\t\t\tName: fieldNameFromSchema(ftyp.Name()),\n\t\t\t\tType: reflect.PointerTo(ftypGo),\n\t\t\t}\n\t\t}\n\t\treturn reflect.StructOf(fieldsGo)\n\tcase *schema.TypeLink:\n\t\treturn goTypeLink\n\tcase *schema.TypeEnum:\n\t\t// TODO: generate int for int reprs by default?\n\t\treturn goTypeString\n\tcase *schema.TypeAny:\n\t\treturn goTypeNode\n\tcase nil:\n\t\tpanic(\"bindnode: unexpected nil schema.Type\")\n\t}\n\tpanic(fmt.Sprintf(\"%T\", typ))\n}\n\n// from IPLD Schema field names like \"foo\" to Go field names like \"Foo\".\nfunc fieldNameFromSchema(name string) string {\n\tfieldName := strings.Title(name) //lint:ignore SA1019 cases.Title doesn't work for this\n\tif !token.IsIdentifier(fieldName) {\n\t\tpanic(fmt.Sprintf(\"bindnode: inferred field name %q is not a valid Go identifier\", fieldName))\n\t}\n\treturn fieldName\n}\n\nvar defaultTypeSystem schema.TypeSystem\n\nfunc init() {\n\tdefaultTypeSystem.Init()\n\n\tdefaultTypeSystem.Accumulate(schemaTypeBool)\n\tdefaultTypeSystem.Accumulate(schemaTypeInt)\n\tdefaultTypeSystem.Accumulate(schemaTypeFloat)\n\tdefaultTypeSystem.Accumulate(schemaTypeString)\n\tdefaultTypeSystem.Accumulate(schemaTypeBytes)\n\tdefaultTypeSystem.Accumulate(schemaTypeLink)\n\tdefaultTypeSystem.Accumulate(schemaTypeAny)\n}\n\n// TODO: support IPLD maps and unions in inferSchema\n\n// TODO: support bringing your own TypeSystem?\n\n// TODO: we should probably avoid re-spawning the same types if the TypeSystem\n// has them, and test that that works as expected\n\n// inferSchema can build a schema from a Go type\nfunc inferSchema(typ reflect.Type, level int) schema.Type {\n\tif level > maxRecursionLevel {\n\t\tpanic(fmt.Sprintf(\"inferSchema: refusing to recurse past %d levels\", maxRecursionLevel))\n\t}\n\tswitch typ.Kind() {\n\tcase reflect.Bool:\n\t\treturn schemaTypeBool\n\tcase reflect.Int64:\n\t\treturn schemaTypeInt\n\tcase reflect.Float64:\n\t\treturn schemaTypeFloat\n\tcase reflect.String:\n\t\treturn schemaTypeString\n\tcase reflect.Struct:\n\t\t// these types must match exactly since we need symmetry of being able to\n\t\t// get the values an also assign values to them\n\t\tif typ == goTypeCid || typ == goTypeCidLink {\n\t\t\treturn schemaTypeLink\n\t\t}\n\n\t\tfieldsSchema := make([]schema.StructField, typ.NumField())\n\t\tfor i := range fieldsSchema {\n\t\t\tfield := typ.Field(i)\n\t\t\tftyp := field.Type\n\t\t\tftypSchema := inferSchema(ftyp, level+1)\n\t\t\tfieldsSchema[i] = schema.SpawnStructField(\n\t\t\t\tfield.Name, // TODO: allow configuring the name with tags\n\t\t\t\tftypSchema.Name(),\n\n\t\t\t\t// TODO: support nullable/optional with tags\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t)\n\t\t}\n\t\tname := typ.Name()\n\t\tif name == \"\" {\n\t\t\tpanic(\"TODO: anonymous composite types\")\n\t\t}\n\t\ttypSchema := schema.SpawnStruct(name, fieldsSchema, nil)\n\t\tdefaultTypeSystem.Accumulate(typSchema)\n\t\treturn typSchema\n\tcase reflect.Slice:\n\t\tif typ.Elem().Kind() == reflect.Uint8 {\n\t\t\t// Special case for []byte.\n\t\t\treturn schemaTypeBytes\n\t\t}\n\n\t\tnullable := false\n\t\tif typ.Elem().Kind() == reflect.Ptr {\n\t\t\tnullable = true\n\t\t}\n\t\tetypSchema := inferSchema(typ.Elem(), level+1)\n\t\tname := typ.Name()\n\t\tif name == \"\" {\n\t\t\tname = \"List_\" + etypSchema.Name()\n\t\t}\n\t\ttypSchema := schema.SpawnList(name, etypSchema.Name(), nullable)\n\t\tdefaultTypeSystem.Accumulate(typSchema)\n\t\treturn typSchema\n\tcase reflect.Interface:\n\t\t// these types must match exactly since we need symmetry of being able to\n\t\t// get the values an also assign values to them\n\t\tif typ == goTypeLink {\n\t\t\treturn schemaTypeLink\n\t\t}\n\t\tif typ == goTypeNode {\n\t\t\treturn schemaTypeAny\n\t\t}\n\t\tpanic(\"bindnode: unable to infer from interface\")\n\t}\n\tpanic(fmt.Sprintf(\"bindnode: unable to infer from type %s\", typ.Kind().String()))\n}\n\n// There are currently 27 reflect.Kind iota values,\n// so 32 should be plenty to ensure we don't panic in practice.\n\nvar kindInt = [32]bool{\n\treflect.Int:   true,\n\treflect.Int8:  true,\n\treflect.Int16: true,\n\treflect.Int32: true,\n\treflect.Int64: true,\n}\n\nvar kindUint = [32]bool{\n\treflect.Uint:   true,\n\treflect.Uint8:  true,\n\treflect.Uint16: true,\n\treflect.Uint32: true,\n\treflect.Uint64: true,\n}\n"
  },
  {
    "path": "node/bindnode/infer_test.go",
    "content": "package bindnode_test\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"html/template\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"runtime/debug\"\n\t\"strings\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/ipfs/go-cid\"\n\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\ntype anyScalar struct {\n\tBool   *bool\n\tInt    *int64\n\tFloat  *float64\n\tString *string\n\tBytes  *[]byte\n\tLink   *datamodel.Link\n}\n\ntype anyRecursive struct {\n\tList *[]string\n\tMap  *struct {\n\t\tKeys   []string\n\t\tValues map[string]string\n\t}\n}\n\nvar prototypeTests = []struct {\n\tname      string\n\tschemaSrc string\n\tptrType   interface{}\n\n\t// Prettified for maintainability, valid DAG-JSON when compacted.\n\tprettyDagJSON string\n}{\n\t{\n\t\tname: \"Scalars\",\n\t\tschemaSrc: `type Root struct {\n\t\t\t\tbool   Bool\n\t\t\t\tint    Int\n\t\t\t\tuint   Int\n\t\t\t\tfloat  Float\n\t\t\t\tstring String\n\t\t\t\tbytes  Bytes\n\t\t\t}`,\n\t\tptrType: (*struct {\n\t\t\tBool   bool\n\t\t\tInt    int64\n\t\t\tUint   uint32\n\t\t\tFloat  float64\n\t\t\tString string\n\t\t\tBytes  []byte\n\t\t})(nil),\n\t\tprettyDagJSON: `{\n\t\t\t\"bool\":   true,\n\t\t\t\"bytes\":  {\"/\": {\"bytes\": \"34cd\"}},\n\t\t\t\"float\":  12.5,\n\t\t\t\"int\":    3,\n\t\t\t\"string\": \"foo\",\n\t\t\t\"uint\":   50\n\t\t}`,\n\t},\n\t{\n\t\tname: \"Links\",\n\t\tschemaSrc: `type Root struct {\n\t\t\t\tlinkCID     Link\n\t\t\t\tlinkGeneric Link\n\t\t\t\tlinkImpl    Link\n\t\t\t}`,\n\t\tptrType: (*struct {\n\t\t\tLinkCID     cid.Cid\n\t\t\tLinkGeneric datamodel.Link\n\t\t\tLinkImpl    cidlink.Link\n\t\t})(nil),\n\t\tprettyDagJSON: `{\n\t\t\t\"linkCID\":     {\"/\": \"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\"},\n\t\t\t\"linkGeneric\": {\"/\": \"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\"},\n\t\t\t\"linkImpl\":    {\"/\": \"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\"}\n\t\t}`,\n\t},\n\t{\n\t\tname: \"Any\",\n\t\t// TODO: also Null\n\t\tschemaSrc: `type Root struct {\n\t\t\t\tanyNodeWithBool   Any\n\t\t\t\tanyNodeWithInt    Any\n\t\t\t\tanyNodeWithFloat  Any\n\t\t\t\tanyNodeWithString Any\n\t\t\t\tanyNodeWithBytes  Any\n\t\t\t\tanyNodeWithList   Any\n\t\t\t\tanyNodeWithMap    Any\n\t\t\t\tanyNodeWithLink   Any\n\n\t\t\t\tanyNodeBehindList [Any]\n\t\t\t\tanyNodeBehindMap  {String:Any}\n\t\t\t}`,\n\t\tptrType: (*struct {\n\t\t\tAnyNodeWithBool   datamodel.Node\n\t\t\tAnyNodeWithInt    datamodel.Node\n\t\t\tAnyNodeWithFloat  datamodel.Node\n\t\t\tAnyNodeWithString datamodel.Node\n\t\t\tAnyNodeWithBytes  datamodel.Node\n\t\t\tAnyNodeWithList   datamodel.Node\n\t\t\tAnyNodeWithMap    datamodel.Node\n\t\t\tAnyNodeWithLink   datamodel.Node\n\n\t\t\tAnyNodeBehindList []datamodel.Node\n\t\t\tAnyNodeBehindMap  struct {\n\t\t\t\tKeys   []string\n\t\t\t\tValues map[string]datamodel.Node\n\t\t\t}\n\t\t})(nil),\n\t\tprettyDagJSON: `{\n\t\t\t\"anyNodeBehindList\": [12.5, {\"x\": false}],\n\t\t\t\"anyNodeBehindMap\":  {\"x\": 123, \"y\": [true, false]},\n\t\t\t\"anyNodeWithBool\":   true,\n\t\t\t\"anyNodeWithBytes\":  {\"/\": {\"bytes\": \"34cd\"}},\n\t\t\t\"anyNodeWithFloat\":  12.5,\n\t\t\t\"anyNodeWithInt\":    3,\n\t\t\t\"anyNodeWithLink\":   {\"/\": \"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\"},\n\t\t\t\"anyNodeWithList\":   [3, 2, 1],\n\t\t\t\"anyNodeWithMap\":    {\"a\": \"x\", \"b\": \"y\"},\n\t\t\t\"anyNodeWithString\": \"foo\"\n\t\t}`,\n\t},\n\t{\n\t\tname: \"Enums\",\n\t\tschemaSrc: `type Root struct {\n\t\t\t\tstringAsString       EnumAsString\n\t\t\t\tstringAsStringCustom EnumAsString\n\t\t\t\tstringAsInt          EnumAsInt\n\t\t\t\tintAsInt             EnumAsInt\n\t\t\t\tuintAsInt            EnumAsInt\n\t\t\t}\n\t\t\ttype EnumAsString enum {\n\t\t\t\t| Nope (\"No\")\n\t\t\t\t| Yep  (\"Yes\")\n\t\t\t\t| Maybe\n\t\t\t}\n\t\t\ttype EnumAsInt enum {\n\t\t\t\t| Nope  (\"10\")\n\t\t\t\t| Yep   (\"11\")\n\t\t\t\t| Maybe (\"12\")\n\t\t\t} representation int`,\n\t\tptrType: (*struct {\n\t\t\tStringAsString       string\n\t\t\tStringAsStringCustom string\n\t\t\tStringAsInt          string\n\t\t\tIntAsInt             int32\n\t\t\tUintAsInt            uint16\n\t\t})(nil),\n\t\tprettyDagJSON: `{\n\t\t\t\"intAsInt\":             12,\n\t\t\t\"stringAsInt\":          10,\n\t\t\t\"stringAsString\":       \"Maybe\",\n\t\t\t\"stringAsStringCustom\": \"Yes\",\n\t\t\t\"uintAsInt\":            11\n\t\t}`,\n\t},\n\t{\n\t\tname: \"ScalarKindedUnions\",\n\t\t// TODO: should we use an \"Any\" type from the prelude?\n\t\tschemaSrc: `type Root struct {\n\t\t\t\tboolAny   AnyScalar\n\t\t\t\tintAny    AnyScalar\n\t\t\t\tfloatAny  AnyScalar\n\t\t\t\tstringAny AnyScalar\n\t\t\t\tbytesAny  AnyScalar\n\t\t\t\tlinkAny   AnyScalar\n\t\t\t}\n\n\t\t\ttype AnyScalar union {\n\t\t\t\t| Bool   bool\n\t\t\t\t| Int    int\n\t\t\t\t| Float  float\n\t\t\t\t| String string\n\t\t\t\t| Bytes  bytes\n\t\t\t\t| Link   link\n\t\t\t} representation kinded`,\n\t\tptrType: (*struct {\n\t\t\tBoolAny   anyScalar\n\t\t\tIntAny    anyScalar\n\t\t\tFloatAny  anyScalar\n\t\t\tStringAny anyScalar\n\t\t\tBytesAny  anyScalar\n\t\t\tLinkAny   anyScalar\n\t\t})(nil),\n\t\tprettyDagJSON: `{\n\t\t\t\"boolAny\":   true,\n\t\t\t\"bytesAny\":  {\"/\": {\"bytes\": \"34cd\"}},\n\t\t\t\"floatAny\":  12.5,\n\t\t\t\"intAny\":    3,\n\t\t\t\"linkAny\":   {\"/\": \"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\"},\n\t\t\t\"stringAny\": \"foo\"\n\t\t}`,\n\t},\n\t{\n\t\tname: \"RecursiveKindedUnions\",\n\t\t// TODO: should we use an \"Any\" type from the prelude?\n\t\t// Especially since we use String map/list element types.\n\t\t// TODO: use inline map/list defs once schema and dsl+dmt support it.\n\t\tschemaSrc: `type Root struct {\n\t\t\t\tlistAny AnyRecursive\n\t\t\t\tmapAny  AnyRecursive\n\t\t\t}\n\n\t\t\ttype List_String [String]\n\t\t\ttype Map_String {String:String}\n\n\t\t\ttype AnyRecursive union {\n\t\t\t\t| List_String list\n\t\t\t\t| Map_String  map\n\t\t\t} representation kinded`,\n\t\tptrType: (*struct {\n\t\t\tListAny anyRecursive\n\t\t\tMapAny  anyRecursive\n\t\t})(nil),\n\t\tprettyDagJSON: `{\n\t\t\t\"listAny\": [\"foo\", \"bar\"],\n\t\t\t\"mapAny\":  {\"a\": \"x\", \"b\": \"y\"}\n\t\t}`,\n\t},\n}\n\nfunc compactJSON(t *testing.T, pretty string) string {\n\tvar buf bytes.Buffer\n\terr := json.Compact(&buf, []byte(pretty))\n\tqt.Assert(t, err, qt.IsNil)\n\treturn buf.String()\n}\n\nfunc dagjsonEncode(t *testing.T, node datamodel.Node) string {\n\tvar sb strings.Builder\n\terr := dagjson.Encode(node, &sb)\n\tqt.Assert(t, err, qt.IsNil)\n\treturn sb.String()\n}\n\nfunc dagjsonDecode(t *testing.T, proto datamodel.NodePrototype, src string) datamodel.Node {\n\tnb := proto.NewBuilder()\n\terr := dagjson.Decode(nb, strings.NewReader(src))\n\tqt.Assert(t, err, qt.IsNil)\n\treturn nb.Build()\n}\n\nfunc TestPrototype(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range prototypeTests {\n\t\ttest := test // don't reuse the range var\n\n\t\tfor _, onlySchema := range []bool{false, true} {\n\t\t\tonlySchema := onlySchema // don't reuse the range var\n\t\t\tsuffix := \"\"\n\t\t\tif onlySchema {\n\t\t\t\tsuffix = \"_onlySchema\"\n\t\t\t}\n\t\t\tt.Run(test.name+suffix, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\tts, err := ipld.LoadSchemaBytes([]byte(test.schemaSrc))\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t\tschemaType := ts.TypeByName(\"Root\")\n\t\t\t\tqt.Assert(t, schemaType, qt.Not(qt.IsNil))\n\n\t\t\t\tptrType := test.ptrType // don't write to the shared test value\n\t\t\t\tif onlySchema {\n\t\t\t\t\tptrType = nil\n\t\t\t\t}\n\t\t\t\tproto := bindnode.Prototype(ptrType, schemaType)\n\n\t\t\t\twantEncoded := compactJSON(t, test.prettyDagJSON)\n\t\t\t\tnode := dagjsonDecode(t, proto.Representation(), wantEncoded).(schema.TypedNode)\n\t\t\t\t// TODO: assert node type matches ptrType\n\n\t\t\t\tencoded := dagjsonEncode(t, node.Representation())\n\t\t\t\tqt.Assert(t, encoded, qt.Equals, wantEncoded)\n\n\t\t\t\t// Verify that doing a dag-json encode of the non-repr node works.\n\t\t\t\t_ = dagjsonEncode(t, node)\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc TestPrototypePointerCombinations(t *testing.T) {\n\tt.Parallel()\n\n\t// TODO: Null\n\t// TODO: cover more schema types and repr strategies.\n\t// Some of them are still using w.val directly without \"nonPtr\" calls.\n\tkindTests := []struct {\n\t\tname         string\n\t\tschemaType   string\n\t\tfieldPtrType interface{}\n\t\tfieldDagJSON string\n\t}{\n\t\t{\"Bool\", \"Bool\", (*bool)(nil), `true`},\n\t\t{\"Int\", \"Int\", (*int64)(nil), `23`},\n\t\t{\"Float\", \"Float\", (*float64)(nil), `34.5`},\n\t\t{\"String\", \"String\", (*string)(nil), `\"foo\"`},\n\t\t{\"Bytes\", \"Bytes\", (*[]byte)(nil), `{\"/\": {\"bytes\": \"34cd\"}}`},\n\t\t{\"Link_CID\", \"Link\", (*cid.Cid)(nil), `{\"/\": \"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\"}`},\n\t\t{\"Link_Impl\", \"Link\", (*cidlink.Link)(nil), `{\"/\": \"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\"}`},\n\t\t{\"Link_Generic\", \"Link\", (*datamodel.Link)(nil), `{\"/\": \"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\"}`},\n\t\t{\"List_String\", \"[String]\", (*[]string)(nil), `[\"foo\", \"bar\"]`},\n\t\t{\"Any_Node_Int\", \"Any\", (*datamodel.Node)(nil), `23`},\n\t\t// TODO: reenable once we don't require pointers for nullable\n\t\t// {\"Any_Pointer_Int\", \"{String: nullable Any}\",\n\t\t// \t(*struct {\n\t\t// \t\tKeys   []string\n\t\t// \t\tValues map[string]datamodel.Node\n\t\t// \t})(nil), `{\"x\":3,\"y\":\"bar\",\"z\":[2.3,4.5]}`},\n\t\t{\"Map_String_Int\", \"{String:Int}\", (*struct {\n\t\t\tKeys   []string\n\t\t\tValues map[string]int64\n\t\t})(nil), `{\"x\":3,\"y\":4}`},\n\t}\n\n\t// For each IPLD kind, we test a matrix of combinations for IPLD's optional\n\t// and nullable fields alongside pointer usage on the Go field side.\n\tmodifiers := []struct {\n\t\tschemaField string // \"\", \"optional\", \"nullable\", \"optional nullable\"\n\t\tgoPointers  int    // 0 (T), 1 (*T), 2 (**T)\n\t}{\n\t\t{\"\", 0},                  // regular IPLD field with Go's T\n\t\t{\"\", 1},                  // regular IPLD field with Go's *T\n\t\t{\"optional\", 0},          // optional IPLD field with Go's T (skipped unless T is nilable)\n\t\t{\"optional\", 1},          // optional IPLD field with Go's *T\n\t\t{\"nullable\", 0},          // nullable IPLD field with Go's T (skipped unless T is nilable)\n\t\t{\"nullable\", 1},          // nullable IPLD field with Go's *T\n\t\t{\"optional nullable\", 2}, // optional and nullable IPLD field with Go's **T\n\t}\n\tfor _, kindTest := range kindTests {\n\t\tfor _, modifier := range modifiers {\n\t\t\t// don't reuse range vars\n\t\t\tkindTest := kindTest\n\t\t\tmodifier := modifier\n\t\t\tgoFieldType := reflect.TypeOf(kindTest.fieldPtrType)\n\t\t\tswitch modifier.goPointers {\n\t\t\tcase 0:\n\t\t\t\tgoFieldType = goFieldType.Elem() // dereference fieldPtrType\n\t\t\tcase 1:\n\t\t\t\t// fieldPtrType already uses one pointer\n\t\t\tcase 2:\n\t\t\t\tgoFieldType = reflect.PointerTo(goFieldType) // dereference fieldPtrType\n\t\t\t}\n\t\t\tif modifier.schemaField != \"\" && !nilable(goFieldType.Kind()) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tt.Run(fmt.Sprintf(\"%s/%s-%dptr\", kindTest.name, modifier.schemaField, modifier.goPointers), func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\tvar buf bytes.Buffer\n\t\t\t\terr := template.Must(template.New(\"\").Parse(`\n\t\t\t\t\t\ttype Root struct {\n\t\t\t\t\t\t\tfield {{.Modifier}} {{.Type}}\n\t\t\t\t\t\t}`)).Execute(&buf,\n\t\t\t\t\tstruct {\n\t\t\t\t\t\tType, Modifier string\n\t\t\t\t\t}{kindTest.schemaType, modifier.schemaField})\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t\tschemaSrc := buf.String()\n\t\t\t\tt.Logf(\"IPLD schema: %s\", schemaSrc)\n\n\t\t\t\t// *struct { Field {{.goFieldType}} }\n\t\t\t\tgoType := reflect.Zero(reflect.PointerTo(reflect.StructOf([]reflect.StructField{\n\t\t\t\t\t{Name: \"Field\", Type: goFieldType},\n\t\t\t\t}))).Interface()\n\t\t\t\tt.Logf(\"Go type: %T\", goType)\n\n\t\t\t\tts, err := ipld.LoadSchemaBytes([]byte(schemaSrc))\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t\tschemaType := ts.TypeByName(\"Root\")\n\t\t\t\tqt.Assert(t, schemaType, qt.Not(qt.IsNil))\n\n\t\t\t\tproto := bindnode.Prototype(goType, schemaType)\n\t\t\t\twantEncodedBytes, err := json.Marshal(map[string]interface{}{\"field\": json.RawMessage(kindTest.fieldDagJSON)})\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t\twantEncoded := string(wantEncodedBytes)\n\n\t\t\t\tnode := dagjsonDecode(t, proto.Representation(), wantEncoded).(schema.TypedNode)\n\n\t\t\t\tencoded := dagjsonEncode(t, node.Representation())\n\t\t\t\tqt.Assert(t, encoded, qt.Equals, wantEncoded)\n\n\t\t\t\t// Assigning with the missing field should only work with optional.\n\t\t\t\tnb := proto.NewBuilder()\n\t\t\t\terr = dagjson.Decode(nb, strings.NewReader(`{}`))\n\t\t\t\tswitch modifier.schemaField {\n\t\t\t\tcase \"optional\", \"optional nullable\":\n\t\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t\t\tnode := nb.Build()\n\t\t\t\t\t// The resulting node should be non-nil with a nil field.\n\t\t\t\t\tnodeVal := reflect.ValueOf(bindnode.Unwrap(node))\n\t\t\t\t\tqt.Assert(t, nodeVal.Elem().FieldByName(\"Field\").IsNil(), qt.IsTrue)\n\t\t\t\tdefault:\n\t\t\t\t\tqt.Assert(t, err, qt.Not(qt.IsNil))\n\t\t\t\t}\n\n\t\t\t\t// Assigning with a null field should only work with nullable.\n\t\t\t\tnb = proto.NewBuilder()\n\t\t\t\terr = dagjson.Decode(nb, strings.NewReader(`{\"field\":null}`))\n\t\t\t\tswitch modifier.schemaField {\n\t\t\t\tcase \"nullable\", \"optional nullable\":\n\t\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t\t\tnode := nb.Build()\n\t\t\t\t\t// The resulting node should be non-nil with a nil field.\n\t\t\t\t\tnodeVal := reflect.ValueOf(bindnode.Unwrap(node))\n\t\t\t\t\tif modifier.schemaField == \"nullable\" {\n\t\t\t\t\t\tqt.Assert(t, nodeVal.Elem().FieldByName(\"Field\").IsNil(), qt.IsTrue)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tqt.Assert(t, nodeVal.Elem().FieldByName(\"Field\").Elem().IsNil(), qt.IsTrue)\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tqt.Assert(t, err, qt.Not(qt.IsNil))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc nilable(kind reflect.Kind) bool {\n\tswitch kind {\n\tcase reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc assembleAsKind(proto datamodel.NodePrototype, schemaType schema.Type, asKind datamodel.Kind) (ipld.Node, error) {\n\tnb := proto.NewBuilder()\n\tswitch asKind {\n\tcase datamodel.Kind_Bool:\n\t\tif err := nb.AssignBool(true); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase datamodel.Kind_Int:\n\t\tif err := nb.AssignInt(123); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase datamodel.Kind_Float:\n\t\tif err := nb.AssignFloat(12.5); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase datamodel.Kind_String:\n\t\tif err := nb.AssignString(\"foo\"); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase datamodel.Kind_Bytes:\n\t\tif err := nb.AssignBytes([]byte(\"\\x00bar\")); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase datamodel.Kind_Link:\n\t\tsomeCid, err := cid.Decode(\"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\")\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := nb.AssignLink(cidlink.Link{Cid: someCid}); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase datamodel.Kind_Map:\n\t\tasm, err := nb.BeginMap(-1)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// First via AssembleKey.\n\t\tif err := asm.AssembleKey().AssignString(\"F1\"); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := asm.AssembleValue().AssignInt(101); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// Then via AssembleEntry.\n\t\tentryAsm, err := asm.AssembleEntry(\"F2\")\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := entryAsm.AssignInt(102); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// If this is a struct, using a missing field should error.\n\t\tif _, ok := schemaType.(*schema.TypeStruct); ok {\n\t\t\tif err := asm.AssembleKey().AssignString(\"MissingKey\"); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif err := asm.AssembleValue().AssignInt(101); err == nil {\n\t\t\t\treturn nil, fmt.Errorf(\"expected error on missing struct key\")\n\t\t\t}\n\t\t}\n\t\tif err := asm.Finish(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase datamodel.Kind_List:\n\t\tasm, err := nb.BeginList(-1)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// Note that we want the list to have two integer elements,\n\t\t// which matches the map entries above,\n\t\t// so that the struct with tuple repr just works too.\n\t\tif err := asm.AssembleValue().AssignInt(101); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := asm.AssembleValue().AssignInt(102); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// If this is a struct, assembling one more tuple entry should error.\n\t\tif _, ok := schemaType.(*schema.TypeStruct); ok {\n\t\t\tif err := asm.AssembleValue().AssignInt(103); err == nil {\n\t\t\t\treturn nil, fmt.Errorf(\"expected error on extra tuple entry\")\n\t\t\t}\n\t\t}\n\t\tif err := asm.Finish(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tnode := nb.Build()\n\tif node == nil {\n\t\t// If we succeeded, node must never be nil.\n\t\treturn nil, fmt.Errorf(\"built node is nil\")\n\t}\n\treturn node, nil\n}\n\nfunc useNodeAsKind(node datamodel.Node, asKind datamodel.Kind) error {\n\tif gotKind := node.Kind(); gotKind != asKind {\n\t\t// Return a dummy error to signal when the kind doesn't match.\n\t\treturn datamodel.ErrWrongKind{MethodName: \"TestKindMismatches_Dummy_Kind\"}\n\t}\n\t// Just check that IsAbsent and IsNull don't panic, for now.\n\t_ = node.IsAbsent()\n\t_ = node.IsNull()\n\n\tproto := node.Prototype()\n\tif proto == nil {\n\t\treturn fmt.Errorf(\"got a null Prototype\")\n\t}\n\n\t// TODO: also check LookupByNode, LookupBySegment\n\tswitch asKind {\n\tcase datamodel.Kind_Bool:\n\t\tif _, err := node.AsBool(); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase datamodel.Kind_Int:\n\t\tif _, err := node.AsInt(); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase datamodel.Kind_Float:\n\t\tif _, err := node.AsFloat(); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase datamodel.Kind_String:\n\t\tif _, err := node.AsString(); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase datamodel.Kind_Bytes:\n\t\tif _, err := node.AsBytes(); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase datamodel.Kind_Link:\n\t\tif _, err := node.AsLink(); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase datamodel.Kind_Map:\n\t\titer := node.MapIterator()\n\t\tif iter == nil {\n\t\t\t// Return a dummy error to signal whether iter is nil or not.\n\t\t\treturn datamodel.ErrWrongKind{MethodName: \"TestKindMismatches_Dummy_MapIterator\"}\n\t\t}\n\t\tfor !iter.Done() {\n\t\t\t_, _, err := iter.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\t// valid element\n\t\tentryNode, err := node.LookupByString(\"F1\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := useNodeAsKind(entryNode, datamodel.Kind_Int); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// missing element\n\t\t_, missingErr := node.LookupByString(\"MissingKey\")\n\t\tswitch err := missingErr.(type) {\n\t\tcase nil:\n\t\t\treturn fmt.Errorf(\"lookup of a missing key succeeded\")\n\t\tcase datamodel.ErrNotExists: // expected for maps\n\t\tcase schema.ErrInvalidKey: // expected for structs\n\t\tdefault:\n\t\t\treturn err\n\t\t}\n\n\t\tswitch l := node.Length(); l {\n\t\tcase 2:\n\t\tcase -1:\n\t\t\t// Return a dummy error to signal whether Length failed.\n\t\t\treturn datamodel.ErrWrongKind{MethodName: \"TestKindMismatches_Dummy_Length\"}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unexpected Length: %d\", l)\n\t\t}\n\tcase datamodel.Kind_List:\n\t\titer := node.ListIterator()\n\t\tif iter == nil {\n\t\t\t// Return a dummy error to signal whether iter is nil or not.\n\t\t\treturn datamodel.ErrWrongKind{MethodName: \"TestKindMismatches_Dummy_ListIterator\"}\n\t\t}\n\t\tfor !iter.Done() {\n\t\t\t_, _, err := iter.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\t// valid element\n\t\tentryNode, err := node.LookupByIndex(1)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := useNodeAsKind(entryNode, datamodel.Kind_Int); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// missing element\n\t\t_, missingErr := node.LookupByIndex(30)\n\t\tswitch err := missingErr.(type) {\n\t\tcase nil:\n\t\t\treturn fmt.Errorf(\"lookup of a missing key succeeded\")\n\t\tcase datamodel.ErrNotExists: // expected for maps\n\t\tcase schema.ErrInvalidKey: // expected for structs\n\t\tdefault:\n\t\t\treturn err\n\t\t}\n\n\t\tswitch l := node.Length(); l {\n\t\tcase 2:\n\t\tcase -1:\n\t\t\t// Return a dummy error to signal whether Length failed.\n\t\t\treturn datamodel.ErrWrongKind{MethodName: \"TestKindMismatches_Dummy_Length\"}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unexpected Length: %d\", l)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc TestKindMismatches(t *testing.T) {\n\tt.Parallel()\n\n\tkindTests := []struct {\n\t\tname      string\n\t\tschemaSrc string\n\t}{\n\t\t{\"Bool\", \"type Root bool\"},\n\t\t{\"Int\", \"type Root int\"},\n\t\t{\"Float\", \"type Root float\"},\n\t\t{\"String\", \"type Root string\"},\n\t\t{\"Bytes\", \"type Root bytes\"},\n\t\t{\"Map\", `\n\t\t\ttype Root {String:Int}\n\t\t`},\n\t\t{\"Struct\", `\n\t\t\ttype Root struct {\n\t\t\t\tF1 Int\n\t\t\t\tF2 Int\n\t\t\t}\n\t\t`},\n\t\t{\"Struct_Tuple\", `\n\t\t\ttype Root struct {\n\t\t\t\tF1 Int\n\t\t\t\tF2 Int\n\t\t\t} representation tuple\n\t\t`},\n\t\t{\"Enum\", `\n\t\t\ttype Root enum {\n\t\t\t\t| Foo (\"foo\")\n\t\t\t\t| Bar (\"bar\")\n\t\t\t\t| Either\n\t\t\t}\n\t\t`},\n\t\t{\"Union_Kinded_onlyString\", `\n\t\t\ttype Root union {\n\t\t\t\t| String string\n\t\t\t} representation kinded\n\t\t`},\n\t\t{\"Union_Kinded_onlyList\", `\n\t\t\ttype Root union {\n\t\t\t\t| List list\n\t\t\t} representation kinded\n\t\t`},\n\t\t// TODO: more schema types and repr strategies\n\t}\n\n\tallKinds := []datamodel.Kind{\n\t\t// datamodel.Kind_Null, TODO\n\t\tdatamodel.Kind_Bool,\n\t\tdatamodel.Kind_Int,\n\t\tdatamodel.Kind_Float,\n\t\tdatamodel.Kind_String,\n\t\tdatamodel.Kind_Bytes,\n\t\tdatamodel.Kind_Link,\n\t\tdatamodel.Kind_Map,\n\t\tdatamodel.Kind_List,\n\t}\n\n\t// TODO: also test for non-repr assemblers and nodes\n\n\tfor _, kindTest := range kindTests {\n\t\t// don't reuse range vars\n\t\tkindTest := kindTest\n\t\tt.Run(kindTest.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t// Note that debug.Stack inside the recover will include the\n\t\t\t\t\t// stack trace for the original panic call.\n\t\t\t\t\tt.Errorf(\"caught panic:\\n%v\\n%s\", r, debug.Stack())\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\tts, err := ipld.LoadSchemaBytes([]byte(kindTest.schemaSrc))\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tschemaType := ts.TypeByName(\"Root\")\n\t\t\tqt.Assert(t, schemaType, qt.Not(qt.IsNil))\n\n\t\t\t// Note that the Go type is inferred.\n\t\t\tproto := bindnode.Prototype(nil, schemaType).Representation()\n\n\t\t\treprBehaviorKind := schemaType.RepresentationBehavior()\n\t\t\tif reprBehaviorKind == datamodel.Kind_Invalid {\n\t\t\t\t// For now, this only applies to kinded unions.\n\t\t\t\t// We'll need to modify this when we test with Any.\n\t\t\t\tmembers := schemaType.(*schema.TypeUnion).Members()\n\t\t\t\tqt.Assert(t, members, qt.HasLen, 1)\n\t\t\t\treprBehaviorKind = members[0].RepresentationBehavior()\n\t\t\t}\n\t\t\tqt.Assert(t, reprBehaviorKind, qt.Not(qt.Equals), datamodel.Kind_Invalid)\n\n\t\t\tfor _, kind := range allKinds {\n\t\t\t\t_, err := assembleAsKind(proto, schemaType, kind)\n\t\t\t\tcomment := qt.Commentf(\"assigned as %v\", kind)\n\t\t\t\t// Assembling should succed iff we used the right kind.\n\t\t\t\tif kind == reprBehaviorKind {\n\t\t\t\t\tqt.Assert(t, err, qt.IsNil, comment)\n\t\t\t\t} else {\n\t\t\t\t\tqt.Assert(t, err, qt.Not(qt.IsNil), comment)\n\t\t\t\t\tqt.Assert(t, err, qt.ErrorAs, new(datamodel.ErrWrongKind), comment)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tnode, err := assembleAsKind(proto, schemaType, reprBehaviorKind)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tnode = node.(schema.TypedNode).Representation()\n\t\t\tnodeKind := node.Kind()\n\n\t\t\tfor _, kind := range allKinds {\n\t\t\t\terr := useNodeAsKind(node, kind)\n\t\t\t\tcomment := qt.Commentf(\"used as %v\", kind)\n\t\t\t\t// Using the node should succed iff we used the right kind.\n\t\t\t\tif kind == nodeKind {\n\t\t\t\t\tqt.Assert(t, err, qt.IsNil, comment)\n\t\t\t\t} else {\n\t\t\t\t\tqt.Assert(t, err, qt.Not(qt.IsNil), comment)\n\t\t\t\t\tqt.Assert(t, err, qt.ErrorAs, new(datamodel.ErrWrongKind), comment)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\ntype verifyBadType struct {\n\tptrType     interface{}\n\tpanicRegexp string\n}\n\ntype (\n\tnamedBool    bool\n\tnamedInt64   int64\n\tnamedFloat64 float64\n\tnamedString  string\n\tnamedBytes   []byte\n)\n\nvar verifyTests = []struct {\n\tname      string\n\tschemaSrc string\n\n\tgoodTypes []interface{}\n\tbadTypes  []verifyBadType\n}{\n\t{\n\t\tname:      \"Bool\",\n\t\tschemaSrc: `type Root bool`,\n\t\tgoodTypes: []interface{}{\n\t\t\t(*bool)(nil),\n\t\t\t(*namedBool)(nil),\n\t\t},\n\t\tbadTypes: []verifyBadType{\n\t\t\t{(*string)(nil), `.*type Root .* type string: kind mismatch;.*`},\n\t\t},\n\t},\n\t{\n\t\tname:      \"Int\",\n\t\tschemaSrc: `type Root int`,\n\t\tgoodTypes: []interface{}{\n\t\t\t(*int)(nil),\n\t\t\t(*namedInt64)(nil),\n\t\t\t(*int8)(nil),\n\t\t\t(*int16)(nil),\n\t\t\t(*int32)(nil),\n\t\t\t(*int64)(nil),\n\t\t},\n\t\tbadTypes: []verifyBadType{\n\t\t\t{(*string)(nil), `.*type Root .* type string: kind mismatch;.*`},\n\t\t},\n\t},\n\t{\n\t\tname:      \"Float\",\n\t\tschemaSrc: `type Root float`,\n\t\tgoodTypes: []interface{}{\n\t\t\t(*float64)(nil),\n\t\t\t(*namedFloat64)(nil),\n\t\t\t(*float32)(nil),\n\t\t},\n\t\tbadTypes: []verifyBadType{\n\t\t\t{(*string)(nil), `.*type Root .* type string: kind mismatch;.*`},\n\t\t},\n\t},\n\t{\n\t\tname:      \"String\",\n\t\tschemaSrc: `type Root string`,\n\t\tgoodTypes: []interface{}{\n\t\t\t(*string)(nil),\n\t\t\t(*namedString)(nil),\n\t\t},\n\t\tbadTypes: []verifyBadType{\n\t\t\t{(*int)(nil), `.*type Root .* type int: kind mismatch;.*`},\n\t\t},\n\t},\n\t{\n\t\tname:      \"Bytes\",\n\t\tschemaSrc: `type Root bytes`,\n\t\tgoodTypes: []interface{}{\n\t\t\t(*[]byte)(nil),\n\t\t\t(*namedBytes)(nil),\n\t\t\t(*[]uint8)(nil), // alias of byte\n\t\t},\n\t\tbadTypes: []verifyBadType{\n\t\t\t{(*int)(nil), `.*type Root .* type int: kind mismatch;.*`},\n\t\t\t{(*[]int)(nil), `.*type Root .* type \\[\\]int: kind mismatch;.*`},\n\t\t},\n\t},\n\t{\n\t\tname:      \"List\",\n\t\tschemaSrc: `type Root [String]`,\n\t\tgoodTypes: []interface{}{\n\t\t\t(*[]string)(nil),\n\t\t\t(*[]namedString)(nil),\n\t\t},\n\t\tbadTypes: []verifyBadType{\n\t\t\t{(*string)(nil), `.*type Root .* type string: kind mismatch;.*`},\n\t\t\t{(*[]int)(nil), `.*type String .* type int: kind mismatch;.*`},\n\t\t\t{(*[3]string)(nil), `.*type Root .* type \\[3\\]string: kind mismatch;.*`},\n\t\t},\n\t},\n\t{\n\t\tname: \"Struct\",\n\t\tschemaSrc: `type Root struct {\n\t\t\t\tint Int\n\t\t\t}`,\n\t\tgoodTypes: []interface{}{\n\t\t\t(*struct{ Int int })(nil),\n\t\t\t(*struct{ Int namedInt64 })(nil),\n\t\t},\n\t\tbadTypes: []verifyBadType{\n\t\t\t{(*string)(nil), `.*type Root .* type string: kind mismatch;.*`},\n\t\t\t{(*struct{ Int bool })(nil), `.*type Int .* type bool: kind mismatch;.*`},\n\t\t\t{(*struct{ Int1, Int2 int })(nil), `.*type Root .* type struct {.*}: 2 vs 1 fields`},\n\t\t},\n\t},\n\t{\n\t\tname:      \"Map\",\n\t\tschemaSrc: `type Root {String:Int}`,\n\t\tgoodTypes: []interface{}{\n\t\t\t(*struct {\n\t\t\t\tKeys   []string\n\t\t\t\tValues map[string]int\n\t\t\t})(nil),\n\t\t\t(*struct {\n\t\t\t\tKeys   []namedString\n\t\t\t\tValues map[namedString]namedInt64\n\t\t\t})(nil),\n\t\t},\n\t\tbadTypes: []verifyBadType{\n\t\t\t{(*string)(nil), `.*type Root .* type string: kind mismatch;.*`},\n\t\t\t{(*struct{ Keys []string })(nil), `.*type Root .*: 1 vs 2 fields`},\n\t\t\t{(*struct{ Values map[string]int })(nil), `.*type Root .*: 1 vs 2 fields`},\n\t\t\t{(*struct {\n\t\t\t\tKeys   string\n\t\t\t\tValues map[string]int\n\t\t\t})(nil), `.*type Root .*: kind mismatch;.*`},\n\t\t\t{(*struct {\n\t\t\t\tKeys   []string\n\t\t\t\tValues string\n\t\t\t})(nil), `.*type Root .*: kind mismatch;.*`},\n\t\t},\n\t},\n\t{\n\t\tname:      \"MapNullableAny\",\n\t\tschemaSrc: `type Root {String:nullable Any}`,\n\t\tgoodTypes: []interface{}{\n\t\t\t(*struct {\n\t\t\t\tKeys   []string\n\t\t\t\tValues map[string]*datamodel.Node\n\t\t\t})(nil),\n\t\t\t(*struct {\n\t\t\t\tKeys   []string\n\t\t\t\tValues map[string]datamodel.Node\n\t\t\t})(nil),\n\t\t},\n\t\tbadTypes: []verifyBadType{\n\t\t\t{(*string)(nil), `.*type Root .* type string: kind mismatch;.*`},\n\t\t},\n\t},\n\t{\n\t\tname: \"Union\",\n\t\tschemaSrc: `type Root union {\n\t\t\t\t| List_String list\n\t\t\t\t| String      string\n\t\t\t} representation kinded\n\n\t\t\ttype List_String [String]\n\t\t\t`,\n\t\tgoodTypes: []interface{}{\n\t\t\t(*struct {\n\t\t\t\tList   *[]string\n\t\t\t\tString *string\n\t\t\t})(nil),\n\t\t\t(*struct {\n\t\t\t\tList   []string\n\t\t\t\tString *string\n\t\t\t})(nil),\n\t\t\t(*struct {\n\t\t\t\tList   *[]namedString\n\t\t\t\tString *namedString\n\t\t\t})(nil),\n\t\t},\n\t\tbadTypes: []verifyBadType{\n\t\t\t{(*string)(nil), `.*type Root .* type string: kind mismatch;.*`},\n\t\t\t{(*struct{ List *[]string })(nil), `.*type Root .*: 1 vs 2 members`},\n\t\t\t{(*struct {\n\t\t\t\tList   []string\n\t\t\t\tString string\n\t\t\t})(nil), `.*type Root .*: union members must be nilable`},\n\t\t\t{(*struct {\n\t\t\t\tList   *[]string\n\t\t\t\tString *int\n\t\t\t})(nil), `.*type String .*: kind mismatch;.*`},\n\t\t},\n\t},\n}\n\nfunc TestSchemaVerify(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range verifyTests {\n\t\ttest := test // don't reuse the range var\n\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts, err := ipld.LoadSchemaBytes([]byte(test.schemaSrc))\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tschemaType := ts.TypeByName(\"Root\")\n\t\t\tqt.Assert(t, schemaType, qt.Not(qt.IsNil))\n\n\t\t\tfor _, ptrType := range test.goodTypes {\n\t\t\t\tproto := bindnode.Prototype(ptrType, schemaType)\n\t\t\t\tqt.Assert(t, proto, qt.Not(qt.IsNil))\n\n\t\t\t\tptrVal := reflect.New(reflect.TypeOf(ptrType).Elem()).Interface()\n\t\t\t\tnode := bindnode.Wrap(ptrVal, schemaType)\n\t\t\t\tqt.Assert(t, node, qt.Not(qt.IsNil))\n\t\t\t}\n\n\t\t\tfor _, bad := range test.badTypes {\n\t\t\t\tqt.Check(t, func() { bindnode.Prototype(bad.ptrType, schemaType) },\n\t\t\t\t\tqt.PanicMatches, bad.panicRegexp)\n\n\t\t\t\tptrVal := reflect.New(reflect.TypeOf(bad.ptrType).Elem()).Interface()\n\t\t\t\tqt.Check(t, func() { bindnode.Wrap(ptrVal, schemaType) },\n\t\t\t\t\tqt.PanicMatches, bad.panicRegexp)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestProduceGoTypes(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range prototypeTests {\n\t\ttest := test // don't reuse the range var\n\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts, err := ipld.LoadSchemaBytes([]byte(test.schemaSrc))\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\t\t// Include a package line and the datamodel import.\n\t\t\tbuf := new(bytes.Buffer)\n\t\t\tfmt.Fprintln(buf, `package p`)\n\t\t\tfmt.Fprintln(buf, `import \"github.com/ipld/go-ipld-prime/datamodel\"`)\n\t\t\tfmt.Fprintln(buf, `var _ datamodel.Link // always used`)\n\t\t\terr = bindnode.ProduceGoTypes(buf, ts)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\t\t// Ensure that the output builds, i.e. typechecks.\n\t\t\tgenPath := filepath.Join(t.TempDir(), \"gen.go\")\n\t\t\terr = os.WriteFile(genPath, buf.Bytes(), 0o666)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\t\tout, err := exec.Command(\"go\", \"build\", genPath).CombinedOutput()\n\t\t\tqt.Assert(t, err, qt.IsNil, qt.Commentf(\"output: %s\", out))\n\n\t\t\t// TODO: check that the generated types are compatible with the schema.\n\t\t})\n\t}\n}\n\nfunc TestRenameAssignNode(t *testing.T) {\n\ttype Foo struct{ I int }\n\n\tts, _ := ipld.LoadSchemaBytes([]byte(`\ntype Foo struct {\n\tI Int (rename \"J\")\n}\n`))\n\tFooProto := bindnode.Prototype((*Foo)(nil), ts.TypeByName(\"Foo\"))\n\n\t// Decode straight into bindnode typed builder\n\tnb := FooProto.Representation().NewBuilder()\n\terr := dagjson.Decode(nb, bytes.NewReader([]byte(`{\"J\":100}`)))\n\tqt.Assert(t, err, qt.IsNil)\n\tnb.Build()\n\n\t// decode into basicnode builder\n\tnb = basicnode.Prototype.Any.NewBuilder()\n\terr = dagjson.Decode(nb, bytes.NewReader([]byte(`{\"J\":100}`)))\n\tqt.Assert(t, err, qt.IsNil)\n\tnode := nb.Build()\n\n\t// AssignNode from the basicnode form\n\tnb = FooProto.Representation().NewBuilder()\n\terr = nb.AssignNode(node)\n\tqt.Assert(t, err, qt.IsNil)\n\tnb.Build()\n}\n\nfunc TestEmptyTypedAssignNode(t *testing.T) {\n\ttype Foo struct {\n\t\tI string\n\t\tJ string\n\t\tK int\n\t}\n\ttype Foo1Optional struct {\n\t\tI string\n\t\tJ string\n\t\tK *int\n\t}\n\ttype Foo2Optional struct {\n\t\tI string\n\t\tJ *string\n\t\tK *int\n\t}\n\ttupleSchema := `type Foo struct {\n\t\tI String\n\t\tJ String\n\t\tK Int\n\t} representation tuple`\n\ttuple1OptionalSchema := `type Foo struct {\n\t\tI String\n\t\tJ String\n\t\tK optional Int\n\t} representation tuple`\n\ttuple2OptionalSchema := `type Foo struct {\n\t\tI String\n\t\tJ optional String\n\t\tK optional Int\n\t} representation tuple`\n\n\ttestCases := map[string]struct {\n\t\tschema  string\n\t\ttyp     interface{}\n\t\tdagJson string\n\t\terr     string\n\t}{\n\t\t\"tuple\": {\n\t\t\tschema:  tupleSchema,\n\t\t\ttyp:     (*Foo)(nil),\n\t\t\tdagJson: `[\"\",\"\",0]`,\n\t\t},\n\t\t\"tuple with 2 absents\": {\n\t\t\tschema:  tupleSchema,\n\t\t\ttyp:     (*Foo)(nil),\n\t\t\tdagJson: `[\"\"]`,\n\t\t\terr:     \"missing required fields: J,K\",\n\t\t},\n\t\t\"tuple with 1 optional\": {\n\t\t\tschema:  tuple1OptionalSchema,\n\t\t\ttyp:     (*Foo1Optional)(nil),\n\t\t\tdagJson: `[\"\",\"\",0]`,\n\t\t},\n\t\t\"tuple with 1 optional and absent\": {\n\t\t\tschema:  tuple1OptionalSchema,\n\t\t\ttyp:     (*Foo1Optional)(nil),\n\t\t\tdagJson: `[\"\",\"\"]`,\n\t\t},\n\t\t\"tuple with 1 optional and 2 absents\": {\n\t\t\tschema:  tuple1OptionalSchema,\n\t\t\ttyp:     (*Foo1Optional)(nil),\n\t\t\tdagJson: `[\"\"]`,\n\t\t\terr:     \"missing required fields: J\",\n\t\t},\n\t\t\"tuple with 2 optional\": {\n\t\t\tschema:  tuple2OptionalSchema,\n\t\t\ttyp:     (*Foo2Optional)(nil),\n\t\t\tdagJson: `[\"\",\"\",0]`,\n\t\t},\n\t\t\"tuple with 2 optional and 1 absent\": {\n\t\t\tschema:  tuple2OptionalSchema,\n\t\t\ttyp:     (*Foo2Optional)(nil),\n\t\t\tdagJson: `[\"\",\"\"]`,\n\t\t},\n\t\t\"tuple with 2 optional and 2 absent\": {\n\t\t\tschema:  tuple2OptionalSchema,\n\t\t\ttyp:     (*Foo2Optional)(nil),\n\t\t\tdagJson: `[\"\"]`,\n\t\t},\n\t\t\"tuple with 2 optional and 3 absent\": {\n\t\t\tschema:  tuple2OptionalSchema,\n\t\t\ttyp:     (*Foo2Optional)(nil),\n\t\t\tdagJson: `[]`,\n\t\t\terr:     \"missing required fields: I\",\n\t\t},\n\t\t\"map\": {\n\t\t\tschema: `type Foo struct {\n\t\t\t\tI String\n\t\t\t\tJ String\n\t\t\t\tK Int\n\t\t\t} representation map\n\t\t\t`,\n\t\t\ttyp:     (*Foo)(nil),\n\t\t\tdagJson: `{\"I\":\"\",\"J\":\"\",\"K\":0}`,\n\t\t},\n\t}\n\n\tfor testCase, data := range testCases {\n\t\tt.Run(testCase, func(t *testing.T) {\n\t\t\tts, _ := ipld.LoadSchemaBytes([]byte(data.schema))\n\t\t\tFooProto := bindnode.Prototype(data.typ, ts.TypeByName(\"Foo\"))\n\n\t\t\t// decode an \"empty\" object into Foo, these are all default values\n\t\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\t\terr := dagjson.Decode(nb, bytes.NewReader([]byte(data.dagJson)))\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tnode := nb.Build()\n\n\t\t\t// AssignNode from the basicnode form\n\t\t\tnb = FooProto.Representation().NewBuilder()\n\t\t\terr = nb.AssignNode(node)\n\t\t\tif data.err == \"\" {\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t} else {\n\t\t\t\tqt.Assert(t, err, qt.ErrorMatches, data.err)\n\t\t\t}\n\t\t\tnb.Build()\n\n\t\t\t// make an \"empty\" form, although none of the fields are optional so we should end up with defaults\n\t\t\tnb = FooProto.Representation().NewBuilder()\n\t\t\tempty := nb.Build()\n\n\t\t\t// AssignNode from the representation of the \"empty\" form, which should pass through default values\n\t\t\tnb = FooProto.Representation().NewBuilder()\n\t\t\terr = nb.AssignNode(empty.(schema.TypedNode).Representation())\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t})\n\t}\n}\n\nfunc TestInferLinksAndAny(t *testing.T) {\n\tlink, err := cid.Decode(\"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\")\n\tqt.Assert(t, err, qt.IsNil)\n\n\ttype Nd struct {\n\t\tA cid.Cid\n\t\tB cidlink.Link\n\t\tC datamodel.Link\n\t\tD datamodel.Node\n\t}\n\n\tproto := bindnode.Prototype(&Nd{}, nil)\n\n\texpected := &Nd{\n\t\tA: link,\n\t\tB: cidlink.Link{Cid: link},\n\t\tC: cidlink.Link{Cid: link},\n\t\tD: basicnode.NewString(\"Any Here\"),\n\t}\n\n\tnode := bindnode.Wrap(expected, proto.Type())\n\n\tbyts, err := ipld.Encode(node, dagjson.Encode)\n\tqt.Assert(t, err, qt.IsNil)\n\n\tqt.Assert(t, string(byts), qt.Equals, `{\"A\":{\"/\":\"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\"},\"B\":{\"/\":\"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\"},\"C\":{\"/\":\"bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi\"},\"D\":\"Any Here\"}`)\n\n\tnodeRt, err := ipld.DecodeUsingPrototype(byts, dagjson.Decode, proto)\n\tqt.Assert(t, err, qt.IsNil)\n\n\tif actual, ok := bindnode.Unwrap(nodeRt).(*Nd); ok {\n\t\tqt.Assert(t, actual, qt.CmpEquals(cmp.Comparer(func(x, y cid.Cid) bool { return x.Equals(y) })), expected)\n\t} else {\n\t\tt.Error(\"expected *Nd from Unwrap\")\n\t}\n}\n"
  },
  {
    "path": "node/bindnode/node.go",
    "content": "package bindnode\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/mixins\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// Assert that we implement all the interfaces as expected.\n// Grouped by the interfaces to implement, roughly.\nvar (\n\t_ datamodel.NodePrototype = (*_prototype)(nil)\n\t_ schema.TypedPrototype   = (*_prototype)(nil)\n\t_ datamodel.NodePrototype = (*_prototypeRepr)(nil)\n\n\t_ datamodel.Node   = (*_node)(nil)\n\t_ schema.TypedNode = (*_node)(nil)\n\t_ datamodel.Node   = (*_nodeRepr)(nil)\n\n\t_ datamodel.Node     = (*_uintNode)(nil)\n\t_ schema.TypedNode   = (*_uintNode)(nil)\n\t_ datamodel.UintNode = (*_uintNode)(nil)\n\t_ datamodel.Node     = (*_uintNodeRepr)(nil)\n\t_ datamodel.UintNode = (*_uintNodeRepr)(nil)\n\n\t_ datamodel.NodeBuilder   = (*_builder)(nil)\n\t_ datamodel.NodeBuilder   = (*_builderRepr)(nil)\n\t_ datamodel.NodeAssembler = (*_assembler)(nil)\n\t_ datamodel.NodeAssembler = (*_assemblerRepr)(nil)\n\t_ datamodel.NodeAssembler = (*_errorAssembler)(nil)\n\t_ datamodel.NodeAssembler = (*_listpairsFieldAssemblerRepr)(nil)\n\n\t_ datamodel.MapAssembler = (*_structAssembler)(nil)\n\t_ datamodel.MapAssembler = (*_structAssemblerRepr)(nil)\n\t_ datamodel.MapIterator  = (*_structIterator)(nil)\n\t_ datamodel.MapIterator  = (*_structIteratorRepr)(nil)\n\n\t_ datamodel.ListAssembler = (*_listAssembler)(nil)\n\t_ datamodel.ListAssembler = (*_listAssemblerRepr)(nil)\n\t_ datamodel.ListAssembler = (*_listStructAssemblerRepr)(nil)\n\t_ datamodel.ListAssembler = (*_listpairsFieldListAssemblerRepr)(nil)\n\t_ datamodel.ListIterator  = (*_listIterator)(nil)\n\t_ datamodel.ListIterator  = (*_tupleIteratorRepr)(nil)\n\t_ datamodel.ListIterator  = (*_listpairsIteratorRepr)(nil)\n\n\t_ datamodel.MapAssembler = (*_unionAssembler)(nil)\n\t_ datamodel.MapAssembler = (*_unionAssemblerRepr)(nil)\n\t_ datamodel.MapIterator  = (*_unionIterator)(nil)\n\t_ datamodel.MapIterator  = (*_unionIteratorRepr)(nil)\n)\n\ntype _prototype struct {\n\tcfg        *config\n\tschemaType schema.Type\n\tgoType     reflect.Type // non-pointer\n}\n\nfunc (w *_prototype) NewBuilder() datamodel.NodeBuilder {\n\treturn &_builder{_assembler{\n\t\tcfg:        w.cfg,\n\t\tschemaType: w.schemaType,\n\t\tval:        reflect.New(w.goType).Elem(),\n\t}}\n}\n\nfunc (w *_prototype) Type() schema.Type {\n\treturn w.schemaType\n}\n\nfunc (w *_prototype) Representation() datamodel.NodePrototype {\n\treturn (*_prototypeRepr)(w)\n}\n\ntype _node struct {\n\tcfg        *config\n\tschemaType schema.Type\n\n\tval reflect.Value // non-pointer\n}\n\n// TODO: only expose TypedNode methods if the schema was explicit.\n// type _typedNode struct {\n// \t_node\n// }\n\nfunc newNode(cfg *config, schemaType schema.Type, val reflect.Value) schema.TypedNode {\n\tif schemaType.TypeKind() == schema.TypeKind_Int && nonPtrVal(val).Kind() == reflect.Uint64 {\n\t\t// special case for uint64 values so we can handle the >int64 range\n\t\t// we give this treatment to all uint64s, regardless of current value\n\t\t// because we have no guarantees the value won't change underneath us\n\t\treturn &_uintNode{\n\t\t\tcfg:        cfg,\n\t\t\tschemaType: schemaType,\n\t\t\tval:        val,\n\t\t}\n\t}\n\treturn &_node{cfg, schemaType, val}\n}\n\nfunc (w *_node) Type() schema.Type {\n\treturn w.schemaType\n}\n\nfunc (w *_node) Representation() datamodel.Node {\n\treturn (*_nodeRepr)(w)\n}\n\nfunc (w *_node) Kind() datamodel.Kind {\n\treturn actualKind(w.schemaType)\n}\n\n// matching schema level types to data model kinds, since our Node and Builder\n// interfaces operate on kinds\nfunc compatibleKind(schemaType schema.Type, kind datamodel.Kind) error {\n\tswitch sch := schemaType.(type) {\n\tcase *schema.TypeAny:\n\t\treturn nil\n\tdefault:\n\t\tactual := actualKind(sch) // ActsLike data model\n\t\tif actual == kind {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Error\n\t\tmethodName := \"\"\n\t\tif pc, _, _, ok := runtime.Caller(1); ok {\n\t\t\tif fn := runtime.FuncForPC(pc); fn != nil {\n\t\t\t\tmethodName = fn.Name()\n\t\t\t\t// Go from \"pkg/path.Type.Method\" to just \"Method\".\n\t\t\t\tmethodName = methodName[strings.LastIndexByte(methodName, '.')+1:]\n\t\t\t}\n\t\t}\n\t\treturn datamodel.ErrWrongKind{\n\t\t\tTypeName:        schemaType.Name(),\n\t\t\tMethodName:      methodName,\n\t\t\tAppropriateKind: datamodel.KindSet{kind},\n\t\t\tActualKind:      actual,\n\t\t}\n\t}\n}\n\nfunc actualKind(schemaType schema.Type) datamodel.Kind {\n\treturn schemaType.TypeKind().ActsLike()\n}\n\nfunc nonPtrVal(val reflect.Value) reflect.Value {\n\t// TODO: support **T as well as *T?\n\tif val.Kind() == reflect.Ptr {\n\t\tif val.IsNil() {\n\t\t\t// TODO: error in this case?\n\t\t\treturn reflect.Value{}\n\t\t}\n\t\tval = val.Elem()\n\t}\n\treturn val\n}\n\nfunc ptrVal(val reflect.Value) reflect.Value {\n\tif val.Kind() == reflect.Ptr {\n\t\treturn val\n\t}\n\treturn val.Addr()\n}\n\nfunc nonPtrType(val reflect.Value) reflect.Type {\n\ttyp := val.Type()\n\tif typ.Kind() == reflect.Ptr {\n\t\treturn typ.Elem()\n\t}\n\treturn typ\n}\n\n// where we need to cal Set(), ensure the Value we're setting is a pointer or\n// not, depending on the field we're setting into.\nfunc matchSettable(val interface{}, to reflect.Value) reflect.Value {\n\tsetVal := nonPtrVal(reflect.ValueOf(val))\n\tif !setVal.Type().AssignableTo(to.Type()) && setVal.Type().ConvertibleTo(to.Type()) {\n\t\tsetVal = setVal.Convert(to.Type())\n\t}\n\treturn setVal\n}\n\nfunc (w *_node) LookupByString(key string) (datamodel.Node, error) {\n\tswitch typ := w.schemaType.(type) {\n\tcase *schema.TypeStruct:\n\t\tfield := typ.Field(key)\n\t\tif field == nil {\n\t\t\treturn nil, schema.ErrInvalidKey{\n\t\t\t\tTypeName: typ.Name(),\n\t\t\t\tKey:      basicnode.NewString(key),\n\t\t\t}\n\t\t}\n\t\tfval := nonPtrVal(w.val).FieldByName(fieldNameFromSchema(key))\n\t\tif !fval.IsValid() {\n\t\t\treturn nil, fmt.Errorf(\"bindnode TODO: go-schema mismatch\")\n\t\t}\n\t\tif field.IsOptional() {\n\t\t\tif fval.IsNil() {\n\t\t\t\treturn datamodel.Absent, nil\n\t\t\t}\n\t\t\tif fval.Kind() == reflect.Ptr {\n\t\t\t\tfval = fval.Elem()\n\t\t\t}\n\t\t}\n\t\tif field.IsNullable() {\n\t\t\tif fval.IsNil() {\n\t\t\t\treturn datamodel.Null, nil\n\t\t\t}\n\t\t\tif fval.Kind() == reflect.Ptr {\n\t\t\t\tfval = fval.Elem()\n\t\t\t}\n\t\t}\n\t\tif _, ok := field.Type().(*schema.TypeAny); ok {\n\t\t\tif customConverter := w.cfg.converterFor(field.Type().Name(), fval); customConverter != nil {\n\t\t\t\t// field is an Any and we have a custom type converter for the type\n\t\t\t\treturn customConverter.customToAny(ptrVal(fval).Interface())\n\t\t\t}\n\t\t\t// field is an Any, safely assume a Node in fval\n\t\t\treturn nonPtrVal(fval).Interface().(datamodel.Node), nil\n\t\t}\n\t\treturn newNode(w.cfg, field.Type(), fval), nil\n\tcase *schema.TypeMap:\n\t\t// maps can only be structs with a Values map\n\t\tvar kval reflect.Value\n\t\tvaluesVal := nonPtrVal(w.val).FieldByName(\"Values\")\n\t\tswitch ktyp := typ.KeyType().(type) {\n\t\tcase *schema.TypeString:\n\t\t\t// plain String keys, so safely use the map key as is\n\t\t\tkval = reflect.ValueOf(key)\n\t\tdefault:\n\t\t\t// key is something other than a string that we need to assemble via\n\t\t\t// the string representation form, use _assemblerRepr to reverse from\n\t\t\t// string to the type that indexes the map\n\t\t\tasm := &_assembler{\n\t\t\t\tcfg:        w.cfg,\n\t\t\t\tschemaType: ktyp,\n\t\t\t\tval:        reflect.New(valuesVal.Type().Key()).Elem(),\n\t\t\t}\n\t\t\tif err := (*_assemblerRepr)(asm).AssignString(key); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tkval = asm.val\n\t\t}\n\t\tfval := valuesVal.MapIndex(kval)\n\t\tif !fval.IsValid() { // not found\n\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)}\n\t\t}\n\t\t// TODO: Error/panic if fval.IsNil() && !typ.ValueIsNullable()?\n\t\t// Otherwise we could have two non-equal Go values (nil map,\n\t\t// non-nil-but-empty map) which represent the exact same IPLD\n\t\t// node when the field is not nullable.\n\t\tif typ.ValueIsNullable() {\n\t\t\tif fval.IsNil() {\n\t\t\t\treturn datamodel.Null, nil\n\t\t\t}\n\t\t\tfval = fval.Elem()\n\t\t}\n\t\tif _, ok := typ.ValueType().(*schema.TypeAny); ok {\n\t\t\tif customConverter := w.cfg.converterFor(typ.ValueType().Name(), fval); customConverter != nil {\n\t\t\t\t// value is an Any and we have a custom type converter for the type\n\t\t\t\treturn customConverter.customToAny(ptrVal(fval).Interface())\n\t\t\t}\n\t\t\t// value is an Any, safely assume a Node in fval\n\t\t\treturn nonPtrVal(fval).Interface().(datamodel.Node), nil\n\t\t}\n\t\treturn newNode(w.cfg, typ.ValueType(), fval), nil\n\tcase *schema.TypeUnion:\n\t\t// treat a union similar to a struct, but we have the member names more\n\t\t// easily accessible to match to 'key'\n\t\tvar idx int\n\t\tvar mtyp schema.Type\n\t\tfor i, member := range typ.Members() {\n\t\t\tif member.Name() == key {\n\t\t\t\tidx = i\n\t\t\t\tmtyp = member\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif mtyp == nil { // not found\n\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)}\n\t\t}\n\t\t// TODO: we could look up the right Go field straight away via idx.\n\t\thaveIdx, mval := unionMember(nonPtrVal(w.val))\n\t\tif haveIdx != idx { // mismatching type\n\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)}\n\t\t}\n\t\treturn newNode(w.cfg, mtyp, mval), nil\n\t}\n\treturn nil, datamodel.ErrWrongKind{\n\t\tTypeName:        w.schemaType.Name(),\n\t\tMethodName:      \"LookupByString\",\n\t\tAppropriateKind: datamodel.KindSet_JustMap,\n\t\tActualKind:      w.Kind(),\n\t}\n}\n\nvar invalidValue reflect.Value\n\n// unionMember finds which union member is set in the corresponding Go struct.\nfunc unionMember(val reflect.Value) (int, reflect.Value) {\n\t// The first non-nil field is a match.\n\tfor i := 0; i < val.NumField(); i++ {\n\t\telemVal := val.Field(i)\n\t\tif elemVal.Kind() != reflect.Ptr {\n\t\t\tpanic(\"bindnode bug: found unexpected non-pointer in a union field\")\n\t\t}\n\t\tif elemVal.IsNil() {\n\t\t\tcontinue\n\t\t}\n\t\treturn i, elemVal.Elem()\n\t}\n\treturn -1, invalidValue\n}\n\nfunc unionSetMember(val reflect.Value, memberIdx int, memberPtr reflect.Value) {\n\t// Reset the entire union struct to zero, to clear any non-nil pointers.\n\tval.Set(reflect.Zero(val.Type()))\n\n\t// Set the index pointer to the given value.\n\tval.Field(memberIdx).Set(memberPtr)\n}\n\nfunc (w *_node) LookupByIndex(idx int64) (datamodel.Node, error) {\n\tswitch typ := w.schemaType.(type) {\n\tcase *schema.TypeList:\n\t\tval := nonPtrVal(w.val)\n\t\t// we should be able assume that val is something we can Len() and Index()\n\t\tif idx < 0 || int(idx) >= val.Len() {\n\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfInt(idx)}\n\t\t}\n\t\tval = val.Index(int(idx))\n\t\t_, isAny := typ.ValueType().(*schema.TypeAny)\n\t\tif isAny {\n\t\t\tif customConverter := w.cfg.converterFor(typ.ValueType().Name(), val); customConverter != nil {\n\t\t\t\t// values are Any and we have a converter for this type that will give us\n\t\t\t\t// a datamodel.Node\n\t\t\t\treturn customConverter.customToAny(ptrVal(val).Interface())\n\t\t\t}\n\t\t}\n\t\tif typ.ValueIsNullable() {\n\t\t\tif val.IsNil() {\n\t\t\t\treturn datamodel.Null, nil\n\t\t\t}\n\t\t\t// nullable elements are assumed to be pointers\n\t\t\tval = val.Elem()\n\t\t}\n\t\tif isAny {\n\t\t\t// Any always yields a plain datamodel.Node\n\t\t\treturn nonPtrVal(val).Interface().(datamodel.Node), nil\n\t\t}\n\t\treturn newNode(w.cfg, typ.ValueType(), val), nil\n\t}\n\treturn nil, datamodel.ErrWrongKind{\n\t\tTypeName:        w.schemaType.Name(),\n\t\tMethodName:      \"LookupByIndex\",\n\t\tAppropriateKind: datamodel.KindSet_JustList,\n\t\tActualKind:      w.Kind(),\n\t}\n}\n\nfunc (w *_node) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\tswitch w.Kind() {\n\tcase datamodel.Kind_Map:\n\t\treturn w.LookupByString(seg.String())\n\tcase datamodel.Kind_List:\n\t\tidx, err := seg.Index()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn w.LookupByIndex(idx)\n\t}\n\treturn nil, datamodel.ErrWrongKind{\n\t\tTypeName:        w.schemaType.Name(),\n\t\tMethodName:      \"LookupBySegment\",\n\t\tAppropriateKind: datamodel.KindSet_Recursive,\n\t\tActualKind:      w.Kind(),\n\t}\n}\n\nfunc (w *_node) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\tswitch w.Kind() {\n\tcase datamodel.Kind_Map:\n\t\ts, err := key.AsString()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn w.LookupByString(s)\n\tcase datamodel.Kind_List:\n\t\ti, err := key.AsInt()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn w.LookupByIndex(i)\n\t}\n\treturn nil, datamodel.ErrWrongKind{\n\t\tTypeName:        w.schemaType.Name(),\n\t\tMethodName:      \"LookupByNode\",\n\t\tAppropriateKind: datamodel.KindSet_Recursive,\n\t\tActualKind:      w.Kind(),\n\t}\n}\n\nfunc (w *_node) MapIterator() datamodel.MapIterator {\n\tval := nonPtrVal(w.val)\n\t// structs, unions and maps can all iterate but they each have different\n\t// access semantics for the underlying type, so we need a different iterator\n\t// for each\n\tswitch typ := w.schemaType.(type) {\n\tcase *schema.TypeStruct:\n\t\treturn &_structIterator{\n\t\t\tcfg:        w.cfg,\n\t\t\tschemaType: typ,\n\t\t\tfields:     typ.Fields(),\n\t\t\tval:        val,\n\t\t}\n\tcase *schema.TypeUnion:\n\t\treturn &_unionIterator{\n\t\t\tcfg:        w.cfg,\n\t\t\tschemaType: typ,\n\t\t\tmembers:    typ.Members(),\n\t\t\tval:        val,\n\t\t}\n\tcase *schema.TypeMap:\n\t\t// we can assume a: struct{Keys []string, Values map[x]y}\n\t\treturn &_mapIterator{\n\t\t\tcfg:        w.cfg,\n\t\t\tschemaType: typ,\n\t\t\tkeysVal:    val.FieldByName(\"Keys\"),\n\t\t\tvaluesVal:  val.FieldByName(\"Values\"),\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_node) ListIterator() datamodel.ListIterator {\n\tval := nonPtrVal(w.val)\n\tswitch typ := w.schemaType.(type) {\n\tcase *schema.TypeList:\n\t\treturn &_listIterator{cfg: w.cfg, schemaType: typ, val: val}\n\t}\n\treturn nil\n}\n\nfunc (w *_node) Length() int64 {\n\tval := nonPtrVal(w.val)\n\tswitch w.Kind() {\n\tcase datamodel.Kind_Map:\n\t\tswitch typ := w.schemaType.(type) {\n\t\tcase *schema.TypeStruct:\n\t\t\treturn int64(len(typ.Fields()))\n\t\tcase *schema.TypeUnion:\n\t\t\treturn 1\n\t\t}\n\t\treturn int64(val.FieldByName(\"Keys\").Len())\n\tcase datamodel.Kind_List:\n\t\treturn int64(val.Len())\n\t}\n\treturn -1\n}\n\n// TODO: better story around pointers and absent/null\n\nfunc (w *_node) IsAbsent() bool {\n\treturn false\n}\n\nfunc (w *_node) IsNull() bool {\n\treturn false\n}\n\n// The AsX methods are matter of fetching the non-pointer form of the underlying\n// value and returning the appropriate Go type. The user may have registered\n// custom converters for the kind being converted, in which case the underlying\n// type may not be the type we need, but the converter will supply it for us.\n\nfunc (w *_node) AsBool() (bool, error) {\n\tif err := compatibleKind(w.schemaType, datamodel.Kind_Bool); err != nil {\n\t\treturn false, err\n\t}\n\tif customConverter := w.cfg.converterFor(w.schemaType.Name(), w.val); customConverter != nil {\n\t\t// user has registered a converter that takes the underlying type and returns a bool\n\t\treturn customConverter.customToBool(ptrVal(w.val).Interface())\n\t}\n\treturn nonPtrVal(w.val).Bool(), nil\n}\n\nfunc (w *_node) AsInt() (int64, error) {\n\tif err := compatibleKind(w.schemaType, datamodel.Kind_Int); err != nil {\n\t\treturn 0, err\n\t}\n\tif customConverter := w.cfg.converterFor(w.schemaType.Name(), w.val); customConverter != nil {\n\t\t// user has registered a converter that takes the underlying type and returns an int\n\t\treturn customConverter.customToInt(ptrVal(w.val).Interface())\n\t}\n\tval := nonPtrVal(w.val)\n\tif kindUint[val.Kind()] {\n\t\tu := val.Uint()\n\t\tif u > math.MaxInt64 {\n\t\t\treturn 0, fmt.Errorf(\"bindnode: integer overflow, %d is too large for an int64\", u)\n\t\t}\n\t\treturn int64(u), nil\n\t}\n\treturn val.Int(), nil\n}\n\nfunc (w *_node) AsFloat() (float64, error) {\n\tif err := compatibleKind(w.schemaType, datamodel.Kind_Float); err != nil {\n\t\treturn 0, err\n\t}\n\tif customConverter := w.cfg.converterFor(w.schemaType.Name(), w.val); customConverter != nil {\n\t\t// user has registered a converter that takes the underlying type and returns a float\n\t\treturn customConverter.customToFloat(ptrVal(w.val).Interface())\n\t}\n\treturn nonPtrVal(w.val).Float(), nil\n}\n\nfunc (w *_node) AsString() (string, error) {\n\tif err := compatibleKind(w.schemaType, datamodel.Kind_String); err != nil {\n\t\treturn \"\", err\n\t}\n\tif customConverter := w.cfg.converterFor(w.schemaType.Name(), w.val); customConverter != nil {\n\t\t// user has registered a converter that takes the underlying type and returns a string\n\t\treturn customConverter.customToString(ptrVal(w.val).Interface())\n\t}\n\treturn nonPtrVal(w.val).String(), nil\n}\n\nfunc (w *_node) AsBytes() ([]byte, error) {\n\tif err := compatibleKind(w.schemaType, datamodel.Kind_Bytes); err != nil {\n\t\treturn nil, err\n\t}\n\tif customConverter := w.cfg.converterFor(w.schemaType.Name(), w.val); customConverter != nil {\n\t\t// user has registered a converter that takes the underlying type and returns a []byte\n\t\treturn customConverter.customToBytes(ptrVal(w.val).Interface())\n\t}\n\treturn nonPtrVal(w.val).Bytes(), nil\n}\n\nfunc (w *_node) AsLink() (datamodel.Link, error) {\n\tif err := compatibleKind(w.schemaType, datamodel.Kind_Link); err != nil {\n\t\treturn nil, err\n\t}\n\tif customConverter := w.cfg.converterFor(w.schemaType.Name(), w.val); customConverter != nil {\n\t\t// user has registered a converter that takes the underlying type and returns a cid.Cid\n\t\tcid, err := customConverter.customToLink(ptrVal(w.val).Interface())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn cidlink.Link{Cid: cid}, nil\n\t}\n\tswitch val := nonPtrVal(w.val).Interface().(type) {\n\tcase datamodel.Link:\n\t\treturn val, nil\n\tcase cid.Cid:\n\t\treturn cidlink.Link{Cid: val}, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"bindnode: unexpected link type %T\", val)\n\t}\n}\n\nfunc (w *_node) Prototype() datamodel.NodePrototype {\n\treturn &_prototype{cfg: w.cfg, schemaType: w.schemaType, goType: w.val.Type()}\n}\n\ntype _builder struct {\n\t_assembler\n}\n\nfunc (w *_builder) Build() datamodel.Node {\n\t// TODO: should we panic if no Assign call was made, just like codegen?\n\treturn newNode(w.cfg, w.schemaType, w.val)\n}\n\nfunc (w *_builder) Reset() {\n\tpanic(\"bindnode TODO: Reset\")\n}\n\ntype _assembler struct {\n\tcfg        *config\n\tschemaType schema.Type\n\tval        reflect.Value // non-pointer\n\n\t// finish is used as an optional post-assemble step.\n\t// For example, assigning to a kinded union uses a finish func\n\t// to set the right union member in the Go union struct,\n\t// which isn't known before the assemble has finished.\n\tfinish func() error\n\n\tnullable bool // true if field or map value is nullable\n}\n\n// createNonPtrVal is used for Set() operations on the underlying value\nfunc (w *_assembler) createNonPtrVal() reflect.Value {\n\tval := w.val\n\t// TODO: if val is not a pointer, we reuse its value.\n\t// If it is a pointer, we allocate a new one and replace it.\n\t// We should probably never reuse the existing value.\n\n\t// TODO: support **T as well as *T?\n\tif val.Kind() == reflect.Ptr {\n\t\t// TODO: Sometimes we call createNonPtrVal before an assignment actually\n\t\t// happens. Does that matter?\n\t\t// If it matters and we only want to modify the destination value on\n\t\t// success, then we should make use of the \"finish\" func.\n\t\tval.Set(reflect.New(val.Type().Elem()))\n\t\tval = val.Elem()\n\t}\n\treturn val\n}\n\nfunc (w *_assembler) Representation() datamodel.NodeAssembler {\n\treturn (*_assemblerRepr)(w)\n}\n\n// basicMapAssembler is for assembling basicnode values, it's only use is for\n// Any fields that end up needing a BeginMap()\ntype basicMapAssembler struct {\n\tdatamodel.MapAssembler\n\n\tbuilder   datamodel.NodeBuilder\n\tparent    *_assembler\n\tconverter *converter\n}\n\nfunc (w *basicMapAssembler) Finish() error {\n\tif err := w.MapAssembler.Finish(); err != nil {\n\t\treturn err\n\t}\n\tbasicNode := w.builder.Build()\n\tif w.converter != nil {\n\t\t// we can assume an Any converter because basicMapAssembler is only for Any\n\t\t// the user has registered the ability to convert a datamodel.Node to the\n\t\t// underlying Go type which may not be a datamodel.Node\n\t\ttyp, err := w.converter.customFromAny(basicNode)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tw.parent.createNonPtrVal().Set(matchSettable(typ, reflect.ValueOf(basicNode)))\n\t} else {\n\t\tw.parent.createNonPtrVal().Set(reflect.ValueOf(basicNode))\n\t}\n\tif w.parent.finish != nil {\n\t\tif err := w.parent.finish(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\tswitch typ := w.schemaType.(type) {\n\tcase *schema.TypeAny:\n\t\tbasicBuilder := basicnode.Prototype.Any.NewBuilder()\n\t\tmapAsm, err := basicBuilder.BeginMap(sizeHint)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconverter := w.cfg.converterFor(w.schemaType.Name(), w.val)\n\t\treturn &basicMapAssembler{MapAssembler: mapAsm, builder: basicBuilder, parent: w, converter: converter}, nil\n\tcase *schema.TypeStruct:\n\t\tval := w.createNonPtrVal()\n\t\t// _structAssembler walks through the fields in order as the entries are\n\t\t// assembled, verifyCompatibility() should mean it's safe to assume that\n\t\t// they match the schema, but we need to keep track of the fields that are\n\t\t// set in case of premature Finish()\n\t\tdoneFields := make([]bool, val.NumField())\n\t\treturn &_structAssembler{\n\t\t\tcfg:        w.cfg,\n\t\t\tschemaType: typ,\n\t\t\tval:        val,\n\t\t\tdoneFields: doneFields,\n\t\t\tfinish:     w.finish,\n\t\t}, nil\n\tcase *schema.TypeMap:\n\t\t// assume a struct{Keys []string, Values map[x]y} that we can fill with\n\t\t// _mapAssembler\n\t\tval := w.createNonPtrVal()\n\t\tkeysVal := val.FieldByName(\"Keys\")\n\t\tvaluesVal := val.FieldByName(\"Values\")\n\t\tif valuesVal.IsNil() {\n\t\t\tvaluesVal.Set(reflect.MakeMap(valuesVal.Type()))\n\t\t}\n\t\treturn &_mapAssembler{\n\t\t\tcfg:        w.cfg,\n\t\t\tschemaType: typ,\n\t\t\tkeysVal:    keysVal,\n\t\t\tvaluesVal:  valuesVal,\n\t\t\tfinish:     w.finish,\n\t\t}, nil\n\tcase *schema.TypeUnion:\n\t\t// we can use _unionAssembler to assemble a union as if it were a map with\n\t\t// a single entry\n\t\tval := w.createNonPtrVal()\n\t\treturn &_unionAssembler{\n\t\t\tcfg:        w.cfg,\n\t\t\tschemaType: typ,\n\t\t\tval:        val,\n\t\t\tfinish:     w.finish,\n\t\t}, nil\n\t}\n\treturn nil, datamodel.ErrWrongKind{\n\t\tTypeName:        w.schemaType.Name(),\n\t\tMethodName:      \"BeginMap\",\n\t\tAppropriateKind: datamodel.KindSet_JustMap,\n\t\tActualKind:      actualKind(w.schemaType),\n\t}\n}\n\n// basicListAssembler is for assembling basicnode values, it's only use is for\n// Any fields that end up needing a BeginList()\ntype basicListAssembler struct {\n\tdatamodel.ListAssembler\n\n\tbuilder   datamodel.NodeBuilder\n\tparent    *_assembler\n\tconverter *converter\n}\n\nfunc (w *basicListAssembler) Finish() error {\n\tif err := w.ListAssembler.Finish(); err != nil {\n\t\treturn err\n\t}\n\tbasicNode := w.builder.Build()\n\tif w.converter != nil {\n\t\t// we can assume an Any converter because basicListAssembler is only for Any\n\t\t// the user has registered the ability to convert a datamodel.Node to the\n\t\t// underlying Go type which may not be a datamodel.Node\n\t\ttyp, err := w.converter.customFromAny(basicNode)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tw.parent.createNonPtrVal().Set(matchSettable(typ, reflect.ValueOf(basicNode)))\n\t} else {\n\t\tw.parent.createNonPtrVal().Set(reflect.ValueOf(basicNode))\n\t}\n\tif w.parent.finish != nil {\n\t\tif err := w.parent.finish(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\tswitch typ := w.schemaType.(type) {\n\tcase *schema.TypeAny:\n\t\tbasicBuilder := basicnode.Prototype.Any.NewBuilder()\n\t\tlistAsm, err := basicBuilder.BeginList(sizeHint)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconverter := w.cfg.converterFor(w.schemaType.Name(), w.val)\n\t\treturn &basicListAssembler{ListAssembler: listAsm, builder: basicBuilder, parent: w, converter: converter}, nil\n\tcase *schema.TypeList:\n\t\t// we should be able to safely assume we're dealing with a Go slice here,\n\t\t// so _listAssembler can append to that\n\t\tval := w.createNonPtrVal()\n\t\treturn &_listAssembler{\n\t\t\tcfg:        w.cfg,\n\t\t\tschemaType: typ,\n\t\t\tval:        val,\n\t\t\tfinish:     w.finish,\n\t\t}, nil\n\t}\n\treturn nil, datamodel.ErrWrongKind{\n\t\tTypeName:        w.schemaType.Name(),\n\t\tMethodName:      \"BeginList\",\n\t\tAppropriateKind: datamodel.KindSet_JustList,\n\t\tActualKind:      actualKind(w.schemaType),\n\t}\n}\n\nfunc (w *_assembler) AssignNull() error {\n\t_, isAny := w.schemaType.(*schema.TypeAny)\n\tif customConverter := w.cfg.converterFor(w.schemaType.Name(), w.val); customConverter != nil && isAny {\n\t\t// an Any field that is being assigned a Null, we pass the Null directly to\n\t\t// the converter, regardless of whether this field is nullable or not\n\t\ttyp, err := customConverter.customFromAny(datamodel.Null)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tw.createNonPtrVal().Set(matchSettable(typ, w.val))\n\t} else {\n\t\tif !w.nullable {\n\t\t\treturn datamodel.ErrWrongKind{\n\t\t\t\tTypeName:   w.schemaType.Name(),\n\t\t\t\tMethodName: \"AssignNull\",\n\t\t\t\t// TODO\n\t\t\t}\n\t\t}\n\t\t// set the zero value for the underlying type as a stand-in for Null\n\t\tw.val.Set(reflect.Zero(w.val.Type()))\n\t}\n\tif w.finish != nil {\n\t\tif err := w.finish(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_assembler) AssignBool(b bool) error {\n\tif err := compatibleKind(w.schemaType, datamodel.Kind_Bool); err != nil {\n\t\treturn err\n\t}\n\tcustomConverter := w.cfg.converterFor(w.schemaType.Name(), w.val)\n\t_, isAny := w.schemaType.(*schema.TypeAny)\n\tif customConverter != nil {\n\t\tvar typ interface{}\n\t\tvar err error\n\t\tif isAny {\n\t\t\t// field is an Any, so the converter will be an Any converter that wants\n\t\t\t// a datamodel.Node to convert to whatever the underlying Go type is\n\t\t\tif typ, err = customConverter.customFromAny(basicnode.NewBool(b)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\t// field is a Bool, but the user has registered a converter from a bool to\n\t\t\t// whatever the underlying Go type is\n\t\t\tif typ, err = customConverter.customFromBool(b); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tw.createNonPtrVal().Set(matchSettable(typ, w.val))\n\t} else {\n\t\tif isAny {\n\t\t\t// Any means the Go type must receive a datamodel.Node\n\t\t\tw.createNonPtrVal().Set(reflect.ValueOf(basicnode.NewBool(b)))\n\t\t} else {\n\t\t\tw.createNonPtrVal().SetBool(b)\n\t\t}\n\t}\n\tif w.finish != nil {\n\t\tif err := w.finish(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_assembler) assignUInt(uin datamodel.UintNode) error {\n\tif err := compatibleKind(w.schemaType, datamodel.Kind_Int); err != nil {\n\t\treturn err\n\t}\n\t_, isAny := w.schemaType.(*schema.TypeAny)\n\t// TODO: customConverter for uint??\n\tif isAny {\n\t\t// Any means the Go type must receive a datamodel.Node\n\t\tw.createNonPtrVal().Set(reflect.ValueOf(uin))\n\t} else {\n\t\ti, err := uin.AsUint()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif kindUint[w.val.Kind()] {\n\t\t\tw.createNonPtrVal().SetUint(i)\n\t\t} else {\n\t\t\t// TODO: check for overflow\n\t\t\tw.createNonPtrVal().SetInt(int64(i))\n\t\t}\n\t}\n\tif w.finish != nil {\n\t\tif err := w.finish(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_assembler) AssignInt(i int64) error {\n\tif err := compatibleKind(w.schemaType, datamodel.Kind_Int); err != nil {\n\t\treturn err\n\t}\n\t// TODO: check for overflow\n\tcustomConverter := w.cfg.converterFor(w.schemaType.Name(), w.val)\n\t_, isAny := w.schemaType.(*schema.TypeAny)\n\tif customConverter != nil {\n\t\tvar typ interface{}\n\t\tvar err error\n\t\tif isAny {\n\t\t\t// field is an Any, so the converter will be an Any converter that wants\n\t\t\t// a datamodel.Node to convert to whatever the underlying Go type is\n\t\t\tif typ, err = customConverter.customFromAny(basicnode.NewInt(i)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\t// field is an Int, but the user has registered a converter from an int to\n\t\t\t// whatever the underlying Go type is\n\t\t\tif typ, err = customConverter.customFromInt(i); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tw.createNonPtrVal().Set(matchSettable(typ, w.val))\n\t} else {\n\t\tif isAny {\n\t\t\t// Any means the Go type must receive a datamodel.Node\n\t\t\tw.createNonPtrVal().Set(reflect.ValueOf(basicnode.NewInt(i)))\n\t\t} else if kindUint[w.val.Kind()] {\n\t\t\tif i < 0 {\n\t\t\t\t// TODO: write a test\n\t\t\t\treturn fmt.Errorf(\"bindnode: cannot assign negative integer to %s\", w.val.Type())\n\t\t\t}\n\t\t\tw.createNonPtrVal().SetUint(uint64(i))\n\t\t} else {\n\t\t\tw.createNonPtrVal().SetInt(i)\n\t\t}\n\t}\n\tif w.finish != nil {\n\t\tif err := w.finish(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_assembler) AssignFloat(f float64) error {\n\tif err := compatibleKind(w.schemaType, datamodel.Kind_Float); err != nil {\n\t\treturn err\n\t}\n\tcustomConverter := w.cfg.converterFor(w.schemaType.Name(), w.val)\n\t_, isAny := w.schemaType.(*schema.TypeAny)\n\tif customConverter != nil {\n\t\tvar typ interface{}\n\t\tvar err error\n\t\tif isAny {\n\t\t\t// field is an Any, so the converter will be an Any converter that wants\n\t\t\t// a datamodel.Node to convert to whatever the underlying Go type is\n\t\t\tif typ, err = customConverter.customFromAny(basicnode.NewFloat(f)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\t// field is a Float, but the user has registered a converter from a float\n\t\t\t// to whatever the underlying Go type is\n\t\t\tif typ, err = customConverter.customFromFloat(f); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tw.createNonPtrVal().Set(matchSettable(typ, w.val))\n\t} else {\n\t\tif isAny {\n\t\t\t// Any means the Go type must receive a datamodel.Node\n\t\t\tw.createNonPtrVal().Set(reflect.ValueOf(basicnode.NewFloat(f)))\n\t\t} else {\n\t\t\tw.createNonPtrVal().SetFloat(f)\n\t\t}\n\t}\n\tif w.finish != nil {\n\t\tif err := w.finish(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_assembler) AssignString(s string) error {\n\tif err := compatibleKind(w.schemaType, datamodel.Kind_String); err != nil {\n\t\treturn err\n\t}\n\tcustomConverter := w.cfg.converterFor(w.schemaType.Name(), w.val)\n\t_, isAny := w.schemaType.(*schema.TypeAny)\n\tif customConverter != nil {\n\t\tvar typ interface{}\n\t\tvar err error\n\t\tif isAny {\n\t\t\t// field is an Any, so the converter will be an Any converter that wants\n\t\t\t// a datamodel.Node to convert to whatever the underlying Go type is\n\t\t\tif typ, err = customConverter.customFromAny(basicnode.NewString(s)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\t// field is a String, but the user has registered a converter from a\n\t\t\t// string to whatever the underlying Go type is\n\t\t\tif typ, err = customConverter.customFromString(s); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tw.createNonPtrVal().Set(matchSettable(typ, w.val))\n\t} else {\n\t\tif isAny {\n\t\t\t// Any means the Go type must receive a datamodel.Node\n\t\t\tw.createNonPtrVal().Set(reflect.ValueOf(basicnode.NewString(s)))\n\t\t} else {\n\t\t\tw.createNonPtrVal().SetString(s)\n\t\t}\n\t}\n\tif w.finish != nil {\n\t\tif err := w.finish(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_assembler) AssignBytes(p []byte) error {\n\tif err := compatibleKind(w.schemaType, datamodel.Kind_Bytes); err != nil {\n\t\treturn err\n\t}\n\tcustomConverter := w.cfg.converterFor(w.schemaType.Name(), w.val)\n\t_, isAny := w.schemaType.(*schema.TypeAny)\n\tif customConverter != nil {\n\t\tvar typ interface{}\n\t\tvar err error\n\t\tif isAny {\n\t\t\t// field is an Any, so the converter will be an Any converter that wants\n\t\t\t// a datamodel.Node to convert to whatever the underlying Go type is\n\t\t\tif typ, err = customConverter.customFromAny(basicnode.NewBytes(p)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\t// field is a Bytes, but the user has registered a converter from a []byte\n\t\t\t// to whatever the underlying Go type is\n\t\t\tif typ, err = customConverter.customFromBytes(p); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tw.createNonPtrVal().Set(matchSettable(typ, w.val))\n\t} else {\n\t\tif isAny {\n\t\t\t// Any means the Go type must receive a datamodel.Node\n\t\t\tw.createNonPtrVal().Set(reflect.ValueOf(basicnode.NewBytes(p)))\n\t\t} else {\n\t\t\tw.createNonPtrVal().SetBytes(p)\n\t\t}\n\t}\n\tif w.finish != nil {\n\t\tif err := w.finish(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_assembler) AssignLink(link datamodel.Link) error {\n\tval := w.createNonPtrVal()\n\t// TODO: newVal.Type() panics if link==nil; add a test and fix.\n\tcustomConverter := w.cfg.converterFor(w.schemaType.Name(), w.val)\n\tif _, ok := w.schemaType.(*schema.TypeAny); ok {\n\t\tif customConverter != nil {\n\t\t\t// field is an Any, so the converter will be an Any converter that wants\n\t\t\t// a datamodel.Node to convert to whatever the underlying Go type is\n\t\t\ttyp, err := customConverter.customFromAny(basicnode.NewLink(link))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tw.createNonPtrVal().Set(matchSettable(typ, w.val))\n\t\t} else {\n\t\t\t// Any means the Go type must receive a datamodel.Node\n\t\t\tval.Set(reflect.ValueOf(basicnode.NewLink(link)))\n\t\t}\n\t} else if customConverter != nil {\n\t\tif cl, ok := link.(cidlink.Link); ok {\n\t\t\t// field is a Link, but the user has registered a converter from a cid.Cid\n\t\t\t// to whatever the underlying Go type is\n\t\t\ttyp, err := customConverter.customFromLink(cl.Cid)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tw.createNonPtrVal().Set(matchSettable(typ, w.val))\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"bindnode: custom converter can only receive a cidlink.Link through AssignLink\")\n\t\t}\n\t} else if newVal := reflect.ValueOf(link); newVal.Type().AssignableTo(val.Type()) {\n\t\t// Directly assignable.\n\t\tval.Set(newVal)\n\t} else if newVal.Type() == goTypeCidLink && goTypeCid.AssignableTo(val.Type()) {\n\t\t// Unbox a cidlink.Link to assign to a go-cid.Cid value.\n\t\tnewVal = newVal.FieldByName(\"Cid\")\n\t\tval.Set(newVal)\n\t} else if actual := actualKind(w.schemaType); actual != datamodel.Kind_Link {\n\t\t// We're assigning a Link to a schema type that isn't a Link.\n\t\treturn datamodel.ErrWrongKind{\n\t\t\tTypeName:        w.schemaType.Name(),\n\t\t\tMethodName:      \"AssignLink\",\n\t\t\tAppropriateKind: datamodel.KindSet_JustLink,\n\t\t\tActualKind:      actualKind(w.schemaType),\n\t\t}\n\t} else {\n\t\t// The schema type is a Link, but we somehow can't assign to the Go value.\n\t\t// Almost certainly a bug; we should have verified for compatibility upfront.\n\t\treturn fmt.Errorf(\"bindnode bug: AssignLink with %s argument can't be used on Go type %s\",\n\t\t\tnewVal.Type(), val.Type())\n\t}\n\tif w.finish != nil {\n\t\tif err := w.finish(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_assembler) AssignNode(node datamodel.Node) error {\n\t// TODO: does this ever trigger?\n\t// newVal := reflect.ValueOf(node)\n\t// if newVal.Type().AssignableTo(w.val.Type()) {\n\t// \tw.val.Set(newVal)\n\t// \treturn nil\n\t// }\n\tif uintNode, ok := node.(datamodel.UintNode); ok {\n\t\treturn w.assignUInt(uintNode)\n\t}\n\treturn datamodel.Copy(node, w)\n}\n\nfunc (w *_assembler) Prototype() datamodel.NodePrototype {\n\treturn &_prototype{cfg: w.cfg, schemaType: w.schemaType, goType: w.val.Type()}\n}\n\n// _structAssembler is used for Struct assembling via BeginMap()\ntype _structAssembler struct {\n\t// TODO: embed _assembler?\n\n\tcfg *config\n\n\tschemaType *schema.TypeStruct\n\tval        reflect.Value // non-pointer\n\tfinish     func() error\n\n\t// TODO: more state checks\n\n\t// TODO: Consider if we could do this in a cheaper way,\n\t// such as looking at the reflect.Value directly.\n\t// If not, at least avoid an extra alloc.\n\tdoneFields []bool\n\n\t// TODO: optimize for structs\n\n\tcurKey _assembler\n\n\tnextIndex int // only used by repr.go\n}\n\nfunc (w *_structAssembler) AssembleKey() datamodel.NodeAssembler {\n\tw.curKey = _assembler{\n\t\tcfg:        w.cfg,\n\t\tschemaType: schemaTypeString,\n\t\tval:        reflect.New(goTypeString).Elem(),\n\t}\n\treturn &w.curKey\n}\n\nfunc (w *_structAssembler) AssembleValue() datamodel.NodeAssembler {\n\t// TODO: optimize this to do one lookup by name\n\tname := w.curKey.val.String()\n\tfield := w.schemaType.Field(name)\n\tif field == nil {\n\t\t// TODO: should've been raised when the key was submitted instead.\n\t\t// TODO: should make well-typed errors for this.\n\t\treturn _errorAssembler{fmt.Errorf(\"bindnode TODO: invalid key: %q is not a field in type %s\", name, w.schemaType.Name())}\n\t\t// panic(schema.ErrInvalidKey{\n\t\t// \tTypeName: w.schemaType.Name(),\n\t\t// \tKey:      basicnode.NewString(name),\n\t\t// })\n\t}\n\tftyp, ok := w.val.Type().FieldByName(fieldNameFromSchema(name))\n\tif !ok {\n\t\t// It is unfortunate this is not detected proactively earlier during bind.\n\t\treturn _errorAssembler{fmt.Errorf(\"schema type %q has field %q, we expect go struct to have field %q\", w.schemaType.Name(), field.Name(), fieldNameFromSchema(name))}\n\t}\n\tif len(ftyp.Index) > 1 {\n\t\treturn _errorAssembler{fmt.Errorf(\"bindnode TODO: embedded fields\")}\n\t}\n\tw.doneFields[ftyp.Index[0]] = true\n\tfval := w.val.FieldByIndex(ftyp.Index)\n\tif field.IsOptional() {\n\t\tif fval.Kind() == reflect.Ptr {\n\t\t\t// ptrVal = new(T); val = *ptrVal\n\t\t\tfval.Set(reflect.New(fval.Type().Elem()))\n\t\t\tfval = fval.Elem()\n\t\t} else {\n\t\t\t// val = *new(T)\n\t\t\tfval.Set(reflect.New(fval.Type()).Elem())\n\t\t}\n\t}\n\t// TODO: reuse same assembler for perf?\n\treturn &_assembler{\n\t\tcfg:        w.cfg,\n\t\tschemaType: field.Type(),\n\t\tval:        fval,\n\t\tnullable:   field.IsNullable(),\n\t}\n}\n\nfunc (w *_structAssembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\tif err := w.AssembleKey().AssignString(k); err != nil {\n\t\treturn nil, err\n\t}\n\tam := w.AssembleValue()\n\treturn am, nil\n}\n\nfunc (w *_structAssembler) Finish() error {\n\tfields := w.schemaType.Fields()\n\tvar missing []string\n\tfor i, field := range fields {\n\t\tif !field.IsOptional() && !w.doneFields[i] {\n\t\t\tmissing = append(missing, field.Name())\n\t\t}\n\t}\n\tif len(missing) > 0 {\n\t\treturn schema.ErrMissingRequiredField{Missing: missing}\n\t}\n\tif w.finish != nil {\n\t\tif err := w.finish(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_structAssembler) KeyPrototype() datamodel.NodePrototype {\n\t// TODO: if the user provided their own schema with their own typesystem,\n\t// the schemaTypeString here may be using the wrong typesystem.\n\treturn &_prototype{cfg: w.cfg, schemaType: schemaTypeString, goType: goTypeString}\n}\n\nfunc (w *_structAssembler) ValuePrototype(k string) datamodel.NodePrototype {\n\tpanic(\"bindnode TODO: struct ValuePrototype\")\n}\n\ntype _errorAssembler struct {\n\terr error\n}\n\nfunc (w _errorAssembler) BeginMap(int64) (datamodel.MapAssembler, error)   { return nil, w.err }\nfunc (w _errorAssembler) BeginList(int64) (datamodel.ListAssembler, error) { return nil, w.err }\nfunc (w _errorAssembler) AssignNull() error                                { return w.err }\nfunc (w _errorAssembler) AssignBool(bool) error                            { return w.err }\nfunc (w _errorAssembler) AssignInt(int64) error                            { return w.err }\nfunc (w _errorAssembler) AssignFloat(float64) error                        { return w.err }\nfunc (w _errorAssembler) AssignString(string) error                        { return w.err }\nfunc (w _errorAssembler) AssignBytes([]byte) error                         { return w.err }\nfunc (w _errorAssembler) AssignLink(datamodel.Link) error                  { return w.err }\nfunc (w _errorAssembler) AssignNode(datamodel.Node) error                  { return w.err }\nfunc (w _errorAssembler) Prototype() datamodel.NodePrototype               { return nil }\n\n// used for Maps which we can assume are of type: struct{Keys []string, Values map[x]y},\n// where we have Keys in keysVal and Values in valuesVal\ntype _mapAssembler struct {\n\tcfg        *config\n\tschemaType *schema.TypeMap\n\tkeysVal    reflect.Value // non-pointer\n\tvaluesVal  reflect.Value // non-pointer\n\tfinish     func() error\n\n\t// TODO: more state checks\n\n\tcurKey _assembler\n}\n\nfunc (w *_mapAssembler) AssembleKey() datamodel.NodeAssembler {\n\tw.curKey = _assembler{\n\t\tcfg:        w.cfg,\n\t\tschemaType: w.schemaType.KeyType(),\n\t\tval:        reflect.New(w.valuesVal.Type().Key()).Elem(),\n\t}\n\treturn &w.curKey\n}\n\nfunc (w *_mapAssembler) AssembleValue() datamodel.NodeAssembler {\n\tkval := w.curKey.val\n\tval := reflect.New(w.valuesVal.Type().Elem()).Elem()\n\tfinish := func() error {\n\t\t// TODO: check for duplicates in keysVal\n\t\tw.keysVal.Set(reflect.Append(w.keysVal, kval))\n\n\t\tw.valuesVal.SetMapIndex(kval, val)\n\t\treturn nil\n\t}\n\treturn &_assembler{\n\t\tcfg:        w.cfg,\n\t\tschemaType: w.schemaType.ValueType(),\n\t\tval:        val,\n\t\tnullable:   w.schemaType.ValueIsNullable(),\n\t\tfinish:     finish,\n\t}\n}\n\nfunc (w *_mapAssembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\tif err := w.AssembleKey().AssignString(k); err != nil {\n\t\treturn nil, err\n\t}\n\tam := w.AssembleValue()\n\treturn am, nil\n}\n\nfunc (w *_mapAssembler) Finish() error {\n\tif w.finish != nil {\n\t\tif err := w.finish(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_mapAssembler) KeyPrototype() datamodel.NodePrototype {\n\treturn &_prototype{cfg: w.cfg, schemaType: w.schemaType.KeyType(), goType: w.valuesVal.Type().Key()}\n}\n\nfunc (w *_mapAssembler) ValuePrototype(k string) datamodel.NodePrototype {\n\treturn &_prototype{cfg: w.cfg, schemaType: w.schemaType.ValueType(), goType: w.valuesVal.Type().Elem()}\n}\n\n// _listAssembler is for operating directly on slices, which we have in val\ntype _listAssembler struct {\n\tcfg        *config\n\tschemaType *schema.TypeList\n\tval        reflect.Value // non-pointer\n\tfinish     func() error\n}\n\nfunc (w *_listAssembler) AssembleValue() datamodel.NodeAssembler {\n\tgoType := w.val.Type().Elem()\n\t// TODO: use a finish func to append\n\tw.val.Set(reflect.Append(w.val, reflect.New(goType).Elem()))\n\treturn &_assembler{\n\t\tcfg:        w.cfg,\n\t\tschemaType: w.schemaType.ValueType(),\n\t\tval:        w.val.Index(w.val.Len() - 1),\n\t\tnullable:   w.schemaType.ValueIsNullable(),\n\t}\n}\n\nfunc (w *_listAssembler) Finish() error {\n\tif w.finish != nil {\n\t\tif err := w.finish(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_listAssembler) ValuePrototype(idx int64) datamodel.NodePrototype {\n\treturn &_prototype{cfg: w.cfg, schemaType: w.schemaType.ValueType(), goType: w.val.Type().Elem()}\n}\n\n// when assembling as a Map but we anticipate a single value, which we need to\n// look up in the union members\ntype _unionAssembler struct {\n\tcfg        *config\n\tschemaType *schema.TypeUnion\n\tval        reflect.Value // non-pointer\n\tfinish     func() error\n\n\t// TODO: more state checks\n\n\tcurKey _assembler\n}\n\nfunc (w *_unionAssembler) AssembleKey() datamodel.NodeAssembler {\n\tw.curKey = _assembler{\n\t\tcfg:        w.cfg,\n\t\tschemaType: schemaTypeString,\n\t\tval:        reflect.New(goTypeString).Elem(),\n\t}\n\treturn &w.curKey\n}\n\nfunc (w *_unionAssembler) AssembleValue() datamodel.NodeAssembler {\n\tname := w.curKey.val.String()\n\tvar idx int\n\tvar mtyp schema.Type\n\tfor i, member := range w.schemaType.Members() {\n\t\tif member.Name() == name {\n\t\t\tidx = i\n\t\t\tmtyp = member\n\t\t\tbreak\n\t\t}\n\t}\n\tif mtyp == nil {\n\t\treturn _errorAssembler{\n\t\t\tschema.ErrNotUnionStructure{\n\t\t\t\tTypeName: w.schemaType.Name(),\n\t\t\t\tDetail:   fmt.Sprintf(\"no member named %q\", name),\n\t\t\t},\n\t\t}\n\t}\n\n\tgoType := w.val.Field(idx).Type().Elem()\n\tvalPtr := reflect.New(goType)\n\tfinish := func() error {\n\t\tunionSetMember(w.val, idx, valPtr)\n\t\treturn nil\n\t}\n\treturn &_assembler{\n\t\tcfg:        w.cfg,\n\t\tschemaType: mtyp,\n\t\tval:        valPtr.Elem(),\n\t\tfinish:     finish,\n\t}\n}\n\nfunc (w *_unionAssembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\tif err := w.AssembleKey().AssignString(k); err != nil {\n\t\treturn nil, err\n\t}\n\tam := w.AssembleValue()\n\treturn am, nil\n}\n\nfunc (w *_unionAssembler) Finish() error {\n\t// TODO(rvagg): I think this might allow setting multiple members of the union\n\t// we need a test for this.\n\thaveIdx, _ := unionMember(w.val)\n\tif haveIdx < 0 {\n\t\treturn schema.ErrNotUnionStructure{TypeName: w.schemaType.Name(), Detail: \"a union must have exactly one entry\"}\n\t}\n\tif w.finish != nil {\n\t\tif err := w.finish(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *_unionAssembler) KeyPrototype() datamodel.NodePrototype {\n\treturn &_prototype{cfg: w.cfg, schemaType: schemaTypeString, goType: goTypeString}\n}\n\nfunc (w *_unionAssembler) ValuePrototype(k string) datamodel.NodePrototype {\n\tpanic(\"bindnode TODO: union ValuePrototype\")\n}\n\n// _structIterator is for iterating over Struct types which operate over Go\n// structs. The iteration order is dictated by Go field declaration order which\n// should match the schema for this type.\ntype _structIterator struct {\n\t// TODO: support embedded fields?\n\tcfg *config\n\n\tschemaType *schema.TypeStruct\n\tfields     []schema.StructField\n\tval        reflect.Value // non-pointer\n\tnextIndex  int\n\n\t// these are only used in repr.go\n\treprEnd int\n}\n\nfunc (w *_structIterator) Next() (key, value datamodel.Node, _ error) {\n\tif w.Done() {\n\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t}\n\tfield := w.fields[w.nextIndex]\n\tval := w.val.Field(w.nextIndex)\n\tw.nextIndex++\n\tkey = basicnode.NewString(field.Name())\n\tif field.IsOptional() {\n\t\tif val.IsNil() {\n\t\t\treturn key, datamodel.Absent, nil\n\t\t}\n\t\tif val.Kind() == reflect.Ptr {\n\t\t\tval = val.Elem()\n\t\t}\n\t}\n\t_, isAny := field.Type().(*schema.TypeAny)\n\tif isAny {\n\t\tif customConverter := w.cfg.converterFor(field.Type().Name(), val); customConverter != nil {\n\t\t\t// field is an Any and we have an Any converter which takes the underlying\n\t\t\t// struct field value and returns a datamodel.Node\n\t\t\tv, err := customConverter.customToAny(ptrVal(val).Interface())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\t\t\treturn key, v, nil\n\t\t}\n\t}\n\tif field.IsNullable() {\n\t\tif val.IsNil() {\n\t\t\treturn key, datamodel.Null, nil\n\t\t}\n\t\tif val.Kind() == reflect.Ptr {\n\t\t\tval = val.Elem()\n\t\t}\n\t}\n\tif isAny {\n\t\t// field holds a datamodel.Node\n\t\treturn key, nonPtrVal(val).Interface().(datamodel.Node), nil\n\t}\n\treturn key, newNode(w.cfg, field.Type(), val), nil\n}\n\nfunc (w *_structIterator) Done() bool {\n\treturn w.nextIndex >= len(w.fields)\n}\n\n// _mapIterator is for iterating over a struct{Keys []string, Values map[x]y},\n// where we have the Keys in keysVal and Values in valuesVal\ntype _mapIterator struct {\n\tcfg        *config\n\tschemaType *schema.TypeMap\n\tkeysVal    reflect.Value // non-pointer\n\tvaluesVal  reflect.Value // non-pointer\n\tnextIndex  int\n}\n\nfunc (w *_mapIterator) Next() (key, value datamodel.Node, _ error) {\n\tif w.Done() {\n\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t}\n\tgoKey := w.keysVal.Index(w.nextIndex)\n\tval := w.valuesVal.MapIndex(goKey)\n\tw.nextIndex++\n\n\tkey = newNode(w.cfg, w.schemaType.KeyType(), goKey)\n\t_, isAny := w.schemaType.ValueType().(*schema.TypeAny)\n\tif isAny {\n\t\tif customConverter := w.cfg.converterFor(w.schemaType.ValueType().Name(), val); customConverter != nil {\n\t\t\t// values of this map are Any and we have an Any converter which takes the\n\t\t\t// underlying map value and returns a datamodel.Node\n\n\t\t\t// TODO(rvagg): can't call ptrVal on a map value that's not a pointer\n\t\t\t// so only map[string]*foo will work for the Values map and an Any\n\t\t\t// converter. Should we check in infer.go?\n\t\t\tval, err := customConverter.customToAny(ptrVal(val).Interface())\n\t\t\treturn key, val, err\n\t\t}\n\t}\n\tif w.schemaType.ValueIsNullable() {\n\t\tif val.IsNil() {\n\t\t\treturn key, datamodel.Null, nil\n\t\t}\n\t\tval = val.Elem() // nullable entries are pointers\n\t}\n\tif isAny {\n\t\t// Values holds datamodel.Nodes\n\t\treturn key, nonPtrVal(val).Interface().(datamodel.Node), nil\n\t}\n\treturn key, newNode(w.cfg, w.schemaType.ValueType(), val), nil\n}\n\nfunc (w *_mapIterator) Done() bool {\n\treturn w.nextIndex >= w.keysVal.Len()\n}\n\n// _listIterator is for iterating over slices, which is held in val\ntype _listIterator struct {\n\tcfg        *config\n\tschemaType *schema.TypeList\n\tval        reflect.Value // non-pointer\n\tnextIndex  int\n}\n\nfunc (w *_listIterator) Next() (index int64, value datamodel.Node, _ error) {\n\tif w.Done() {\n\t\treturn 0, nil, datamodel.ErrIteratorOverread{}\n\t}\n\tidx := int64(w.nextIndex)\n\tval := w.val.Index(w.nextIndex)\n\tw.nextIndex++\n\tif w.schemaType.ValueIsNullable() {\n\t\tif val.IsNil() {\n\t\t\treturn idx, datamodel.Null, nil\n\t\t}\n\t\tval = val.Elem() // nullable values are pointers\n\t}\n\tif _, ok := w.schemaType.ValueType().(*schema.TypeAny); ok {\n\t\tif customConverter := w.cfg.converterFor(w.schemaType.ValueType().Name(), val); customConverter != nil {\n\t\t\t// values are Any and we have an Any converter which can take whatever\n\t\t\t// the underlying Go type in this slice is and return a datamodel.Node\n\t\t\tval, err := customConverter.customToAny(ptrVal(val).Interface())\n\t\t\treturn idx, val, err\n\t\t}\n\t\t// values are Any, assume that they are datamodel.Nodes\n\t\treturn idx, nonPtrVal(val).Interface().(datamodel.Node), nil\n\t}\n\treturn idx, newNode(w.cfg, w.schemaType.ValueType(), val), nil\n}\n\nfunc (w *_listIterator) Done() bool {\n\treturn w.nextIndex >= w.val.Len()\n}\n\ntype _unionIterator struct {\n\t// TODO: support embedded fields?\n\tcfg        *config\n\tschemaType *schema.TypeUnion\n\tmembers    []schema.Type\n\tval        reflect.Value // non-pointer\n\n\tdone bool\n}\n\nfunc (w *_unionIterator) Next() (key, value datamodel.Node, _ error) {\n\t// we can only call this once for a union since a union can only have one\n\t// entry even though it behaves like a Map\n\tif w.Done() {\n\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t}\n\tw.done = true\n\n\thaveIdx, mval := unionMember(w.val)\n\tif haveIdx < 0 {\n\t\treturn nil, nil, fmt.Errorf(\"bindnode: union %s has no member\", w.val.Type())\n\t}\n\tmtyp := w.members[haveIdx]\n\n\tnode := newNode(w.cfg, mtyp, mval)\n\tkey = basicnode.NewString(mtyp.Name())\n\treturn key, node, nil\n}\n\nfunc (w *_unionIterator) Done() bool {\n\treturn w.done\n}\n\n// --- uint64 special case handling\n\ntype _uintNode struct {\n\tcfg        *config\n\tschemaType schema.Type\n\n\tval reflect.Value // non-pointer\n}\n\nfunc (tu *_uintNode) Type() schema.Type {\n\treturn tu.schemaType\n}\nfunc (tu *_uintNode) Representation() datamodel.Node {\n\treturn (*_uintNodeRepr)(tu)\n}\nfunc (_uintNode) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Int\n}\nfunc (_uintNode) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupByString(\"\")\n}\nfunc (_uintNode) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupByNode(nil)\n}\nfunc (_uintNode) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupByIndex(0)\n}\nfunc (_uintNode) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupBySegment(seg)\n}\nfunc (_uintNode) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (_uintNode) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (_uintNode) Length() int64 {\n\treturn -1\n}\nfunc (_uintNode) IsAbsent() bool {\n\treturn false\n}\nfunc (_uintNode) IsNull() bool {\n\treturn false\n}\nfunc (_uintNode) AsBool() (bool, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsBool()\n}\nfunc (tu *_uintNode) AsInt() (int64, error) {\n\treturn (*_uintNodeRepr)(tu).AsInt()\n}\nfunc (tu *_uintNode) AsUint() (uint64, error) {\n\treturn (*_uintNodeRepr)(tu).AsUint()\n}\nfunc (_uintNode) AsFloat() (float64, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsFloat()\n}\nfunc (_uintNode) AsString() (string, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsString()\n}\nfunc (_uintNode) AsBytes() ([]byte, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsBytes()\n}\nfunc (_uintNode) AsLink() (datamodel.Link, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsLink()\n}\nfunc (_uintNode) Prototype() datamodel.NodePrototype {\n\treturn basicnode.Prototype__Int{}\n}\n\n// we need this for _uintNode#Representation() so we don't return a TypeNode\ntype _uintNodeRepr _uintNode\n\nfunc (_uintNodeRepr) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Int\n}\nfunc (_uintNodeRepr) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupByString(\"\")\n}\nfunc (_uintNodeRepr) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupByNode(nil)\n}\nfunc (_uintNodeRepr) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupByIndex(0)\n}\nfunc (_uintNodeRepr) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"int\"}.LookupBySegment(seg)\n}\nfunc (_uintNodeRepr) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (_uintNodeRepr) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (_uintNodeRepr) Length() int64 {\n\treturn -1\n}\nfunc (_uintNodeRepr) IsAbsent() bool {\n\treturn false\n}\nfunc (_uintNodeRepr) IsNull() bool {\n\treturn false\n}\nfunc (_uintNodeRepr) AsBool() (bool, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsBool()\n}\nfunc (tu *_uintNodeRepr) AsInt() (int64, error) {\n\tif err := compatibleKind(tu.schemaType, datamodel.Kind_Int); err != nil {\n\t\treturn 0, err\n\t}\n\tif customConverter := tu.cfg.converterFor(tu.schemaType.Name(), tu.val); customConverter != nil {\n\t\t// user has registered a converter that takes the underlying type and returns an int\n\t\treturn customConverter.customToInt(ptrVal(tu.val).Interface())\n\t}\n\tval := nonPtrVal(tu.val)\n\t// we can assume it's a uint64 at this point\n\tu := val.Uint()\n\tif u > math.MaxInt64 {\n\t\treturn 0, fmt.Errorf(\"bindnode: integer overflow, %d is too large for an int64\", u)\n\t}\n\treturn int64(u), nil\n}\nfunc (tu *_uintNodeRepr) AsUint() (uint64, error) {\n\tif err := compatibleKind(tu.schemaType, datamodel.Kind_Int); err != nil {\n\t\treturn 0, err\n\t}\n\t// TODO(rvagg): do we want a converter option for uint values? do we combine it\n\t// with int converters?\n\t// we can assume it's a uint64 at this point\n\treturn nonPtrVal(tu.val).Uint(), nil\n}\nfunc (_uintNodeRepr) AsFloat() (float64, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsFloat()\n}\nfunc (_uintNodeRepr) AsString() (string, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsString()\n}\nfunc (_uintNodeRepr) AsBytes() ([]byte, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsBytes()\n}\nfunc (_uintNodeRepr) AsLink() (datamodel.Link, error) {\n\treturn mixins.Int{TypeName: \"int\"}.AsLink()\n}\nfunc (_uintNodeRepr) Prototype() datamodel.NodePrototype {\n\treturn basicnode.Prototype__Int{}\n}\n"
  },
  {
    "path": "node/bindnode/registry/registry.go",
    "content": "package registry\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"reflect\"\n\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/codec\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\ntype prototypeData struct {\n\tproto   schema.TypedPrototype\n\toptions []bindnode.Option\n}\n\n// BindnodeRegistry holds TypedPrototype and bindnode options for Go types and\n// will use that data for conversion operations.\ntype BindnodeRegistry map[reflect.Type]prototypeData\n\n// NewRegistry creates a new BindnodeRegistry\nfunc NewRegistry() BindnodeRegistry {\n\treturn make(BindnodeRegistry)\n}\n\nfunc typeOf(ptrValue interface{}) reflect.Type {\n\tval := reflect.ValueOf(ptrValue).Type()\n\tfor val.Kind() == reflect.Ptr {\n\t\tval = val.Elem()\n\t}\n\treturn val\n}\n\nfunc (br BindnodeRegistry) prototypeDataFor(ptrType interface{}) prototypeData {\n\ttyp := typeOf(ptrType)\n\tproto, ok := br[typ]\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"bindnode utils: type has not been registered: %s\", typ.Name()))\n\t}\n\treturn proto\n}\n\n// RegisterType registers ptrType with schema such that it can be wrapped and\n// unwrapped without needing the schema, Type, or TypedPrototype.\n// Typically the typeName will match the Go type name, but it can be whatever\n// is defined in the schema for the type being registered.\n// Registering the same type twice on this registry will cause an error.\n// This call may also error if the schema is invalid or the type doesn't match\n// the schema. Additionally, panics from within bindnode's initial prototype\n// checks will be captured and returned as errors from this function.\nfunc (br BindnodeRegistry) RegisterType(ptrType interface{}, schema string, typeName string, options ...bindnode.Option) (err error) {\n\ttyp := typeOf(ptrType)\n\tif _, ok := br[typ]; ok {\n\t\treturn fmt.Errorf(\"bindnode utils: type already registered: %s\", typ.Name())\n\t}\n\ttypeSystem, err := ipld.LoadSchemaBytes([]byte(schema))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bindnode utils: failed to load schema: %s\", err.Error())\n\t}\n\tschemaType := typeSystem.TypeByName(typeName)\n\tif schemaType == nil {\n\t\treturn fmt.Errorf(\"bindnode utils: schema for [%T] does not contain that named type [%s]\", ptrType, typ.Name())\n\t}\n\n\t// focusing on bindnode setup panics\n\tdefer func() {\n\t\tif rec := recover(); rec != nil {\n\t\t\tswitch v := rec.(type) {\n\t\t\tcase string:\n\t\t\t\terr = errors.New(v)\n\t\t\tcase error:\n\t\t\t\terr = v\n\t\t\tdefault:\n\t\t\t\tpanic(rec)\n\t\t\t}\n\t\t}\n\t}()\n\n\tproto := bindnode.Prototype(ptrType, schemaType, options...)\n\tbr[typ] = prototypeData{\n\t\tproto,\n\t\toptions,\n\t}\n\n\treturn err\n}\n\n// IsRegistered can be used to determine if the type has already been registered\n// within this registry.\n// Using RegisterType on an already registered type will cause a panic, so where\n// this may be the case, IsRegistered can be used to check.\nfunc (br BindnodeRegistry) IsRegistered(ptrType interface{}) bool {\n\t_, ok := br[typeOf(ptrType)]\n\treturn ok\n}\n\n// TypeFromReader deserializes bytes using the given codec from a Reader and\n// instantiates the Go type that's provided as a pointer via the ptrValue\n// argument.\nfunc (br BindnodeRegistry) TypeFromReader(r io.Reader, ptrValue interface{}, decoder codec.Decoder) (interface{}, error) {\n\tprotoData := br.prototypeDataFor(ptrValue)\n\tnode, err := ipld.DecodeStreamingUsingPrototype(r, decoder, protoData.proto)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttyp := bindnode.Unwrap(node)\n\treturn typ, nil\n}\n\n// TypeFromBytes deserializes bytes using the given codec from its bytes and\n// instantiates the Go type that's provided as a pointer via the ptrValue\n// argument.\nfunc (br BindnodeRegistry) TypeFromBytes(byts []byte, ptrValue interface{}, decoder codec.Decoder) (interface{}, error) {\n\tprotoData := br.prototypeDataFor(ptrValue)\n\tnode, err := ipld.DecodeUsingPrototype(byts, decoder, protoData.proto)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttyp := bindnode.Unwrap(node)\n\treturn typ, nil\n}\n\n// TypeFromNode converts an datamodel.Node into an appropriate Go type that's\n// provided as a pointer via the ptrValue argument.\nfunc (br BindnodeRegistry) TypeFromNode(node datamodel.Node, ptrValue interface{}) (interface{}, error) {\n\tprotoData := br.prototypeDataFor(ptrValue)\n\tif tn, ok := node.(schema.TypedNode); ok {\n\t\tnode = tn.Representation()\n\t}\n\tbuilder := protoData.proto.Representation().NewBuilder()\n\terr := builder.AssignNode(node)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttyp := bindnode.Unwrap(builder.Build())\n\treturn typ, nil\n}\n\n// TypeToNode converts a Go type that's provided as a pointer via the ptrValue\n// argument to an schema.TypedNode.\nfunc (br BindnodeRegistry) TypeToNode(ptrValue interface{}) schema.TypedNode {\n\tprotoData := br.prototypeDataFor(ptrValue)\n\treturn bindnode.Wrap(ptrValue, protoData.proto.Type(), protoData.options...)\n}\n\n// TypeToWriter is a utility method that serializes a Go type that's provided as\n// a pointer via the ptrValue argument through the given codec to a Writer.\nfunc (br BindnodeRegistry) TypeToWriter(ptrValue interface{}, w io.Writer, encoder codec.Encoder) error {\n\treturn ipld.EncodeStreaming(w, br.TypeToNode(ptrValue), encoder)\n}\n\n// TypeToBytes is a utility method that serializes a Go type that's provided as\n// a pointer via the ptrValue argument through the given codec and returns the\n// bytes.\nfunc (br BindnodeRegistry) TypeToBytes(ptrValue interface{}, encoder codec.Encoder) ([]byte, error) {\n\treturn ipld.Encode(br.TypeToNode(ptrValue), encoder)\n}\n"
  },
  {
    "path": "node/bindnode/registry/registry_test.go",
    "content": "package registry_test\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"math\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/codec/dagcbor\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode/registry\"\n\n\tqt \"github.com/frankban/quicktest\"\n)\n\ntype HexString string\ntype Foo struct {\n\tInt  int\n\tBool bool\n}\n\nfunc TestRegistry(t *testing.T) {\n\treg := registry.NewRegistry()\n\tqt.Assert(t, reg.IsRegistered((*Foo)(nil)), qt.IsFalse)\n\tqt.Assert(t, reg.IsRegistered((*HexString)(nil)), qt.IsFalse)\n\n\terr := reg.RegisterType((*Foo)(nil),\n\t\t`type Foo struct {\n\t\t\tInt Int\n\t\t\tBool Bool\n\t\t}`, \"Foo\")\n\tqt.Assert(t, err, qt.IsNil)\n\n\terr = reg.RegisterType((*HexString)(nil), \"type HS bytes\", \"HS\", bindnode.TypedBytesConverter(\n\t\t(*HexString)(nil),\n\t\tfunc(b []byte) (interface{}, error) {\n\t\t\treturn HexString(hex.EncodeToString(b)), nil\n\t\t},\n\t\tfunc(i interface{}) ([]byte, error) {\n\t\t\ts, _ := i.(*HexString)\n\t\t\treturn hex.DecodeString(string(*s))\n\t\t}))\n\tqt.Assert(t, err, qt.IsNil)\n\n\tqt.Assert(t, reg.IsRegistered((*Foo)(nil)), qt.IsTrue)\n\tqt.Assert(t, reg.IsRegistered((*HexString)(nil)), qt.IsTrue)\n\n\thsi, err := reg.TypeFromNode(basicnode.NewBytes([]byte{0, 1, 2, 3, 4}), (*HexString)(nil))\n\tqt.Assert(t, err, qt.IsNil)\n\ths, ok := hsi.(*HexString)\n\tqt.Assert(t, ok, qt.IsTrue)\n\tqt.Assert(t, string(*hs), qt.Equals, \"0001020304\")\n\n\tbyts, _ := hex.DecodeString(\"a263496e74386364426f6f6cf4\")\n\tfooi, err := reg.TypeFromBytes(byts, (*Foo)(nil), dagcbor.Decode)\n\tqt.Assert(t, err, qt.IsNil)\n\tfoo, ok := fooi.(*Foo)\n\tqt.Assert(t, ok, qt.IsTrue)\n\tqt.Assert(t, *foo, qt.Equals, Foo{Int: -100, Bool: false})\n\n\tbyts, err = reg.TypeToBytes(&Foo{Int: -100, Bool: false}, dagjson.Encode)\n\tqt.Assert(t, err, qt.IsNil)\n\tqt.Assert(t, string(byts), qt.Equals, `{\"Bool\":false,\"Int\":-100}`)\n\n\tbyts, _ = hex.DecodeString(\"a263496e741a7fffffff64426f6f6cf5\")\n\tfooi, err = reg.TypeFromReader(bytes.NewReader(byts), (*Foo)(nil), dagcbor.Decode)\n\tqt.Assert(t, err, qt.IsNil)\n\tfoo, ok = fooi.(*Foo)\n\tqt.Assert(t, ok, qt.IsTrue)\n\tqt.Assert(t, *foo, qt.Equals, Foo{Int: math.MaxInt32, Bool: true})\n\n\tw := bytes.Buffer{}\n\terr = reg.TypeToWriter(&Foo{Int: math.MaxInt32, Bool: true}, &w, dagjson.Encode)\n\tqt.Assert(t, err, qt.IsNil)\n\tqt.Assert(t, w.String(), qt.Equals, `{\"Bool\":true,\"Int\":2147483647}`)\n}\n\nfunc TestRegistryErrors(t *testing.T) {\n\treg := registry.NewRegistry()\n\terr := reg.RegisterType((*Foo)(nil), `type Nope nope {}`, \"Foo\")\n\tqt.Assert(t, err, qt.ErrorMatches, `.*unknown type keyword: \"nope\".*`)\n\n\terr = reg.RegisterType((*HexString)(nil), \"type HS string\", \"HS\")\n\tqt.Assert(t, err, qt.IsNil)\n\n\terr = reg.RegisterType((*HexString)(nil), \"type HS2 string\", \"HS2\")\n\tqt.Assert(t, err, qt.ErrorMatches, `.*type already registered: HexString`)\n\n\terr = reg.RegisterType((*Foo)(nil), \"type NotFoo string\", \"Foo\")\n\tqt.Assert(t, err, qt.ErrorMatches, `.*does not contain that named type.*`)\n\n\terr = reg.RegisterType((*Foo)(nil),\n\t\t`type Foo struct {\n\t\t\tNotInt String\n\t\t\tNotBool Float\n\t\t}`, \"Foo\")\n\tqt.Assert(t, err, qt.ErrorMatches, `.*kind mismatch.*`)\n}\n"
  },
  {
    "path": "node/bindnode/repr.go",
    "content": "package bindnode\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc reprNode(node datamodel.Node) datamodel.Node {\n\tif node, ok := node.(schema.TypedNode); ok {\n\t\treturn node.Representation()\n\t}\n\t// datamodel.Absent and datamodel.Null are not typed.\n\t// TODO: is this a problem? surely a typed struct's fields are always\n\t// typed, even when absent or null.\n\treturn node\n}\n\nfunc reprStrategy(typ schema.Type) interface{} {\n\t// Can't use an interface check, as each method has a different result type.\n\t// TODO: consider inlining this type switch at each call site,\n\t// as the call sites need the underlying schema.Type too.\n\tswitch typ := typ.(type) {\n\tcase *schema.TypeStruct:\n\t\treturn typ.RepresentationStrategy()\n\tcase *schema.TypeUnion:\n\t\treturn typ.RepresentationStrategy()\n\tcase *schema.TypeEnum:\n\t\treturn typ.RepresentationStrategy()\n\t}\n\treturn nil\n}\n\ntype _prototypeRepr _prototype\n\nfunc (w *_prototypeRepr) NewBuilder() datamodel.NodeBuilder {\n\treturn &_builderRepr{_assemblerRepr{\n\t\tcfg:        w.cfg,\n\t\tschemaType: w.schemaType,\n\t\tval:        reflect.New(w.goType).Elem(),\n\t}}\n}\n\ntype _nodeRepr _node\n\nfunc (w *_nodeRepr) Kind() datamodel.Kind {\n\tswitch reprStrategy(w.schemaType).(type) {\n\tcase schema.StructRepresentation_Stringjoin:\n\t\treturn datamodel.Kind_String\n\tcase schema.StructRepresentation_Map:\n\t\treturn datamodel.Kind_Map\n\tcase schema.StructRepresentation_Tuple, schema.StructRepresentation_ListPairs:\n\t\treturn datamodel.Kind_List\n\tcase schema.UnionRepresentation_Keyed:\n\t\treturn datamodel.Kind_Map\n\tcase schema.UnionRepresentation_Kinded:\n\t\thaveIdx, _ := unionMember(w.val)\n\t\tif haveIdx < 0 {\n\t\t\tpanic(fmt.Sprintf(\"bindnode: kinded union %s has no member\", w.val.Type()))\n\t\t}\n\t\tmtyp := w.schemaType.(*schema.TypeUnion).Members()[haveIdx]\n\t\treturn mtyp.RepresentationBehavior()\n\tcase schema.UnionRepresentation_Stringprefix:\n\t\treturn datamodel.Kind_String\n\tcase schema.EnumRepresentation_Int:\n\t\treturn datamodel.Kind_Int\n\tcase schema.EnumRepresentation_String:\n\t\treturn datamodel.Kind_String\n\tdefault:\n\t\treturn (*_node)(w).Kind()\n\t}\n}\n\nfunc outboundMappedKey(stg schema.StructRepresentation_Map, key string) string {\n\t// TODO: why doesn't stg just allow us to \"get\" by the key string?\n\tfield := schema.SpawnStructField(key, \"\", false, false)\n\tmappedKey := stg.GetFieldKey(field)\n\treturn mappedKey\n}\n\nfunc inboundMappedKey(typ *schema.TypeStruct, stg schema.StructRepresentation_Map, key string) string {\n\t// TODO: can't do a \"reverse\" lookup... needs better API probably.\n\tfields := typ.Fields()\n\tfor _, field := range fields {\n\t\tmappedKey := stg.GetFieldKey(field)\n\t\tif key == mappedKey {\n\t\t\treturn field.Name()\n\t\t}\n\t}\n\treturn key // fallback to the same key\n}\n\nfunc outboundMappedType(stg schema.UnionRepresentation_Keyed, key string) string {\n\t// TODO: why doesn't stg just allow us to \"get\" by the key string?\n\ttyp := schema.SpawnBool(key)\n\tmappedKey := stg.GetDiscriminant(typ)\n\treturn mappedKey\n}\n\nfunc inboundMappedType(typ *schema.TypeUnion, stg schema.UnionRepresentation_Keyed, key string) string {\n\t// TODO: can't do a \"reverse\" lookup... needs better API probably.\n\tfor _, member := range typ.Members() {\n\t\tmappedKey := stg.GetDiscriminant(member)\n\t\tif key == mappedKey {\n\t\t\t// println(key, \"rev-mapped to\", field.Name())\n\t\t\treturn member.Name()\n\t\t}\n\t}\n\t// println(key, \"had no mapping\")\n\treturn key // fallback to the same key\n}\n\n// asKinded can be called on a kinded union node to obtain a node\n// representing one of its members, identified by kind.\nfunc (w *_nodeRepr) asKinded(stg schema.UnionRepresentation_Kinded, kind datamodel.Kind) *_nodeRepr {\n\tname := stg.GetMember(kind)\n\tmembers := w.schemaType.(*schema.TypeUnion).Members()\n\tfor i, member := range members {\n\t\tif member.Name() != name {\n\t\t\tcontinue\n\t\t}\n\t\tw2 := *w\n\t\tw2.val = w.val.Field(i).Elem()\n\t\tw2.schemaType = member\n\t\treturn &w2\n\t}\n\tpanic(\"bindnode TODO: GetMember result is missing?\")\n}\n\nfunc (w *_nodeRepr) LookupByString(key string) (datamodel.Node, error) {\n\tif stg, ok := reprStrategy(w.schemaType).(schema.UnionRepresentation_Kinded); ok {\n\t\tw = w.asKinded(stg, datamodel.Kind_Map)\n\t}\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.StructRepresentation_Map:\n\t\trevKey := inboundMappedKey(w.schemaType.(*schema.TypeStruct), stg, key)\n\t\tv, err := (*_node)(w).LookupByString(revKey)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn reprNode(v), nil\n\tcase schema.UnionRepresentation_Keyed:\n\t\trevKey := inboundMappedType(w.schemaType.(*schema.TypeUnion), stg, key)\n\t\tv, err := (*_node)(w).LookupByString(revKey)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn reprNode(v), nil\n\tdefault:\n\t\tv, err := (*_node)(w).LookupByString(key)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn reprNode(v), nil\n\t}\n}\n\nfunc (w *_nodeRepr) LookupByIndex(idx int64) (datamodel.Node, error) {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_List).LookupByIndex(idx)\n\tcase schema.StructRepresentation_Tuple:\n\t\tfields := w.schemaType.(*schema.TypeStruct).Fields()\n\t\tif idx < 0 || int(idx) >= len(fields) {\n\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfInt(idx)}\n\t\t}\n\t\tfield := fields[idx]\n\t\tv, err := (*_node)(w).LookupByString(field.Name())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn reprNode(v), nil\n\tcase schema.StructRepresentation_ListPairs:\n\t\tfields := w.schemaType.(*schema.TypeStruct).Fields()\n\t\tif idx < 0 || int(idx) >= len(fields) {\n\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfInt(idx)}\n\t\t}\n\t\tvar curField int64\n\t\tfor _, field := range fields {\n\t\t\tvalue, err := (*_node)(w).LookupByString(field.Name())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif value.IsAbsent() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif curField == idx {\n\t\t\t\treturn buildListpairsField(basicnode.NewString(field.Name()), reprNode(value))\n\t\t\t}\n\t\t\tcurField++\n\t\t}\n\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfInt(idx)}\n\tdefault:\n\t\tv, err := (*_node)(w).LookupByIndex(idx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn reprNode(v), nil\n\t}\n}\n\nfunc (w *_nodeRepr) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\tswitch w.Kind() {\n\tcase datamodel.Kind_Map:\n\t\treturn w.LookupByString(seg.String())\n\tcase datamodel.Kind_List:\n\t\tidx, err := seg.Index()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn w.LookupByIndex(idx)\n\t}\n\treturn nil, datamodel.ErrWrongKind{\n\t\tTypeName:        w.schemaType.Name(),\n\t\tMethodName:      \"LookupBySegment\",\n\t\tAppropriateKind: datamodel.KindSet_Recursive,\n\t\tActualKind:      w.Kind(),\n\t}\n}\n\nfunc (w *_nodeRepr) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\tswitch w.Kind() {\n\tcase datamodel.Kind_Map:\n\t\ts, err := key.AsString()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn w.LookupByString(s)\n\tcase datamodel.Kind_List:\n\t\ti, err := key.AsInt()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn w.LookupByIndex(i)\n\t}\n\treturn nil, datamodel.ErrWrongKind{\n\t\tTypeName:        w.schemaType.Name(),\n\t\tMethodName:      \"LookupByNode\",\n\t\tAppropriateKind: datamodel.KindSet_Recursive,\n\t\tActualKind:      w.Kind(),\n\t}\n}\n\nfunc (w *_nodeRepr) MapIterator() datamodel.MapIterator {\n\t// TODO: we can try to reuse reprStrategy here and elsewhere\n\tif stg, ok := reprStrategy(w.schemaType).(schema.UnionRepresentation_Kinded); ok {\n\t\tw = w.asKinded(stg, datamodel.Kind_Map)\n\t}\n\tswitch reprStrategy(w.schemaType).(type) {\n\tcase schema.StructRepresentation_Map:\n\t\titr := (*_node)(w).MapIterator().(*_structIterator)\n\t\t// When we reach the last non-absent field, we should stop.\n\t\titr.reprEnd = int(w.lengthMinusTrailingAbsents())\n\t\treturn (*_structIteratorRepr)(itr)\n\tcase schema.UnionRepresentation_Keyed:\n\t\titr := (*_node)(w).MapIterator().(*_unionIterator)\n\t\treturn (*_unionIteratorRepr)(itr)\n\tdefault:\n\t\titer, _ := (*_node)(w).MapIterator().(*_mapIterator)\n\t\tif iter == nil {\n\t\t\treturn nil\n\t\t}\n\t\treturn (*_mapIteratorRepr)(iter)\n\t}\n}\n\ntype _mapIteratorRepr _mapIterator\n\nfunc (w *_mapIteratorRepr) Next() (key, value datamodel.Node, _ error) {\n\tk, v, err := (*_mapIterator)(w).Next()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\treturn reprNode(k), reprNode(v), nil\n}\n\nfunc (w *_mapIteratorRepr) Done() bool {\n\treturn w.nextIndex >= w.keysVal.Len()\n}\n\nfunc (w *_nodeRepr) ListIterator() datamodel.ListIterator {\n\tif stg, ok := reprStrategy(w.schemaType).(schema.UnionRepresentation_Kinded); ok {\n\t\tw = w.asKinded(stg, datamodel.Kind_List)\n\t}\n\tswitch reprStrategy(w.schemaType).(type) {\n\tcase schema.StructRepresentation_Tuple:\n\t\ttyp := w.schemaType.(*schema.TypeStruct)\n\t\titer := _tupleIteratorRepr{cfg: w.cfg, schemaType: typ, fields: typ.Fields(), val: w.val}\n\t\titer.reprEnd = int(w.lengthMinusTrailingAbsents())\n\t\treturn &iter\n\tcase schema.StructRepresentation_ListPairs:\n\t\ttyp := w.schemaType.(*schema.TypeStruct)\n\t\titer := _listpairsIteratorRepr{cfg: w.cfg, schemaType: typ, fields: typ.Fields(), val: w.val}\n\t\titer.reprEnd = int(w.lengthMinusTrailingAbsents())\n\t\treturn &iter\n\tdefault:\n\t\titer, _ := (*_node)(w).ListIterator().(*_listIterator)\n\t\tif iter == nil {\n\t\t\treturn nil\n\t\t}\n\t\treturn (*_listIteratorRepr)(iter)\n\t}\n}\n\ntype _listIteratorRepr _listIterator\n\nfunc (w *_listIteratorRepr) Next() (index int64, value datamodel.Node, _ error) {\n\tidx, v, err := (*_listIterator)(w).Next()\n\tif err != nil {\n\t\treturn idx, nil, err\n\t}\n\treturn idx, reprNode(v), nil\n}\n\nfunc (w *_listIteratorRepr) Done() bool {\n\treturn w.nextIndex >= w.val.Len()\n}\n\nfunc (w *_nodeRepr) lengthMinusAbsents() int64 {\n\tfields := w.schemaType.(*schema.TypeStruct).Fields()\n\tn := int64(len(fields))\n\tfor i, field := range fields {\n\t\tif field.IsOptional() && w.val.Field(i).IsNil() {\n\t\t\tn--\n\t\t}\n\t}\n\treturn n\n}\n\ntype _tupleIteratorRepr struct {\n\t// TODO: support embedded fields?\n\tcfg        *config\n\tschemaType *schema.TypeStruct\n\tfields     []schema.StructField\n\tval        reflect.Value // non-pointer\n\tnextIndex  int\n\n\t// these are only used in repr.go\n\treprEnd int\n}\n\nfunc (w *_tupleIteratorRepr) Next() (index int64, value datamodel.Node, _ error) {\n\tfor {\n\t\tidx := w.nextIndex\n\t\t_, value, err := (*_structIterator)(w).Next()\n\t\tif err != nil {\n\t\t\treturn 0, nil, err\n\t\t}\n\t\tif w.nextIndex <= w.reprEnd {\n\t\t\treturn int64(idx), reprNode(value), nil\n\t\t}\n\t}\n}\n\nfunc (w *_tupleIteratorRepr) Done() bool {\n\treturn w.nextIndex >= w.reprEnd\n}\n\ntype _listpairsIteratorRepr struct {\n\tcfg        *config\n\tschemaType *schema.TypeStruct\n\tfields     []schema.StructField\n\tval        reflect.Value // non-pointer\n\tnextIndex  int\n\n\t// these are only used in repr.go\n\treprEnd int\n}\n\nfunc (w *_listpairsIteratorRepr) Next() (index int64, value datamodel.Node, _ error) {\n\tfor {\n\t\tif w.Done() {\n\t\t\treturn 0, nil, datamodel.ErrIteratorOverread{}\n\t\t}\n\t\tidx := w.nextIndex\n\t\tkey, value, err := (*_structIterator)(w).Next()\n\t\tif err != nil {\n\t\t\treturn 0, nil, err\n\t\t}\n\t\tif value.IsAbsent() || w.nextIndex > w.reprEnd {\n\t\t\tcontinue\n\t\t}\n\t\tfield, err := buildListpairsField(key, reprNode(value))\n\t\tif err != nil {\n\t\t\treturn 0, nil, err\n\t\t}\n\t\treturn int64(idx), field, nil\n\t}\n}\n\nfunc (w *_listpairsIteratorRepr) Done() bool {\n\treturn w.nextIndex >= w.reprEnd\n}\n\nfunc buildListpairsField(key, value datamodel.Node) (datamodel.Node, error) {\n\tnb := basicnode.Prototype.List.NewBuilder()\n\tla, err := nb.BeginList(2)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := la.AssembleValue().AssignNode(key); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := la.AssembleValue().AssignNode(value); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := la.Finish(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn nb.Build(), nil\n}\n\nfunc (w *_nodeRepr) lengthMinusTrailingAbsents() int64 {\n\tfields := w.schemaType.(*schema.TypeStruct).Fields()\n\tfor i := len(fields) - 1; i >= 0; i-- {\n\t\tfield := fields[i]\n\t\tif !field.IsOptional() || !w.val.Field(i).IsNil() {\n\t\t\treturn int64(i + 1)\n\t\t}\n\t}\n\treturn 0\n}\n\nfunc (w *_nodeRepr) Length() int64 {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.StructRepresentation_Stringjoin:\n\t\treturn -1\n\tcase schema.StructRepresentation_Map:\n\t\treturn w.lengthMinusAbsents()\n\tcase schema.StructRepresentation_Tuple:\n\t\treturn w.lengthMinusTrailingAbsents()\n\tcase schema.StructRepresentation_ListPairs:\n\t\treturn w.lengthMinusAbsents()\n\tcase schema.UnionRepresentation_Keyed:\n\t\treturn (*_node)(w).Length()\n\tcase schema.UnionRepresentation_Kinded:\n\t\tw = w.asKinded(stg, w.Kind())\n\t\treturn (*_node)(w).Length()\n\tdefault:\n\t\treturn (*_node)(w).Length()\n\t}\n}\n\nfunc (w *_nodeRepr) IsAbsent() bool {\n\tif reprStrategy(w.schemaType) == nil {\n\t\treturn (*_node)(w).IsAbsent()\n\t}\n\treturn false\n}\n\nfunc (w *_nodeRepr) IsNull() bool {\n\tif reprStrategy(w.schemaType) == nil {\n\t\treturn (*_node)(w).IsNull()\n\t}\n\treturn false\n}\n\nfunc (w *_nodeRepr) AsBool() (bool, error) {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_Bool).AsBool()\n\tdefault:\n\t\treturn (*_node)(w).AsBool()\n\t}\n}\n\nfunc (w *_nodeRepr) AsInt() (int64, error) {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_Int).AsInt()\n\tcase schema.EnumRepresentation_Int:\n\t\tkind := w.val.Kind()\n\t\tif kind == reflect.String {\n\t\t\ts, err := (*_node)(w).AsString()\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\tmapped, ok := stg[s]\n\t\t\tif !ok {\n\t\t\t\t// We assume that the schema strategy is correct,\n\t\t\t\t// so we can only fail if the stored string isn't a valid member.\n\t\t\t\treturn 0, fmt.Errorf(\"AsInt: %q is not a valid member of enum %s\", s, w.schemaType.Name())\n\t\t\t}\n\t\t\t// TODO: the strategy type should probably use int64 rather than int\n\t\t\treturn int64(mapped), nil\n\t\t}\n\t\tvar i int\n\t\t// TODO: check for overflows\n\t\tif kindInt[kind] {\n\t\t\ti = int(w.val.Int())\n\t\t} else if kindUint[kind] {\n\t\t\ti = int(w.val.Uint())\n\t\t} else {\n\t\t\treturn 0, fmt.Errorf(\"AsInt: unexpected kind: %s\", kind)\n\t\t}\n\t\tfor _, reprInt := range stg {\n\t\t\tif reprInt == i {\n\t\t\t\treturn int64(i), nil\n\t\t\t}\n\t\t}\n\t\t// We assume that the schema strategy is correct,\n\t\t// so we can only fail if the stored string isn't a valid member.\n\t\treturn 0, fmt.Errorf(\"AsInt: %d is not a valid member of enum %s\", i, w.schemaType.Name())\n\tdefault:\n\t\treturn (*_node)(w).AsInt()\n\t}\n}\n\nfunc (w *_nodeRepr) AsFloat() (float64, error) {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_Float).AsFloat()\n\tdefault:\n\t\treturn (*_node)(w).AsFloat()\n\t}\n}\n\nfunc (w *_nodeRepr) AsString() (string, error) {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.StructRepresentation_Stringjoin:\n\t\tvar b strings.Builder\n\t\titr := (*_node)(w).MapIterator()\n\t\tfirst := true\n\t\tfor !itr.Done() {\n\t\t\t_, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\ts, err := reprNode(v).AsString()\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\tif first {\n\t\t\t\tfirst = false\n\t\t\t} else {\n\t\t\t\tb.WriteString(stg.GetDelim())\n\t\t\t}\n\t\t\tb.WriteString(s)\n\t\t}\n\t\treturn b.String(), nil\n\tcase schema.UnionRepresentation_Stringprefix:\n\t\thaveIdx, mval := unionMember(w.val)\n\t\tmtyp := w.schemaType.(*schema.TypeUnion).Members()[haveIdx]\n\n\t\tw2 := *w\n\t\tw2.val = mval\n\t\tw2.schemaType = mtyp\n\t\ts, err := w2.AsString()\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tname := stg.GetDiscriminant(mtyp)\n\t\treturn name + stg.GetDelim() + s, nil\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_String).AsString()\n\tcase schema.EnumRepresentation_String:\n\t\ts, err := (*_node)(w).AsString()\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif mapped := stg[s]; mapped != \"\" {\n\t\t\treturn mapped, nil\n\t\t}\n\t\tmembers := w.schemaType.(*schema.TypeEnum).Members()\n\t\tfor _, member := range members {\n\t\t\tif s == member {\n\t\t\t\treturn s, nil\n\t\t\t}\n\t\t}\n\t\tfor k, v := range stg {\n\t\t\t// a programming error? we may have the enum string value rather than the type\n\t\t\tif v == s {\n\t\t\t\treturn \"\", fmt.Errorf(\"AsString: %q is not a valid member of enum %s (bindnode works at the type level; did you mean %q?)\", s, w.schemaType.Name(), k)\n\t\t\t}\n\t\t}\n\t\treturn \"\", fmt.Errorf(\"AsString: %q is not a valid member of enum %s\", s, w.schemaType.Name())\n\tdefault:\n\t\treturn (*_node)(w).AsString()\n\t}\n}\n\nfunc (w *_nodeRepr) AsBytes() ([]byte, error) {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_Bytes).AsBytes()\n\tdefault:\n\t\treturn (*_node)(w).AsBytes()\n\t}\n}\n\nfunc (w *_nodeRepr) AsLink() (datamodel.Link, error) {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_Link).AsLink()\n\tdefault:\n\t\treturn (*_node)(w).AsLink()\n\t}\n}\n\nfunc (w *_nodeRepr) Prototype() datamodel.NodePrototype {\n\treturn (*_prototypeRepr)((*_node)(w).Prototype().(*_prototype))\n}\n\ntype _builderRepr struct {\n\t_assemblerRepr\n}\n\n// TODO: returning a repr node here is probably good, but there's a gotcha: one\n// can go from a typed node to a repr node via the Representation method, but\n// not the other way. That's probably why codegen returns a typed node here.\n// The solution might be to add a way to go from the repr node to its parent\n// typed node.\n\nfunc (w *_builderRepr) Build() datamodel.Node {\n\t// TODO: see the notes above.\n\t// return &_nodeRepr{schemaType: w.schemaType, val: w.val}\n\treturn &_node{cfg: w.cfg, schemaType: w.schemaType, val: w.val}\n}\n\nfunc (w *_builderRepr) Reset() {\n\tpanic(\"bindnode TODO: Reset\")\n}\n\ntype _assemblerRepr struct {\n\tcfg        *config\n\tschemaType schema.Type\n\tval        reflect.Value // non-pointer\n\tfinish     func() error\n\n\tnullable bool\n}\n\nfunc assemblerRepr(am datamodel.NodeAssembler) datamodel.NodeAssembler {\n\tswitch am := am.(type) {\n\tcase *_assembler:\n\t\treturn (*_assemblerRepr)(am)\n\tcase _errorAssembler:\n\t\treturn am\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unexpected NodeAssembler type: %T\", am))\n\t}\n}\n\nfunc (w *_assemblerRepr) asKinded(stg schema.UnionRepresentation_Kinded, kind datamodel.Kind) datamodel.NodeAssembler {\n\tname := stg.GetMember(kind)\n\tmembers := w.schemaType.(*schema.TypeUnion).Members()\n\tkindSet := make([]datamodel.Kind, 0, len(members))\n\tfor idx, member := range members {\n\t\tif member.Name() != name {\n\t\t\tkindSet = append(kindSet, member.RepresentationBehavior())\n\t\t\tcontinue\n\t\t}\n\t\tw2 := *w\n\t\tgoType := w.val.Field(idx).Type().Elem()\n\t\tvalPtr := reflect.New(goType)\n\t\tw2.val = valPtr.Elem()\n\t\tw2.schemaType = member\n\n\t\t// Layer a new finish func on top, to set Index/Value.\n\t\tw2.finish = func() error {\n\t\t\tunionSetMember(w.val, idx, valPtr)\n\t\t\tif w.finish != nil {\n\t\t\t\tif err := w.finish(); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\treturn &w2\n\t}\n\treturn _errorAssembler{datamodel.ErrWrongKind{\n\t\tTypeName:        w.schemaType.Name() + \".Repr\",\n\t\tMethodName:      \"\", // TODO: we could fill it via runtime.Callers\n\t\tAppropriateKind: datamodel.KindSet(kindSet),\n\t\tActualKind:      kind,\n\t}}\n}\n\nfunc (w *_assemblerRepr) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\tif stg, ok := reprStrategy(w.schemaType).(schema.UnionRepresentation_Kinded); ok {\n\t\treturn w.asKinded(stg, datamodel.Kind_Map).BeginMap(sizeHint)\n\t}\n\tasm, err := (*_assembler)(w).BeginMap(sizeHint)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch asm := asm.(type) {\n\tcase *_structAssembler:\n\t\treturn (*_structAssemblerRepr)(asm), nil\n\tcase *_mapAssembler:\n\t\treturn (*_mapAssemblerRepr)(asm), nil\n\tcase *_unionAssembler:\n\t\treturn (*_unionAssemblerRepr)(asm), nil\n\tcase *basicMapAssembler:\n\t\treturn asm, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"bindnode BeginMap TODO: %T\", asm)\n\t}\n}\n\nfunc (w *_assemblerRepr) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_List).BeginList(sizeHint)\n\tcase schema.StructRepresentation_Tuple, schema.StructRepresentation_ListPairs:\n\t\tasm, err := (*_assembler)(w).BeginMap(sizeHint)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn (*_listStructAssemblerRepr)(asm.(*_structAssembler)), nil\n\tdefault:\n\t\tasm, err := (*_assembler)(w).BeginList(sizeHint)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif _, ok := asm.(*basicListAssembler); ok {\n\t\t\treturn asm, nil\n\t\t}\n\t\treturn (*_listAssemblerRepr)(asm.(*_listAssembler)), nil\n\t}\n}\n\nfunc (w *_assemblerRepr) AssignNull() error {\n\treturn (*_assembler)(w).AssignNull()\n}\n\nfunc (w *_assemblerRepr) AssignBool(b bool) error {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_Bool).AssignBool(b)\n\tdefault:\n\t\treturn (*_assembler)(w).AssignBool(b)\n\t}\n}\n\nfunc (w *_assemblerRepr) assignUInt(uin datamodel.UintNode) error {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_Int).(*_assemblerRepr).assignUInt(uin)\n\tcase schema.EnumRepresentation_Int:\n\t\tuin, err := uin.AsUint()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn fmt.Errorf(\"AssignInt: %d is not a valid member of enum %s\", uin, w.schemaType.Name())\n\tdefault:\n\t\treturn (*_assembler)(w).assignUInt(uin)\n\t}\n}\n\nfunc (w *_assemblerRepr) AssignInt(i int64) error {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_Int).AssignInt(i)\n\tcase schema.EnumRepresentation_Int:\n\t\tfor member, reprInt := range stg {\n\t\t\tif int64(reprInt) != i {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tval := (*_assembler)(w).createNonPtrVal()\n\t\t\tkind := val.Kind()\n\t\t\tif kind == reflect.String {\n\t\t\t\t// Reuse AssignString so we don't have to repeat ten lines.\n\t\t\t\treturn (*_assembler)(w).AssignString(member)\n\t\t\t}\n\t\t\t// Short-cut to storing the repr int directly, akin to node.go's AssignInt.\n\t\t\tif kindInt[kind] {\n\t\t\t\tval.SetInt(i)\n\t\t\t} else if kindUint[kind] {\n\t\t\t\tif i < 0 {\n\t\t\t\t\t// TODO: write a test\n\t\t\t\t\treturn fmt.Errorf(\"bindnode: cannot assign negative integer to %s\", w.val.Type())\n\t\t\t\t}\n\t\t\t\tval.SetUint(uint64(i))\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"AsInt: unexpected kind: %s\", val.Kind())\n\t\t\t}\n\t\t\tif w.finish != nil {\n\t\t\t\tif err := w.finish(); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"AssignInt: %d is not a valid member of enum %s\", i, w.schemaType.Name())\n\tdefault:\n\t\treturn (*_assembler)(w).AssignInt(i)\n\t}\n}\n\nfunc (w *_assemblerRepr) AssignFloat(f float64) error {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_Float).AssignFloat(f)\n\tdefault:\n\t\treturn (*_assembler)(w).AssignFloat(f)\n\t}\n}\n\nfunc (w *_assemblerRepr) AssignString(s string) error {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.StructRepresentation_Stringjoin:\n\t\tfields := w.schemaType.(*schema.TypeStruct).Fields()\n\t\tparts := strings.Split(s, stg.GetDelim())\n\t\tif len(parts) != len(fields) {\n\t\t\treturn fmt.Errorf(\"bindnode TODO: len mismatch\")\n\t\t}\n\t\tmapAsm, err := (*_assembler)(w).BeginMap(-1)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor i, field := range fields {\n\t\t\tentryAsm, err := mapAsm.AssembleEntry(field.Name())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tentryAsm = assemblerRepr(entryAsm)\n\t\t\tif err := entryAsm.AssignString(parts[i]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn mapAsm.Finish()\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_String).AssignString(s)\n\tcase schema.UnionRepresentation_Stringprefix:\n\t\thasDelim := stg.GetDelim() != \"\"\n\n\t\tvar prefix, remainder string\n\t\tif hasDelim {\n\t\t\tparts := strings.SplitN(s, stg.GetDelim(), 2)\n\t\t\tif len(parts) != 2 {\n\t\t\t\treturn fmt.Errorf(\"schema rejects data: the union type %s expects delimiter %q, and it was not found in the data %q\", w.schemaType.Name(), stg.GetDelim(), s)\n\t\t\t}\n\t\t\tprefix, remainder = parts[0], parts[1]\n\t\t}\n\n\t\tmembers := w.schemaType.(*schema.TypeUnion).Members()\n\t\tfor idx, member := range members {\n\t\t\tdescrm := stg.GetDiscriminant(member)\n\t\t\tif hasDelim {\n\t\t\t\tif stg.GetDiscriminant(member) != prefix {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif !strings.HasPrefix(s, descrm) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tremainder = s[len(descrm):]\n\t\t\t}\n\n\t\t\t// TODO: DRY: this has much in common with the asKinded method; it differs only in that we picked idx already in a different way.\n\t\t\tw2 := *w\n\t\t\tgoType := w.val.Field(idx).Type().Elem()\n\t\t\tvalPtr := reflect.New(goType)\n\t\t\tw2.val = valPtr.Elem()\n\t\t\tw2.schemaType = member\n\t\t\tw2.finish = func() error {\n\t\t\t\tunionSetMember(w.val, idx, valPtr)\n\t\t\t\tif w.finish != nil {\n\t\t\t\t\tif err := w.finish(); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn w2.AssignString(remainder)\n\t\t}\n\t\treturn fmt.Errorf(\"schema rejects data: the union type %s requires a known prefix, and it was not found in the data %q\", w.schemaType.Name(), s)\n\tcase schema.EnumRepresentation_String:\n\t\t// Note that we need to do a reverse lookup.\n\t\tfor member, mapped := range stg {\n\t\t\tif mapped == s {\n\t\t\t\treturn (*_assembler)(w).AssignString(member)\n\t\t\t}\n\t\t}\n\t\tmembers := w.schemaType.(*schema.TypeEnum).Members()\n\t\tfor _, member := range members {\n\t\t\tif s == member {\n\t\t\t\treturn (*_assembler)(w).AssignString(member)\n\t\t\t}\n\t\t}\n\t\treturn fmt.Errorf(\"AssignString: %q is not a valid member of enum %s\", s, w.schemaType.Name())\n\tcase schema.EnumRepresentation_Int:\n\t\treturn datamodel.ErrWrongKind{\n\t\t\tTypeName:        w.schemaType.Name(),\n\t\t\tMethodName:      \"AssignString\",\n\t\t\tAppropriateKind: datamodel.KindSet_JustInt,\n\t\t\tActualKind:      datamodel.Kind_String,\n\t\t}\n\tdefault:\n\t\treturn (*_assembler)(w).AssignString(s)\n\t}\n}\n\nfunc (w *_assemblerRepr) AssignBytes(p []byte) error {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_Bytes).AssignBytes(p)\n\tdefault:\n\t\treturn (*_assembler)(w).AssignBytes(p)\n\t}\n}\n\nfunc (w *_assemblerRepr) AssignLink(link datamodel.Link) error {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Kinded:\n\t\treturn w.asKinded(stg, datamodel.Kind_Link).AssignLink(link)\n\tdefault:\n\t\treturn (*_assembler)(w).AssignLink(link)\n\t}\n}\n\nfunc (w *_assemblerRepr) AssignNode(node datamodel.Node) error {\n\t// TODO: attempt to take a shortcut, like assembler.AssignNode\n\tif uintNode, ok := node.(datamodel.UintNode); ok {\n\t\treturn w.assignUInt(uintNode)\n\t}\n\treturn datamodel.Copy(node, w)\n}\n\nfunc (w *_assemblerRepr) Prototype() datamodel.NodePrototype {\n\tpanic(\"bindnode TODO: Assembler.Prototype\")\n}\n\ntype _structAssemblerRepr _structAssembler\n\nfunc (w *_structAssemblerRepr) AssembleKey() datamodel.NodeAssembler {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.StructRepresentation_Map:\n\t\treturn (*_structAssembler)(w).AssembleKey()\n\tcase schema.StructRepresentation_Stringjoin,\n\t\tschema.StructRepresentation_StringPairs:\n\t\t// TODO: perhaps the ErrorWrongKind type should also be extended to explicitly describe whether the method was applied on bare DM, type-level, or repr-level.\n\t\treturn _errorAssembler{datamodel.ErrWrongKind{\n\t\t\tTypeName:        w.schemaType.Name() + \".Repr\",\n\t\t\tMethodName:      \"AssembleKey\",\n\t\t\tAppropriateKind: datamodel.KindSet_JustMap,\n\t\t\tActualKind:      datamodel.Kind_String,\n\t\t}}\n\tcase schema.StructRepresentation_Tuple, schema.StructRepresentation_ListPairs:\n\t\treturn _errorAssembler{datamodel.ErrWrongKind{\n\t\t\tTypeName:        w.schemaType.Name() + \".Repr\",\n\t\t\tMethodName:      \"AssembleKey\",\n\t\t\tAppropriateKind: datamodel.KindSet_JustMap,\n\t\t\tActualKind:      datamodel.Kind_List,\n\t\t}}\n\tdefault:\n\t\treturn _errorAssembler{fmt.Errorf(\"bindnode AssembleKey TODO: %T\", stg)}\n\t}\n}\n\nfunc (w *_structAssemblerRepr) AssembleValue() datamodel.NodeAssembler {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.StructRepresentation_Map:\n\t\tkey := w.curKey.val.String()\n\t\trevKey := inboundMappedKey(w.schemaType, stg, key)\n\t\tw.curKey.val.SetString(revKey)\n\n\t\tvalAsm := (*_structAssembler)(w).AssembleValue()\n\t\tvalAsm = assemblerRepr(valAsm)\n\t\treturn valAsm\n\tdefault:\n\t\treturn _errorAssembler{fmt.Errorf(\"bindnode AssembleValue TODO: %T\", stg)}\n\t}\n}\n\nfunc (w *_structAssemblerRepr) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\tif err := w.AssembleKey().AssignString(k); err != nil {\n\t\treturn nil, err\n\t}\n\tam := w.AssembleValue()\n\treturn am, nil\n}\n\nfunc (w *_structAssemblerRepr) Finish() error {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.StructRepresentation_Map:\n\t\terr := (*_structAssembler)(w).Finish()\n\t\tif err, ok := err.(schema.ErrMissingRequiredField); ok {\n\t\t\tfor i, name := range err.Missing {\n\t\t\t\tserial := outboundMappedKey(stg, name)\n\t\t\t\tif serial != name {\n\t\t\t\t\terr.Missing[i] += fmt.Sprintf(\" (serial:%q)\", serial)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn err\n\tdefault:\n\t\treturn fmt.Errorf(\"bindnode Finish TODO: %T\", stg)\n\t}\n}\n\nfunc (w *_structAssemblerRepr) KeyPrototype() datamodel.NodePrototype {\n\tpanic(\"bindnode TODO\")\n}\n\nfunc (w *_structAssemblerRepr) ValuePrototype(k string) datamodel.NodePrototype {\n\tpanic(\"bindnode TODO: struct ValuePrototype\")\n}\n\ntype _mapAssemblerRepr _mapAssembler\n\nfunc (w *_mapAssemblerRepr) AssembleKey() datamodel.NodeAssembler {\n\tasm := (*_mapAssembler)(w).AssembleKey()\n\treturn (*_assemblerRepr)(asm.(*_assembler))\n}\n\nfunc (w *_mapAssemblerRepr) AssembleValue() datamodel.NodeAssembler {\n\tasm := (*_mapAssembler)(w).AssembleValue()\n\treturn (*_assemblerRepr)(asm.(*_assembler))\n}\n\nfunc (w *_mapAssemblerRepr) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\tif err := w.AssembleKey().AssignString(k); err != nil {\n\t\treturn nil, err\n\t}\n\tam := w.AssembleValue()\n\treturn am, nil\n}\n\nfunc (w *_mapAssemblerRepr) Finish() error {\n\treturn (*_mapAssembler)(w).Finish()\n}\n\nfunc (w *_mapAssemblerRepr) KeyPrototype() datamodel.NodePrototype {\n\tpanic(\"bindnode TODO\")\n}\n\nfunc (w *_mapAssemblerRepr) ValuePrototype(k string) datamodel.NodePrototype {\n\tpanic(\"bindnode TODO: struct ValuePrototype\")\n}\n\ntype _listStructAssemblerRepr _structAssembler\n\nfunc (w *_listStructAssemblerRepr) AssembleValue() datamodel.NodeAssembler {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.StructRepresentation_Tuple:\n\t\tfields := w.schemaType.Fields()\n\t\tif w.nextIndex >= len(fields) {\n\t\t\treturn _errorAssembler{datamodel.ErrNotExists{\n\t\t\t\tSegment: datamodel.PathSegmentOfInt(int64(w.nextIndex)),\n\t\t\t}}\n\t\t}\n\t\tfield := fields[w.nextIndex]\n\t\tw.doneFields[w.nextIndex] = true\n\t\tw.nextIndex++\n\n\t\tentryAsm, err := (*_structAssembler)(w).AssembleEntry(field.Name())\n\t\tif err != nil {\n\t\t\treturn _errorAssembler{err}\n\t\t}\n\t\tentryAsm = assemblerRepr(entryAsm)\n\t\treturn entryAsm\n\tcase schema.StructRepresentation_ListPairs:\n\t\treturn &_listpairsFieldAssemblerRepr{parent: (*_structAssembler)(w)}\n\tdefault:\n\t\treturn _errorAssembler{fmt.Errorf(\"bindnode AssembleValue TODO: %T\", stg)}\n\t}\n}\n\nfunc (w *_listStructAssemblerRepr) Finish() error {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.StructRepresentation_Tuple, schema.StructRepresentation_ListPairs:\n\t\treturn (*_structAssembler)(w).Finish()\n\tdefault:\n\t\treturn fmt.Errorf(\"bindnode Finish TODO: %T\", stg)\n\t}\n}\n\nfunc (w *_listStructAssemblerRepr) ValuePrototype(idx int64) datamodel.NodePrototype {\n\tpanic(\"bindnode TODO: list ValuePrototype\")\n}\n\ntype _listpairsFieldAssemblerRepr struct {\n\tparent *_structAssembler\n}\n\nfunc (w _listpairsFieldAssemblerRepr) BeginMap(int64) (datamodel.MapAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{\n\t\tTypeName:        w.parent.schemaType.Name(),\n\t\tMethodName:      \"BeginMap\",\n\t\tAppropriateKind: datamodel.KindSet_JustList,\n\t\tActualKind:      datamodel.Kind_Map,\n\t}\n}\nfunc (w *_listpairsFieldAssemblerRepr) BeginList(int64) (datamodel.ListAssembler, error) {\n\treturn &_listpairsFieldListAssemblerRepr{parent: w.parent}, nil\n}\nfunc (w _listpairsFieldAssemblerRepr) AssignNull() error {\n\treturn datamodel.ErrWrongKind{\n\t\tTypeName:        w.parent.schemaType.Name(),\n\t\tMethodName:      \"AssignNull\",\n\t\tAppropriateKind: datamodel.KindSet_JustList,\n\t\tActualKind:      datamodel.Kind_Map,\n\t}\n}\nfunc (w _listpairsFieldAssemblerRepr) AssignBool(bool) error {\n\treturn datamodel.ErrWrongKind{\n\t\tTypeName:        w.parent.schemaType.Name(),\n\t\tMethodName:      \"AssignBool\",\n\t\tAppropriateKind: datamodel.KindSet_JustList,\n\t\tActualKind:      datamodel.Kind_Map,\n\t}\n}\nfunc (w _listpairsFieldAssemblerRepr) AssignInt(int64) error {\n\treturn datamodel.ErrWrongKind{\n\t\tTypeName:        w.parent.schemaType.Name(),\n\t\tMethodName:      \"AssignInt\",\n\t\tAppropriateKind: datamodel.KindSet_JustList,\n\t\tActualKind:      datamodel.Kind_Map,\n\t}\n}\nfunc (w _listpairsFieldAssemblerRepr) AssignFloat(float64) error {\n\treturn datamodel.ErrWrongKind{\n\t\tTypeName:        w.parent.schemaType.Name(),\n\t\tMethodName:      \"AssignFloat\",\n\t\tAppropriateKind: datamodel.KindSet_JustList,\n\t\tActualKind:      datamodel.Kind_Map,\n\t}\n}\nfunc (w _listpairsFieldAssemblerRepr) AssignString(string) error {\n\treturn datamodel.ErrWrongKind{\n\t\tTypeName:        w.parent.schemaType.Name(),\n\t\tMethodName:      \"AssignString\",\n\t\tAppropriateKind: datamodel.KindSet_JustList,\n\t\tActualKind:      datamodel.Kind_Map,\n\t}\n}\nfunc (w _listpairsFieldAssemblerRepr) AssignBytes([]byte) error {\n\treturn datamodel.ErrWrongKind{\n\t\tTypeName:        w.parent.schemaType.Name(),\n\t\tMethodName:      \"AssignBytes\",\n\t\tAppropriateKind: datamodel.KindSet_JustList,\n\t\tActualKind:      datamodel.Kind_Map,\n\t}\n}\nfunc (w _listpairsFieldAssemblerRepr) AssignLink(datamodel.Link) error {\n\treturn datamodel.ErrWrongKind{\n\t\tTypeName:        w.parent.schemaType.Name(),\n\t\tMethodName:      \"AssignLink\",\n\t\tAppropriateKind: datamodel.KindSet_JustList,\n\t\tActualKind:      datamodel.Kind_Map,\n\t}\n}\n\nfunc (w *_listpairsFieldAssemblerRepr) AssignNode(n datamodel.Node) error {\n\treturn datamodel.Copy(n, w)\n}\n\nfunc (w _listpairsFieldAssemblerRepr) Prototype() datamodel.NodePrototype {\n\tpanic(\"bindnode TODO: listpairs field Prototype\")\n}\n\ntype _listpairsFieldListAssemblerRepr struct {\n\tparent *_structAssembler\n\tidx    int\n}\n\nfunc (w *_listpairsFieldListAssemblerRepr) AssembleValue() datamodel.NodeAssembler {\n\tw.idx++\n\tswitch w.idx {\n\tcase 1:\n\t\treturn w.parent.AssembleKey()\n\tcase 2:\n\t\tasm := w.parent.AssembleValue()\n\t\treturn assemblerRepr(asm.(*_assembler))\n\tdefault:\n\t\treturn _errorAssembler{fmt.Errorf(\"bindnode: too many values in listpairs field\")}\n\t}\n}\n\nfunc (w *_listpairsFieldListAssemblerRepr) Finish() error {\n\treturn nil\n}\n\nfunc (w *_listpairsFieldListAssemblerRepr) ValuePrototype(idx int64) datamodel.NodePrototype {\n\tpanic(\"bindnode TODO: listpairs field ValuePrototype\")\n}\n\n// Note that lists do not have any representation strategy right now.\ntype _listAssemblerRepr _listAssembler\n\nfunc (w *_listAssemblerRepr) AssembleValue() datamodel.NodeAssembler {\n\tasm := (*_listAssembler)(w).AssembleValue()\n\treturn (*_assemblerRepr)(asm.(*_assembler))\n}\n\nfunc (w *_listAssemblerRepr) Finish() error {\n\treturn (*_listAssembler)(w).Finish()\n}\n\nfunc (w *_listAssemblerRepr) ValuePrototype(idx int64) datamodel.NodePrototype {\n\tpanic(\"bindnode TODO: list ValuePrototype\")\n}\n\ntype _unionAssemblerRepr _unionAssembler\n\nfunc (w *_unionAssemblerRepr) AssembleKey() datamodel.NodeAssembler {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Keyed:\n\t\treturn (*_unionAssembler)(w).AssembleKey()\n\tdefault:\n\t\treturn _errorAssembler{fmt.Errorf(\"bindnode AssembleKey TODO: %T\", stg)}\n\t}\n}\n\nfunc (w *_unionAssemblerRepr) AssembleValue() datamodel.NodeAssembler {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Keyed:\n\t\tkey := w.curKey.val.String()\n\t\trevKey := inboundMappedType(w.schemaType, stg, key)\n\t\tw.curKey.val.SetString(revKey)\n\n\t\tvalAsm := (*_unionAssembler)(w).AssembleValue()\n\t\tvalAsm = assemblerRepr(valAsm)\n\t\treturn valAsm\n\tdefault:\n\t\treturn _errorAssembler{fmt.Errorf(\"bindnode AssembleValue TODO: %T\", stg)}\n\t}\n}\n\nfunc (w *_unionAssemblerRepr) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\tif err := w.AssembleKey().AssignString(k); err != nil {\n\t\treturn nil, err\n\t}\n\tam := w.AssembleValue()\n\treturn am, nil\n}\n\nfunc (w *_unionAssemblerRepr) Finish() error {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Keyed:\n\t\treturn (*_unionAssembler)(w).Finish()\n\tdefault:\n\t\treturn fmt.Errorf(\"bindnode Finish TODO: %T\", stg)\n\t}\n}\n\nfunc (w *_unionAssemblerRepr) KeyPrototype() datamodel.NodePrototype {\n\tpanic(\"bindnode TODO\")\n}\n\nfunc (w *_unionAssemblerRepr) ValuePrototype(k string) datamodel.NodePrototype {\n\tpanic(\"bindnode TODO: union ValuePrototype\")\n}\n\ntype _structIteratorRepr _structIterator\n\nfunc (w *_structIteratorRepr) Next() (key, value datamodel.Node, _ error) {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.StructRepresentation_Map:\n\t\tfor {\n\t\t\tkey, value, err := (*_structIterator)(w).Next()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\t\t\tif value.IsAbsent() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tkeyStr, _ := key.AsString()\n\t\t\tmappedKey := outboundMappedKey(stg, keyStr)\n\t\t\tif mappedKey != keyStr {\n\t\t\t\tkey = basicnode.NewString(mappedKey)\n\t\t\t}\n\t\t\treturn key, reprNode(value), nil\n\t\t}\n\tdefault:\n\t\treturn nil, nil, fmt.Errorf(\"bindnode Next TODO: %T\", stg)\n\t}\n}\n\nfunc (w *_structIteratorRepr) Done() bool {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.StructRepresentation_Map:\n\t\t// TODO: the fact that repr map iterators skip absents should be\n\t\t// documented somewhere\n\t\treturn w.nextIndex >= w.reprEnd\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"bindnode Done TODO: %T\", stg))\n\t}\n}\n\ntype _unionIteratorRepr _unionIterator\n\nfunc (w *_unionIteratorRepr) Next() (key, value datamodel.Node, _ error) {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Keyed:\n\t\tkey, value, err := (*_unionIterator)(w).Next()\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tkeyStr, _ := key.AsString()\n\t\tmappedKey := outboundMappedType(stg, keyStr)\n\t\tif mappedKey != keyStr {\n\t\t\tkey = basicnode.NewString(mappedKey)\n\t\t}\n\t\treturn key, reprNode(value), nil\n\tdefault:\n\t\treturn nil, nil, fmt.Errorf(\"bindnode Next TODO: %T\", stg)\n\t}\n}\n\nfunc (w *_unionIteratorRepr) Done() bool {\n\tswitch stg := reprStrategy(w.schemaType).(type) {\n\tcase schema.UnionRepresentation_Keyed:\n\t\treturn (*_unionIterator)(w).Done()\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"bindnode Done TODO: %T\", stg))\n\t}\n}\n"
  },
  {
    "path": "node/bindnode/schema_test.go",
    "content": "package bindnode_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// For now, we simply run all schema tests with Prototype.\n// In the future, forSchemaTest might return multiple engines.\n\nfunc forSchemaTest(name string) []tests.EngineSubtest {\n\tif name == \"Links\" {\n\t\t// TODO(mvdan): support typed links; see https://github.com/ipld/go-ipld-prime/issues/272\n\t\treturn nil\n\t}\n\tif name == \"UnionKeyedComplexChildren\" {\n\t\treturn nil // Specifically, 'InhabitantB/repr-create_with_AK+AV' borks, because it needs representation-level AssignNode to support more.\n\t}\n\treturn []tests.EngineSubtest{{\n\t\tEngine: &bindEngine{},\n\t}}\n}\n\nfunc TestSchema(t *testing.T) {\n\tt.Parallel()\n\n\ttests.SchemaTestAll(t, forSchemaTest)\n}\n\nvar _ tests.Engine = (*bindEngine)(nil)\n\ntype bindEngine struct {\n\tts schema.TypeSystem\n}\n\nfunc (e *bindEngine) Init(t *testing.T, ts schema.TypeSystem) {\n\te.ts = ts\n}\n\nfunc (e *bindEngine) PrototypeByName(name string) datamodel.NodePrototype {\n\twantRepr := strings.HasSuffix(name, \".Repr\")\n\tif wantRepr {\n\t\tname = strings.TrimSuffix(name, \".Repr\")\n\t}\n\tschemaType := e.ts.TypeByName(name)\n\tif wantRepr {\n\t\treturn bindnode.Prototype(nil, schemaType).Representation()\n\t}\n\treturn bindnode.Prototype(nil, schemaType)\n}\n"
  },
  {
    "path": "node/bindnode/testdata/fuzz/FuzzBindnodeViaDagCBOR/164dd28629e6a5637f02c6eaad32eee5bf8ea41ce6d1dae95334a7db7dd6188f",
    "content": "go test fuzz v1\n[]byte(\"\\xa1etypes\\xa0\")\n[]byte(\"\\xf9\\xfc\\x00\")\n"
  },
  {
    "path": "node/bindnode/testdata/fuzz/FuzzBindnodeViaDagCBOR/199afa754020c4587bc87633033b4e56ecdb5ecc2bb0dbac46b799d6c18c5201",
    "content": "go test fuzz v1\n[]byte(\"\\xa1etypes\\xa1d0000\\xa0\")\n[]byte(\"0\")\n"
  },
  {
    "path": "node/bindnode/testdata/fuzz/FuzzBindnodeViaDagCBOR/2c17d42168478a0837ebba66f6aa98bdf4bb81b5196062d0e6b23c8b0325be6a",
    "content": "go test fuzz v1\n[]byte(\"\\xa1etypes\\xa1dRoot\\xa1fstruct\\xa2ffields\\xa2b00\\xa1dtypedBoolb00\\xa1dtypeeBytesnrepresentation\\xa1cmap\\xa0\")\n[]byte(\"0\")\n"
  },
  {
    "path": "node/bindnode/testdata/fuzz/FuzzBindnodeViaDagCBOR/425499b0c3693d87a0b11db10d21c540283dfb88610d114eb5b23485d5c2f342",
    "content": "go test fuzz v1\n[]byte(\"\\xa1etypes\\xa1dRoot\\xa1cmap\\xa2gkeyTypefStringivalueTypecInt\")\n[]byte(\"\\xa2ac0a00\")\n"
  },
  {
    "path": "node/bindnode/testdata/fuzz/FuzzBindnodeViaDagCBOR/636f8e5cdaf52572b826e615a9bdf90f15f8acf2880b467b3949f5356c2ddded",
    "content": "go test fuzz v1\n[]byte(\"\\xa1etypes\\xa1dRoot\\xa1fstruct\\xa2ffields\\xa2b00\\xa1dtyped0000b00\\xa1dtypee00000nrepresentation\\xa1cmap\\xa0\")\n[]byte(\"0\")\n"
  },
  {
    "path": "node/bindnode/testdata/fuzz/FuzzBindnodeViaDagCBOR/669d57fbbe55b8ceb7e78e3ccd3b90e76c4b740d25284a66eac8aac0dbb2475d",
    "content": "go test fuzz v1\n[]byte(\"\\xa1etypes\\xa1dRoot\\xa1eunion\\xa2gmembers\\x82cIntfStringnrepresentation\\xa1ekeyed\\xa2a0c000a0a000000\")\n[]byte(\"\\xa1a00000\")\n"
  },
  {
    "path": "node/bindnode/testdata/fuzz/FuzzBindnodeViaDagCBOR/7f9a6898dead41ba2f5fd4f07f2ddb44d54e7648d66e54982d09996bc720cf56",
    "content": "go test fuzz v1\n[]byte(\"\\xa1etypes\\xa1dRoot\\xa1dlist\\xa1ivalueTypedRootcInt\")\n[]byte(\"\\x810\")\n"
  },
  {
    "path": "node/bindnode/testdata/fuzz/FuzzBindnodeViaDagCBOR/821c248529299bb6b68e443e4b00cc11c6605f766f25e619d85e6d6b40a33dac",
    "content": "go test fuzz v1\n[]byte(\"\\xa1etypes\\xa1dRoot\\xa1denum\\xa2gmembers\\x82c000c000nrepresentation\\xa1cint\\xa2c0000c0000\")\n[]byte(\"a000\")\n"
  },
  {
    "path": "node/bindnode/testdata/fuzz/FuzzBindnodeViaDagCBOR/bf7c410983f3e696a03e743df1bc6f606137871f7fb557af74836b7aa04e56ad",
    "content": "go test fuzz v1\n[]byte(\"\\xa1etypes\\xa0\")\n[]byte(\"\\xf9|\\x00\")\n"
  },
  {
    "path": "node/bindnode/testdata/fuzz/FuzzBindnodeViaDagCBOR/dc95e9aad454ed9109e93b824f92d4bb00c9c778af29e6fcb38a6083c78d7dbb",
    "content": "go test fuzz v1\n[]byte(\"\\xa1etypes\\xa1d0000\\xa1dlist\\xa1ivalueTypea0\")\n[]byte(\"\\xfa\\u007f\\xff00\")\n"
  },
  {
    "path": "node/bindnode/testdata/fuzz/FuzzBindnodeViaDagCBOR/f63d4652cdac3208fc0a0d0b755615320443b60ef80c0ecdef99c9d895ae2124",
    "content": "go test fuzz v1\n[]byte(\"\\xa1etypes\\xa1dRoot\\xa1eunion\\xa2gmembers\\x82cIntfStringnrepresentation\\xa1ekeyed\\xa0\")\n[]byte(\"\\xa1a00\")\n"
  },
  {
    "path": "node/bindnode/testdata/fuzz/FuzzBindnodeViaDagCBOR/fe73a19655fff8b93193c3e90f9cd7b24b10ae0467175cf2264ff3ec135215a6",
    "content": "go test fuzz v1\n[]byte(\"\\xa1etypes\\xa1dRoot\\xa1denum\\xa2gmembers\\x82a1b00nrepresentation\\xa1fstring\\xa2a0a0a0`\")\n[]byte(\"\\u007f\\xff\")\n"
  },
  {
    "path": "node/doc.go",
    "content": "/*\nThe 'node' package gathers various general purpose Node implementations;\nthe first one you should jump to is 'node/basicnode'.\n\nThere's no code in this package itself; it's just for grouping.\n\nThe `Node` interface itself is in the `ipld` package,\nwhich is the parent of this.\n\nThe 'node/mixins' package contains reusable component code for building\nyour own node implementations, should you desire to do so.\nThis includes standardized behavioral tests (!), which are\nin the 'node/mixins/tests' package.\n\nOther planned subpackages include:\na cbor-native Node implementation (which can optimize performance in some\ncases by lazily parsing serial\tdata, and also retaining it as byte slice\nreferences for minimizing reserialization work for small mutations);\na Node implementation which works over golang native types by use of reflection;\na Node implementation which supports Schema type constraints and works\nwithout compile-time/codegen support by delegating storage to another Node implementation;\netc.\n\nYou can create your own Node implementations, too.\nThere's nothing special about being in this package.\n\nOther Node implementations not found here may include those which\nare output from Schema-powered codegen!\n*/\npackage node\n"
  },
  {
    "path": "node/gendemo/doc.go",
    "content": "// The gendemo package contains some what codegen output code,\n// so that it can demonstrate what schema-based codegen looks and acts like.\n//\n// The main purpose is to benchmark things,\n// and to provide an easy-to-look-at _thing_ for prospective users\n// who want to lay eyes on generated code without needing to get up-and-running with the generator themselves.\n//\n// This package is absolutely _not_ full of general purpose node implementations\n// that you should use in _any_ application.\n//\n// The input info for the code generation is in `gen.go` file.\n// (This is currently wired directly in code; in the future, the same instructions\n// will be extracted to an IPLD Schema file and standard tools will be used to process it.)\n// The code generation is triggered by `go:generate` comments in the `doc.go` file.\n\n//go:generate go run gen.go\n\npackage gendemo\n"
  },
  {
    "path": "node/gendemo/gen.go",
    "content": "//go:build ignore\n\npackage main\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\tgengo \"github.com/ipld/go-ipld-prime/schema/gen/go\"\n)\n\nfunc main() {\n\tpkgName := \"gendemo\"\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tadjCfg := &gengo.AdjunctCfg{}\n\tts.Accumulate(schema.SpawnInt(\"Int\"))\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnStruct(\"Msg3\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"whee\", \"Int\", false, false),\n\t\t\tschema.SpawnStructField(\"woot\", \"Int\", false, false),\n\t\t\tschema.SpawnStructField(\"waga\", \"Int\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationMap(nil),\n\t))\n\tts.Accumulate(schema.SpawnMap(\"Map__String__Msg3\",\n\t\t\"String\", \"Msg3\", false))\n\tts.Accumulate(schema.SpawnBool(\"Bar\"))\n\tts.Accumulate(schema.SpawnString(\"Baz\"))\n\tts.Accumulate(schema.SpawnInt(\"Foo\"))\n\tts.Accumulate(schema.SpawnUnion(\"UnionKinded\",\n\t\t[]schema.TypeName{\n\t\t\t\"Foo\",\n\t\t\t\"Bar\",\n\t\t\t\"Baz\",\n\t\t}, schema.SpawnUnionRepresentationKinded(\n\t\t\tmap[datamodel.Kind]schema.TypeName{\n\t\t\t\tdatamodel.Kind_Int:    \"Foo\",\n\t\t\t\tdatamodel.Kind_Bool:   \"Bar\",\n\t\t\t\tdatamodel.Kind_String: \"Baz\",\n\t\t\t}),\n\t))\n\tgengo.Generate(\".\", pkgName, ts, adjCfg)\n}\n"
  },
  {
    "path": "node/gendemo/gendemo_test.go",
    "content": "package gendemo\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nfunc BenchmarkMapStrInt_3n_AssembleStandard(b *testing.B) {\n\ttests.SpecBenchmarkMapStrInt_3n_AssembleStandard(b, _Msg3__Prototype{})\n}\nfunc BenchmarkMapStrInt_3n_AssembleEntry(b *testing.B) {\n\ttests.SpecBenchmarkMapStrInt_3n_AssembleEntry(b, _Msg3__Prototype{})\n}\nfunc BenchmarkMapStrInt_3n_Iteration(b *testing.B) {\n\ttests.SpecBenchmarkMapStrInt_3n_Iteration(b, _Msg3__Prototype{})\n}\nfunc BenchmarkSpec_Marshal_Map3StrInt(b *testing.B) {\n\ttests.BenchmarkSpec_Marshal_Map3StrInt(b, _Msg3__Prototype{})\n}\nfunc BenchmarkSpec_Unmarshal_Map3StrInt(b *testing.B) {\n\ttests.BenchmarkSpec_Unmarshal_Map3StrInt(b, _Msg3__Prototype{})\n}\n\nfunc BenchmarkSpec_Marshal_MapNStrMap3StrInt(b *testing.B) {\n\ttests.BenchmarkSpec_Marshal_MapNStrMap3StrInt(b, _Map__String__Msg3__Prototype{})\n}\nfunc BenchmarkSpec_Unmarshal_MapNStrMap3StrInt(b *testing.B) {\n\ttests.BenchmarkSpec_Unmarshal_MapNStrMap3StrInt(b, _Map__String__Msg3__Prototype{})\n}\n\n// the standard 'walk' benchmarks don't work yet because those use selectors and use the prototype we give them for that, which...\n//  does not fly: cramming selector keys into assemblers meant for struct types from our test corpus?  nope.\n//   this is a known shortcut-become-bug with the design of the 'walk' benchmarks; we'll have to fix soon.\n"
  },
  {
    "path": "node/gendemo/ipldsch_minima.go",
    "content": "package gendemo\n\n// Code generated by go-ipld-prime gengo.  DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nconst (\n\tmidvalue  = schema.Maybe(4)\n\tallowNull = schema.Maybe(5)\n)\n\ntype maState uint8\n\nconst (\n\tmaState_initial maState = iota\n\tmaState_midKey\n\tmaState_expectValue\n\tmaState_midValue\n\tmaState_finished\n)\n\ntype laState uint8\n\nconst (\n\tlaState_initial laState = iota\n\tlaState_midValue\n\tlaState_finished\n)\n\ntype _ErrorThunkAssembler struct {\n\te error\n}\n\nfunc (ea _ErrorThunkAssembler) BeginMap(_ int64) (datamodel.MapAssembler, error)   { return nil, ea.e }\nfunc (ea _ErrorThunkAssembler) BeginList(_ int64) (datamodel.ListAssembler, error) { return nil, ea.e }\nfunc (ea _ErrorThunkAssembler) AssignNull() error                                  { return ea.e }\nfunc (ea _ErrorThunkAssembler) AssignBool(bool) error                              { return ea.e }\nfunc (ea _ErrorThunkAssembler) AssignInt(int64) error                              { return ea.e }\nfunc (ea _ErrorThunkAssembler) AssignFloat(float64) error                          { return ea.e }\nfunc (ea _ErrorThunkAssembler) AssignString(string) error                          { return ea.e }\nfunc (ea _ErrorThunkAssembler) AssignBytes([]byte) error                           { return ea.e }\nfunc (ea _ErrorThunkAssembler) AssignLink(datamodel.Link) error                    { return ea.e }\nfunc (ea _ErrorThunkAssembler) AssignNode(datamodel.Node) error                    { return ea.e }\nfunc (ea _ErrorThunkAssembler) Prototype() datamodel.NodePrototype {\n\tpanic(fmt.Errorf(\"cannot get prototype from error-carrying assembler: already derailed with error: %w\", ea.e))\n}\n"
  },
  {
    "path": "node/gendemo/ipldsch_satisfaction.go",
    "content": "package gendemo\n\n// Code generated by go-ipld-prime gengo.  DO NOT EDIT.\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/mixins\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc (n Bar) Bool() bool {\n\treturn n.x\n}\nfunc (_Bar__Prototype) FromBool(v bool) (Bar, error) {\n\tn := _Bar{v}\n\treturn &n, nil\n}\n\ntype _Bar__Maybe struct {\n\tm schema.Maybe\n\tv _Bar\n}\ntype MaybeBar = *_Bar__Maybe\n\nfunc (m MaybeBar) IsNull() bool {\n\treturn m.m == schema.Maybe_Null\n}\nfunc (m MaybeBar) IsAbsent() bool {\n\treturn m.m == schema.Maybe_Absent\n}\nfunc (m MaybeBar) Exists() bool {\n\treturn m.m == schema.Maybe_Value\n}\nfunc (m MaybeBar) AsNode() datamodel.Node {\n\tswitch m.m {\n\tcase schema.Maybe_Absent:\n\t\treturn datamodel.Absent\n\tcase schema.Maybe_Null:\n\t\treturn datamodel.Null\n\tcase schema.Maybe_Value:\n\t\treturn &m.v\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (m MaybeBar) Must() Bar {\n\tif !m.Exists() {\n\t\tpanic(\"unbox of a maybe rejected\")\n\t}\n\treturn &m.v\n}\n\nvar _ datamodel.Node = (Bar)(&_Bar{})\nvar _ schema.TypedNode = (Bar)(&_Bar{})\n\nfunc (Bar) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Bool\n}\nfunc (Bar) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.Bool{TypeName: \"gendemo.Bar\"}.LookupByString(\"\")\n}\nfunc (Bar) LookupByNode(datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.Bool{TypeName: \"gendemo.Bar\"}.LookupByNode(nil)\n}\nfunc (Bar) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Bool{TypeName: \"gendemo.Bar\"}.LookupByIndex(0)\n}\nfunc (Bar) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.Bool{TypeName: \"gendemo.Bar\"}.LookupBySegment(seg)\n}\nfunc (Bar) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (Bar) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (Bar) Length() int64 {\n\treturn -1\n}\nfunc (Bar) IsAbsent() bool {\n\treturn false\n}\nfunc (Bar) IsNull() bool {\n\treturn false\n}\nfunc (n Bar) AsBool() (bool, error) {\n\treturn n.x, nil\n}\nfunc (Bar) AsInt() (int64, error) {\n\treturn mixins.Bool{TypeName: \"gendemo.Bar\"}.AsInt()\n}\nfunc (Bar) AsFloat() (float64, error) {\n\treturn mixins.Bool{TypeName: \"gendemo.Bar\"}.AsFloat()\n}\nfunc (Bar) AsString() (string, error) {\n\treturn mixins.Bool{TypeName: \"gendemo.Bar\"}.AsString()\n}\nfunc (Bar) AsBytes() ([]byte, error) {\n\treturn mixins.Bool{TypeName: \"gendemo.Bar\"}.AsBytes()\n}\nfunc (Bar) AsLink() (datamodel.Link, error) {\n\treturn mixins.Bool{TypeName: \"gendemo.Bar\"}.AsLink()\n}\nfunc (Bar) Prototype() datamodel.NodePrototype {\n\treturn _Bar__Prototype{}\n}\n\ntype _Bar__Prototype struct{}\n\nfunc (_Bar__Prototype) NewBuilder() datamodel.NodeBuilder {\n\tvar nb _Bar__Builder\n\tnb.Reset()\n\treturn &nb\n}\n\ntype _Bar__Builder struct {\n\t_Bar__Assembler\n}\n\nfunc (nb *_Bar__Builder) Build() datamodel.Node {\n\tif *nb.m != schema.Maybe_Value {\n\t\tpanic(\"invalid state: cannot call Build on an assembler that's not finished\")\n\t}\n\treturn nb.w\n}\nfunc (nb *_Bar__Builder) Reset() {\n\tvar w _Bar\n\tvar m schema.Maybe\n\t*nb = _Bar__Builder{_Bar__Assembler{w: &w, m: &m}}\n}\n\ntype _Bar__Assembler struct {\n\tw *_Bar\n\tm *schema.Maybe\n}\n\nfunc (na *_Bar__Assembler) reset() {}\nfunc (_Bar__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.BoolAssembler{TypeName: \"gendemo.Bar\"}.BeginMap(0)\n}\nfunc (_Bar__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.BoolAssembler{TypeName: \"gendemo.Bar\"}.BeginList(0)\n}\nfunc (na *_Bar__Assembler) AssignNull() error {\n\tswitch *na.m {\n\tcase allowNull:\n\t\t*na.m = schema.Maybe_Null\n\t\treturn nil\n\tcase schema.Maybe_Absent:\n\t\treturn mixins.BoolAssembler{TypeName: \"gendemo.Bar\"}.AssignNull()\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t}\n\tpanic(\"unreachable\")\n}\nfunc (na *_Bar__Assembler) AssignBool(v bool) error {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t}\n\tna.w.x = v\n\t*na.m = schema.Maybe_Value\n\treturn nil\n}\nfunc (_Bar__Assembler) AssignInt(int64) error {\n\treturn mixins.BoolAssembler{TypeName: \"gendemo.Bar\"}.AssignInt(0)\n}\nfunc (_Bar__Assembler) AssignFloat(float64) error {\n\treturn mixins.BoolAssembler{TypeName: \"gendemo.Bar\"}.AssignFloat(0)\n}\nfunc (_Bar__Assembler) AssignString(string) error {\n\treturn mixins.BoolAssembler{TypeName: \"gendemo.Bar\"}.AssignString(\"\")\n}\nfunc (_Bar__Assembler) AssignBytes([]byte) error {\n\treturn mixins.BoolAssembler{TypeName: \"gendemo.Bar\"}.AssignBytes(nil)\n}\nfunc (_Bar__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.BoolAssembler{TypeName: \"gendemo.Bar\"}.AssignLink(nil)\n}\nfunc (na *_Bar__Assembler) AssignNode(v datamodel.Node) error {\n\tif v.IsNull() {\n\t\treturn na.AssignNull()\n\t}\n\tif v2, ok := v.(*_Bar); ok {\n\t\tswitch *na.m {\n\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t}\n\t\t*na.w = *v2\n\t\t*na.m = schema.Maybe_Value\n\t\treturn nil\n\t}\n\tif v2, err := v.AsBool(); err != nil {\n\t\treturn err\n\t} else {\n\t\treturn na.AssignBool(v2)\n\t}\n}\nfunc (_Bar__Assembler) Prototype() datamodel.NodePrototype {\n\treturn _Bar__Prototype{}\n}\nfunc (Bar) Type() schema.Type {\n\treturn nil /*TODO:typelit*/\n}\nfunc (n Bar) Representation() datamodel.Node {\n\treturn (*_Bar__Repr)(n)\n}\n\ntype _Bar__Repr = _Bar\n\nvar _ datamodel.Node = &_Bar__Repr{}\n\ntype _Bar__ReprPrototype = _Bar__Prototype\ntype _Bar__ReprAssembler = _Bar__Assembler\n\nfunc (n Baz) String() string {\n\treturn n.x\n}\nfunc (_Baz__Prototype) fromString(w *_Baz, v string) error {\n\t*w = _Baz{v}\n\treturn nil\n}\nfunc (_Baz__Prototype) FromString(v string) (Baz, error) {\n\tn := _Baz{v}\n\treturn &n, nil\n}\n\ntype _Baz__Maybe struct {\n\tm schema.Maybe\n\tv _Baz\n}\ntype MaybeBaz = *_Baz__Maybe\n\nfunc (m MaybeBaz) IsNull() bool {\n\treturn m.m == schema.Maybe_Null\n}\nfunc (m MaybeBaz) IsAbsent() bool {\n\treturn m.m == schema.Maybe_Absent\n}\nfunc (m MaybeBaz) Exists() bool {\n\treturn m.m == schema.Maybe_Value\n}\nfunc (m MaybeBaz) AsNode() datamodel.Node {\n\tswitch m.m {\n\tcase schema.Maybe_Absent:\n\t\treturn datamodel.Absent\n\tcase schema.Maybe_Null:\n\t\treturn datamodel.Null\n\tcase schema.Maybe_Value:\n\t\treturn &m.v\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (m MaybeBaz) Must() Baz {\n\tif !m.Exists() {\n\t\tpanic(\"unbox of a maybe rejected\")\n\t}\n\treturn &m.v\n}\n\nvar _ datamodel.Node = (Baz)(&_Baz{})\nvar _ schema.TypedNode = (Baz)(&_Baz{})\n\nfunc (Baz) Kind() datamodel.Kind {\n\treturn datamodel.Kind_String\n}\nfunc (Baz) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"gendemo.Baz\"}.LookupByString(\"\")\n}\nfunc (Baz) LookupByNode(datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"gendemo.Baz\"}.LookupByNode(nil)\n}\nfunc (Baz) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"gendemo.Baz\"}.LookupByIndex(0)\n}\nfunc (Baz) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"gendemo.Baz\"}.LookupBySegment(seg)\n}\nfunc (Baz) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (Baz) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (Baz) Length() int64 {\n\treturn -1\n}\nfunc (Baz) IsAbsent() bool {\n\treturn false\n}\nfunc (Baz) IsNull() bool {\n\treturn false\n}\nfunc (Baz) AsBool() (bool, error) {\n\treturn mixins.String{TypeName: \"gendemo.Baz\"}.AsBool()\n}\nfunc (Baz) AsInt() (int64, error) {\n\treturn mixins.String{TypeName: \"gendemo.Baz\"}.AsInt()\n}\nfunc (Baz) AsFloat() (float64, error) {\n\treturn mixins.String{TypeName: \"gendemo.Baz\"}.AsFloat()\n}\nfunc (n Baz) AsString() (string, error) {\n\treturn n.x, nil\n}\nfunc (Baz) AsBytes() ([]byte, error) {\n\treturn mixins.String{TypeName: \"gendemo.Baz\"}.AsBytes()\n}\nfunc (Baz) AsLink() (datamodel.Link, error) {\n\treturn mixins.String{TypeName: \"gendemo.Baz\"}.AsLink()\n}\nfunc (Baz) Prototype() datamodel.NodePrototype {\n\treturn _Baz__Prototype{}\n}\n\ntype _Baz__Prototype struct{}\n\nfunc (_Baz__Prototype) NewBuilder() datamodel.NodeBuilder {\n\tvar nb _Baz__Builder\n\tnb.Reset()\n\treturn &nb\n}\n\ntype _Baz__Builder struct {\n\t_Baz__Assembler\n}\n\nfunc (nb *_Baz__Builder) Build() datamodel.Node {\n\tif *nb.m != schema.Maybe_Value {\n\t\tpanic(\"invalid state: cannot call Build on an assembler that's not finished\")\n\t}\n\treturn nb.w\n}\nfunc (nb *_Baz__Builder) Reset() {\n\tvar w _Baz\n\tvar m schema.Maybe\n\t*nb = _Baz__Builder{_Baz__Assembler{w: &w, m: &m}}\n}\n\ntype _Baz__Assembler struct {\n\tw *_Baz\n\tm *schema.Maybe\n}\n\nfunc (na *_Baz__Assembler) reset() {}\nfunc (_Baz__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Baz\"}.BeginMap(0)\n}\nfunc (_Baz__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Baz\"}.BeginList(0)\n}\nfunc (na *_Baz__Assembler) AssignNull() error {\n\tswitch *na.m {\n\tcase allowNull:\n\t\t*na.m = schema.Maybe_Null\n\t\treturn nil\n\tcase schema.Maybe_Absent:\n\t\treturn mixins.StringAssembler{TypeName: \"gendemo.Baz\"}.AssignNull()\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t}\n\tpanic(\"unreachable\")\n}\nfunc (_Baz__Assembler) AssignBool(bool) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Baz\"}.AssignBool(false)\n}\nfunc (_Baz__Assembler) AssignInt(int64) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Baz\"}.AssignInt(0)\n}\nfunc (_Baz__Assembler) AssignFloat(float64) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Baz\"}.AssignFloat(0)\n}\nfunc (na *_Baz__Assembler) AssignString(v string) error {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t}\n\tna.w.x = v\n\t*na.m = schema.Maybe_Value\n\treturn nil\n}\nfunc (_Baz__Assembler) AssignBytes([]byte) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Baz\"}.AssignBytes(nil)\n}\nfunc (_Baz__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Baz\"}.AssignLink(nil)\n}\nfunc (na *_Baz__Assembler) AssignNode(v datamodel.Node) error {\n\tif v.IsNull() {\n\t\treturn na.AssignNull()\n\t}\n\tif v2, ok := v.(*_Baz); ok {\n\t\tswitch *na.m {\n\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t}\n\t\t*na.w = *v2\n\t\t*na.m = schema.Maybe_Value\n\t\treturn nil\n\t}\n\tif v2, err := v.AsString(); err != nil {\n\t\treturn err\n\t} else {\n\t\treturn na.AssignString(v2)\n\t}\n}\nfunc (_Baz__Assembler) Prototype() datamodel.NodePrototype {\n\treturn _Baz__Prototype{}\n}\nfunc (Baz) Type() schema.Type {\n\treturn nil /*TODO:typelit*/\n}\nfunc (n Baz) Representation() datamodel.Node {\n\treturn (*_Baz__Repr)(n)\n}\n\ntype _Baz__Repr = _Baz\n\nvar _ datamodel.Node = &_Baz__Repr{}\n\ntype _Baz__ReprPrototype = _Baz__Prototype\ntype _Baz__ReprAssembler = _Baz__Assembler\n\nfunc (n Foo) Int() int64 {\n\treturn n.x\n}\nfunc (_Foo__Prototype) FromInt(v int64) (Foo, error) {\n\tn := _Foo{v}\n\treturn &n, nil\n}\n\ntype _Foo__Maybe struct {\n\tm schema.Maybe\n\tv _Foo\n}\ntype MaybeFoo = *_Foo__Maybe\n\nfunc (m MaybeFoo) IsNull() bool {\n\treturn m.m == schema.Maybe_Null\n}\nfunc (m MaybeFoo) IsAbsent() bool {\n\treturn m.m == schema.Maybe_Absent\n}\nfunc (m MaybeFoo) Exists() bool {\n\treturn m.m == schema.Maybe_Value\n}\nfunc (m MaybeFoo) AsNode() datamodel.Node {\n\tswitch m.m {\n\tcase schema.Maybe_Absent:\n\t\treturn datamodel.Absent\n\tcase schema.Maybe_Null:\n\t\treturn datamodel.Null\n\tcase schema.Maybe_Value:\n\t\treturn &m.v\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (m MaybeFoo) Must() Foo {\n\tif !m.Exists() {\n\t\tpanic(\"unbox of a maybe rejected\")\n\t}\n\treturn &m.v\n}\n\nvar _ datamodel.Node = (Foo)(&_Foo{})\nvar _ schema.TypedNode = (Foo)(&_Foo{})\n\nfunc (Foo) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Int\n}\nfunc (Foo) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Foo\"}.LookupByString(\"\")\n}\nfunc (Foo) LookupByNode(datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Foo\"}.LookupByNode(nil)\n}\nfunc (Foo) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Foo\"}.LookupByIndex(0)\n}\nfunc (Foo) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Foo\"}.LookupBySegment(seg)\n}\nfunc (Foo) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (Foo) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (Foo) Length() int64 {\n\treturn -1\n}\nfunc (Foo) IsAbsent() bool {\n\treturn false\n}\nfunc (Foo) IsNull() bool {\n\treturn false\n}\nfunc (Foo) AsBool() (bool, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Foo\"}.AsBool()\n}\nfunc (n Foo) AsInt() (int64, error) {\n\treturn n.x, nil\n}\nfunc (Foo) AsFloat() (float64, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Foo\"}.AsFloat()\n}\nfunc (Foo) AsString() (string, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Foo\"}.AsString()\n}\nfunc (Foo) AsBytes() ([]byte, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Foo\"}.AsBytes()\n}\nfunc (Foo) AsLink() (datamodel.Link, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Foo\"}.AsLink()\n}\nfunc (Foo) Prototype() datamodel.NodePrototype {\n\treturn _Foo__Prototype{}\n}\n\ntype _Foo__Prototype struct{}\n\nfunc (_Foo__Prototype) NewBuilder() datamodel.NodeBuilder {\n\tvar nb _Foo__Builder\n\tnb.Reset()\n\treturn &nb\n}\n\ntype _Foo__Builder struct {\n\t_Foo__Assembler\n}\n\nfunc (nb *_Foo__Builder) Build() datamodel.Node {\n\tif *nb.m != schema.Maybe_Value {\n\t\tpanic(\"invalid state: cannot call Build on an assembler that's not finished\")\n\t}\n\treturn nb.w\n}\nfunc (nb *_Foo__Builder) Reset() {\n\tvar w _Foo\n\tvar m schema.Maybe\n\t*nb = _Foo__Builder{_Foo__Assembler{w: &w, m: &m}}\n}\n\ntype _Foo__Assembler struct {\n\tw *_Foo\n\tm *schema.Maybe\n}\n\nfunc (na *_Foo__Assembler) reset() {}\nfunc (_Foo__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.IntAssembler{TypeName: \"gendemo.Foo\"}.BeginMap(0)\n}\nfunc (_Foo__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.IntAssembler{TypeName: \"gendemo.Foo\"}.BeginList(0)\n}\nfunc (na *_Foo__Assembler) AssignNull() error {\n\tswitch *na.m {\n\tcase allowNull:\n\t\t*na.m = schema.Maybe_Null\n\t\treturn nil\n\tcase schema.Maybe_Absent:\n\t\treturn mixins.IntAssembler{TypeName: \"gendemo.Foo\"}.AssignNull()\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t}\n\tpanic(\"unreachable\")\n}\nfunc (_Foo__Assembler) AssignBool(bool) error {\n\treturn mixins.IntAssembler{TypeName: \"gendemo.Foo\"}.AssignBool(false)\n}\nfunc (na *_Foo__Assembler) AssignInt(v int64) error {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t}\n\tna.w.x = v\n\t*na.m = schema.Maybe_Value\n\treturn nil\n}\nfunc (_Foo__Assembler) AssignFloat(float64) error {\n\treturn mixins.IntAssembler{TypeName: \"gendemo.Foo\"}.AssignFloat(0)\n}\nfunc (_Foo__Assembler) AssignString(string) error {\n\treturn mixins.IntAssembler{TypeName: \"gendemo.Foo\"}.AssignString(\"\")\n}\nfunc (_Foo__Assembler) AssignBytes([]byte) error {\n\treturn mixins.IntAssembler{TypeName: \"gendemo.Foo\"}.AssignBytes(nil)\n}\nfunc (_Foo__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.IntAssembler{TypeName: \"gendemo.Foo\"}.AssignLink(nil)\n}\nfunc (na *_Foo__Assembler) AssignNode(v datamodel.Node) error {\n\tif v.IsNull() {\n\t\treturn na.AssignNull()\n\t}\n\tif v2, ok := v.(*_Foo); ok {\n\t\tswitch *na.m {\n\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t}\n\t\t*na.w = *v2\n\t\t*na.m = schema.Maybe_Value\n\t\treturn nil\n\t}\n\tif v2, err := v.AsInt(); err != nil {\n\t\treturn err\n\t} else {\n\t\treturn na.AssignInt(v2)\n\t}\n}\nfunc (_Foo__Assembler) Prototype() datamodel.NodePrototype {\n\treturn _Foo__Prototype{}\n}\nfunc (Foo) Type() schema.Type {\n\treturn nil /*TODO:typelit*/\n}\nfunc (n Foo) Representation() datamodel.Node {\n\treturn (*_Foo__Repr)(n)\n}\n\ntype _Foo__Repr = _Foo\n\nvar _ datamodel.Node = &_Foo__Repr{}\n\ntype _Foo__ReprPrototype = _Foo__Prototype\ntype _Foo__ReprAssembler = _Foo__Assembler\n\nfunc (n Int) Int() int64 {\n\treturn n.x\n}\nfunc (_Int__Prototype) FromInt(v int64) (Int, error) {\n\tn := _Int{v}\n\treturn &n, nil\n}\n\ntype _Int__Maybe struct {\n\tm schema.Maybe\n\tv _Int\n}\ntype MaybeInt = *_Int__Maybe\n\nfunc (m MaybeInt) IsNull() bool {\n\treturn m.m == schema.Maybe_Null\n}\nfunc (m MaybeInt) IsAbsent() bool {\n\treturn m.m == schema.Maybe_Absent\n}\nfunc (m MaybeInt) Exists() bool {\n\treturn m.m == schema.Maybe_Value\n}\nfunc (m MaybeInt) AsNode() datamodel.Node {\n\tswitch m.m {\n\tcase schema.Maybe_Absent:\n\t\treturn datamodel.Absent\n\tcase schema.Maybe_Null:\n\t\treturn datamodel.Null\n\tcase schema.Maybe_Value:\n\t\treturn &m.v\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (m MaybeInt) Must() Int {\n\tif !m.Exists() {\n\t\tpanic(\"unbox of a maybe rejected\")\n\t}\n\treturn &m.v\n}\n\nvar _ datamodel.Node = (Int)(&_Int{})\nvar _ schema.TypedNode = (Int)(&_Int{})\n\nfunc (Int) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Int\n}\nfunc (Int) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Int\"}.LookupByString(\"\")\n}\nfunc (Int) LookupByNode(datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Int\"}.LookupByNode(nil)\n}\nfunc (Int) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Int\"}.LookupByIndex(0)\n}\nfunc (Int) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Int\"}.LookupBySegment(seg)\n}\nfunc (Int) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (Int) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (Int) Length() int64 {\n\treturn -1\n}\nfunc (Int) IsAbsent() bool {\n\treturn false\n}\nfunc (Int) IsNull() bool {\n\treturn false\n}\nfunc (Int) AsBool() (bool, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Int\"}.AsBool()\n}\nfunc (n Int) AsInt() (int64, error) {\n\treturn n.x, nil\n}\nfunc (Int) AsFloat() (float64, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Int\"}.AsFloat()\n}\nfunc (Int) AsString() (string, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Int\"}.AsString()\n}\nfunc (Int) AsBytes() ([]byte, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Int\"}.AsBytes()\n}\nfunc (Int) AsLink() (datamodel.Link, error) {\n\treturn mixins.Int{TypeName: \"gendemo.Int\"}.AsLink()\n}\nfunc (Int) Prototype() datamodel.NodePrototype {\n\treturn _Int__Prototype{}\n}\n\ntype _Int__Prototype struct{}\n\nfunc (_Int__Prototype) NewBuilder() datamodel.NodeBuilder {\n\tvar nb _Int__Builder\n\tnb.Reset()\n\treturn &nb\n}\n\ntype _Int__Builder struct {\n\t_Int__Assembler\n}\n\nfunc (nb *_Int__Builder) Build() datamodel.Node {\n\tif *nb.m != schema.Maybe_Value {\n\t\tpanic(\"invalid state: cannot call Build on an assembler that's not finished\")\n\t}\n\treturn nb.w\n}\nfunc (nb *_Int__Builder) Reset() {\n\tvar w _Int\n\tvar m schema.Maybe\n\t*nb = _Int__Builder{_Int__Assembler{w: &w, m: &m}}\n}\n\ntype _Int__Assembler struct {\n\tw *_Int\n\tm *schema.Maybe\n}\n\nfunc (na *_Int__Assembler) reset() {}\nfunc (_Int__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.IntAssembler{TypeName: \"gendemo.Int\"}.BeginMap(0)\n}\nfunc (_Int__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.IntAssembler{TypeName: \"gendemo.Int\"}.BeginList(0)\n}\nfunc (na *_Int__Assembler) AssignNull() error {\n\tswitch *na.m {\n\tcase allowNull:\n\t\t*na.m = schema.Maybe_Null\n\t\treturn nil\n\tcase schema.Maybe_Absent:\n\t\treturn mixins.IntAssembler{TypeName: \"gendemo.Int\"}.AssignNull()\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t}\n\tpanic(\"unreachable\")\n}\nfunc (_Int__Assembler) AssignBool(bool) error {\n\treturn mixins.IntAssembler{TypeName: \"gendemo.Int\"}.AssignBool(false)\n}\nfunc (na *_Int__Assembler) AssignInt(v int64) error {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t}\n\tna.w.x = v\n\t*na.m = schema.Maybe_Value\n\treturn nil\n}\nfunc (_Int__Assembler) AssignFloat(float64) error {\n\treturn mixins.IntAssembler{TypeName: \"gendemo.Int\"}.AssignFloat(0)\n}\nfunc (_Int__Assembler) AssignString(string) error {\n\treturn mixins.IntAssembler{TypeName: \"gendemo.Int\"}.AssignString(\"\")\n}\nfunc (_Int__Assembler) AssignBytes([]byte) error {\n\treturn mixins.IntAssembler{TypeName: \"gendemo.Int\"}.AssignBytes(nil)\n}\nfunc (_Int__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.IntAssembler{TypeName: \"gendemo.Int\"}.AssignLink(nil)\n}\nfunc (na *_Int__Assembler) AssignNode(v datamodel.Node) error {\n\tif v.IsNull() {\n\t\treturn na.AssignNull()\n\t}\n\tif v2, ok := v.(*_Int); ok {\n\t\tswitch *na.m {\n\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t}\n\t\t*na.w = *v2\n\t\t*na.m = schema.Maybe_Value\n\t\treturn nil\n\t}\n\tif v2, err := v.AsInt(); err != nil {\n\t\treturn err\n\t} else {\n\t\treturn na.AssignInt(v2)\n\t}\n}\nfunc (_Int__Assembler) Prototype() datamodel.NodePrototype {\n\treturn _Int__Prototype{}\n}\nfunc (Int) Type() schema.Type {\n\treturn nil /*TODO:typelit*/\n}\nfunc (n Int) Representation() datamodel.Node {\n\treturn (*_Int__Repr)(n)\n}\n\ntype _Int__Repr = _Int\n\nvar _ datamodel.Node = &_Int__Repr{}\n\ntype _Int__ReprPrototype = _Int__Prototype\ntype _Int__ReprAssembler = _Int__Assembler\n\nfunc (n *_Map__String__Msg3) Lookup(k String) Msg3 {\n\tv, exists := n.m[*k]\n\tif !exists {\n\t\treturn nil\n\t}\n\treturn v\n}\nfunc (n *_Map__String__Msg3) LookupMaybe(k String) MaybeMsg3 {\n\tv, exists := n.m[*k]\n\tif !exists {\n\t\treturn &_Map__String__Msg3__valueAbsent\n\t}\n\treturn &_Msg3__Maybe{\n\t\tm: schema.Maybe_Value,\n\t\tv: v,\n\t}\n}\n\nvar _Map__String__Msg3__valueAbsent = _Msg3__Maybe{m: schema.Maybe_Absent}\n\nfunc (n Map__String__Msg3) Iterator() *Map__String__Msg3__Itr {\n\treturn &Map__String__Msg3__Itr{n, 0}\n}\n\ntype Map__String__Msg3__Itr struct {\n\tn   Map__String__Msg3\n\tidx int\n}\n\nfunc (itr *Map__String__Msg3__Itr) Next() (k String, v Msg3) {\n\tif itr.idx >= len(itr.n.t) {\n\t\treturn nil, nil\n\t}\n\tx := &itr.n.t[itr.idx]\n\tk = &x.k\n\tv = &x.v\n\titr.idx++\n\treturn\n}\nfunc (itr *Map__String__Msg3__Itr) Done() bool {\n\treturn itr.idx >= len(itr.n.t)\n}\n\ntype _Map__String__Msg3__Maybe struct {\n\tm schema.Maybe\n\tv _Map__String__Msg3\n}\ntype MaybeMap__String__Msg3 = *_Map__String__Msg3__Maybe\n\nfunc (m MaybeMap__String__Msg3) IsNull() bool {\n\treturn m.m == schema.Maybe_Null\n}\nfunc (m MaybeMap__String__Msg3) IsAbsent() bool {\n\treturn m.m == schema.Maybe_Absent\n}\nfunc (m MaybeMap__String__Msg3) Exists() bool {\n\treturn m.m == schema.Maybe_Value\n}\nfunc (m MaybeMap__String__Msg3) AsNode() datamodel.Node {\n\tswitch m.m {\n\tcase schema.Maybe_Absent:\n\t\treturn datamodel.Absent\n\tcase schema.Maybe_Null:\n\t\treturn datamodel.Null\n\tcase schema.Maybe_Value:\n\t\treturn &m.v\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (m MaybeMap__String__Msg3) Must() Map__String__Msg3 {\n\tif !m.Exists() {\n\t\tpanic(\"unbox of a maybe rejected\")\n\t}\n\treturn &m.v\n}\n\nvar _ datamodel.Node = (Map__String__Msg3)(&_Map__String__Msg3{})\nvar _ schema.TypedNode = (Map__String__Msg3)(&_Map__String__Msg3{})\n\nfunc (Map__String__Msg3) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Map\n}\nfunc (n Map__String__Msg3) LookupByString(k string) (datamodel.Node, error) {\n\tvar k2 _String\n\tif err := (_String__ReprPrototype{}).fromString(&k2, k); err != nil {\n\t\treturn nil, err // TODO wrap in some kind of ErrInvalidKey\n\t}\n\tv, exists := n.m[k2]\n\tif !exists {\n\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(k)}\n\t}\n\treturn v, nil\n}\nfunc (n Map__String__Msg3) LookupByNode(k datamodel.Node) (datamodel.Node, error) {\n\tk2, ok := k.(String)\n\tif !ok {\n\t\tpanic(\"todo invalid key type error\")\n\t\t// 'schema.ErrInvalidKey{TypeName:\"gendemo.Map__String__Msg3\", Key:&_String{k}}' doesn't quite cut it: need room to explain the type, and it's not guaranteed k can be turned into a string at all\n\t}\n\tv, exists := n.m[*k2]\n\tif !exists {\n\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(k2.String())}\n\t}\n\treturn v, nil\n}\nfunc (Map__String__Msg3) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Map__String__Msg3\"}.LookupByIndex(0)\n}\nfunc (n Map__String__Msg3) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn n.LookupByString(seg.String())\n}\nfunc (n Map__String__Msg3) MapIterator() datamodel.MapIterator {\n\treturn &_Map__String__Msg3__MapItr{n, 0}\n}\n\ntype _Map__String__Msg3__MapItr struct {\n\tn   Map__String__Msg3\n\tidx int\n}\n\nfunc (itr *_Map__String__Msg3__MapItr) Next() (k datamodel.Node, v datamodel.Node, _ error) {\n\tif itr.idx >= len(itr.n.t) {\n\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t}\n\tx := &itr.n.t[itr.idx]\n\tk = &x.k\n\tv = &x.v\n\titr.idx++\n\treturn\n}\nfunc (itr *_Map__String__Msg3__MapItr) Done() bool {\n\treturn itr.idx >= len(itr.n.t)\n}\n\nfunc (Map__String__Msg3) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (n Map__String__Msg3) Length() int64 {\n\treturn int64(len(n.t))\n}\nfunc (Map__String__Msg3) IsAbsent() bool {\n\treturn false\n}\nfunc (Map__String__Msg3) IsNull() bool {\n\treturn false\n}\nfunc (Map__String__Msg3) AsBool() (bool, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Map__String__Msg3\"}.AsBool()\n}\nfunc (Map__String__Msg3) AsInt() (int64, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Map__String__Msg3\"}.AsInt()\n}\nfunc (Map__String__Msg3) AsFloat() (float64, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Map__String__Msg3\"}.AsFloat()\n}\nfunc (Map__String__Msg3) AsString() (string, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Map__String__Msg3\"}.AsString()\n}\nfunc (Map__String__Msg3) AsBytes() ([]byte, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Map__String__Msg3\"}.AsBytes()\n}\nfunc (Map__String__Msg3) AsLink() (datamodel.Link, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Map__String__Msg3\"}.AsLink()\n}\nfunc (Map__String__Msg3) Prototype() datamodel.NodePrototype {\n\treturn _Map__String__Msg3__Prototype{}\n}\n\ntype _Map__String__Msg3__Prototype struct{}\n\nfunc (_Map__String__Msg3__Prototype) NewBuilder() datamodel.NodeBuilder {\n\tvar nb _Map__String__Msg3__Builder\n\tnb.Reset()\n\treturn &nb\n}\n\ntype _Map__String__Msg3__Builder struct {\n\t_Map__String__Msg3__Assembler\n}\n\nfunc (nb *_Map__String__Msg3__Builder) Build() datamodel.Node {\n\tif *nb.m != schema.Maybe_Value {\n\t\tpanic(\"invalid state: cannot call Build on an assembler that's not finished\")\n\t}\n\treturn nb.w\n}\nfunc (nb *_Map__String__Msg3__Builder) Reset() {\n\tvar w _Map__String__Msg3\n\tvar m schema.Maybe\n\t*nb = _Map__String__Msg3__Builder{_Map__String__Msg3__Assembler{w: &w, m: &m}}\n}\n\ntype _Map__String__Msg3__Assembler struct {\n\tw     *_Map__String__Msg3\n\tm     *schema.Maybe\n\tstate maState\n\n\tcm schema.Maybe\n\tka _String__Assembler\n\tva _Msg3__Assembler\n}\n\nfunc (na *_Map__String__Msg3__Assembler) reset() {\n\tna.state = maState_initial\n\tna.ka.reset()\n\tna.va.reset()\n}\nfunc (na *_Map__String__Msg3__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: it makes no sense to 'begin' twice on the same assembler!\")\n\t}\n\t*na.m = midvalue\n\tif sizeHint < 0 {\n\t\tsizeHint = 0\n\t}\n\tna.w.m = make(map[_String]*_Msg3, sizeHint)\n\tna.w.t = make([]_Map__String__Msg3__entry, 0, sizeHint)\n\treturn na, nil\n}\nfunc (_Map__String__Msg3__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3\"}.BeginList(0)\n}\nfunc (na *_Map__String__Msg3__Assembler) AssignNull() error {\n\tswitch *na.m {\n\tcase allowNull:\n\t\t*na.m = schema.Maybe_Null\n\t\treturn nil\n\tcase schema.Maybe_Absent:\n\t\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3\"}.AssignNull()\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t}\n\tpanic(\"unreachable\")\n}\nfunc (_Map__String__Msg3__Assembler) AssignBool(bool) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3\"}.AssignBool(false)\n}\nfunc (_Map__String__Msg3__Assembler) AssignInt(int64) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3\"}.AssignInt(0)\n}\nfunc (_Map__String__Msg3__Assembler) AssignFloat(float64) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3\"}.AssignFloat(0)\n}\nfunc (_Map__String__Msg3__Assembler) AssignString(string) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3\"}.AssignString(\"\")\n}\nfunc (_Map__String__Msg3__Assembler) AssignBytes([]byte) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3\"}.AssignBytes(nil)\n}\nfunc (_Map__String__Msg3__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3\"}.AssignLink(nil)\n}\nfunc (na *_Map__String__Msg3__Assembler) AssignNode(v datamodel.Node) error {\n\tif v.IsNull() {\n\t\treturn na.AssignNull()\n\t}\n\tif v2, ok := v.(*_Map__String__Msg3); ok {\n\t\tswitch *na.m {\n\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\tcase midvalue:\n\t\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t\t}\n\t\t*na.w = *v2\n\t\t*na.m = schema.Maybe_Value\n\t\treturn nil\n\t}\n\tif v.Kind() != datamodel.Kind_Map {\n\t\treturn datamodel.ErrWrongKind{TypeName: \"gendemo.Map__String__Msg3\", MethodName: \"AssignNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: v.Kind()}\n\t}\n\titr := v.MapIterator()\n\tfor !itr.Done() {\n\t\tk, v, err := itr.Next()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := na.AssembleKey().AssignNode(k); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn na.Finish()\n}\nfunc (_Map__String__Msg3__Assembler) Prototype() datamodel.NodePrototype {\n\treturn _Map__String__Msg3__Prototype{}\n}\nfunc (ma *_Map__String__Msg3__Assembler) keyFinishTidy() bool {\n\tswitch ma.cm {\n\tcase schema.Maybe_Value:\n\t\tma.ka.w = nil\n\t\ttz := &ma.w.t[len(ma.w.t)-1]\n\t\tma.cm = schema.Maybe_Absent\n\t\tma.state = maState_expectValue\n\t\tma.w.m[tz.k] = &tz.v\n\t\tma.va.w = &tz.v\n\t\tma.va.m = &ma.cm\n\t\tma.ka.reset()\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\nfunc (ma *_Map__String__Msg3__Assembler) valueFinishTidy() bool {\n\tswitch ma.cm {\n\tcase schema.Maybe_Value:\n\t\tma.va.w = nil\n\t\tma.cm = schema.Maybe_Absent\n\t\tma.state = maState_initial\n\t\tma.va.reset()\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\nfunc (ma *_Map__String__Msg3__Assembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling another key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called on an assembler that's already finished\")\n\t}\n\n\tvar k2 _String\n\tif err := (_String__ReprPrototype{}).fromString(&k2, k); err != nil {\n\t\treturn nil, err // TODO wrap in some kind of ErrInvalidKey\n\t}\n\tif _, exists := ma.w.m[k2]; exists {\n\t\treturn nil, datamodel.ErrRepeatedMapKey{Key: &k2}\n\t}\n\tma.w.t = append(ma.w.t, _Map__String__Msg3__entry{k: k2})\n\ttz := &ma.w.t[len(ma.w.t)-1]\n\tma.state = maState_midValue\n\n\tma.w.m[k2] = &tz.v\n\tma.va.w = &tz.v\n\tma.va.m = &ma.cm\n\treturn &ma.va, nil\n}\nfunc (ma *_Map__String__Msg3__Assembler) AssembleKey() datamodel.NodeAssembler {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling another key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: AssembleKey cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleKey cannot be called on an assembler that's already finished\")\n\t}\n\tma.w.t = append(ma.w.t, _Map__String__Msg3__entry{})\n\tma.state = maState_midKey\n\tma.ka.m = &ma.cm\n\tma.ka.w = &ma.w.t[len(ma.w.t)-1].k\n\treturn &ma.ka\n}\nfunc (ma *_Map__String__Msg3__Assembler) AssembleValue() datamodel.NodeAssembler {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\tpanic(\"invalid state: AssembleValue cannot be called when no key is primed\")\n\tcase maState_midKey:\n\t\tif !ma.keyFinishTidy() {\n\t\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling a key\")\n\t\t} // if tidy success: carry on\n\tcase maState_expectValue:\n\t\t// carry on\n\tcase maState_midValue:\n\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling another value\")\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleValue cannot be called on an assembler that's already finished\")\n\t}\n\tma.state = maState_midValue\n\treturn &ma.va\n}\nfunc (ma *_Map__String__Msg3__Assembler) Finish() error {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: Finish cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on\n\tcase maState_finished:\n\t\tpanic(\"invalid state: Finish cannot be called on an assembler that's already finished\")\n\t}\n\tma.state = maState_finished\n\t*ma.m = schema.Maybe_Value\n\treturn nil\n}\nfunc (ma *_Map__String__Msg3__Assembler) KeyPrototype() datamodel.NodePrototype {\n\treturn _String__Prototype{}\n}\nfunc (ma *_Map__String__Msg3__Assembler) ValuePrototype(_ string) datamodel.NodePrototype {\n\treturn _Msg3__Prototype{}\n}\nfunc (Map__String__Msg3) Type() schema.Type {\n\treturn nil /*TODO:typelit*/\n}\nfunc (n Map__String__Msg3) Representation() datamodel.Node {\n\treturn (*_Map__String__Msg3__Repr)(n)\n}\n\ntype _Map__String__Msg3__Repr _Map__String__Msg3\n\nvar _ datamodel.Node = &_Map__String__Msg3__Repr{}\n\nfunc (_Map__String__Msg3__Repr) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Map\n}\nfunc (nr *_Map__String__Msg3__Repr) LookupByString(k string) (datamodel.Node, error) {\n\tv, err := (Map__String__Msg3)(nr).LookupByString(k)\n\tif err != nil || v == datamodel.Null {\n\t\treturn v, err\n\t}\n\treturn v.(Msg3).Representation(), nil\n}\nfunc (nr *_Map__String__Msg3__Repr) LookupByNode(k datamodel.Node) (datamodel.Node, error) {\n\tv, err := (Map__String__Msg3)(nr).LookupByNode(k)\n\tif err != nil || v == datamodel.Null {\n\t\treturn v, err\n\t}\n\treturn v.(Msg3).Representation(), nil\n}\nfunc (_Map__String__Msg3__Repr) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Map__String__Msg3.Repr\"}.LookupByIndex(0)\n}\nfunc (n _Map__String__Msg3__Repr) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn n.LookupByString(seg.String())\n}\nfunc (nr *_Map__String__Msg3__Repr) MapIterator() datamodel.MapIterator {\n\treturn &_Map__String__Msg3__ReprMapItr{(Map__String__Msg3)(nr), 0}\n}\n\ntype _Map__String__Msg3__ReprMapItr _Map__String__Msg3__MapItr\n\nfunc (itr *_Map__String__Msg3__ReprMapItr) Next() (k datamodel.Node, v datamodel.Node, err error) {\n\tk, v, err = (*_Map__String__Msg3__MapItr)(itr).Next()\n\tif err != nil || v == datamodel.Null {\n\t\treturn\n\t}\n\treturn k, v.(Msg3).Representation(), nil\n}\nfunc (itr *_Map__String__Msg3__ReprMapItr) Done() bool {\n\treturn (*_Map__String__Msg3__MapItr)(itr).Done()\n}\n\nfunc (_Map__String__Msg3__Repr) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (rn *_Map__String__Msg3__Repr) Length() int64 {\n\treturn int64(len(rn.t))\n}\nfunc (_Map__String__Msg3__Repr) IsAbsent() bool {\n\treturn false\n}\nfunc (_Map__String__Msg3__Repr) IsNull() bool {\n\treturn false\n}\nfunc (_Map__String__Msg3__Repr) AsBool() (bool, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Map__String__Msg3.Repr\"}.AsBool()\n}\nfunc (_Map__String__Msg3__Repr) AsInt() (int64, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Map__String__Msg3.Repr\"}.AsInt()\n}\nfunc (_Map__String__Msg3__Repr) AsFloat() (float64, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Map__String__Msg3.Repr\"}.AsFloat()\n}\nfunc (_Map__String__Msg3__Repr) AsString() (string, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Map__String__Msg3.Repr\"}.AsString()\n}\nfunc (_Map__String__Msg3__Repr) AsBytes() ([]byte, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Map__String__Msg3.Repr\"}.AsBytes()\n}\nfunc (_Map__String__Msg3__Repr) AsLink() (datamodel.Link, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Map__String__Msg3.Repr\"}.AsLink()\n}\nfunc (_Map__String__Msg3__Repr) Prototype() datamodel.NodePrototype {\n\treturn _Map__String__Msg3__ReprPrototype{}\n}\n\ntype _Map__String__Msg3__ReprPrototype struct{}\n\nfunc (_Map__String__Msg3__ReprPrototype) NewBuilder() datamodel.NodeBuilder {\n\tvar nb _Map__String__Msg3__ReprBuilder\n\tnb.Reset()\n\treturn &nb\n}\n\ntype _Map__String__Msg3__ReprBuilder struct {\n\t_Map__String__Msg3__ReprAssembler\n}\n\nfunc (nb *_Map__String__Msg3__ReprBuilder) Build() datamodel.Node {\n\tif *nb.m != schema.Maybe_Value {\n\t\tpanic(\"invalid state: cannot call Build on an assembler that's not finished\")\n\t}\n\treturn nb.w\n}\nfunc (nb *_Map__String__Msg3__ReprBuilder) Reset() {\n\tvar w _Map__String__Msg3\n\tvar m schema.Maybe\n\t*nb = _Map__String__Msg3__ReprBuilder{_Map__String__Msg3__ReprAssembler{w: &w, m: &m}}\n}\n\ntype _Map__String__Msg3__ReprAssembler struct {\n\tw     *_Map__String__Msg3\n\tm     *schema.Maybe\n\tstate maState\n\n\tcm schema.Maybe\n\tka _String__ReprAssembler\n\tva _Msg3__ReprAssembler\n}\n\nfunc (na *_Map__String__Msg3__ReprAssembler) reset() {\n\tna.state = maState_initial\n\tna.ka.reset()\n\tna.va.reset()\n}\nfunc (na *_Map__String__Msg3__ReprAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: it makes no sense to 'begin' twice on the same assembler!\")\n\t}\n\t*na.m = midvalue\n\tif sizeHint < 0 {\n\t\tsizeHint = 0\n\t}\n\tna.w.m = make(map[_String]*_Msg3, sizeHint)\n\tna.w.t = make([]_Map__String__Msg3__entry, 0, sizeHint)\n\treturn na, nil\n}\nfunc (_Map__String__Msg3__ReprAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3.Repr\"}.BeginList(0)\n}\nfunc (na *_Map__String__Msg3__ReprAssembler) AssignNull() error {\n\tswitch *na.m {\n\tcase allowNull:\n\t\t*na.m = schema.Maybe_Null\n\t\treturn nil\n\tcase schema.Maybe_Absent:\n\t\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3.Repr.Repr\"}.AssignNull()\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t}\n\tpanic(\"unreachable\")\n}\nfunc (_Map__String__Msg3__ReprAssembler) AssignBool(bool) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3.Repr\"}.AssignBool(false)\n}\nfunc (_Map__String__Msg3__ReprAssembler) AssignInt(int64) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3.Repr\"}.AssignInt(0)\n}\nfunc (_Map__String__Msg3__ReprAssembler) AssignFloat(float64) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3.Repr\"}.AssignFloat(0)\n}\nfunc (_Map__String__Msg3__ReprAssembler) AssignString(string) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3.Repr\"}.AssignString(\"\")\n}\nfunc (_Map__String__Msg3__ReprAssembler) AssignBytes([]byte) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3.Repr\"}.AssignBytes(nil)\n}\nfunc (_Map__String__Msg3__ReprAssembler) AssignLink(datamodel.Link) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Map__String__Msg3.Repr\"}.AssignLink(nil)\n}\nfunc (na *_Map__String__Msg3__ReprAssembler) AssignNode(v datamodel.Node) error {\n\tif v.IsNull() {\n\t\treturn na.AssignNull()\n\t}\n\tif v2, ok := v.(*_Map__String__Msg3); ok {\n\t\tswitch *na.m {\n\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\tcase midvalue:\n\t\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t\t}\n\t\t*na.w = *v2\n\t\t*na.m = schema.Maybe_Value\n\t\treturn nil\n\t}\n\tif v.Kind() != datamodel.Kind_Map {\n\t\treturn datamodel.ErrWrongKind{TypeName: \"gendemo.Map__String__Msg3.Repr\", MethodName: \"AssignNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: v.Kind()}\n\t}\n\titr := v.MapIterator()\n\tfor !itr.Done() {\n\t\tk, v, err := itr.Next()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := na.AssembleKey().AssignNode(k); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn na.Finish()\n}\nfunc (_Map__String__Msg3__ReprAssembler) Prototype() datamodel.NodePrototype {\n\treturn _Map__String__Msg3__ReprPrototype{}\n}\nfunc (ma *_Map__String__Msg3__ReprAssembler) keyFinishTidy() bool {\n\tswitch ma.cm {\n\tcase schema.Maybe_Value:\n\t\tma.ka.w = nil\n\t\ttz := &ma.w.t[len(ma.w.t)-1]\n\t\tma.cm = schema.Maybe_Absent\n\t\tma.state = maState_expectValue\n\t\tma.w.m[tz.k] = &tz.v\n\t\tma.va.w = &tz.v\n\t\tma.va.m = &ma.cm\n\t\tma.ka.reset()\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\nfunc (ma *_Map__String__Msg3__ReprAssembler) valueFinishTidy() bool {\n\tswitch ma.cm {\n\tcase schema.Maybe_Value:\n\t\tma.va.w = nil\n\t\tma.cm = schema.Maybe_Absent\n\t\tma.state = maState_initial\n\t\tma.va.reset()\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\nfunc (ma *_Map__String__Msg3__ReprAssembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling another key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called on an assembler that's already finished\")\n\t}\n\n\tvar k2 _String\n\tif err := (_String__ReprPrototype{}).fromString(&k2, k); err != nil {\n\t\treturn nil, err // TODO wrap in some kind of ErrInvalidKey\n\t}\n\tif _, exists := ma.w.m[k2]; exists {\n\t\treturn nil, datamodel.ErrRepeatedMapKey{Key: &k2}\n\t}\n\tma.w.t = append(ma.w.t, _Map__String__Msg3__entry{k: k2})\n\ttz := &ma.w.t[len(ma.w.t)-1]\n\tma.state = maState_midValue\n\n\tma.w.m[k2] = &tz.v\n\tma.va.w = &tz.v\n\tma.va.m = &ma.cm\n\treturn &ma.va, nil\n}\nfunc (ma *_Map__String__Msg3__ReprAssembler) AssembleKey() datamodel.NodeAssembler {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling another key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: AssembleKey cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleKey cannot be called on an assembler that's already finished\")\n\t}\n\tma.w.t = append(ma.w.t, _Map__String__Msg3__entry{})\n\tma.state = maState_midKey\n\tma.ka.m = &ma.cm\n\tma.ka.w = &ma.w.t[len(ma.w.t)-1].k\n\treturn &ma.ka\n}\nfunc (ma *_Map__String__Msg3__ReprAssembler) AssembleValue() datamodel.NodeAssembler {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\tpanic(\"invalid state: AssembleValue cannot be called when no key is primed\")\n\tcase maState_midKey:\n\t\tif !ma.keyFinishTidy() {\n\t\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling a key\")\n\t\t} // if tidy success: carry on\n\tcase maState_expectValue:\n\t\t// carry on\n\tcase maState_midValue:\n\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling another value\")\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleValue cannot be called on an assembler that's already finished\")\n\t}\n\tma.state = maState_midValue\n\treturn &ma.va\n}\nfunc (ma *_Map__String__Msg3__ReprAssembler) Finish() error {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: Finish cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on\n\tcase maState_finished:\n\t\tpanic(\"invalid state: Finish cannot be called on an assembler that's already finished\")\n\t}\n\tma.state = maState_finished\n\t*ma.m = schema.Maybe_Value\n\treturn nil\n}\nfunc (ma *_Map__String__Msg3__ReprAssembler) KeyPrototype() datamodel.NodePrototype {\n\treturn _String__ReprPrototype{}\n}\nfunc (ma *_Map__String__Msg3__ReprAssembler) ValuePrototype(_ string) datamodel.NodePrototype {\n\treturn _Msg3__ReprPrototype{}\n}\n\nfunc (n _Msg3) FieldWhee() Int {\n\treturn &n.whee\n}\nfunc (n _Msg3) FieldWoot() Int {\n\treturn &n.woot\n}\nfunc (n _Msg3) FieldWaga() Int {\n\treturn &n.waga\n}\n\ntype _Msg3__Maybe struct {\n\tm schema.Maybe\n\tv Msg3\n}\ntype MaybeMsg3 = *_Msg3__Maybe\n\nfunc (m MaybeMsg3) IsNull() bool {\n\treturn m.m == schema.Maybe_Null\n}\nfunc (m MaybeMsg3) IsAbsent() bool {\n\treturn m.m == schema.Maybe_Absent\n}\nfunc (m MaybeMsg3) Exists() bool {\n\treturn m.m == schema.Maybe_Value\n}\nfunc (m MaybeMsg3) AsNode() datamodel.Node {\n\tswitch m.m {\n\tcase schema.Maybe_Absent:\n\t\treturn datamodel.Absent\n\tcase schema.Maybe_Null:\n\t\treturn datamodel.Null\n\tcase schema.Maybe_Value:\n\t\treturn m.v\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (m MaybeMsg3) Must() Msg3 {\n\tif !m.Exists() {\n\t\tpanic(\"unbox of a maybe rejected\")\n\t}\n\treturn m.v\n}\n\nvar (\n\tfieldName__Msg3_Whee = _String{\"whee\"}\n\tfieldName__Msg3_Woot = _String{\"woot\"}\n\tfieldName__Msg3_Waga = _String{\"waga\"}\n)\nvar _ datamodel.Node = (Msg3)(&_Msg3{})\nvar _ schema.TypedNode = (Msg3)(&_Msg3{})\n\nfunc (Msg3) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Map\n}\nfunc (n Msg3) LookupByString(key string) (datamodel.Node, error) {\n\tswitch key {\n\tcase \"whee\":\n\t\treturn &n.whee, nil\n\tcase \"woot\":\n\t\treturn &n.woot, nil\n\tcase \"waga\":\n\t\treturn &n.waga, nil\n\tdefault:\n\t\treturn nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: datamodel.PathSegmentOfString(key)}\n\t}\n}\nfunc (n Msg3) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\tks, err := key.AsString()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn n.LookupByString(ks)\n}\nfunc (Msg3) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Msg3\"}.LookupByIndex(0)\n}\nfunc (n Msg3) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn n.LookupByString(seg.String())\n}\nfunc (n Msg3) MapIterator() datamodel.MapIterator {\n\treturn &_Msg3__MapItr{n, 0}\n}\n\ntype _Msg3__MapItr struct {\n\tn   Msg3\n\tidx int\n}\n\nfunc (itr *_Msg3__MapItr) Next() (k datamodel.Node, v datamodel.Node, _ error) {\n\tif itr.idx >= 3 {\n\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t}\n\tswitch itr.idx {\n\tcase 0:\n\t\tk = &fieldName__Msg3_Whee\n\t\tv = &itr.n.whee\n\tcase 1:\n\t\tk = &fieldName__Msg3_Woot\n\t\tv = &itr.n.woot\n\tcase 2:\n\t\tk = &fieldName__Msg3_Waga\n\t\tv = &itr.n.waga\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n\titr.idx++\n\treturn\n}\nfunc (itr *_Msg3__MapItr) Done() bool {\n\treturn itr.idx >= 3\n}\n\nfunc (Msg3) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (Msg3) Length() int64 {\n\treturn 3\n}\nfunc (Msg3) IsAbsent() bool {\n\treturn false\n}\nfunc (Msg3) IsNull() bool {\n\treturn false\n}\nfunc (Msg3) AsBool() (bool, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Msg3\"}.AsBool()\n}\nfunc (Msg3) AsInt() (int64, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Msg3\"}.AsInt()\n}\nfunc (Msg3) AsFloat() (float64, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Msg3\"}.AsFloat()\n}\nfunc (Msg3) AsString() (string, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Msg3\"}.AsString()\n}\nfunc (Msg3) AsBytes() ([]byte, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Msg3\"}.AsBytes()\n}\nfunc (Msg3) AsLink() (datamodel.Link, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Msg3\"}.AsLink()\n}\nfunc (Msg3) Prototype() datamodel.NodePrototype {\n\treturn _Msg3__Prototype{}\n}\n\ntype _Msg3__Prototype struct{}\n\nfunc (_Msg3__Prototype) NewBuilder() datamodel.NodeBuilder {\n\tvar nb _Msg3__Builder\n\tnb.Reset()\n\treturn &nb\n}\n\ntype _Msg3__Builder struct {\n\t_Msg3__Assembler\n}\n\nfunc (nb *_Msg3__Builder) Build() datamodel.Node {\n\tif *nb.m != schema.Maybe_Value {\n\t\tpanic(\"invalid state: cannot call Build on an assembler that's not finished\")\n\t}\n\treturn nb.w\n}\nfunc (nb *_Msg3__Builder) Reset() {\n\tvar w _Msg3\n\tvar m schema.Maybe\n\t*nb = _Msg3__Builder{_Msg3__Assembler{w: &w, m: &m}}\n}\n\ntype _Msg3__Assembler struct {\n\tw     *_Msg3\n\tm     *schema.Maybe\n\tstate maState\n\ts     int\n\tf     int\n\n\tcm      schema.Maybe\n\tca_whee _Int__Assembler\n\tca_woot _Int__Assembler\n\tca_waga _Int__Assembler\n}\n\nfunc (na *_Msg3__Assembler) reset() {\n\tna.state = maState_initial\n\tna.s = 0\n\tna.ca_whee.reset()\n\tna.ca_woot.reset()\n\tna.ca_waga.reset()\n}\n\nvar (\n\tfieldBit__Msg3_Whee        = 1 << 0\n\tfieldBit__Msg3_Woot        = 1 << 1\n\tfieldBit__Msg3_Waga        = 1 << 2\n\tfieldBits__Msg3_sufficient = 0 + 1<<0 + 1<<1 + 1<<2\n)\n\nfunc (na *_Msg3__Assembler) BeginMap(int64) (datamodel.MapAssembler, error) {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: it makes no sense to 'begin' twice on the same assembler!\")\n\t}\n\t*na.m = midvalue\n\tif na.w == nil {\n\t\tna.w = &_Msg3{}\n\t}\n\treturn na, nil\n}\nfunc (_Msg3__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3\"}.BeginList(0)\n}\nfunc (na *_Msg3__Assembler) AssignNull() error {\n\tswitch *na.m {\n\tcase allowNull:\n\t\t*na.m = schema.Maybe_Null\n\t\treturn nil\n\tcase schema.Maybe_Absent:\n\t\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3\"}.AssignNull()\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t}\n\tpanic(\"unreachable\")\n}\nfunc (_Msg3__Assembler) AssignBool(bool) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3\"}.AssignBool(false)\n}\nfunc (_Msg3__Assembler) AssignInt(int64) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3\"}.AssignInt(0)\n}\nfunc (_Msg3__Assembler) AssignFloat(float64) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3\"}.AssignFloat(0)\n}\nfunc (_Msg3__Assembler) AssignString(string) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3\"}.AssignString(\"\")\n}\nfunc (_Msg3__Assembler) AssignBytes([]byte) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3\"}.AssignBytes(nil)\n}\nfunc (_Msg3__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3\"}.AssignLink(nil)\n}\nfunc (na *_Msg3__Assembler) AssignNode(v datamodel.Node) error {\n\tif v.IsNull() {\n\t\treturn na.AssignNull()\n\t}\n\tif v2, ok := v.(*_Msg3); ok {\n\t\tswitch *na.m {\n\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\tcase midvalue:\n\t\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t\t}\n\t\tif na.w == nil {\n\t\t\tna.w = v2\n\t\t\t*na.m = schema.Maybe_Value\n\t\t\treturn nil\n\t\t}\n\t\t*na.w = *v2\n\t\t*na.m = schema.Maybe_Value\n\t\treturn nil\n\t}\n\tif v.Kind() != datamodel.Kind_Map {\n\t\treturn datamodel.ErrWrongKind{TypeName: \"gendemo.Msg3\", MethodName: \"AssignNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: v.Kind()}\n\t}\n\titr := v.MapIterator()\n\tfor !itr.Done() {\n\t\tk, v, err := itr.Next()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := na.AssembleKey().AssignNode(k); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn na.Finish()\n}\nfunc (_Msg3__Assembler) Prototype() datamodel.NodePrototype {\n\treturn _Msg3__Prototype{}\n}\nfunc (ma *_Msg3__Assembler) valueFinishTidy() bool {\n\tswitch ma.f {\n\tcase 0:\n\t\tswitch ma.cm {\n\t\tcase schema.Maybe_Value:\n\t\t\tma.ca_whee.w = nil\n\t\t\tma.cm = schema.Maybe_Absent\n\t\t\tma.state = maState_initial\n\t\t\treturn true\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\tcase 1:\n\t\tswitch ma.cm {\n\t\tcase schema.Maybe_Value:\n\t\t\tma.ca_woot.w = nil\n\t\t\tma.cm = schema.Maybe_Absent\n\t\t\tma.state = maState_initial\n\t\t\treturn true\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\tcase 2:\n\t\tswitch ma.cm {\n\t\tcase schema.Maybe_Value:\n\t\t\tma.ca_waga.w = nil\n\t\t\tma.cm = schema.Maybe_Absent\n\t\t\tma.state = maState_initial\n\t\t\treturn true\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (ma *_Msg3__Assembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling another key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called on an assembler that's already finished\")\n\t}\n\tswitch k {\n\tcase \"whee\":\n\t\tif ma.s&fieldBit__Msg3_Whee != 0 {\n\t\t\treturn nil, datamodel.ErrRepeatedMapKey{Key: &fieldName__Msg3_Whee}\n\t\t}\n\t\tma.s += fieldBit__Msg3_Whee\n\t\tma.state = maState_midValue\n\t\tma.f = 0\n\t\tma.ca_whee.w = &ma.w.whee\n\t\tma.ca_whee.m = &ma.cm\n\t\treturn &ma.ca_whee, nil\n\tcase \"woot\":\n\t\tif ma.s&fieldBit__Msg3_Woot != 0 {\n\t\t\treturn nil, datamodel.ErrRepeatedMapKey{Key: &fieldName__Msg3_Woot}\n\t\t}\n\t\tma.s += fieldBit__Msg3_Woot\n\t\tma.state = maState_midValue\n\t\tma.f = 1\n\t\tma.ca_woot.w = &ma.w.woot\n\t\tma.ca_woot.m = &ma.cm\n\t\treturn &ma.ca_woot, nil\n\tcase \"waga\":\n\t\tif ma.s&fieldBit__Msg3_Waga != 0 {\n\t\t\treturn nil, datamodel.ErrRepeatedMapKey{Key: &fieldName__Msg3_Waga}\n\t\t}\n\t\tma.s += fieldBit__Msg3_Waga\n\t\tma.state = maState_midValue\n\t\tma.f = 2\n\t\tma.ca_waga.w = &ma.w.waga\n\t\tma.ca_waga.m = &ma.cm\n\t\treturn &ma.ca_waga, nil\n\t}\n\treturn nil, schema.ErrInvalidKey{TypeName: \"gendemo.Msg3\", Key: &_String{k}}\n}\nfunc (ma *_Msg3__Assembler) AssembleKey() datamodel.NodeAssembler {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling another key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: AssembleKey cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleKey cannot be called on an assembler that's already finished\")\n\t}\n\tma.state = maState_midKey\n\treturn (*_Msg3__KeyAssembler)(ma)\n}\nfunc (ma *_Msg3__Assembler) AssembleValue() datamodel.NodeAssembler {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\tpanic(\"invalid state: AssembleValue cannot be called when no key is primed\")\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling a key\")\n\tcase maState_expectValue:\n\t\t// carry on\n\tcase maState_midValue:\n\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling another value\")\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleValue cannot be called on an assembler that's already finished\")\n\t}\n\tma.state = maState_midValue\n\tswitch ma.f {\n\tcase 0:\n\t\tma.ca_whee.w = &ma.w.whee\n\t\tma.ca_whee.m = &ma.cm\n\t\treturn &ma.ca_whee\n\tcase 1:\n\t\tma.ca_woot.w = &ma.w.woot\n\t\tma.ca_woot.m = &ma.cm\n\t\treturn &ma.ca_woot\n\tcase 2:\n\t\tma.ca_waga.w = &ma.w.waga\n\t\tma.ca_waga.m = &ma.cm\n\t\treturn &ma.ca_waga\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (ma *_Msg3__Assembler) Finish() error {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: Finish cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on\n\tcase maState_finished:\n\t\tpanic(\"invalid state: Finish cannot be called on an assembler that's already finished\")\n\t}\n\tif ma.s&fieldBits__Msg3_sufficient != fieldBits__Msg3_sufficient {\n\t\terr := schema.ErrMissingRequiredField{Missing: make([]string, 0)}\n\t\tif ma.s&fieldBit__Msg3_Whee == 0 {\n\t\t\terr.Missing = append(err.Missing, \"whee\")\n\t\t}\n\t\tif ma.s&fieldBit__Msg3_Woot == 0 {\n\t\t\terr.Missing = append(err.Missing, \"woot\")\n\t\t}\n\t\tif ma.s&fieldBit__Msg3_Waga == 0 {\n\t\t\terr.Missing = append(err.Missing, \"waga\")\n\t\t}\n\t\treturn err\n\t}\n\tma.state = maState_finished\n\t*ma.m = schema.Maybe_Value\n\treturn nil\n}\nfunc (ma *_Msg3__Assembler) KeyPrototype() datamodel.NodePrototype {\n\treturn _String__Prototype{}\n}\nfunc (ma *_Msg3__Assembler) ValuePrototype(k string) datamodel.NodePrototype {\n\tpanic(\"todo structbuilder mapassembler valueprototype\")\n}\n\ntype _Msg3__KeyAssembler _Msg3__Assembler\n\nfunc (_Msg3__KeyAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.KeyAssembler\"}.BeginMap(0)\n}\nfunc (_Msg3__KeyAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.KeyAssembler\"}.BeginList(0)\n}\nfunc (na *_Msg3__KeyAssembler) AssignNull() error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.KeyAssembler\"}.AssignNull()\n}\nfunc (_Msg3__KeyAssembler) AssignBool(bool) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.KeyAssembler\"}.AssignBool(false)\n}\nfunc (_Msg3__KeyAssembler) AssignInt(int64) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.KeyAssembler\"}.AssignInt(0)\n}\nfunc (_Msg3__KeyAssembler) AssignFloat(float64) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.KeyAssembler\"}.AssignFloat(0)\n}\nfunc (ka *_Msg3__KeyAssembler) AssignString(k string) error {\n\tif ka.state != maState_midKey {\n\t\tpanic(\"misuse: KeyAssembler held beyond its valid lifetime\")\n\t}\n\tswitch k {\n\tcase \"whee\":\n\t\tif ka.s&fieldBit__Msg3_Whee != 0 {\n\t\t\treturn datamodel.ErrRepeatedMapKey{Key: &fieldName__Msg3_Whee}\n\t\t}\n\t\tka.s += fieldBit__Msg3_Whee\n\t\tka.state = maState_expectValue\n\t\tka.f = 0\n\t\treturn nil\n\tcase \"woot\":\n\t\tif ka.s&fieldBit__Msg3_Woot != 0 {\n\t\t\treturn datamodel.ErrRepeatedMapKey{Key: &fieldName__Msg3_Woot}\n\t\t}\n\t\tka.s += fieldBit__Msg3_Woot\n\t\tka.state = maState_expectValue\n\t\tka.f = 1\n\t\treturn nil\n\tcase \"waga\":\n\t\tif ka.s&fieldBit__Msg3_Waga != 0 {\n\t\t\treturn datamodel.ErrRepeatedMapKey{Key: &fieldName__Msg3_Waga}\n\t\t}\n\t\tka.s += fieldBit__Msg3_Waga\n\t\tka.state = maState_expectValue\n\t\tka.f = 2\n\t\treturn nil\n\tdefault:\n\t\treturn schema.ErrInvalidKey{TypeName: \"gendemo.Msg3\", Key: &_String{k}}\n\t}\n}\nfunc (_Msg3__KeyAssembler) AssignBytes([]byte) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.KeyAssembler\"}.AssignBytes(nil)\n}\nfunc (_Msg3__KeyAssembler) AssignLink(datamodel.Link) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.KeyAssembler\"}.AssignLink(nil)\n}\nfunc (ka *_Msg3__KeyAssembler) AssignNode(v datamodel.Node) error {\n\tif v2, err := v.AsString(); err != nil {\n\t\treturn err\n\t} else {\n\t\treturn ka.AssignString(v2)\n\t}\n}\nfunc (_Msg3__KeyAssembler) Prototype() datamodel.NodePrototype {\n\treturn _String__Prototype{}\n}\nfunc (Msg3) Type() schema.Type {\n\treturn nil /*TODO:typelit*/\n}\nfunc (n Msg3) Representation() datamodel.Node {\n\treturn (*_Msg3__Repr)(n)\n}\n\ntype _Msg3__Repr _Msg3\n\nvar (\n\tfieldName__Msg3_Whee_serial = _String{\"whee\"}\n\tfieldName__Msg3_Woot_serial = _String{\"woot\"}\n\tfieldName__Msg3_Waga_serial = _String{\"waga\"}\n)\nvar _ datamodel.Node = &_Msg3__Repr{}\n\nfunc (_Msg3__Repr) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Map\n}\nfunc (n *_Msg3__Repr) LookupByString(key string) (datamodel.Node, error) {\n\tswitch key {\n\tcase \"whee\":\n\t\treturn n.whee.Representation(), nil\n\tcase \"woot\":\n\t\treturn n.woot.Representation(), nil\n\tcase \"waga\":\n\t\treturn n.waga.Representation(), nil\n\tdefault:\n\t\treturn nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: datamodel.PathSegmentOfString(key)}\n\t}\n}\nfunc (n *_Msg3__Repr) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\tks, err := key.AsString()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn n.LookupByString(ks)\n}\nfunc (_Msg3__Repr) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Msg3.Repr\"}.LookupByIndex(0)\n}\nfunc (n _Msg3__Repr) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn n.LookupByString(seg.String())\n}\nfunc (n *_Msg3__Repr) MapIterator() datamodel.MapIterator {\n\treturn &_Msg3__ReprMapItr{n, 0}\n}\n\ntype _Msg3__ReprMapItr struct {\n\tn   *_Msg3__Repr\n\tidx int\n}\n\nfunc (itr *_Msg3__ReprMapItr) Next() (k datamodel.Node, v datamodel.Node, _ error) {\n\tif itr.idx >= 3 {\n\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t}\n\tswitch itr.idx {\n\tcase 0:\n\t\tk = &fieldName__Msg3_Whee_serial\n\t\tv = itr.n.whee.Representation()\n\tcase 1:\n\t\tk = &fieldName__Msg3_Woot_serial\n\t\tv = itr.n.woot.Representation()\n\tcase 2:\n\t\tk = &fieldName__Msg3_Waga_serial\n\t\tv = itr.n.waga.Representation()\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n\titr.idx++\n\treturn\n}\nfunc (itr *_Msg3__ReprMapItr) Done() bool {\n\treturn itr.idx >= 3\n}\nfunc (_Msg3__Repr) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (rn *_Msg3__Repr) Length() int64 {\n\tl := 3\n\treturn int64(l)\n}\nfunc (_Msg3__Repr) IsAbsent() bool {\n\treturn false\n}\nfunc (_Msg3__Repr) IsNull() bool {\n\treturn false\n}\nfunc (_Msg3__Repr) AsBool() (bool, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Msg3.Repr\"}.AsBool()\n}\nfunc (_Msg3__Repr) AsInt() (int64, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Msg3.Repr\"}.AsInt()\n}\nfunc (_Msg3__Repr) AsFloat() (float64, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Msg3.Repr\"}.AsFloat()\n}\nfunc (_Msg3__Repr) AsString() (string, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Msg3.Repr\"}.AsString()\n}\nfunc (_Msg3__Repr) AsBytes() ([]byte, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Msg3.Repr\"}.AsBytes()\n}\nfunc (_Msg3__Repr) AsLink() (datamodel.Link, error) {\n\treturn mixins.Map{TypeName: \"gendemo.Msg3.Repr\"}.AsLink()\n}\nfunc (_Msg3__Repr) Prototype() datamodel.NodePrototype {\n\treturn _Msg3__ReprPrototype{}\n}\n\ntype _Msg3__ReprPrototype struct{}\n\nfunc (_Msg3__ReprPrototype) NewBuilder() datamodel.NodeBuilder {\n\tvar nb _Msg3__ReprBuilder\n\tnb.Reset()\n\treturn &nb\n}\n\ntype _Msg3__ReprBuilder struct {\n\t_Msg3__ReprAssembler\n}\n\nfunc (nb *_Msg3__ReprBuilder) Build() datamodel.Node {\n\tif *nb.m != schema.Maybe_Value {\n\t\tpanic(\"invalid state: cannot call Build on an assembler that's not finished\")\n\t}\n\treturn nb.w\n}\nfunc (nb *_Msg3__ReprBuilder) Reset() {\n\tvar w _Msg3\n\tvar m schema.Maybe\n\t*nb = _Msg3__ReprBuilder{_Msg3__ReprAssembler{w: &w, m: &m}}\n}\n\ntype _Msg3__ReprAssembler struct {\n\tw     *_Msg3\n\tm     *schema.Maybe\n\tstate maState\n\ts     int\n\tf     int\n\n\tcm      schema.Maybe\n\tca_whee _Int__ReprAssembler\n\tca_woot _Int__ReprAssembler\n\tca_waga _Int__ReprAssembler\n}\n\nfunc (na *_Msg3__ReprAssembler) reset() {\n\tna.state = maState_initial\n\tna.s = 0\n\tna.ca_whee.reset()\n\tna.ca_woot.reset()\n\tna.ca_waga.reset()\n}\nfunc (na *_Msg3__ReprAssembler) BeginMap(int64) (datamodel.MapAssembler, error) {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: it makes no sense to 'begin' twice on the same assembler!\")\n\t}\n\t*na.m = midvalue\n\tif na.w == nil {\n\t\tna.w = &_Msg3{}\n\t}\n\treturn na, nil\n}\nfunc (_Msg3__ReprAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3.Repr\"}.BeginList(0)\n}\nfunc (na *_Msg3__ReprAssembler) AssignNull() error {\n\tswitch *na.m {\n\tcase allowNull:\n\t\t*na.m = schema.Maybe_Null\n\t\treturn nil\n\tcase schema.Maybe_Absent:\n\t\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3.Repr.Repr\"}.AssignNull()\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t}\n\tpanic(\"unreachable\")\n}\nfunc (_Msg3__ReprAssembler) AssignBool(bool) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3.Repr\"}.AssignBool(false)\n}\nfunc (_Msg3__ReprAssembler) AssignInt(int64) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3.Repr\"}.AssignInt(0)\n}\nfunc (_Msg3__ReprAssembler) AssignFloat(float64) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3.Repr\"}.AssignFloat(0)\n}\nfunc (_Msg3__ReprAssembler) AssignString(string) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3.Repr\"}.AssignString(\"\")\n}\nfunc (_Msg3__ReprAssembler) AssignBytes([]byte) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3.Repr\"}.AssignBytes(nil)\n}\nfunc (_Msg3__ReprAssembler) AssignLink(datamodel.Link) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.Msg3.Repr\"}.AssignLink(nil)\n}\nfunc (na *_Msg3__ReprAssembler) AssignNode(v datamodel.Node) error {\n\tif v.IsNull() {\n\t\treturn na.AssignNull()\n\t}\n\tif v2, ok := v.(*_Msg3); ok {\n\t\tswitch *na.m {\n\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\tcase midvalue:\n\t\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t\t}\n\t\tif na.w == nil {\n\t\t\tna.w = v2\n\t\t\t*na.m = schema.Maybe_Value\n\t\t\treturn nil\n\t\t}\n\t\t*na.w = *v2\n\t\t*na.m = schema.Maybe_Value\n\t\treturn nil\n\t}\n\tif v.Kind() != datamodel.Kind_Map {\n\t\treturn datamodel.ErrWrongKind{TypeName: \"gendemo.Msg3.Repr\", MethodName: \"AssignNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: v.Kind()}\n\t}\n\titr := v.MapIterator()\n\tfor !itr.Done() {\n\t\tk, v, err := itr.Next()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := na.AssembleKey().AssignNode(k); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn na.Finish()\n}\nfunc (_Msg3__ReprAssembler) Prototype() datamodel.NodePrototype {\n\treturn _Msg3__ReprPrototype{}\n}\nfunc (ma *_Msg3__ReprAssembler) valueFinishTidy() bool {\n\tswitch ma.f {\n\tcase 0:\n\t\tswitch ma.cm {\n\t\tcase schema.Maybe_Value:\n\t\t\tma.cm = schema.Maybe_Absent\n\t\t\tma.state = maState_initial\n\t\t\treturn true\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\tcase 1:\n\t\tswitch ma.cm {\n\t\tcase schema.Maybe_Value:\n\t\t\tma.cm = schema.Maybe_Absent\n\t\t\tma.state = maState_initial\n\t\t\treturn true\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\tcase 2:\n\t\tswitch ma.cm {\n\t\tcase schema.Maybe_Value:\n\t\t\tma.cm = schema.Maybe_Absent\n\t\t\tma.state = maState_initial\n\t\t\treturn true\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (ma *_Msg3__ReprAssembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling another key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called on an assembler that's already finished\")\n\t}\n\tswitch k {\n\tcase \"whee\":\n\t\tif ma.s&fieldBit__Msg3_Whee != 0 {\n\t\t\treturn nil, datamodel.ErrRepeatedMapKey{Key: &fieldName__Msg3_Whee_serial}\n\t\t}\n\t\tma.s += fieldBit__Msg3_Whee\n\t\tma.state = maState_midValue\n\t\tma.f = 0\n\t\tma.ca_whee.w = &ma.w.whee\n\t\tma.ca_whee.m = &ma.cm\n\t\treturn &ma.ca_whee, nil\n\tcase \"woot\":\n\t\tif ma.s&fieldBit__Msg3_Woot != 0 {\n\t\t\treturn nil, datamodel.ErrRepeatedMapKey{Key: &fieldName__Msg3_Woot_serial}\n\t\t}\n\t\tma.s += fieldBit__Msg3_Woot\n\t\tma.state = maState_midValue\n\t\tma.f = 1\n\t\tma.ca_woot.w = &ma.w.woot\n\t\tma.ca_woot.m = &ma.cm\n\t\treturn &ma.ca_woot, nil\n\tcase \"waga\":\n\t\tif ma.s&fieldBit__Msg3_Waga != 0 {\n\t\t\treturn nil, datamodel.ErrRepeatedMapKey{Key: &fieldName__Msg3_Waga_serial}\n\t\t}\n\t\tma.s += fieldBit__Msg3_Waga\n\t\tma.state = maState_midValue\n\t\tma.f = 2\n\t\tma.ca_waga.w = &ma.w.waga\n\t\tma.ca_waga.m = &ma.cm\n\t\treturn &ma.ca_waga, nil\n\tdefault:\n\t}\n\treturn nil, schema.ErrInvalidKey{TypeName: \"gendemo.Msg3.Repr\", Key: &_String{k}}\n}\nfunc (ma *_Msg3__ReprAssembler) AssembleKey() datamodel.NodeAssembler {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling another key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: AssembleKey cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleKey cannot be called on an assembler that's already finished\")\n\t}\n\tma.state = maState_midKey\n\treturn (*_Msg3__ReprKeyAssembler)(ma)\n}\nfunc (ma *_Msg3__ReprAssembler) AssembleValue() datamodel.NodeAssembler {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\tpanic(\"invalid state: AssembleValue cannot be called when no key is primed\")\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling a key\")\n\tcase maState_expectValue:\n\t\t// carry on\n\tcase maState_midValue:\n\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling another value\")\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleValue cannot be called on an assembler that's already finished\")\n\t}\n\tma.state = maState_midValue\n\tswitch ma.f {\n\tcase 0:\n\t\tma.ca_whee.w = &ma.w.whee\n\t\tma.ca_whee.m = &ma.cm\n\t\treturn &ma.ca_whee\n\tcase 1:\n\t\tma.ca_woot.w = &ma.w.woot\n\t\tma.ca_woot.m = &ma.cm\n\t\treturn &ma.ca_woot\n\tcase 2:\n\t\tma.ca_waga.w = &ma.w.waga\n\t\tma.ca_waga.m = &ma.cm\n\t\treturn &ma.ca_waga\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (ma *_Msg3__ReprAssembler) Finish() error {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: Finish cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on\n\tcase maState_finished:\n\t\tpanic(\"invalid state: Finish cannot be called on an assembler that's already finished\")\n\t}\n\tif ma.s&fieldBits__Msg3_sufficient != fieldBits__Msg3_sufficient {\n\t\terr := schema.ErrMissingRequiredField{Missing: make([]string, 0)}\n\t\tif ma.s&fieldBit__Msg3_Whee == 0 {\n\t\t\terr.Missing = append(err.Missing, \"whee\")\n\t\t}\n\t\tif ma.s&fieldBit__Msg3_Woot == 0 {\n\t\t\terr.Missing = append(err.Missing, \"woot\")\n\t\t}\n\t\tif ma.s&fieldBit__Msg3_Waga == 0 {\n\t\t\terr.Missing = append(err.Missing, \"waga\")\n\t\t}\n\t\treturn err\n\t}\n\tma.state = maState_finished\n\t*ma.m = schema.Maybe_Value\n\treturn nil\n}\nfunc (ma *_Msg3__ReprAssembler) KeyPrototype() datamodel.NodePrototype {\n\treturn _String__Prototype{}\n}\nfunc (ma *_Msg3__ReprAssembler) ValuePrototype(k string) datamodel.NodePrototype {\n\tpanic(\"todo structbuilder mapassembler repr valueprototype\")\n}\n\ntype _Msg3__ReprKeyAssembler _Msg3__ReprAssembler\n\nfunc (_Msg3__ReprKeyAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.Repr.KeyAssembler\"}.BeginMap(0)\n}\nfunc (_Msg3__ReprKeyAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.Repr.KeyAssembler\"}.BeginList(0)\n}\nfunc (na *_Msg3__ReprKeyAssembler) AssignNull() error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.Repr.KeyAssembler\"}.AssignNull()\n}\nfunc (_Msg3__ReprKeyAssembler) AssignBool(bool) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.Repr.KeyAssembler\"}.AssignBool(false)\n}\nfunc (_Msg3__ReprKeyAssembler) AssignInt(int64) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.Repr.KeyAssembler\"}.AssignInt(0)\n}\nfunc (_Msg3__ReprKeyAssembler) AssignFloat(float64) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.Repr.KeyAssembler\"}.AssignFloat(0)\n}\nfunc (ka *_Msg3__ReprKeyAssembler) AssignString(k string) error {\n\tif ka.state != maState_midKey {\n\t\tpanic(\"misuse: KeyAssembler held beyond its valid lifetime\")\n\t}\n\tswitch k {\n\tcase \"whee\":\n\t\tif ka.s&fieldBit__Msg3_Whee != 0 {\n\t\t\treturn datamodel.ErrRepeatedMapKey{Key: &fieldName__Msg3_Whee_serial}\n\t\t}\n\t\tka.s += fieldBit__Msg3_Whee\n\t\tka.state = maState_expectValue\n\t\tka.f = 0\n\t\treturn nil\n\tcase \"woot\":\n\t\tif ka.s&fieldBit__Msg3_Woot != 0 {\n\t\t\treturn datamodel.ErrRepeatedMapKey{Key: &fieldName__Msg3_Woot_serial}\n\t\t}\n\t\tka.s += fieldBit__Msg3_Woot\n\t\tka.state = maState_expectValue\n\t\tka.f = 1\n\t\treturn nil\n\tcase \"waga\":\n\t\tif ka.s&fieldBit__Msg3_Waga != 0 {\n\t\t\treturn datamodel.ErrRepeatedMapKey{Key: &fieldName__Msg3_Waga_serial}\n\t\t}\n\t\tka.s += fieldBit__Msg3_Waga\n\t\tka.state = maState_expectValue\n\t\tka.f = 2\n\t\treturn nil\n\t}\n\treturn schema.ErrInvalidKey{TypeName: \"gendemo.Msg3.Repr\", Key: &_String{k}}\n}\nfunc (_Msg3__ReprKeyAssembler) AssignBytes([]byte) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.Repr.KeyAssembler\"}.AssignBytes(nil)\n}\nfunc (_Msg3__ReprKeyAssembler) AssignLink(datamodel.Link) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.Msg3.Repr.KeyAssembler\"}.AssignLink(nil)\n}\nfunc (ka *_Msg3__ReprKeyAssembler) AssignNode(v datamodel.Node) error {\n\tif v2, err := v.AsString(); err != nil {\n\t\treturn err\n\t} else {\n\t\treturn ka.AssignString(v2)\n\t}\n}\nfunc (_Msg3__ReprKeyAssembler) Prototype() datamodel.NodePrototype {\n\treturn _String__Prototype{}\n}\n\nfunc (n String) String() string {\n\treturn n.x\n}\nfunc (_String__Prototype) fromString(w *_String, v string) error {\n\t*w = _String{v}\n\treturn nil\n}\nfunc (_String__Prototype) FromString(v string) (String, error) {\n\tn := _String{v}\n\treturn &n, nil\n}\n\ntype _String__Maybe struct {\n\tm schema.Maybe\n\tv _String\n}\ntype MaybeString = *_String__Maybe\n\nfunc (m MaybeString) IsNull() bool {\n\treturn m.m == schema.Maybe_Null\n}\nfunc (m MaybeString) IsAbsent() bool {\n\treturn m.m == schema.Maybe_Absent\n}\nfunc (m MaybeString) Exists() bool {\n\treturn m.m == schema.Maybe_Value\n}\nfunc (m MaybeString) AsNode() datamodel.Node {\n\tswitch m.m {\n\tcase schema.Maybe_Absent:\n\t\treturn datamodel.Absent\n\tcase schema.Maybe_Null:\n\t\treturn datamodel.Null\n\tcase schema.Maybe_Value:\n\t\treturn &m.v\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (m MaybeString) Must() String {\n\tif !m.Exists() {\n\t\tpanic(\"unbox of a maybe rejected\")\n\t}\n\treturn &m.v\n}\n\nvar _ datamodel.Node = (String)(&_String{})\nvar _ schema.TypedNode = (String)(&_String{})\n\nfunc (String) Kind() datamodel.Kind {\n\treturn datamodel.Kind_String\n}\nfunc (String) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"gendemo.String\"}.LookupByString(\"\")\n}\nfunc (String) LookupByNode(datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"gendemo.String\"}.LookupByNode(nil)\n}\nfunc (String) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"gendemo.String\"}.LookupByIndex(0)\n}\nfunc (String) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.String{TypeName: \"gendemo.String\"}.LookupBySegment(seg)\n}\nfunc (String) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (String) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (String) Length() int64 {\n\treturn -1\n}\nfunc (String) IsAbsent() bool {\n\treturn false\n}\nfunc (String) IsNull() bool {\n\treturn false\n}\nfunc (String) AsBool() (bool, error) {\n\treturn mixins.String{TypeName: \"gendemo.String\"}.AsBool()\n}\nfunc (String) AsInt() (int64, error) {\n\treturn mixins.String{TypeName: \"gendemo.String\"}.AsInt()\n}\nfunc (String) AsFloat() (float64, error) {\n\treturn mixins.String{TypeName: \"gendemo.String\"}.AsFloat()\n}\nfunc (n String) AsString() (string, error) {\n\treturn n.x, nil\n}\nfunc (String) AsBytes() ([]byte, error) {\n\treturn mixins.String{TypeName: \"gendemo.String\"}.AsBytes()\n}\nfunc (String) AsLink() (datamodel.Link, error) {\n\treturn mixins.String{TypeName: \"gendemo.String\"}.AsLink()\n}\nfunc (String) Prototype() datamodel.NodePrototype {\n\treturn _String__Prototype{}\n}\n\ntype _String__Prototype struct{}\n\nfunc (_String__Prototype) NewBuilder() datamodel.NodeBuilder {\n\tvar nb _String__Builder\n\tnb.Reset()\n\treturn &nb\n}\n\ntype _String__Builder struct {\n\t_String__Assembler\n}\n\nfunc (nb *_String__Builder) Build() datamodel.Node {\n\tif *nb.m != schema.Maybe_Value {\n\t\tpanic(\"invalid state: cannot call Build on an assembler that's not finished\")\n\t}\n\treturn nb.w\n}\nfunc (nb *_String__Builder) Reset() {\n\tvar w _String\n\tvar m schema.Maybe\n\t*nb = _String__Builder{_String__Assembler{w: &w, m: &m}}\n}\n\ntype _String__Assembler struct {\n\tw *_String\n\tm *schema.Maybe\n}\n\nfunc (na *_String__Assembler) reset() {}\nfunc (_String__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.String\"}.BeginMap(0)\n}\nfunc (_String__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.String\"}.BeginList(0)\n}\nfunc (na *_String__Assembler) AssignNull() error {\n\tswitch *na.m {\n\tcase allowNull:\n\t\t*na.m = schema.Maybe_Null\n\t\treturn nil\n\tcase schema.Maybe_Absent:\n\t\treturn mixins.StringAssembler{TypeName: \"gendemo.String\"}.AssignNull()\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t}\n\tpanic(\"unreachable\")\n}\nfunc (_String__Assembler) AssignBool(bool) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.String\"}.AssignBool(false)\n}\nfunc (_String__Assembler) AssignInt(int64) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.String\"}.AssignInt(0)\n}\nfunc (_String__Assembler) AssignFloat(float64) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.String\"}.AssignFloat(0)\n}\nfunc (na *_String__Assembler) AssignString(v string) error {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t}\n\tna.w.x = v\n\t*na.m = schema.Maybe_Value\n\treturn nil\n}\nfunc (_String__Assembler) AssignBytes([]byte) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.String\"}.AssignBytes(nil)\n}\nfunc (_String__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.String\"}.AssignLink(nil)\n}\nfunc (na *_String__Assembler) AssignNode(v datamodel.Node) error {\n\tif v.IsNull() {\n\t\treturn na.AssignNull()\n\t}\n\tif v2, ok := v.(*_String); ok {\n\t\tswitch *na.m {\n\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t}\n\t\t*na.w = *v2\n\t\t*na.m = schema.Maybe_Value\n\t\treturn nil\n\t}\n\tif v2, err := v.AsString(); err != nil {\n\t\treturn err\n\t} else {\n\t\treturn na.AssignString(v2)\n\t}\n}\nfunc (_String__Assembler) Prototype() datamodel.NodePrototype {\n\treturn _String__Prototype{}\n}\nfunc (String) Type() schema.Type {\n\treturn nil /*TODO:typelit*/\n}\nfunc (n String) Representation() datamodel.Node {\n\treturn (*_String__Repr)(n)\n}\n\ntype _String__Repr = _String\n\nvar _ datamodel.Node = &_String__Repr{}\n\ntype _String__ReprPrototype = _String__Prototype\ntype _String__ReprAssembler = _String__Assembler\n\nfunc (n _UnionKinded) AsInterface() _UnionKinded__iface {\n\tswitch n.tag {\n\tcase 1:\n\t\treturn &n.x1\n\tcase 2:\n\t\treturn &n.x2\n\tcase 3:\n\t\treturn &n.x3\n\tdefault:\n\t\tpanic(\"invalid union state; how did you create this object?\")\n\t}\n}\n\ntype _UnionKinded__Maybe struct {\n\tm schema.Maybe\n\tv UnionKinded\n}\ntype MaybeUnionKinded = *_UnionKinded__Maybe\n\nfunc (m MaybeUnionKinded) IsNull() bool {\n\treturn m.m == schema.Maybe_Null\n}\nfunc (m MaybeUnionKinded) IsAbsent() bool {\n\treturn m.m == schema.Maybe_Absent\n}\nfunc (m MaybeUnionKinded) Exists() bool {\n\treturn m.m == schema.Maybe_Value\n}\nfunc (m MaybeUnionKinded) AsNode() datamodel.Node {\n\tswitch m.m {\n\tcase schema.Maybe_Absent:\n\t\treturn datamodel.Absent\n\tcase schema.Maybe_Null:\n\t\treturn datamodel.Null\n\tcase schema.Maybe_Value:\n\t\treturn m.v\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (m MaybeUnionKinded) Must() UnionKinded {\n\tif !m.Exists() {\n\t\tpanic(\"unbox of a maybe rejected\")\n\t}\n\treturn m.v\n}\n\nvar (\n\tmemberName__UnionKinded_Foo = _String{\"Foo\"}\n\tmemberName__UnionKinded_Bar = _String{\"Bar\"}\n\tmemberName__UnionKinded_Baz = _String{\"Baz\"}\n)\nvar _ datamodel.Node = (UnionKinded)(&_UnionKinded{})\nvar _ schema.TypedNode = (UnionKinded)(&_UnionKinded{})\n\nfunc (UnionKinded) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Map\n}\nfunc (n UnionKinded) LookupByString(key string) (datamodel.Node, error) {\n\tswitch key {\n\tcase \"Foo\":\n\t\tif n.tag != 1 {\n\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)}\n\t\t}\n\t\treturn &n.x1, nil\n\tcase \"Bar\":\n\t\tif n.tag != 2 {\n\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)}\n\t\t}\n\t\treturn &n.x2, nil\n\tcase \"Baz\":\n\t\tif n.tag != 3 {\n\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)}\n\t\t}\n\t\treturn &n.x3, nil\n\tdefault:\n\t\treturn nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: datamodel.PathSegmentOfString(key)}\n\t}\n}\nfunc (n UnionKinded) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\tks, err := key.AsString()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn n.LookupByString(ks)\n}\nfunc (UnionKinded) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Map{TypeName: \"gendemo.UnionKinded\"}.LookupByIndex(0)\n}\nfunc (n UnionKinded) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn n.LookupByString(seg.String())\n}\nfunc (n UnionKinded) MapIterator() datamodel.MapIterator {\n\treturn &_UnionKinded__MapItr{n, false}\n}\n\ntype _UnionKinded__MapItr struct {\n\tn    UnionKinded\n\tdone bool\n}\n\nfunc (itr *_UnionKinded__MapItr) Next() (k datamodel.Node, v datamodel.Node, _ error) {\n\tif itr.done {\n\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t}\n\tswitch itr.n.tag {\n\tcase 1:\n\t\tk, v = &memberName__UnionKinded_Foo, &itr.n.x1\n\tcase 2:\n\t\tk, v = &memberName__UnionKinded_Bar, &itr.n.x2\n\tcase 3:\n\t\tk, v = &memberName__UnionKinded_Baz, &itr.n.x3\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n\titr.done = true\n\treturn\n}\nfunc (itr *_UnionKinded__MapItr) Done() bool {\n\treturn itr.done\n}\n\nfunc (UnionKinded) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (UnionKinded) Length() int64 {\n\treturn 1\n}\nfunc (UnionKinded) IsAbsent() bool {\n\treturn false\n}\nfunc (UnionKinded) IsNull() bool {\n\treturn false\n}\nfunc (UnionKinded) AsBool() (bool, error) {\n\treturn mixins.Map{TypeName: \"gendemo.UnionKinded\"}.AsBool()\n}\nfunc (UnionKinded) AsInt() (int64, error) {\n\treturn mixins.Map{TypeName: \"gendemo.UnionKinded\"}.AsInt()\n}\nfunc (UnionKinded) AsFloat() (float64, error) {\n\treturn mixins.Map{TypeName: \"gendemo.UnionKinded\"}.AsFloat()\n}\nfunc (UnionKinded) AsString() (string, error) {\n\treturn mixins.Map{TypeName: \"gendemo.UnionKinded\"}.AsString()\n}\nfunc (UnionKinded) AsBytes() ([]byte, error) {\n\treturn mixins.Map{TypeName: \"gendemo.UnionKinded\"}.AsBytes()\n}\nfunc (UnionKinded) AsLink() (datamodel.Link, error) {\n\treturn mixins.Map{TypeName: \"gendemo.UnionKinded\"}.AsLink()\n}\nfunc (UnionKinded) Prototype() datamodel.NodePrototype {\n\treturn _UnionKinded__Prototype{}\n}\n\ntype _UnionKinded__Prototype struct{}\n\nfunc (_UnionKinded__Prototype) NewBuilder() datamodel.NodeBuilder {\n\tvar nb _UnionKinded__Builder\n\tnb.Reset()\n\treturn &nb\n}\n\ntype _UnionKinded__Builder struct {\n\t_UnionKinded__Assembler\n}\n\nfunc (nb *_UnionKinded__Builder) Build() datamodel.Node {\n\tif *nb.m != schema.Maybe_Value {\n\t\tpanic(\"invalid state: cannot call Build on an assembler that's not finished\")\n\t}\n\treturn nb.w\n}\nfunc (nb *_UnionKinded__Builder) Reset() {\n\tvar w _UnionKinded\n\tvar m schema.Maybe\n\t*nb = _UnionKinded__Builder{_UnionKinded__Assembler{w: &w, m: &m}}\n}\n\ntype _UnionKinded__Assembler struct {\n\tw     *_UnionKinded\n\tm     *schema.Maybe\n\tstate maState\n\n\tcm  schema.Maybe\n\tca1 _Foo__Assembler\n\n\tca2 _Bar__Assembler\n\n\tca3 _Baz__Assembler\n\tca  uint\n}\n\nfunc (na *_UnionKinded__Assembler) reset() {\n\tna.state = maState_initial\n\tswitch na.ca {\n\tcase 0:\n\t\treturn\n\tcase 1:\n\t\tna.ca1.reset()\n\n\tcase 2:\n\t\tna.ca2.reset()\n\n\tcase 3:\n\t\tna.ca3.reset()\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n\tna.ca = 0\n\tna.cm = schema.Maybe_Absent\n}\nfunc (na *_UnionKinded__Assembler) BeginMap(int64) (datamodel.MapAssembler, error) {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: it makes no sense to 'begin' twice on the same assembler!\")\n\t}\n\t*na.m = midvalue\n\tif na.w == nil {\n\t\tna.w = &_UnionKinded{}\n\t}\n\treturn na, nil\n}\nfunc (_UnionKinded__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.UnionKinded\"}.BeginList(0)\n}\nfunc (na *_UnionKinded__Assembler) AssignNull() error {\n\tswitch *na.m {\n\tcase allowNull:\n\t\t*na.m = schema.Maybe_Null\n\t\treturn nil\n\tcase schema.Maybe_Absent:\n\t\treturn mixins.MapAssembler{TypeName: \"gendemo.UnionKinded\"}.AssignNull()\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t}\n\tpanic(\"unreachable\")\n}\nfunc (_UnionKinded__Assembler) AssignBool(bool) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.UnionKinded\"}.AssignBool(false)\n}\nfunc (_UnionKinded__Assembler) AssignInt(int64) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.UnionKinded\"}.AssignInt(0)\n}\nfunc (_UnionKinded__Assembler) AssignFloat(float64) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.UnionKinded\"}.AssignFloat(0)\n}\nfunc (_UnionKinded__Assembler) AssignString(string) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.UnionKinded\"}.AssignString(\"\")\n}\nfunc (_UnionKinded__Assembler) AssignBytes([]byte) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.UnionKinded\"}.AssignBytes(nil)\n}\nfunc (_UnionKinded__Assembler) AssignLink(datamodel.Link) error {\n\treturn mixins.MapAssembler{TypeName: \"gendemo.UnionKinded\"}.AssignLink(nil)\n}\nfunc (na *_UnionKinded__Assembler) AssignNode(v datamodel.Node) error {\n\tif v.IsNull() {\n\t\treturn na.AssignNull()\n\t}\n\tif v2, ok := v.(*_UnionKinded); ok {\n\t\tswitch *na.m {\n\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\tcase midvalue:\n\t\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t\t}\n\t\tif na.w == nil {\n\t\t\tna.w = v2\n\t\t\t*na.m = schema.Maybe_Value\n\t\t\treturn nil\n\t\t}\n\t\t*na.w = *v2\n\t\t*na.m = schema.Maybe_Value\n\t\treturn nil\n\t}\n\tif v.Kind() != datamodel.Kind_Map {\n\t\treturn datamodel.ErrWrongKind{TypeName: \"gendemo.UnionKinded\", MethodName: \"AssignNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: v.Kind()}\n\t}\n\titr := v.MapIterator()\n\tfor !itr.Done() {\n\t\tk, v, err := itr.Next()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := na.AssembleKey().AssignNode(k); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn na.Finish()\n}\nfunc (_UnionKinded__Assembler) Prototype() datamodel.NodePrototype {\n\treturn _UnionKinded__Prototype{}\n}\nfunc (ma *_UnionKinded__Assembler) valueFinishTidy() bool {\n\tswitch ma.cm {\n\tcase schema.Maybe_Value:\n\t\tma.state = maState_initial\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\nfunc (ma *_UnionKinded__Assembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling another key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on for the moment, but we'll still be erroring shortly.\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleEntry cannot be called on an assembler that's already finished\")\n\t}\n\tif ma.ca != 0 {\n\t\treturn nil, schema.ErrNotUnionStructure{TypeName: \"gendemo.UnionKinded\", Detail: \"cannot add another entry -- a union can only contain one thing!\"}\n\t}\n\tswitch k {\n\tcase \"Foo\":\n\t\tma.state = maState_midValue\n\t\tma.ca = 1\n\t\tma.w.tag = 1\n\t\tma.ca1.w = &ma.w.x1\n\t\tma.ca1.m = &ma.cm\n\t\treturn &ma.ca1, nil\n\tcase \"Bar\":\n\t\tma.state = maState_midValue\n\t\tma.ca = 2\n\t\tma.w.tag = 2\n\t\tma.ca2.w = &ma.w.x2\n\t\tma.ca2.m = &ma.cm\n\t\treturn &ma.ca2, nil\n\tcase \"Baz\":\n\t\tma.state = maState_midValue\n\t\tma.ca = 3\n\t\tma.w.tag = 3\n\t\tma.ca3.w = &ma.w.x3\n\t\tma.ca3.m = &ma.cm\n\t\treturn &ma.ca3, nil\n\t}\n\treturn nil, schema.ErrInvalidKey{TypeName: \"gendemo.UnionKinded\", Key: &_String{k}}\n}\nfunc (ma *_UnionKinded__Assembler) AssembleKey() datamodel.NodeAssembler {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling another key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: AssembleKey cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on for the moment, but we'll still be erroring shortly... or rather, the keyassembler will be.\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleKey cannot be called on an assembler that's already finished\")\n\t}\n\tma.state = maState_midKey\n\treturn (*_UnionKinded__KeyAssembler)(ma)\n}\nfunc (ma *_UnionKinded__Assembler) AssembleValue() datamodel.NodeAssembler {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\tpanic(\"invalid state: AssembleValue cannot be called when no key is primed\")\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling a key\")\n\tcase maState_expectValue:\n\t\t// carry on\n\tcase maState_midValue:\n\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling another value\")\n\tcase maState_finished:\n\t\tpanic(\"invalid state: AssembleValue cannot be called on an assembler that's already finished\")\n\t}\n\tma.state = maState_midValue\n\tswitch ma.ca {\n\tcase 1:\n\t\tma.ca1.w = &ma.w.x1\n\t\tma.ca1.m = &ma.cm\n\t\treturn &ma.ca1\n\tcase 2:\n\t\tma.ca2.w = &ma.w.x2\n\t\tma.ca2.m = &ma.cm\n\t\treturn &ma.ca2\n\tcase 3:\n\t\tma.ca3.w = &ma.w.x3\n\t\tma.ca3.m = &ma.cm\n\t\treturn &ma.ca3\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (ma *_UnionKinded__Assembler) Finish() error {\n\tswitch ma.state {\n\tcase maState_initial:\n\t\t// carry on\n\tcase maState_midKey:\n\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a key\")\n\tcase maState_expectValue:\n\t\tpanic(\"invalid state: Finish cannot be called when expecting start of value assembly\")\n\tcase maState_midValue:\n\t\tif !ma.valueFinishTidy() {\n\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a value\")\n\t\t} // if tidy success: carry on\n\tcase maState_finished:\n\t\tpanic(\"invalid state: Finish cannot be called on an assembler that's already finished\")\n\t}\n\tif ma.ca == 0 {\n\t\treturn schema.ErrNotUnionStructure{TypeName: \"gendemo.UnionKinded\", Detail: \"a union must have exactly one entry (not none)!\"}\n\t}\n\tma.state = maState_finished\n\t*ma.m = schema.Maybe_Value\n\treturn nil\n}\nfunc (ma *_UnionKinded__Assembler) KeyPrototype() datamodel.NodePrototype {\n\treturn _String__Prototype{}\n}\nfunc (ma *_UnionKinded__Assembler) ValuePrototype(k string) datamodel.NodePrototype {\n\tswitch k {\n\tcase \"Foo\":\n\t\treturn _Foo__Prototype{}\n\tcase \"Bar\":\n\t\treturn _Bar__Prototype{}\n\tcase \"Baz\":\n\t\treturn _Baz__Prototype{}\n\tdefault:\n\t\treturn nil\n\t}\n}\n\ntype _UnionKinded__KeyAssembler _UnionKinded__Assembler\n\nfunc (_UnionKinded__KeyAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.UnionKinded.KeyAssembler\"}.BeginMap(0)\n}\nfunc (_UnionKinded__KeyAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.UnionKinded.KeyAssembler\"}.BeginList(0)\n}\nfunc (na *_UnionKinded__KeyAssembler) AssignNull() error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.UnionKinded.KeyAssembler\"}.AssignNull()\n}\nfunc (_UnionKinded__KeyAssembler) AssignBool(bool) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.UnionKinded.KeyAssembler\"}.AssignBool(false)\n}\nfunc (_UnionKinded__KeyAssembler) AssignInt(int64) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.UnionKinded.KeyAssembler\"}.AssignInt(0)\n}\nfunc (_UnionKinded__KeyAssembler) AssignFloat(float64) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.UnionKinded.KeyAssembler\"}.AssignFloat(0)\n}\nfunc (ka *_UnionKinded__KeyAssembler) AssignString(k string) error {\n\tif ka.state != maState_midKey {\n\t\tpanic(\"misuse: KeyAssembler held beyond its valid lifetime\")\n\t}\n\tif ka.ca != 0 {\n\t\treturn schema.ErrNotUnionStructure{TypeName: \"gendemo.UnionKinded\", Detail: \"cannot add another entry -- a union can only contain one thing!\"}\n\t}\n\tswitch k {\n\tcase \"Foo\":\n\t\tka.ca = 1\n\t\tka.w.tag = 1\n\t\tka.state = maState_expectValue\n\t\treturn nil\n\tcase \"Bar\":\n\t\tka.ca = 2\n\t\tka.w.tag = 2\n\t\tka.state = maState_expectValue\n\t\treturn nil\n\tcase \"Baz\":\n\t\tka.ca = 3\n\t\tka.w.tag = 3\n\t\tka.state = maState_expectValue\n\t\treturn nil\n\t}\n\treturn schema.ErrInvalidKey{TypeName: \"gendemo.UnionKinded\", Key: &_String{k}} // TODO: error quality: ErrInvalidUnionDiscriminant ?\n}\nfunc (_UnionKinded__KeyAssembler) AssignBytes([]byte) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.UnionKinded.KeyAssembler\"}.AssignBytes(nil)\n}\nfunc (_UnionKinded__KeyAssembler) AssignLink(datamodel.Link) error {\n\treturn mixins.StringAssembler{TypeName: \"gendemo.UnionKinded.KeyAssembler\"}.AssignLink(nil)\n}\nfunc (ka *_UnionKinded__KeyAssembler) AssignNode(v datamodel.Node) error {\n\tif v2, err := v.AsString(); err != nil {\n\t\treturn err\n\t} else {\n\t\treturn ka.AssignString(v2)\n\t}\n}\nfunc (_UnionKinded__KeyAssembler) Prototype() datamodel.NodePrototype {\n\treturn _String__Prototype{}\n}\nfunc (UnionKinded) Type() schema.Type {\n\treturn nil /*TODO:typelit*/\n}\nfunc (n UnionKinded) Representation() datamodel.Node {\n\treturn (*_UnionKinded__Repr)(n)\n}\n\ntype _UnionKinded__Repr _UnionKinded\n\nvar _ datamodel.Node = &_UnionKinded__Repr{}\n\nfunc (n *_UnionKinded__Repr) Kind() datamodel.Kind {\n\tswitch n.tag {\n\tcase 1:\n\t\treturn datamodel.Kind_Int\n\tcase 2:\n\t\treturn datamodel.Kind_Bool\n\tcase 3:\n\t\treturn datamodel.Kind_String\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (n *_UnionKinded__Repr) LookupByString(key string) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: \"gendemo.UnionKinded.Repr\", MethodName: \"LookupByString\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: n.Kind()}\n}\nfunc (n *_UnionKinded__Repr) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: \"gendemo.UnionKinded.Repr\", MethodName: \"LookupByNode\", AppropriateKind: datamodel.KindSet_Recursive, ActualKind: n.Kind()}\n}\nfunc (n *_UnionKinded__Repr) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: \"gendemo.UnionKinded.Repr\", MethodName: \"LookupByIndex\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: n.Kind()}\n}\nfunc (n *_UnionKinded__Repr) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: \"gendemo.UnionKinded.Repr\", MethodName: \"LookupBySegment\", AppropriateKind: datamodel.KindSet_Recursive, ActualKind: n.Kind()}\n}\nfunc (n *_UnionKinded__Repr) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (n *_UnionKinded__Repr) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (n *_UnionKinded__Repr) Length() int64 {\n\treturn -1\n}\nfunc (n *_UnionKinded__Repr) IsAbsent() bool {\n\treturn false\n}\nfunc (n *_UnionKinded__Repr) IsNull() bool {\n\treturn false\n}\nfunc (n *_UnionKinded__Repr) AsBool() (bool, error) {\n\tswitch n.tag {\n\tcase 2:\n\t\treturn n.x2.Representation().AsBool()\n\tdefault:\n\t\treturn false, datamodel.ErrWrongKind{TypeName: \"gendemo.UnionKinded.Repr\", MethodName: \"AsBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: n.Kind()}\n\t}\n}\nfunc (n *_UnionKinded__Repr) AsInt() (int64, error) {\n\tswitch n.tag {\n\tcase 1:\n\t\treturn n.x1.Representation().AsInt()\n\tdefault:\n\t\treturn 0, datamodel.ErrWrongKind{TypeName: \"gendemo.UnionKinded.Repr\", MethodName: \"AsInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: n.Kind()}\n\t}\n}\nfunc (n *_UnionKinded__Repr) AsFloat() (float64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: \"gendemo.UnionKinded.Repr\", MethodName: \"AsFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: n.Kind()}\n}\nfunc (n *_UnionKinded__Repr) AsString() (string, error) {\n\tswitch n.tag {\n\tcase 3:\n\t\treturn n.x3.Representation().AsString()\n\tdefault:\n\t\treturn \"\", datamodel.ErrWrongKind{TypeName: \"gendemo.UnionKinded.Repr\", MethodName: \"AsString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: n.Kind()}\n\t}\n}\nfunc (n *_UnionKinded__Repr) AsBytes() ([]byte, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: \"gendemo.UnionKinded.Repr\", MethodName: \"AsBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: n.Kind()}\n}\nfunc (n *_UnionKinded__Repr) AsLink() (datamodel.Link, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: \"gendemo.UnionKinded.Repr\", MethodName: \"AsLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: n.Kind()}\n}\nfunc (_UnionKinded__Repr) Prototype() datamodel.NodePrototype {\n\treturn _UnionKinded__ReprPrototype{}\n}\n\ntype _UnionKinded__ReprPrototype struct{}\n\nfunc (_UnionKinded__ReprPrototype) NewBuilder() datamodel.NodeBuilder {\n\tvar nb _UnionKinded__ReprBuilder\n\tnb.Reset()\n\treturn &nb\n}\n\ntype _UnionKinded__ReprBuilder struct {\n\t_UnionKinded__ReprAssembler\n}\n\nfunc (nb *_UnionKinded__ReprBuilder) Build() datamodel.Node {\n\tif *nb.m != schema.Maybe_Value {\n\t\tpanic(\"invalid state: cannot call Build on an assembler that's not finished\")\n\t}\n\treturn nb.w\n}\nfunc (nb *_UnionKinded__ReprBuilder) Reset() {\n\tvar w _UnionKinded\n\tvar m schema.Maybe\n\t*nb = _UnionKinded__ReprBuilder{_UnionKinded__ReprAssembler{w: &w, m: &m}}\n}\n\ntype _UnionKinded__ReprAssembler struct {\n\tw   *_UnionKinded\n\tm   *schema.Maybe\n\tca1 _Foo__ReprAssembler\n\tca2 _Bar__ReprAssembler\n\tca3 _Baz__ReprAssembler\n\tca  uint\n}\n\nfunc (na *_UnionKinded__ReprAssembler) reset() {\n\tswitch na.ca {\n\tcase 0:\n\t\treturn\n\tcase 1:\n\t\tna.ca1.reset()\n\tcase 2:\n\t\tna.ca2.reset()\n\tcase 3:\n\t\tna.ca3.reset()\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n\tna.ca = 0\n}\nfunc (na *_UnionKinded__ReprAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already working on a larger structure!\")\n\t}\n\treturn nil, schema.ErrNotUnionStructure{TypeName: \"gendemo.UnionKinded.Repr\", Detail: \"BeginMap called but is not valid for any of the kinds that are valid members of this union\"}\n}\nfunc (na *_UnionKinded__ReprAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already working on a larger structure!\")\n\t}\n\treturn nil, schema.ErrNotUnionStructure{TypeName: \"gendemo.UnionKinded.Repr\", Detail: \"BeginList called but is not valid for any of the kinds that are valid members of this union\"}\n}\nfunc (na *_UnionKinded__ReprAssembler) AssignNull() error {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already working on a larger structure!\")\n\t}\n\treturn schema.ErrNotUnionStructure{TypeName: \"gendemo.UnionKinded.Repr\", Detail: \"AssignNull called but is not valid for any of the kinds that are valid members of this union\"}\n}\nfunc (na *_UnionKinded__ReprAssembler) AssignBool(v bool) error {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already working on a larger structure!\")\n\t}\n\tif na.w == nil {\n\t\tna.w = &_UnionKinded{}\n\t}\n\tna.ca = 2\n\tna.w.tag = 2\n\tna.ca2.w = &na.w.x2\n\tna.ca2.m = na.m\n\treturn na.ca2.AssignBool(v)\n}\nfunc (na *_UnionKinded__ReprAssembler) AssignInt(v int64) error {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already working on a larger structure!\")\n\t}\n\tif na.w == nil {\n\t\tna.w = &_UnionKinded{}\n\t}\n\tna.ca = 1\n\tna.w.tag = 1\n\tna.ca1.w = &na.w.x1\n\tna.ca1.m = na.m\n\treturn na.ca1.AssignInt(v)\n}\nfunc (na *_UnionKinded__ReprAssembler) AssignFloat(v float64) error {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already working on a larger structure!\")\n\t}\n\treturn schema.ErrNotUnionStructure{TypeName: \"gendemo.UnionKinded.Repr\", Detail: \"AssignFloat called but is not valid for any of the kinds that are valid members of this union\"}\n}\nfunc (na *_UnionKinded__ReprAssembler) AssignString(v string) error {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already working on a larger structure!\")\n\t}\n\tif na.w == nil {\n\t\tna.w = &_UnionKinded{}\n\t}\n\tna.ca = 3\n\tna.w.tag = 3\n\tna.ca3.w = &na.w.x3\n\tna.ca3.m = na.m\n\treturn na.ca3.AssignString(v)\n}\nfunc (na *_UnionKinded__ReprAssembler) AssignBytes(v []byte) error {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already working on a larger structure!\")\n\t}\n\treturn schema.ErrNotUnionStructure{TypeName: \"gendemo.UnionKinded.Repr\", Detail: \"AssignBytes called but is not valid for any of the kinds that are valid members of this union\"}\n}\nfunc (na *_UnionKinded__ReprAssembler) AssignLink(v datamodel.Link) error {\n\tswitch *na.m {\n\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\tcase midvalue:\n\t\tpanic(\"invalid state: cannot assign into assembler that's already working on a larger structure!\")\n\t}\n\treturn schema.ErrNotUnionStructure{TypeName: \"gendemo.UnionKinded.Repr\", Detail: \"AssignLink called but is not valid for any of the kinds that are valid members of this union\"}\n}\nfunc (na *_UnionKinded__ReprAssembler) AssignNode(v datamodel.Node) error {\n\tif v.IsNull() {\n\t\treturn na.AssignNull()\n\t}\n\tif v2, ok := v.(*_UnionKinded); ok {\n\t\tswitch *na.m {\n\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\tcase midvalue:\n\t\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t\t}\n\t\tif na.w == nil {\n\t\t\tna.w = v2\n\t\t\t*na.m = schema.Maybe_Value\n\t\t\treturn nil\n\t\t}\n\t\t*na.w = *v2\n\t\t*na.m = schema.Maybe_Value\n\t\treturn nil\n\t}\n\tswitch v.Kind() {\n\tcase datamodel.Kind_Bool:\n\t\tv2, _ := v.AsBool()\n\t\treturn na.AssignBool(v2)\n\tcase datamodel.Kind_Int:\n\t\tv2, _ := v.AsInt()\n\t\treturn na.AssignInt(v2)\n\tcase datamodel.Kind_Float:\n\t\tv2, _ := v.AsFloat()\n\t\treturn na.AssignFloat(v2)\n\tcase datamodel.Kind_String:\n\t\tv2, _ := v.AsString()\n\t\treturn na.AssignString(v2)\n\tcase datamodel.Kind_Bytes:\n\t\tv2, _ := v.AsBytes()\n\t\treturn na.AssignBytes(v2)\n\tcase datamodel.Kind_Map:\n\t\tna, err := na.BeginMap(v.Length())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\titr := v.MapIterator()\n\t\tfor !itr.Done() {\n\t\t\tk, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := na.AssembleKey().AssignNode(k); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn na.Finish()\n\tcase datamodel.Kind_List:\n\t\tna, err := na.BeginList(v.Length())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\titr := v.ListIterator()\n\t\tfor !itr.Done() {\n\t\t\t_, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn na.Finish()\n\tcase datamodel.Kind_Link:\n\t\tv2, _ := v.AsLink()\n\t\treturn na.AssignLink(v2)\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (na *_UnionKinded__ReprAssembler) Prototype() datamodel.NodePrototype {\n\treturn _UnionKinded__ReprPrototype{}\n}\n"
  },
  {
    "path": "node/gendemo/ipldsch_types.go",
    "content": "package gendemo\n\n// Code generated by go-ipld-prime gengo.  DO NOT EDIT.\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\nvar _ datamodel.Node = nil // suppress errors when this dependency is not referenced\n// Type is a struct embeding a NodePrototype/Type for every Node implementation in this package.\n// One of its major uses is to start the construction of a value.\n// You can use it like this:\n//\n//\tgendemo.Type.YourTypeName.NewBuilder().BeginMap() //...\n//\n// and:\n//\n//\tgendemo.Type.OtherTypeName.NewBuilder().AssignString(\"x\") // ...\nvar Type typeSlab\n\ntype typeSlab struct {\n\tBar                     _Bar__Prototype\n\tBar__Repr               _Bar__ReprPrototype\n\tBaz                     _Baz__Prototype\n\tBaz__Repr               _Baz__ReprPrototype\n\tFoo                     _Foo__Prototype\n\tFoo__Repr               _Foo__ReprPrototype\n\tInt                     _Int__Prototype\n\tInt__Repr               _Int__ReprPrototype\n\tMap__String__Msg3       _Map__String__Msg3__Prototype\n\tMap__String__Msg3__Repr _Map__String__Msg3__ReprPrototype\n\tMsg3                    _Msg3__Prototype\n\tMsg3__Repr              _Msg3__ReprPrototype\n\tString                  _String__Prototype\n\tString__Repr            _String__ReprPrototype\n\tUnionKinded             _UnionKinded__Prototype\n\tUnionKinded__Repr       _UnionKinded__ReprPrototype\n}\n\n// --- type definitions follow ---\n\n// Bar matches the IPLD Schema type \"Bar\".  It has bool kind.\ntype Bar = *_Bar\ntype _Bar struct{ x bool }\n\n// Baz matches the IPLD Schema type \"Baz\".  It has string kind.\ntype Baz = *_Baz\ntype _Baz struct{ x string }\n\n// Foo matches the IPLD Schema type \"Foo\".  It has int kind.\ntype Foo = *_Foo\ntype _Foo struct{ x int64 }\n\n// Int matches the IPLD Schema type \"Int\".  It has int kind.\ntype Int = *_Int\ntype _Int struct{ x int64 }\n\n// Map__String__Msg3 matches the IPLD Schema type \"Map__String__Msg3\".  It has map kind.\ntype Map__String__Msg3 = *_Map__String__Msg3\ntype _Map__String__Msg3 struct {\n\tm map[_String]*_Msg3\n\tt []_Map__String__Msg3__entry\n}\ntype _Map__String__Msg3__entry struct {\n\tk _String\n\tv _Msg3\n}\n\n// Msg3 matches the IPLD Schema type \"Msg3\".  It has struct type-kind, and may be interrogated like map kind.\ntype Msg3 = *_Msg3\ntype _Msg3 struct {\n\twhee _Int\n\twoot _Int\n\twaga _Int\n}\n\n// String matches the IPLD Schema type \"String\".  It has string kind.\ntype String = *_String\ntype _String struct{ x string }\n\n// UnionKinded matches the IPLD Schema type \"UnionKinded\".\n// UnionKinded has union typekind, which means its data model behaviors are that of a map kind.\ntype UnionKinded = *_UnionKinded\ntype _UnionKinded struct {\n\ttag uint\n\tx1  _Foo\n\tx2  _Bar\n\tx3  _Baz\n}\ntype _UnionKinded__iface interface {\n\t_UnionKinded__member()\n}\n\nfunc (_Foo) _UnionKinded__member() {}\nfunc (_Bar) _UnionKinded__member() {}\nfunc (_Baz) _UnionKinded__member() {}\n"
  },
  {
    "path": "node/mixins/HACKME.md",
    "content": "node mixins and how to use them\n===============================\n\nThese mixins are here to:\n\n1. reduce the amount of code you need to write to create a new Node implementation, and\n2. standardize a lot of the error handling for common cases (especially, around kinds).\n\n\"Reduce the amount of code\" also has an application in codegen,\nwhere while it doesn't save any human effort, it does reduce GLOC size.\n(Or more precisely, it doesn't save *lines*, since we use them in verbose style,\nbut it does make those lines an awful lot shorter.)\n\nNote that these mixins are _not_ particularly here to help with performance.\n\n- all `ErrWrongKind` error are returned by value, which means a `runtime.convT2I` which means a heap allocation.\n  The error paths will therefore never be \"fast\"; it will *always* be cheaper\n  to check `kind` in advance than to probe and handle errors, if efficiency is your goal.\n- in general, there's really no way to improve upon the performance of having these methods simply writen directlyon your type.\n\nThese mixins will affect struct size if you use them via embed.\nThey can also be used without any effect on struct size if used more verbosely.\n\nThe binary/assembly output size is not affected by use of the mixins.\n(If using them verbosely -- e.g. still declaring methods on your type\nand using `return mixins.Kind{\"TypeName\"}.Method()` in the method body --\nthe end result is the inliner kicks in, and the end result is almost\nidentical binary size.)\n\nSummary:\n\n- SLOC: good, or neutral depending on use\n- GLOC: good\n- standardized: good\n- speed: neutral\n- mem size: neutral if used verbosely, bad if used most tersely\n- asm size: neutral\n"
  },
  {
    "path": "node/mixins/bool.go",
    "content": "package mixins\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// Bool can be embedded in a struct to provide all the methods that\n// have fixed output for any int-kinded nodes.\n// (Mostly this includes all the methods which simply return ErrWrongKind.)\n// Other methods will still need to be implemented to finish conforming to Node.\n//\n// To conserve memory and get a TypeName in errors without embedding,\n// write methods on your type with a body that simply initializes this struct\n// and immediately uses the relevant method;\n// this is more verbose in source, but compiles to a tighter result:\n// in memory, there's no embed; and in runtime, the calls will be inlined\n// and thus have no cost in execution time.\ntype Bool struct {\n\tTypeName string\n}\n\nfunc (Bool) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Bool\n}\nfunc (x Bool) LookupByString(string) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByString\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Bool}\n}\nfunc (x Bool) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Bool}\n}\nfunc (x Bool) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByIndex\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: datamodel.Kind_Bool}\n}\nfunc (x Bool) LookupBySegment(datamodel.PathSegment) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupBySegment\", AppropriateKind: datamodel.KindSet_Recursive, ActualKind: datamodel.Kind_Bool}\n}\nfunc (Bool) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (Bool) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (Bool) Length() int64 {\n\treturn -1\n}\nfunc (Bool) IsAbsent() bool {\n\treturn false\n}\nfunc (Bool) IsNull() bool {\n\treturn false\n}\nfunc (x Bool) AsInt() (int64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_Bool}\n}\nfunc (x Bool) AsFloat() (float64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: datamodel.Kind_Bool}\n}\nfunc (x Bool) AsString() (string, error) {\n\treturn \"\", datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: datamodel.Kind_Bool}\n}\nfunc (x Bool) AsBytes() ([]byte, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: datamodel.Kind_Bool}\n}\nfunc (x Bool) AsLink() (datamodel.Link, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: datamodel.Kind_Bool}\n}\n\n// BoolAssembler has similar purpose as Bool, but for (you guessed it)\n// the NodeAssembler interface rather than the Node interface.\ntype BoolAssembler struct {\n\tTypeName string\n}\n\nfunc (x BoolAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginMap\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Bool}\n}\nfunc (x BoolAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginList\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: datamodel.Kind_Bool}\n}\nfunc (x BoolAssembler) AssignNull() error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignNull\", AppropriateKind: datamodel.KindSet_JustNull, ActualKind: datamodel.Kind_Bool}\n}\nfunc (x BoolAssembler) AssignInt(int64) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_Bool}\n}\nfunc (x BoolAssembler) AssignFloat(float64) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: datamodel.Kind_Bool}\n}\nfunc (x BoolAssembler) AssignString(string) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: datamodel.Kind_Bool}\n}\nfunc (x BoolAssembler) AssignBytes([]byte) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: datamodel.Kind_Bool}\n}\nfunc (x BoolAssembler) AssignLink(datamodel.Link) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: datamodel.Kind_Bool}\n}\n"
  },
  {
    "path": "node/mixins/bytes.go",
    "content": "package mixins\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// Bytes can be embedded in a struct to provide all the methods that\n// have fixed output for any int-kinded nodes.\n// (Mostly this includes all the methods which simply return ErrWrongKind.)\n// Other methods will still need to be implemented to finish conforming to Node.\n//\n// To conserve memory and get a TypeName in errors without embedding,\n// write methods on your type with a body that simply initializes this struct\n// and immediately uses the relevant method;\n// this is more verbose in source, but compiles to a tighter result:\n// in memory, there's no embed; and in runtime, the calls will be inlined\n// and thus have no cost in execution time.\ntype Bytes struct {\n\tTypeName string\n}\n\nfunc (Bytes) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Bytes\n}\nfunc (x Bytes) LookupByString(string) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByString\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (x Bytes) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (x Bytes) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByIndex\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (x Bytes) LookupBySegment(datamodel.PathSegment) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupBySegment\", AppropriateKind: datamodel.KindSet_Recursive, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (Bytes) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (Bytes) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (Bytes) Length() int64 {\n\treturn -1\n}\nfunc (Bytes) IsAbsent() bool {\n\treturn false\n}\nfunc (Bytes) IsNull() bool {\n\treturn false\n}\nfunc (x Bytes) AsBool() (bool, error) {\n\treturn false, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (x Bytes) AsInt() (int64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (x Bytes) AsFloat() (float64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (x Bytes) AsString() (string, error) {\n\treturn \"\", datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (x Bytes) AsLink() (datamodel.Link, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: datamodel.Kind_Bytes}\n}\n\n// BytesAssembler has similar purpose as Bytes, but for (you guessed it)\n// the NodeAssembler interface rather than the Node interface.\ntype BytesAssembler struct {\n\tTypeName string\n}\n\nfunc (x BytesAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginMap\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (x BytesAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginList\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (x BytesAssembler) AssignNull() error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignNull\", AppropriateKind: datamodel.KindSet_JustNull, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (x BytesAssembler) AssignBool(bool) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (x BytesAssembler) AssignInt(int64) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (x BytesAssembler) AssignFloat(float64) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (x BytesAssembler) AssignString(string) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: datamodel.Kind_Bytes}\n}\nfunc (x BytesAssembler) AssignLink(datamodel.Link) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: datamodel.Kind_Bytes}\n}\n"
  },
  {
    "path": "node/mixins/delim.go",
    "content": "package mixins\n\n// This file is a little different than most of its siblings in this package.\n// It's not really much of a \"mixin\".  More of a util function junkdrawer.\n//\n// Implementations of Data Model Nodes are unlikely to need these.\n// Implementations of Schema-level Node *are* likely to need these, however.\n//\n// Our codegen implementation emits calls to these functions.\n// (And having these functions in a package that's already an unconditional\n// import in files emitted by codegen makes the codegen significantly simpler.)\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// SplitExact is much like strings.Split but will error if the number of\n// substrings is other than the expected count.\n//\n// SplitExact is used by the 'stringjoin' representation for structs.\n//\n// The 'count' parameter is a length.  In other words, if you expect\n// the zero'th index to be present in the result, you should ask for\n// a count of at least '1'.\n// Using this function with 'count' less than 2 is rather strange.\nfunc SplitExact(s string, sep string, count int) ([]string, error) {\n\tss := strings.Split(s, sep)\n\tif len(ss) != count {\n\t\treturn nil, fmt.Errorf(\"expected %d instances of the delimiter, found %d\", count-1, len(ss)-1)\n\t}\n\treturn ss, nil\n}\n\n// SplitN is an alias of strings.SplitN, which is only present here to\n// make it usable in codegen packages without requiring conditional imports\n// in the generation process.\nfunc SplitN(s, sep string, n int) []string {\n\treturn strings.SplitN(s, sep, n)\n}\n"
  },
  {
    "path": "node/mixins/delim_test.go",
    "content": "package mixins\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\tqt \"github.com/frankban/quicktest\"\n)\n\nfunc TestSplitExact(t *testing.T) {\n\ttype expect struct {\n\t\tvalue []string\n\t\terr   error\n\t}\n\ttype tcase struct {\n\t\ts      string\n\t\tsep    string\n\t\tcount  int\n\t\texpect expect\n\t}\n\tfor _, ent := range []tcase{\n\t\t{\"\", \"\", 0, expect{[]string{}, nil}},\n\t\t{\"\", \":\", 1, expect{[]string{\"\"}, nil}},\n\t\t{\"x\", \":\", 1, expect{[]string{\"x\"}, nil}},\n\t\t{\"x:y\", \":\", 2, expect{[]string{\"x\", \"y\"}, nil}},\n\t\t{\"x:y:\", \":\", 2, expect{nil, fmt.Errorf(\"expected 1 instances of the delimiter, found 2\")}},\n\t\t{\":x:y\", \":\", 2, expect{nil, fmt.Errorf(\"expected 1 instances of the delimiter, found 2\")}},\n\t\t{\"x:y:\", \":\", 3, expect{[]string{\"x\", \"y\", \"\"}, nil}},\n\t} {\n\t\tvalue, err := SplitExact(ent.s, ent.sep, ent.count)\n\t\tent2 := tcase{ent.s, ent.sep, ent.count, expect{value, err}}\n\t\tqt.Check(t, ent2, qt.CmpEquals(cmp.Exporter(func(reflect.Type) bool { return true })), ent)\n\t}\n}\n"
  },
  {
    "path": "node/mixins/float.go",
    "content": "package mixins\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// Float can be embedded in a struct to provide all the methods that\n// have fixed output for any int-kinded nodes.\n// (Mostly this includes all the methods which simply return ErrWrongKind.)\n// Other methods will still need to be implemented to finish conforming to Node.\n//\n// To conserve memory and get a TypeName in errors without embedding,\n// write methods on your type with a body that simply initializes this struct\n// and immediately uses the relevant method;\n// this is more verbose in source, but compiles to a tighter result:\n// in memory, there's no embed; and in runtime, the calls will be inlined\n// and thus have no cost in execution time.\ntype Float struct {\n\tTypeName string\n}\n\nfunc (Float) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Float\n}\nfunc (x Float) LookupByString(string) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByString\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Float}\n}\nfunc (x Float) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Float}\n}\nfunc (x Float) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByIndex\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: datamodel.Kind_Float}\n}\nfunc (x Float) LookupBySegment(datamodel.PathSegment) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupBySegment\", AppropriateKind: datamodel.KindSet_Recursive, ActualKind: datamodel.Kind_Float}\n}\nfunc (Float) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (Float) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (Float) Length() int64 {\n\treturn -1\n}\nfunc (Float) IsAbsent() bool {\n\treturn false\n}\nfunc (Float) IsNull() bool {\n\treturn false\n}\nfunc (x Float) AsBool() (bool, error) {\n\treturn false, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: datamodel.Kind_Float}\n}\nfunc (x Float) AsInt() (int64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_Float}\n}\nfunc (x Float) AsString() (string, error) {\n\treturn \"\", datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: datamodel.Kind_Float}\n}\nfunc (x Float) AsBytes() ([]byte, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: datamodel.Kind_Float}\n}\nfunc (x Float) AsLink() (datamodel.Link, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: datamodel.Kind_Float}\n}\n\n// FloatAssembler has similar purpose as Float, but for (you guessed it)\n// the NodeAssembler interface rather than the Node interface.\ntype FloatAssembler struct {\n\tTypeName string\n}\n\nfunc (x FloatAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginMap\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Float}\n}\nfunc (x FloatAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginList\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: datamodel.Kind_Float}\n}\nfunc (x FloatAssembler) AssignNull() error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignNull\", AppropriateKind: datamodel.KindSet_JustNull, ActualKind: datamodel.Kind_Float}\n}\nfunc (x FloatAssembler) AssignBool(bool) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: datamodel.Kind_Float}\n}\nfunc (x FloatAssembler) AssignInt(int64) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_Float}\n}\nfunc (x FloatAssembler) AssignString(string) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: datamodel.Kind_Float}\n}\nfunc (x FloatAssembler) AssignBytes([]byte) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: datamodel.Kind_Float}\n}\nfunc (x FloatAssembler) AssignLink(datamodel.Link) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: datamodel.Kind_Float}\n}\n"
  },
  {
    "path": "node/mixins/int.go",
    "content": "package mixins\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// Int can be embedded in a struct to provide all the methods that\n// have fixed output for any int-kinded nodes.\n// (Mostly this includes all the methods which simply return ErrWrongKind.)\n// Other methods will still need to be implemented to finish conforming to Node.\n//\n// To conserve memory and get a TypeName in errors without embedding,\n// write methods on your type with a body that simply initializes this struct\n// and immediately uses the relevant method;\n// this is more verbose in source, but compiles to a tighter result:\n// in memory, there's no embed; and in runtime, the calls will be inlined\n// and thus have no cost in execution time.\ntype Int struct {\n\tTypeName string\n}\n\nfunc (Int) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Int\n}\nfunc (x Int) LookupByString(string) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByString\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Int}\n}\nfunc (x Int) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Int}\n}\nfunc (x Int) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByIndex\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: datamodel.Kind_Int}\n}\nfunc (x Int) LookupBySegment(datamodel.PathSegment) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupBySegment\", AppropriateKind: datamodel.KindSet_Recursive, ActualKind: datamodel.Kind_Int}\n}\nfunc (Int) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (Int) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (Int) Length() int64 {\n\treturn -1\n}\nfunc (Int) IsAbsent() bool {\n\treturn false\n}\nfunc (Int) IsNull() bool {\n\treturn false\n}\nfunc (x Int) AsBool() (bool, error) {\n\treturn false, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: datamodel.Kind_Int}\n}\nfunc (x Int) AsFloat() (float64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: datamodel.Kind_Int}\n}\nfunc (x Int) AsString() (string, error) {\n\treturn \"\", datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: datamodel.Kind_Int}\n}\nfunc (x Int) AsBytes() ([]byte, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: datamodel.Kind_Int}\n}\nfunc (x Int) AsLink() (datamodel.Link, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: datamodel.Kind_Int}\n}\n\n// IntAssembler has similar purpose as Int, but for (you guessed it)\n// the NodeAssembler interface rather than the Node interface.\ntype IntAssembler struct {\n\tTypeName string\n}\n\nfunc (x IntAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginMap\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Int}\n}\nfunc (x IntAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginList\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: datamodel.Kind_Int}\n}\nfunc (x IntAssembler) AssignNull() error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignNull\", AppropriateKind: datamodel.KindSet_JustNull, ActualKind: datamodel.Kind_Int}\n}\nfunc (x IntAssembler) AssignBool(bool) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: datamodel.Kind_Int}\n}\nfunc (x IntAssembler) AssignFloat(float64) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: datamodel.Kind_Int}\n}\nfunc (x IntAssembler) AssignString(string) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: datamodel.Kind_Int}\n}\nfunc (x IntAssembler) AssignBytes([]byte) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: datamodel.Kind_Int}\n}\nfunc (x IntAssembler) AssignLink(datamodel.Link) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: datamodel.Kind_Int}\n}\n"
  },
  {
    "path": "node/mixins/link.go",
    "content": "package mixins\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// Link can be embedded in a struct to provide all the methods that\n// have fixed output for any int-kinded nodes.\n// (Mostly this includes all the methods which simply return ErrWrongKind.)\n// Other methods will still need to be implemented to finish conforming to Node.\n//\n// To conserve memory and get a TypeName in errors without embedding,\n// write methods on your type with a body that simply initializes this struct\n// and immediately uses the relevant method;\n// this is more verbose in source, but compiles to a tighter result:\n// in memory, there's no embed; and in runtime, the calls will be inlined\n// and thus have no cost in execution time.\ntype Link struct {\n\tTypeName string\n}\n\nfunc (Link) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Link\n}\nfunc (x Link) LookupByString(string) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByString\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Link}\n}\nfunc (x Link) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Link}\n}\nfunc (x Link) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByIndex\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: datamodel.Kind_Link}\n}\nfunc (x Link) LookupBySegment(datamodel.PathSegment) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupBySegment\", AppropriateKind: datamodel.KindSet_Recursive, ActualKind: datamodel.Kind_Link}\n}\nfunc (Link) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (Link) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (Link) Length() int64 {\n\treturn -1\n}\nfunc (Link) IsAbsent() bool {\n\treturn false\n}\nfunc (Link) IsNull() bool {\n\treturn false\n}\nfunc (x Link) AsBool() (bool, error) {\n\treturn false, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: datamodel.Kind_Link}\n}\nfunc (x Link) AsInt() (int64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_Link}\n}\nfunc (x Link) AsFloat() (float64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: datamodel.Kind_Link}\n}\nfunc (x Link) AsString() (string, error) {\n\treturn \"\", datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: datamodel.Kind_Link}\n}\nfunc (x Link) AsBytes() ([]byte, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: datamodel.Kind_Link}\n}\n\n// LinkAssembler has similar purpose as Link, but for (you guessed it)\n// the NodeAssembler interface rather than the Node interface.\ntype LinkAssembler struct {\n\tTypeName string\n}\n\nfunc (x LinkAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginMap\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_Link}\n}\nfunc (x LinkAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginList\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: datamodel.Kind_Link}\n}\nfunc (x LinkAssembler) AssignNull() error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignNull\", AppropriateKind: datamodel.KindSet_JustNull, ActualKind: datamodel.Kind_Link}\n}\nfunc (x LinkAssembler) AssignBool(bool) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: datamodel.Kind_Link}\n}\nfunc (x LinkAssembler) AssignInt(int64) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_Link}\n}\nfunc (x LinkAssembler) AssignFloat(float64) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: datamodel.Kind_Link}\n}\nfunc (x LinkAssembler) AssignString(string) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: datamodel.Kind_Link}\n}\nfunc (x LinkAssembler) AssignBytes([]byte) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: datamodel.Kind_Link}\n}\n"
  },
  {
    "path": "node/mixins/list.go",
    "content": "package mixins\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// List can be embedded in a struct to provide all the methods that\n// have fixed output for any int-kinded nodes.\n// (Mostly this includes all the methods which simply return ErrWrongKind.)\n// Other methods will still need to be implemented to finish conforming to Node.\n//\n// To conserve memory and get a TypeName in errors without embedding,\n// write methods on your type with a body that simply initializes this struct\n// and immediately uses the relevant method;\n// this is more verbose in source, but compiles to a tighter result:\n// in memory, there's no embed; and in runtime, the calls will be inlined\n// and thus have no cost in execution time.\ntype List struct {\n\tTypeName string\n}\n\nfunc (List) Kind() datamodel.Kind {\n\treturn datamodel.Kind_List\n}\nfunc (x List) LookupByString(string) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByString\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_List}\n}\nfunc (x List) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_List}\n}\nfunc (List) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (List) IsAbsent() bool {\n\treturn false\n}\nfunc (List) IsNull() bool {\n\treturn false\n}\nfunc (x List) AsBool() (bool, error) {\n\treturn false, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: datamodel.Kind_List}\n}\nfunc (x List) AsInt() (int64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_List}\n}\nfunc (x List) AsFloat() (float64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: datamodel.Kind_List}\n}\nfunc (x List) AsString() (string, error) {\n\treturn \"\", datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: datamodel.Kind_List}\n}\nfunc (x List) AsBytes() ([]byte, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: datamodel.Kind_List}\n}\nfunc (x List) AsLink() (datamodel.Link, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: datamodel.Kind_List}\n}\n\n// ListAssembler has similar purpose as List, but for (you guessed it)\n// the NodeAssembler interface rather than the Node interface.\ntype ListAssembler struct {\n\tTypeName string\n}\n\nfunc (x ListAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginMap\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_List}\n}\nfunc (x ListAssembler) AssignNull() error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignNull\", AppropriateKind: datamodel.KindSet_JustNull, ActualKind: datamodel.Kind_List}\n}\nfunc (x ListAssembler) AssignBool(bool) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: datamodel.Kind_List}\n}\nfunc (x ListAssembler) AssignInt(int64) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_List}\n}\nfunc (x ListAssembler) AssignFloat(float64) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: datamodel.Kind_List}\n}\nfunc (x ListAssembler) AssignString(string) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: datamodel.Kind_List}\n}\nfunc (x ListAssembler) AssignBytes([]byte) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: datamodel.Kind_List}\n}\nfunc (x ListAssembler) AssignLink(datamodel.Link) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: datamodel.Kind_List}\n}\n"
  },
  {
    "path": "node/mixins/map.go",
    "content": "package mixins\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// Map can be embedded in a struct to provide all the methods that\n// have fixed output for any map-kinded nodes.\n// (Mostly this includes all the methods which simply return ErrWrongKind.)\n// Other methods will still need to be implemented to finish conforming to Node.\n//\n// To conserve memory and get a TypeName in errors without embedding,\n// write methods on your type with a body that simply initializes this struct\n// and immediately uses the relevant method;\n// this is more verbose in source, but compiles to a tighter result:\n// in memory, there's no embed; and in runtime, the calls will be inlined\n// and thus have no cost in execution time.\ntype Map struct {\n\tTypeName string\n}\n\nfunc (Map) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Map\n}\nfunc (x Map) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByIndex\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: datamodel.Kind_Map}\n}\nfunc (Map) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (Map) IsAbsent() bool {\n\treturn false\n}\nfunc (Map) IsNull() bool {\n\treturn false\n}\nfunc (x Map) AsBool() (bool, error) {\n\treturn false, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: datamodel.Kind_Map}\n}\nfunc (x Map) AsInt() (int64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_Map}\n}\nfunc (x Map) AsFloat() (float64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: datamodel.Kind_Map}\n}\nfunc (x Map) AsString() (string, error) {\n\treturn \"\", datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: datamodel.Kind_Map}\n}\nfunc (x Map) AsBytes() ([]byte, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: datamodel.Kind_Map}\n}\nfunc (x Map) AsLink() (datamodel.Link, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: datamodel.Kind_Map}\n}\n\n// MapAssembler has similar purpose as Map, but for (you guessed it)\n// the NodeAssembler interface rather than the Node interface.\ntype MapAssembler struct {\n\tTypeName string\n}\n\nfunc (x MapAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginList\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: datamodel.Kind_Map}\n}\nfunc (x MapAssembler) AssignNull() error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignNull\", AppropriateKind: datamodel.KindSet_JustNull, ActualKind: datamodel.Kind_Map}\n}\nfunc (x MapAssembler) AssignBool(bool) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: datamodel.Kind_Map}\n}\nfunc (x MapAssembler) AssignInt(int64) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_Map}\n}\nfunc (x MapAssembler) AssignFloat(float64) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: datamodel.Kind_Map}\n}\nfunc (x MapAssembler) AssignString(string) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignString\", AppropriateKind: datamodel.KindSet_JustString, ActualKind: datamodel.Kind_Map}\n}\nfunc (x MapAssembler) AssignBytes([]byte) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: datamodel.Kind_Map}\n}\nfunc (x MapAssembler) AssignLink(datamodel.Link) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: datamodel.Kind_Map}\n}\n"
  },
  {
    "path": "node/mixins/string.go",
    "content": "package mixins\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// String can be embedded in a struct to provide all the methods that\n// have fixed output for any string-kinded nodes.\n// (Mostly this includes all the methods which simply return ErrWrongKind.)\n// Other methods will still need to be implemented to finish conforming to Node.\n//\n// To conserve memory and get a TypeName in errors without embedding,\n// write methods on your type with a body that simply initializes this struct\n// and immediately uses the relevant method;\n// this is more verbose in source, but compiles to a tighter result:\n// in memory, there's no embed; and in runtime, the calls will be inlined\n// and thus have no cost in execution time.\ntype String struct {\n\tTypeName string\n}\n\nfunc (String) Kind() datamodel.Kind {\n\treturn datamodel.Kind_String\n}\nfunc (x String) LookupByString(string) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByString\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_String}\n}\nfunc (x String) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_String}\n}\nfunc (x String) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByIndex\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: datamodel.Kind_String}\n}\nfunc (x String) LookupBySegment(datamodel.PathSegment) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupBySegment\", AppropriateKind: datamodel.KindSet_Recursive, ActualKind: datamodel.Kind_String}\n}\nfunc (String) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (String) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (String) Length() int64 {\n\treturn -1\n}\nfunc (String) IsAbsent() bool {\n\treturn false\n}\nfunc (String) IsNull() bool {\n\treturn false\n}\nfunc (x String) AsBool() (bool, error) {\n\treturn false, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: datamodel.Kind_String}\n}\nfunc (x String) AsInt() (int64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_String}\n}\nfunc (x String) AsFloat() (float64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: datamodel.Kind_String}\n}\nfunc (x String) AsBytes() ([]byte, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: datamodel.Kind_String}\n}\nfunc (x String) AsLink() (datamodel.Link, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: datamodel.Kind_String}\n}\n\n// StringAssembler has similar purpose as String, but for (you guessed it)\n// the NodeAssembler interface rather than the Node interface.\ntype StringAssembler struct {\n\tTypeName string\n}\n\nfunc (x StringAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginMap\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: datamodel.Kind_String}\n}\nfunc (x StringAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginList\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: datamodel.Kind_String}\n}\nfunc (x StringAssembler) AssignNull() error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignNull\", AppropriateKind: datamodel.KindSet_JustNull, ActualKind: datamodel.Kind_String}\n}\nfunc (x StringAssembler) AssignBool(bool) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBool\", AppropriateKind: datamodel.KindSet_JustBool, ActualKind: datamodel.Kind_String}\n}\nfunc (x StringAssembler) AssignInt(int64) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignInt\", AppropriateKind: datamodel.KindSet_JustInt, ActualKind: datamodel.Kind_String}\n}\nfunc (x StringAssembler) AssignFloat(float64) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignFloat\", AppropriateKind: datamodel.KindSet_JustFloat, ActualKind: datamodel.Kind_String}\n}\nfunc (x StringAssembler) AssignBytes([]byte) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBytes\", AppropriateKind: datamodel.KindSet_JustBytes, ActualKind: datamodel.Kind_String}\n}\nfunc (x StringAssembler) AssignLink(datamodel.Link) error {\n\treturn datamodel.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignLink\", AppropriateKind: datamodel.KindSet_JustLink, ActualKind: datamodel.Kind_String}\n}\n"
  },
  {
    "path": "node/mixins/tmplMixin.txt",
    "content": "// copy this and remove methods that aren't relevant to your kind.\n// this has not been scripted.\n// (the first part is trivial; the second part is not; and this updates rarely.  https://xkcd.com/1205/ applies.)\n\npackage mixins\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// @Kind@ can be embedded in a struct to provide all the methods that\n// have fixed output for any int-kinded nodes.\n// (Mostly this includes all the methods which simply return ErrWrongKind.)\n// Other methods will still need to be implemented to finish conforming to Node.\n//\n// To conserve memory and get a TypeName in errors without embedding,\n// write methods on your type with a body that simply initializes this struct\n// and immediately uses the relevant method;\n// this is more verbose in source, but compiles to a tighter result:\n// in memory, there's no embed; and in runtime, the calls will be inlined\n// and thus have no cost in execution time.\ntype @Kind@ struct {\n\tTypeName string\n}\n\nfunc (@Kind@) Kind() ipld.Kind {\n\treturn ipld.Kind_@Kind@\n}\nfunc (x @Kind@) LookupByString(string) (ipld.Node, error) {\n\treturn nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByString\", AppropriateKind: ipld.KindSet_JustMap, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@) LookupByNode(key ipld.Node) (ipld.Node, error) {\n\treturn nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByNode\", AppropriateKind: ipld.KindSet_JustMap, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@) LookupByIndex(idx int) (ipld.Node, error) {\n\treturn nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupByIndex\", AppropriateKind: ipld.KindSet_JustList, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@) LookupBySegment(ipld.PathSegment) (ipld.Node, error) {\n\treturn nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"LookupBySegment\", AppropriateKind: ipld.KindSet_Recursive, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (@Kind@) MapIterator() ipld.MapIterator {\n\treturn nil\n}\nfunc (@Kind@) ListIterator() ipld.ListIterator {\n\treturn nil\n}\nfunc (@Kind@) Length() int {\n\treturn -1\n}\nfunc (@Kind@) IsAbsent() bool {\n\treturn false\n}\nfunc (@Kind@) IsNull() bool {\n\treturn false\n}\nfunc (x @Kind@) AsBool() (bool, error) {\n\treturn false, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBool\", AppropriateKind: ipld.KindSet_JustBool, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@) AsInt() (int, error) {\n\treturn 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsInt\", AppropriateKind: ipld.KindSet_JustInt, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@) AsFloat() (float64, error) {\n\treturn 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsFloat\", AppropriateKind: ipld.KindSet_JustFloat, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@) AsString() (string, error) {\n\treturn \"\", ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsString\", AppropriateKind: ipld.KindSet_JustString, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@) AsBytes() ([]byte, error) {\n\treturn nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsBytes\", AppropriateKind: ipld.KindSet_JustBytes, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@) AsLink() (ipld.Link, error) {\n\treturn nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AsLink\", AppropriateKind: ipld.KindSet_JustLink, ActualKind: ipld.Kind_@Kind@}\n}\n\n// @Kind@Assembler has similar purpose as @Kind@, but for (you guessed it)\n// the NodeAssembler interface rather than the Node interface.\ntype @Kind@Assembler struct {\n\tTypeName string\n}\n\nfunc (x @Kind@Assembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) {\n\treturn nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginMap\", AppropriateKind: ipld.KindSet_JustMap, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@Assembler) BeginList(sizeHint int) (ipld.ListAssembler, error) {\n\treturn nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"BeginList\", AppropriateKind: ipld.KindSet_JustList, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@Assembler) AssignNull() error {\n\treturn ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignNull\", AppropriateKind: ipld.KindSet_JustNull, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@Assembler) AssignBool(bool) error {\n\treturn ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBool\", AppropriateKind: ipld.KindSet_JustBool, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@Assembler) AssignInt(int) error {\n\treturn ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignInt\", AppropriateKind: ipld.KindSet_JustInt, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@Assembler) AssignFloat(float64) error {\n\treturn ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignFloat\", AppropriateKind: ipld.KindSet_JustFloat, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@Assembler) AssignString(string) error {\n\treturn ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignString\", AppropriateKind: ipld.KindSet_JustString, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@Assembler) AssignBytes([]byte) error {\n\treturn ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignBytes\", AppropriateKind: ipld.KindSet_JustBytes, ActualKind: ipld.Kind_@Kind@}\n}\nfunc (x @Kind@Assembler) AssignLink(ipld.Link) error {\n\treturn ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: \"AssignLink\", AppropriateKind: ipld.KindSet_JustLink, ActualKind: ipld.Kind_@Kind@}\n}\n"
  },
  {
    "path": "node/tests/HACKME.md",
    "content": "HACKME\n======\n\nThis package is for reusable tests and benchmarks.\nThese test and benchmark functions work over the Node and NodeBuilder interfaces,\nso they should work to test compatibility and compare performance of various implementations of Node.\n\nThis is easier said than done.\n\n\nNaming conventions\n------------------\n\n### name prefix\n\nAll reusable test functions start with the name prefix `TestSpec_`.\n\nAll reusable benchmarks start with the name prefix `BenchmarkSpec_`.\n\nThe \"Test\" and \"Benchmark\" prefixes are as per the requirements of the\ngolang standard `testing` package.  They take `*testing.T` and `*testing.B`\narguments respectively.  They also take at least one interface argument\nwhich is how you give your Node implementation to the test spec.\n\nThe word \"Spec\" reflects on the fact that these are reusable/standardized tests.\n\nWe recommend you copy-paste these method names outright into the package of your Node implementation.\nIt's not necessary, but it's nice for consistency.\n(In the future, there may be tooling to help make automated comparisons\nof different Node implementation's relative performance; this would\nnecessarily rely on consistent names across packages.)\n\nIf your Node implementation package has *more* tests and benchmarks that\n*are not* from this reusable set, that's great -- but don't use the \"Spec\"\nword as a segment of their name; it'll make processing bulk output easier.\n\n### full pattern\n\nThe full pattern is:\n\n`BenchmarkSpec_{Application}_{FixtureCohort}/codec={codec}/n={size}`\n\n- `{Application}` means what feature or big-picture behavior we're testing.\n  Examples include \"Marshal\", \"Unmarshal\", \"Walk\", etc.\n- `{FixtureCohort}` means... well, see the names from the 'corpus' subpackage;\n  it should be literally one of those strings.\n- `n={size}` will be present for variable-scale benchmarks.\n  You'll have to consider the Application and FixtureCohort to understand the\n  context of what part of the data is being varied in size, though.\n- `codec={codec}` is an example of extra info that might exist for some applications.\n  For example, it might include \"json\" and \"cbor\" for \"Marshal\" and \"Unmarshal\",\n  but will not be seen at all in other applications like \"Walk\".\n\nThe parts after the slash are those which are handled internally.\nFor those, you call the `BenchmarkSpec_*` function name (stopping before the first slash),\nand that function will call `b.Run` to make sub-tests for all the variations.\nFor example, when you call `BenchmarkSpec_Walk_MapNStrMap3StrInt`, that one call\nwill result in a suite of tests for various sizes, each of which will be denoted\nin the output by `BenchmarkSpec_Walk_MapNStrMap3StrInt/n=1`, then `.../n=2`, etc.\n\n### variable scale benchmarks\n\nSome corpuses have fixed sizes.  Some are variable.\n\nWith fixed-size corpuses, you'll see an integer in the \"FixtureCohort\" name.\nFor variable-size corpuses, you'll see the letter \"N\" in place of an integer.\n\nSee the docs in the 'corpus' subpackage for more discussion of this.\n"
  },
  {
    "path": "node/tests/byteSpecs.go",
    "content": "package tests\n\nimport (\n\t\"io\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\nfunc SpecTestBytes(t *testing.T, np datamodel.NodePrototype) {\n\tt.Run(\"byte node\", func(t *testing.T) {\n\t\tnb := np.NewBuilder()\n\t\terr := nb.AssignBytes([]byte(\"asdf\"))\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tn := nb.Build()\n\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Bytes)\n\t\tqt.Check(t, n.IsNull(), qt.IsFalse)\n\t\tx, err := n.AsBytes()\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, x, qt.DeepEquals, []byte(\"asdf\"))\n\n\t\tlbn, ok := n.(datamodel.LargeBytesNode)\n\t\tif ok {\n\t\t\tstr, err := lbn.AsLargeBytes()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tbytes, err := io.ReadAll(str)\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, bytes, qt.DeepEquals, []byte(\"asdf\"))\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "node/tests/checkers.go",
    "content": "package tests\n\nimport (\n\t\"errors\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/printer\"\n)\n\n// NodeContentEquals checks whether two nodes have equal content by first encoding them via\n// printer.Sprint, then checking that the generated encodings are identical.\n//\n// Use DeepNodeContentsEquals if you want a less strict comparison that does not\n// require map keys to be in the same order.\n//\n// See: printer.Sprint.\nvar NodeContentEquals = &nodeContentEqualsChecker{}\n\ntype nodeContentEqualsChecker struct{}\n\nfunc (n *nodeContentEqualsChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) error {\n\twant := args[0]\n\tif want == nil {\n\t\treturn qt.IsNil.Check(got, args, note)\n\t}\n\tif got == nil {\n\t\treturn qt.IsNotNil.Check(got, args, note)\n\t}\n\twantNode, ok := want.(datamodel.Node)\n\tif !ok {\n\t\treturn errors.New(\"this checker only supports checking datamodel.Node values\")\n\t}\n\twantPrint := printer.Sprint(wantNode)\n\n\tgotNode, ok := got.(datamodel.Node)\n\tif !ok {\n\t\treturn errors.New(\"this checker only supports checking datamodel.Node values\")\n\t}\n\tgotPrint := printer.Sprint(gotNode)\n\treturn qt.Equals.Check(gotPrint, []interface{}{wantPrint}, note)\n}\n\nfunc (n *nodeContentEqualsChecker) ArgNames() []string {\n\treturn []string{\"got\", \"want node\"}\n}\n\n// DeepNodeContentsEquals checks whether two nodes have equal content by\n// walking the nodes recursively and comparing their contents. This is similar\n// to datamodel.DeepEquals except that map keys DO NOT need to be strictly\n// the same order to be considered equal.\n//\n// Use NodeContentEquals if you want a more strict comparison.\nvar DeepNodeContentsEquals = &deepNodeContentsEqualsChecker{}\n\ntype deepNodeContentsEqualsChecker struct{}\n\nfunc (n *deepNodeContentsEqualsChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) error {\n\twant := args[0]\n\tif want == nil {\n\t\treturn qt.IsNil.Check(got, args, note)\n\t}\n\tif got == nil {\n\t\treturn qt.IsNotNil.Check(got, args, note)\n\t}\n\twantNode, ok := want.(datamodel.Node)\n\tif !ok {\n\t\treturn errors.New(\"this checker only supports checking datamodel.Node values\")\n\t}\n\n\tgotNode, ok := got.(datamodel.Node)\n\tif !ok {\n\t\treturn errors.New(\"this checker only supports checking datamodel.Node values\")\n\t}\n\n\treturn deepEqualCheck(gotNode, wantNode, note)\n}\n\nfunc (n *deepNodeContentsEqualsChecker) ArgNames() []string {\n\treturn []string{\"got\", \"want node\"}\n}\n\nfunc deepEqualCheck(x, y datamodel.Node, note func(key string, value interface{})) error {\n\tif x == nil || y == nil {\n\t\tif err := qt.Equals.Check(x, []interface{}{y}, note); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\txk, yk := x.Kind(), y.Kind()\n\tif err := qt.Equals.Check(xk, []interface{}{yk}, note); err != nil {\n\t\treturn err\n\t}\n\n\tswitch xk {\n\n\t// Scalar kinds.\n\tcase datamodel.Kind_Null:\n\t\treturn qt.Equals.Check(x.IsNull(), []interface{}{y.IsNull()}, note)\n\tcase datamodel.Kind_Bool:\n\t\txv, err := x.AsBool()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tyv, err := y.AsBool()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn qt.Equals.Check(xv, []interface{}{yv}, note)\n\tcase datamodel.Kind_Int:\n\t\txv, err := x.AsInt()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tyv, err := y.AsInt()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn qt.Equals.Check(xv, []interface{}{yv}, note)\n\tcase datamodel.Kind_Float:\n\t\txv, err := x.AsFloat()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tyv, err := y.AsFloat()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn qt.Equals.Check(xv, []interface{}{yv}, note)\n\tcase datamodel.Kind_String:\n\t\txv, err := x.AsString()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tyv, err := y.AsString()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn qt.Equals.Check(xv, []interface{}{yv}, note)\n\tcase datamodel.Kind_Bytes:\n\t\txv, err := x.AsBytes()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tyv, err := y.AsBytes()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn qt.Equals.Check(string(xv), []interface{}{string(yv)}, note)\n\tcase datamodel.Kind_Link:\n\t\txv, err := x.AsLink()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tyv, err := y.AsLink()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\t// Links are just compared via ==.\n\t\t// This requires the types to exactly match,\n\t\t// and the values to be equal as per == too.\n\t\t// This will generally work,\n\t\t// as ipld-prime assumes link types to be consistent.\n\t\treturn qt.Equals.Check(xv, []interface{}{yv}, note)\n\n\t// Recursive kinds.\n\tcase datamodel.Kind_Map:\n\t\tif err := qt.Equals.Check(x.Length(), []interface{}{y.Length()}, note); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tykeys := make([]string, y.Length())\n\t\tyitr := y.MapIterator()\n\t\tfor !yitr.Done() {\n\t\t\tykey, _, err := yitr.Next()\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tyk, err := ykey.AsString()\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tykeys = append(ykeys, yk)\n\t\t}\n\t\txitr := x.MapIterator()\n\t\tfor !xitr.Done() {\n\t\t\txkey, xval, err := xitr.Next()\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\txk, err := xkey.AsString()\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tif err := qt.Contains.Check(ykeys, []interface{}{xk}, note); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tyval, err := y.LookupByNode(xkey)\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tif err := deepEqualCheck(xval, yval, note); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\tcase datamodel.Kind_List:\n\t\tif err := qt.Equals.Check(x.Length(), []interface{}{y.Length()}, note); err != nil {\n\t\t\treturn err\n\t\t}\n\t\txitr := x.ListIterator()\n\t\tyitr := y.ListIterator()\n\t\tfor !xitr.Done() && !yitr.Done() {\n\t\t\t_, xval, err := xitr.Next()\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\t_, yval, err := yitr.Next()\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tif err := deepEqualCheck(xval, yval, note); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\n\t// As per the docs, other kinds such as Invalid are not deeply equal.\n\tdefault:\n\t\tpanic(\"bad kind\")\n\t}\n}\n"
  },
  {
    "path": "node/tests/checkers_test.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc Test_nodeContentEqualsChecker_Check(t *testing.T) {\n\tsomeNode := basicnode.Prototype__String{}.NewBuilder().Build()\n\tnb := basicnode.Prototype__String{}.NewBuilder()\n\terr := nb.AssignString(\"fish\")\n\tqt.Assert(t, err, qt.IsNil)\n\tsomeOtherNode := nb.Build()\n\n\ttests := []struct {\n\t\tname    string\n\t\tgot     interface{}\n\t\twant    interface{}\n\t\twantErr string\n\t}{\n\t\t{\n\t\t\tname:    \"nilWantIsError\",\n\t\t\tgot:     \"not a node\",\n\t\t\twant:    nil,\n\t\t\twantErr: \"got non-nil value\",\n\t\t},\n\t\t{\n\t\t\tname:    \"nonNodeAsWantIsError\",\n\t\t\tgot:     \"not a node\",\n\t\t\twant:    someNode,\n\t\t\twantErr: \"this checker only supports checking datamodel.Node values\",\n\t\t},\n\t\t{\n\t\t\tname:    \"nonNodeAsGotIsError\",\n\t\t\tgot:     someNode,\n\t\t\twant:    \"not a node\",\n\t\t\twantErr: \"this checker only supports checking datamodel.Node values\",\n\t\t},\n\t\t{\n\t\t\tname: \"nilWantAndGotAreEqual\",\n\t\t\tgot:  nil,\n\t\t\twant: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"equivalentNodesAreEqual\",\n\t\t\tgot:  someNode,\n\t\t\twant: someNode,\n\t\t},\n\t\t{\n\t\t\tname:    \"differentNodesAreNotEqual\",\n\t\t\tgot:     someNode,\n\t\t\twant:    someOtherNode,\n\t\t\twantErr: \"values are not equal\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := NodeContentEquals.Check(tt.got, []interface{}{tt.want}, nil)\n\t\t\tif tt.wantErr == \"\" {\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t} else {\n\t\t\t\tqt.Assert(t, err, qt.Not(qt.IsNil))\n\t\t\t\tqt.Assert(t, err.Error(), qt.Equals, tt.wantErr)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "node/tests/corpus/corpus.go",
    "content": "/*\nThe corpus package exports some values useful for building tests and benchmarks.\n\nValues come as JSON strings.  It is assumed you can unmarshal those.\nThe reason we do this is so that this corpus package doesn't import\nany particular concrete implementation of ipld.Node... since that would\nmake it ironically incapable of being used for that Node's tests.\n\nThe naming convention is roughly as follows:\n\n  - {Kind}{{Count}|N}{KeyKind}{ValueKind}\n  - 'Kind' is usually 'Map' or 'List'.\n    It can also be a scalar like 'Int', in which case that's it.\n  - If a specific int is given for 'Count', that's the size of the thing;\n  - if 'N' is present, it's a scalable corpus and you can decide the size.\n  - 'KeyKind' is present for maps (it will be string...).\n  - 'ValueKind' is present for maps and lists.  It can recurse.\n\nOf course, this naming convention is not perfectly specific,\nbut it's usually enough for our needs, or at least enough to get started.\nSome corpuses designed for probing (for example) tuple-represented structs\nwill end up with interesting designations for various reasons:\n\n  - some corpuses are meant to test struct semantics.\n    This is usually what it means when you see fixed size maps.\n    \"List5Various\" can also be this reason (it's for tuple-represented structs).\n  - some corpuses are meant to test nullable or optional semantics.\n    These might have name suffixes like \"WithNull\" to indicate this.\n\nEverything is exported as a function, for consistency.\nMany functions need no args.\nSome functions need an argument for \"N\".\n\nIf you're using these corpuses in a benchmark, don't forget to call\n`b.ResetTimer()` after getting the corpus.\n*/\npackage corpus\n\nimport (\n\t\"fmt\"\n)\n\nfunc Map3StrInt() string {\n\treturn `{\"whee\":1,\"woot\":2,\"waga\":3}`\n}\n\nfunc MapNStrInt(n int) string {\n\treturn `{` + ents(n, func(i int) string {\n\t\treturn fmt.Sprintf(`\"k%d\":%d`, i, i)\n\t}) + `}`\n}\n\nfunc MapNStrMap3StrInt(n int) string {\n\treturn `{` + ents(n, func(i int) string {\n\t\treturn fmt.Sprintf(`\"k%d\":`, i) +\n\t\t\tfmt.Sprintf(`{\"whee\":%d,\"woot\":%d,\"waga\":%d}`, i*3+1, i*3+2, i*3+3)\n\t}) + `}`\n}\n"
  },
  {
    "path": "node/tests/corpus/corpus_test.go",
    "content": "package corpus\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/must\"\n)\n\n/*\n\tSanity check that our corpuses are actually correct JSON in this package,\n\tbefore we start letting other packages find that out for us the hard way.\n*/\n\nfunc TestCorpusValidity(t *testing.T) {\n\tmust.True(json.Valid([]byte(MapNStrInt(0))))\n\tmust.True(json.Valid([]byte(MapNStrInt(1))))\n\tmust.True(json.Valid([]byte(MapNStrInt(2))))\n\tmust.True(json.Valid([]byte(MapNStrMap3StrInt(0))))\n\tmust.True(json.Valid([]byte(MapNStrMap3StrInt(1))))\n\tmust.True(json.Valid([]byte(MapNStrMap3StrInt(2))))\n}\n"
  },
  {
    "path": "node/tests/corpus/util.go",
    "content": "package corpus\n\nimport (\n\t\"bytes\"\n)\n\nfunc ents(n int, segFn func(i int) string) string {\n\tif n <= 0 {\n\t\treturn \"\"\n\t}\n\tvar buf bytes.Buffer\n\tfor i := 0; i < n; i++ {\n\t\tbuf.WriteString(segFn(i))\n\t\tbuf.WriteString(`,`)\n\t}\n\tbuf.Truncate(buf.Len() - 1)\n\treturn buf.String()\n}\n"
  },
  {
    "path": "node/tests/listSpecs.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n)\n\nfunc SpecTestListString(t *testing.T, np datamodel.NodePrototype) {\n\tt.Run(\"list<string>, 3 entries\", func(t *testing.T) {\n\t\tn := fluent.MustBuildList(np, 3, func(la fluent.ListAssembler) {\n\t\t\tla.AssembleValue().AssignString(\"one\")\n\t\t\tla.AssembleValue().AssignString(\"two\")\n\t\t\tla.AssembleValue().AssignString(\"three\")\n\t\t})\n\t\tt.Run(\"reads back out\", func(t *testing.T) {\n\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(3))\n\n\t\t\tv, err := n.LookupByIndex(0)\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, must.String(v), qt.Equals, \"one\")\n\n\t\t\tv, err = n.LookupByIndex(1)\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, must.String(v), qt.Equals, \"two\")\n\n\t\t\tv, err = n.LookupByIndex(2)\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, must.String(v), qt.Equals, \"three\")\n\t\t})\n\t\tt.Run(\"reads via iteration\", func(t *testing.T) {\n\t\t\titr := n.ListIterator()\n\n\t\t\tqt.Check(t, itr.Done(), qt.IsFalse)\n\t\t\tidx, v, err := itr.Next()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, idx, qt.Equals, int64(0))\n\t\t\tqt.Check(t, must.String(v), qt.Equals, \"one\")\n\n\t\t\tqt.Check(t, itr.Done(), qt.IsFalse)\n\t\t\tidx, v, err = itr.Next()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, idx, qt.Equals, int64(1))\n\t\t\tqt.Check(t, must.String(v), qt.Equals, \"two\")\n\n\t\t\tqt.Check(t, itr.Done(), qt.IsFalse)\n\t\t\tidx, v, err = itr.Next()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, idx, qt.Equals, int64(2))\n\t\t\tqt.Check(t, must.String(v), qt.Equals, \"three\")\n\n\t\t\tqt.Check(t, itr.Done(), qt.IsTrue)\n\t\t\tidx, v, err = itr.Next()\n\t\t\tqt.Check(t, err, qt.Equals, datamodel.ErrIteratorOverread{})\n\t\t\tqt.Check(t, idx, qt.Equals, int64(-1))\n\t\t\tqt.Check(t, v, qt.IsNil)\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "node/tests/mapBenchmarks.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n)\n\nfunc SpecBenchmarkMapStrInt_3n_AssembleStandard(b *testing.B, np datamodel.NodePrototype) {\n\tfor i := 0; i < b.N; i++ {\n\t\tsink = buildMapStrIntN3(np)\n\t}\n}\n\nfunc SpecBenchmarkMapStrInt_3n_AssembleEntry(b *testing.B, np datamodel.NodePrototype) {\n\tfor i := 0; i < b.N; i++ {\n\t\tnb := np.NewBuilder()\n\t\tma, err := nb.BeginMap(3)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tif va, err := ma.AssembleEntry(\"whee\"); err != nil {\n\t\t\tpanic(err)\n\t\t} else {\n\t\t\tmust.NotError(va.AssignInt(1))\n\t\t}\n\t\tif va, err := ma.AssembleEntry(\"woot\"); err != nil {\n\t\t\tpanic(err)\n\t\t} else {\n\t\t\tmust.NotError(va.AssignInt(2))\n\t\t}\n\t\tif va, err := ma.AssembleEntry(\"waga\"); err != nil {\n\t\t\tpanic(err)\n\t\t} else {\n\t\t\tmust.NotError(va.AssignInt(3))\n\t\t}\n\t\tmust.NotError(ma.Finish())\n\t\tsink = nb.Build()\n\t}\n}\n\nfunc SpecBenchmarkMapStrInt_3n_Iteration(b *testing.B, np datamodel.NodePrototype) {\n\tn := buildMapStrIntN3(np)\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\titr := n.MapIterator()\n\t\tfor k, v, _ := itr.Next(); !itr.Done(); k, v, _ = itr.Next() {\n\t\t\tsink = k\n\t\t\tsink = v\n\t\t}\n\t}\n}\n\n// n25 -->\n\nfunc SpecBenchmarkMapStrInt_25n_AssembleStandard(b *testing.B, np datamodel.NodePrototype) {\n\tfor i := 0; i < b.N; i++ {\n\t\tsink = buildMapStrIntN25(np)\n\t}\n}\n\nfunc SpecBenchmarkMapStrInt_25n_AssembleEntry(b *testing.B, np datamodel.NodePrototype) {\n\tfor i := 0; i < b.N; i++ {\n\t\tnb := np.NewBuilder()\n\t\tma, err := nb.BeginMap(25)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tfor i := 1; i <= 25; i++ {\n\t\t\tif va, err := ma.AssembleEntry(tableStrInt[i-1].s); err != nil {\n\t\t\t\tpanic(err)\n\t\t\t} else {\n\t\t\t\tmust.NotError(va.AssignInt(tableStrInt[i-1].i))\n\t\t\t}\n\t\t}\n\t\tmust.NotError(ma.Finish())\n\t\tsink = nb.Build()\n\t}\n}\n\nfunc SpecBenchmarkMapStrInt_25n_Iteration(b *testing.B, np datamodel.NodePrototype) {\n\tn := buildMapStrIntN25(np)\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\titr := n.MapIterator()\n\t\tfor k, v, _ := itr.Next(); !itr.Done(); k, v, _ = itr.Next() {\n\t\t\tsink = k\n\t\t\tsink = v\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "node/tests/mapBenchmarks_test.go",
    "content": "package tests\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/must\"\n)\n\n// This is analogous to the 'MapStrInt_3n' suite of benchmarks,\n// but against a golang native map in regular go code,\n// for getting a baseline impression to compare other things against.\nfunc BenchmarkMapStrInt_3n_BaselineNativeMapAssignSimpleKeys(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tx := make(map[string]int, 3)\n\t\tx[\"whee\"] = 1\n\t\tx[\"woot\"] = 2\n\t\tx[\"waga\"] = 3\n\t\tsink = x\n\t}\n}\n\nfunc BenchmarkMapStrInt_3n_BaselineJsonUnmarshalMapSimpleKeys(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tx := make(map[string]int, 3)\n\t\tmust.NotError(json.Unmarshal([]byte(`{\"whee\":1,\"woot\":2,\"waga\":3}`), &x))\n\t\tsink = x\n\t}\n}\n\nfunc BenchmarkMapStrInt_3n_BaselineJsonMarshalMapSimpleKeys(b *testing.B) {\n\tx := map[string]int{\"whee\": 1, \"woot\": 2, \"waga\": 3}\n\tfor i := 0; i < b.N; i++ {\n\t\tbs, err := json.Marshal(x)\n\t\tmust.NotError(err)\n\t\tsink = bs\n\t}\n}\n\nvar (\n\tsink_s string\n\tsink_i int64\n)\n\nfunc BenchmarkMapStrInt_3n_BaselineNativeMapIterationSimpleKeys(b *testing.B) {\n\tx := make(map[string]int64, 3)\n\tx[\"whee\"] = 1\n\tx[\"woot\"] = 2\n\tx[\"waga\"] = 3\n\tsink = x\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tfor k, v := range x {\n\t\t\tsink_s = k\n\t\t\tsink_i = v\n\t\t}\n\t}\n}\n\n// n25 -->\n\nfunc BenchmarkMapStrInt_25n_BaselineNativeMapAssignSimpleKeys(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tx := make(map[string]int64, 25)\n\t\tfor i := 1; i <= 25; i++ {\n\t\t\tx[tableStrInt[i-1].s] = tableStrInt[i-1].i\n\t\t}\n\t\tsink = x\n\t}\n}\n\nfunc BenchmarkMapStrInt_25n_BaselineNativeMapIterationSimpleKeys(b *testing.B) {\n\tx := make(map[string]int64, 25)\n\tfor i := 1; i <= 25; i++ {\n\t\tx[tableStrInt[i-1].s] = tableStrInt[i-1].i\n\t}\n\tsink = x\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tfor k, v := range x {\n\t\t\tsink_s = k\n\t\t\tsink_i = v\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "node/tests/mapFixtures.go",
    "content": "package tests\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n)\n\nvar tableStrInt = [25]struct {\n\ts string\n\ti int64\n}{}\n\nfunc init() {\n\tfor i := int64(1); i <= 25; i++ {\n\t\ttableStrInt[i-1] = struct {\n\t\t\ts string\n\t\t\ti int64\n\t\t}{fmt.Sprintf(\"k%d\", i), i}\n\t}\n}\n\n// extracted for reuse between correctness tests and benchmarks\nfunc buildMapStrIntN3(np datamodel.NodePrototype) datamodel.Node {\n\tnb := np.NewBuilder()\n\tma, err := nb.BeginMap(3)\n\tmust.NotError(err)\n\tmust.NotError(ma.AssembleKey().AssignString(\"whee\"))\n\tmust.NotError(ma.AssembleValue().AssignInt(1))\n\tmust.NotError(ma.AssembleKey().AssignString(\"woot\"))\n\tmust.NotError(ma.AssembleValue().AssignInt(2))\n\tmust.NotError(ma.AssembleKey().AssignString(\"waga\"))\n\tmust.NotError(ma.AssembleValue().AssignInt(3))\n\tmust.NotError(ma.Finish())\n\treturn nb.Build()\n}\n\n// extracted for reuse across benchmarks\nfunc buildMapStrIntN25(np datamodel.NodePrototype) datamodel.Node {\n\tnb := np.NewBuilder()\n\tma, err := nb.BeginMap(25)\n\tmust.NotError(err)\n\tfor i := 1; i <= 25; i++ {\n\t\tmust.NotError(ma.AssembleKey().AssignString(tableStrInt[i-1].s))\n\t\tmust.NotError(ma.AssembleValue().AssignInt(tableStrInt[i-1].i))\n\t}\n\tmust.NotError(ma.Finish())\n\treturn nb.Build()\n}\n"
  },
  {
    "path": "node/tests/mapSpecs.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n)\n\nfunc SpecTestMapStrInt(t *testing.T, np datamodel.NodePrototype) {\n\tt.Run(\"map<str,int>, 3 entries\", func(t *testing.T) {\n\t\tn := buildMapStrIntN3(np)\n\t\tt.Run(\"reads back out\", func(t *testing.T) {\n\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(3))\n\n\t\t\tv, err := n.LookupByString(\"whee\")\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tv2, err := v.AsInt()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, v2, qt.Equals, int64(1))\n\n\t\t\tv, err = n.LookupByString(\"waga\")\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tv2, err = v.AsInt()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, v2, qt.Equals, int64(3))\n\n\t\t\tv, err = n.LookupByString(\"woot\")\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tv2, err = v.AsInt()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, v2, qt.Equals, int64(2))\n\t\t})\n\t\tt.Run(\"reads via iteration\", func(t *testing.T) {\n\t\t\titr := n.MapIterator()\n\n\t\t\tqt.Check(t, itr.Done(), qt.IsFalse)\n\t\t\tk, v, err := itr.Next()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tk2, err := k.AsString()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, k2, qt.Equals, \"whee\")\n\t\t\tv2, err := v.AsInt()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, v2, qt.Equals, int64(1))\n\n\t\t\tqt.Check(t, itr.Done(), qt.IsFalse)\n\t\t\tk, v, err = itr.Next()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tk2, err = k.AsString()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, k2, qt.Equals, \"woot\")\n\t\t\tv2, err = v.AsInt()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, v2, qt.Equals, int64(2))\n\n\t\t\tqt.Check(t, itr.Done(), qt.IsFalse)\n\t\t\tk, v, err = itr.Next()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tk2, err = k.AsString()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, k2, qt.Equals, \"waga\")\n\t\t\tv2, err = v.AsInt()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, v2, qt.Equals, int64(3))\n\n\t\t\tqt.Check(t, itr.Done(), qt.IsTrue)\n\t\t\tk, v, err = itr.Next()\n\t\t\tqt.Check(t, err, qt.Equals, datamodel.ErrIteratorOverread{})\n\t\t\tqt.Check(t, k, qt.IsNil)\n\t\t\tqt.Check(t, v, qt.IsNil)\n\t\t})\n\t\tt.Run(\"reads for absent keys error sensibly\", func(t *testing.T) {\n\t\t\tv, err := n.LookupByString(\"nope\")\n\t\t\tqt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{})\n\t\t\tqt.Check(t, err, qt.ErrorMatches, `key not found: \"nope\"`)\n\t\t\tqt.Check(t, v, qt.IsNil)\n\t\t})\n\t})\n\tt.Run(\"repeated key should error\", func(t *testing.T) {\n\t\tnb := np.NewBuilder()\n\t\tma, err := nb.BeginMap(3)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tif err := ma.AssembleKey().AssignString(\"whee\"); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tif err := ma.AssembleValue().AssignInt(1); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tif err := ma.AssembleKey().AssignString(\"whee\"); err != nil {\n\t\t\tqt.Check(t, err, qt.ErrorAs, &datamodel.ErrRepeatedMapKey{})\n\t\t\t// No string assertion at present -- how that should be presented for typed stuff is unsettled\n\t\t\t//  (and if it's clever, it'll differ from untyped, which will mean no assertion possible!).\n\t\t}\n\t})\n\tt.Run(\"using expired child assemblers should panic\", func(t *testing.T) {\n\t\tnb := np.NewBuilder()\n\t\tma, err := nb.BeginMap(3)\n\t\tmust.NotError(err)\n\n\t\t// Assemble a key, and then try to assign it again.  Latter should fail.\n\t\tka := ma.AssembleKey()\n\t\tmust.NotError(ka.AssignString(\"whee\"))\n\t\tfunc() {\n\t\t\tdefer func() { recover() }()\n\t\t\tka.AssignString(\"woo\")\n\t\t\tt.Fatal(\"must not be reached\")\n\t\t}()\n\n\t\t// Assemble a value, and then try to assign it again.  Latter should fail.\n\t\t// (This does assume your system can continue after disregarding the last error.)\n\t\tva := ma.AssembleValue()\n\t\tmust.NotError(va.AssignInt(1))\n\t\tfunc() {\n\t\t\tdefer func() { recover() }()\n\t\t\tva.AssignInt(2)\n\t\t\tt.Fatal(\"must not be reached\")\n\t\t}()\n\n\t\t// ... and neither of these should've had visible effects!\n\t\tqt.Check(t, ma.Finish(), qt.IsNil)\n\t\tn := nb.Build()\n\t\tqt.Check(t, n.Length(), qt.Equals, int64(1))\n\t\tv, err := n.LookupByString(\"whee\")\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tv2, err := v.AsInt()\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, v2, qt.Equals, int64(1))\n\t})\n\tt.Run(\"builder reset works\", func(t *testing.T) {\n\t\t// TODO\n\t})\n}\n\nfunc SpecTestMapStrMapStrInt(t *testing.T, np datamodel.NodePrototype) {\n\tt.Run(\"map<str,map<str,int>>\", func(t *testing.T) {\n\t\tnb := np.NewBuilder()\n\t\tma, err := nb.BeginMap(3)\n\t\tmust.NotError(err)\n\t\tmust.NotError(ma.AssembleKey().AssignString(\"whee\"))\n\t\tfunc(ma datamodel.MapAssembler, err error) {\n\t\t\tmust.NotError(ma.AssembleKey().AssignString(\"m1k1\"))\n\t\t\tmust.NotError(ma.AssembleValue().AssignInt(1))\n\t\t\tmust.NotError(ma.AssembleKey().AssignString(\"m1k2\"))\n\t\t\tmust.NotError(ma.AssembleValue().AssignInt(2))\n\t\t\tmust.NotError(ma.Finish())\n\t\t}(ma.AssembleValue().BeginMap(2))\n\t\tmust.NotError(ma.AssembleKey().AssignString(\"woot\"))\n\t\tfunc(ma datamodel.MapAssembler, err error) {\n\t\t\tmust.NotError(ma.AssembleKey().AssignString(\"m2k1\"))\n\t\t\tmust.NotError(ma.AssembleValue().AssignInt(3))\n\t\t\tmust.NotError(ma.AssembleKey().AssignString(\"m2k2\"))\n\t\t\tmust.NotError(ma.AssembleValue().AssignInt(4))\n\t\t\tmust.NotError(ma.Finish())\n\t\t}(ma.AssembleValue().BeginMap(2))\n\t\tmust.NotError(ma.AssembleKey().AssignString(\"waga\"))\n\t\tfunc(ma datamodel.MapAssembler, err error) {\n\t\t\tmust.NotError(ma.AssembleKey().AssignString(\"m3k1\"))\n\t\t\tmust.NotError(ma.AssembleValue().AssignInt(5))\n\t\t\tmust.NotError(ma.AssembleKey().AssignString(\"m3k2\"))\n\t\t\tmust.NotError(ma.AssembleValue().AssignInt(6))\n\t\t\tmust.NotError(ma.Finish())\n\t\t}(ma.AssembleValue().BeginMap(2))\n\t\tmust.NotError(ma.Finish())\n\t\tn := nb.Build()\n\n\t\tt.Run(\"reads back out\", func(t *testing.T) {\n\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(3))\n\n\t\t\tv, err := n.LookupByString(\"woot\")\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tv2, err := v.LookupByString(\"m2k1\")\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tv3, err := v2.AsInt()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, v3, qt.Equals, int64(3))\n\t\t\tv2, err = v.LookupByString(\"m2k2\")\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tv3, err = v2.AsInt()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, v3, qt.Equals, int64(4))\n\t\t})\n\t})\n}\n\nfunc SpecTestMapStrListStr(t *testing.T, np datamodel.NodePrototype) {\n\tt.Run(\"map<str,list<str>>\", func(t *testing.T) {\n\t\tnb := np.NewBuilder()\n\t\tma, err := nb.BeginMap(3)\n\t\tmust.NotError(err)\n\t\tmust.NotError(ma.AssembleKey().AssignString(\"asdf\"))\n\t\tfunc(la datamodel.ListAssembler, err error) {\n\t\t\tmust.NotError(la.AssembleValue().AssignString(\"eleven\"))\n\t\t\tmust.NotError(la.AssembleValue().AssignString(\"twelve\"))\n\t\t\tmust.NotError(la.AssembleValue().AssignString(\"thirteen\"))\n\t\t\tmust.NotError(la.Finish())\n\t\t}(ma.AssembleValue().BeginList(3))\n\t\tmust.NotError(ma.AssembleKey().AssignString(\"qwer\"))\n\t\tfunc(la datamodel.ListAssembler, err error) {\n\t\t\tmust.NotError(la.AssembleValue().AssignString(\"twentyone\"))\n\t\t\tmust.NotError(la.AssembleValue().AssignString(\"twentytwo\"))\n\t\t\tmust.NotError(la.Finish())\n\t\t}(ma.AssembleValue().BeginList(2))\n\t\tmust.NotError(ma.AssembleKey().AssignString(\"zxcv\"))\n\t\tfunc(la datamodel.ListAssembler, err error) {\n\t\t\tmust.NotError(la.AssembleValue().AssignString(\"thirtyone\"))\n\t\t\tmust.NotError(la.Finish())\n\t\t}(ma.AssembleValue().BeginList(1))\n\t\tmust.NotError(ma.Finish())\n\t\tn := nb.Build()\n\n\t\tt.Run(\"reads back out\", func(t *testing.T) {\n\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(3))\n\n\t\t\tv, err := n.LookupByString(\"qwer\")\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tv2, err := v.LookupByIndex(1)\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tv3, err := v2.AsString()\n\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\tqt.Check(t, v3, qt.Equals, \"twentytwo\")\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "node/tests/marshalBenchmarks.go",
    "content": "package tests\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/codec/json\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/node/tests/corpus\"\n)\n\n// All of the marshalling and unmarshalling benchmark specs use JSON.\n// This does mean we're measuring a bunch of stuff that has nothing to do\n//  with the core operations of the Node/NodeBuilder interface.\n// We do this so that:\n// - we get a reasonable picture of how much time is spent in the IPLD Data Model\n//    versus how much time is spent in the serialization efforts;\n// - we can make direct comparisons to the standard library json marshalling\n//    and unmarshalling, thus having a back-of-the-envelope baseline to compare.\n\nfunc BenchmarkSpec_Marshal_Map3StrInt(b *testing.B, np datamodel.NodePrototype) {\n\tnb := np.NewBuilder()\n\tmust.NotError(json.Decode(nb, strings.NewReader(`{\"whee\":1,\"woot\":2,\"waga\":3}`)))\n\tn := nb.Build()\n\tb.ResetTimer()\n\tvar err error\n\tfor i := 0; i < b.N; i++ {\n\t\tvar buf bytes.Buffer\n\t\terr = json.Encode(n, &buf)\n\t\tsink = buf\n\t}\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc BenchmarkSpec_Marshal_MapNStrMap3StrInt(b *testing.B, np datamodel.NodePrototype) {\n\tfor _, n := range []int{0, 1, 2, 4, 8, 16, 32} {\n\t\tb.Run(fmt.Sprintf(\"n=%d\", n), func(b *testing.B) {\n\t\t\tmsg := corpus.MapNStrMap3StrInt(n)\n\t\t\tnode := mustNodeFromJsonString(np, msg)\n\t\t\tb.ResetTimer()\n\n\t\t\tvar buf bytes.Buffer\n\t\t\tvar err error\n\t\t\tfor i := 0; i < b.N; i++ {\n\t\t\t\tbuf = bytes.Buffer{}\n\t\t\t\terr = json.Encode(node, &buf)\n\t\t\t}\n\n\t\t\tb.StopTimer()\n\t\t\tif err != nil {\n\t\t\t\tb.Fatalf(\"encode errored: %s\", err)\n\t\t\t}\n\t\t\tif buf.String() != msg {\n\t\t\t\tb.Fatalf(\"encode result didn't match corpus\")\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "node/tests/schema.go",
    "content": "package tests\n\nimport \"testing\"\n\n// use a table instead of a map, to get a consistent order\n\nvar allSchemaTests = []struct {\n\tname string\n\tfn   func(*testing.T, Engine)\n}{\n\t{\"Links\", SchemaTestLinks},\n\t{\"ListsContainingMaybe\", SchemaTestListsContainingMaybe},\n\t{\"ListsContainingLists\", SchemaTestListsContainingLists},\n\t{\"MapsContainingMaybe\", SchemaTestMapsContainingMaybe},\n\t{\"MapsContainingMaps\", SchemaTestMapsContainingMaps},\n\t{\"MapsWithComplexKeys\", SchemaTestMapsWithComplexKeys},\n\t{\"Scalars\", SchemaTestScalars},\n\t{\"RequiredFields\", SchemaTestRequiredFields},\n\t{\"StructNesting\", SchemaTestStructNesting},\n\t{\"StructReprStringjoin\", SchemaTestStructReprStringjoin},\n\t{\"StructReprTuple\", SchemaTestStructReprTuple},\n\t{\"StructReprListPairs\", SchemaTestStructReprListPairs},\n\t{\"StructsContainingMaybe\", SchemaTestStructsContainingMaybe},\n\t{\"UnionKeyed\", SchemaTestUnionKeyed},\n\t{\"UnionKeyedComplexChildren\", SchemaTestUnionKeyedComplexChildren},\n\t{\"UnionKeyedReset\", SchemaTestUnionKeyedReset},\n\t{\"UnionKinded\", SchemaTestUnionKinded},\n\t{\"UnionStringprefix\", SchemaTestUnionStringprefix},\n}\n\ntype EngineSubtest struct {\n\tName   string // subtest name\n\tEngine Engine\n}\n\nfunc SchemaTestAll(t *testing.T, forTest func(name string) []EngineSubtest) {\n\tfor _, test := range allSchemaTests {\n\t\ttest := test // do not reuse the range variable\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tsubtests := forTest(test.name)\n\t\t\tif len(subtests) == 0 {\n\t\t\t\tt.Skip(\"no engine provided to SchemaTestAll\")\n\t\t\t}\n\t\t\tif len(subtests) == 1 {\n\t\t\t\tsub := subtests[0]\n\t\t\t\tif sub.Name != \"\" {\n\t\t\t\t\tt.Fatal(\"a single engine shouldn't be named\")\n\t\t\t\t}\n\t\t\t\ttest.fn(t, sub.Engine)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tfor _, sub := range subtests {\n\t\t\t\tif sub.Name == \"\" {\n\t\t\t\t\tt.Fatal(\"multiple engines should be named\")\n\t\t\t\t}\n\t\t\t\tt.Run(sub.Name, func(t *testing.T) {\n\t\t\t\t\ttest.fn(t, sub.Engine)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "node/tests/schemaLinks.go",
    "content": "package tests\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/storage/memstore\"\n\t\"github.com/ipld/go-ipld-prime/traversal\"\n\t\"github.com/ipld/go-ipld-prime/traversal/selector\"\n\t\"github.com/ipld/go-ipld-prime/traversal/selector/builder\"\n)\n\nvar store = memstore.Store{}\n\nfunc encode(n datamodel.Node) (datamodel.Node, datamodel.Link) {\n\tlp := cidlink.LinkPrototype{Prefix: cid.Prefix{\n\t\tVersion:  1,\n\t\tCodec:    0x0129,\n\t\tMhType:   0x13,\n\t\tMhLength: 4,\n\t}}\n\tlsys := cidlink.DefaultLinkSystem()\n\tlsys.SetWriteStorage(&store)\n\n\tlnk, err := lsys.Store(linking.LinkContext{}, lp, n)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn n, lnk\n}\n\nfunc SchemaTestLinks(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnInt(\"Int\"))\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnList(\"ListOfStrings\", \"String\", false))\n\n\tts.Accumulate(schema.SpawnLink(\"Link\"))                                        // &Any\n\tts.Accumulate(schema.SpawnLinkReference(\"IntLink\", \"Int\"))                     // &Int\n\tts.Accumulate(schema.SpawnLinkReference(\"StringLink\", \"String\"))               // &String\n\tts.Accumulate(schema.SpawnLinkReference(\"ListOfStringsLink\", \"ListOfStrings\")) // &ListOfStrings\n\n\tts.Accumulate(schema.SpawnStruct(\"LinkStruct\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"any\", \"Link\", false, false),\n\t\t\tschema.SpawnStructField(\"int\", \"IntLink\", false, false),\n\t\t\tschema.SpawnStructField(\"str\", \"StringLink\", false, false),\n\t\t\tschema.SpawnStructField(\"strlist\", \"ListOfStringsLink\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationMap(map[string]string{}),\n\t))\n\n\tengine.Init(t, ts)\n\n\tt.Run(\"typed linkage traversal\", func(t *testing.T) {\n\t\t_, intNodeLnk := func() (datamodel.Node, datamodel.Link) {\n\t\t\tnp := engine.PrototypeByName(\"Int\")\n\t\t\tnb := np.NewBuilder()\n\t\t\tnb.AssignInt(101)\n\t\t\treturn encode(nb.Build())\n\t\t}()\n\t\t_, stringNodeLnk := encode(fluent.MustBuild(engine.PrototypeByName(\"String\"), func(na fluent.NodeAssembler) {\n\t\t\tna.AssignString(\"a string\")\n\t\t}))\n\t\t_, listOfStringsNodeLnk := encode(fluent.MustBuildList(engine.PrototypeByName(\"ListOfStrings\"), 3, func(la fluent.ListAssembler) {\n\t\t\tla.AssembleValue().AssignString(\"s1\")\n\t\t\tla.AssembleValue().AssignString(\"s2\")\n\t\t\tla.AssembleValue().AssignString(\"s3\")\n\t\t}))\n\t\tlinkStructNode, _ := encode(fluent.MustBuildMap(engine.PrototypeByName(\"LinkStruct\"), 4, func(ma fluent.MapAssembler) {\n\t\t\tma.AssembleEntry(\"any\").AssignLink(stringNodeLnk)\n\t\t\tma.AssembleEntry(\"int\").AssignLink(intNodeLnk)\n\t\t\tma.AssembleEntry(\"str\").AssignLink(stringNodeLnk)\n\t\t\tma.AssembleEntry(\"strlist\").AssignLink(listOfStringsNodeLnk)\n\t\t}))\n\n\t\tssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any)\n\t\tss := ssb.ExploreRecursive(selector.RecursionLimitDepth(3), ssb.ExploreUnion(\n\t\t\tssb.Matcher(),\n\t\t\tssb.ExploreAll(ssb.ExploreRecursiveEdge()),\n\t\t))\n\t\ts, err := ss.Selector()\n\t\tqt.Check(t, err, qt.IsNil)\n\n\t\tvar order int\n\t\tlsys := cidlink.DefaultLinkSystem()\n\t\tlsys.SetReadStorage(&store)\n\t\terr = traversal.Progress{\n\t\t\tCfg: &traversal.Config{\n\t\t\t\tLinkSystem: lsys,\n\t\t\t\tLinkTargetNodePrototypeChooser: func(lnk datamodel.Link, lnkCtx linking.LinkContext) (datamodel.NodePrototype, error) {\n\t\t\t\t\tif tlnkNd, ok := lnkCtx.LinkNode.(schema.TypedLinkNode); ok {\n\t\t\t\t\t\treturn tlnkNd.LinkTargetNodePrototype(), nil\n\t\t\t\t\t}\n\t\t\t\t\treturn basicnode.Prototype.Any, nil\n\t\t\t\t},\n\t\t\t},\n\t\t}.WalkMatching(linkStructNode, s, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\tbuf := new(bytes.Buffer)\n\t\t\tdagjson.Encode(n, buf)\n\t\t\tfmt.Printf(\"Walked %d: %v\\n\", order, buf.String())\n\t\t\tswitch order {\n\t\t\tcase 0: // root\n\t\t\t\tqt.Check(t, n.Prototype(), qt.Equals, engine.PrototypeByName(\"LinkStruct\"))\n\t\t\tcase 1: // from an &Any\n\t\t\t\tqt.Check(t, n.Prototype(), qt.Equals, basicnode.Prototype__String{})\n\t\t\tcase 2: // &Int\n\t\t\t\tqt.Check(t, n.Prototype(), qt.Equals, engine.PrototypeByName(\"Int\"))\n\t\t\tcase 3: // &String\n\t\t\t\tqt.Check(t, n.Prototype(), qt.Equals, engine.PrototypeByName(\"String\"))\n\t\t\tcase 4: // &ListOfStrings\n\t\t\t\tqt.Check(t, n.Prototype(), qt.Equals, engine.PrototypeByName(\"ListOfStrings\"))\n\t\t\tcase 5:\n\t\t\t\tfallthrough\n\t\t\tcase 6:\n\t\t\t\tfallthrough\n\t\t\tcase 7:\n\t\t\t\tqt.Check(t, n.Prototype(), qt.Equals, engine.PrototypeByName(\"String\"))\n\t\t\t}\n\t\t\torder++\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, order, qt.Equals, 8)\n\t})\n}\n"
  },
  {
    "path": "node/tests/schemaLists.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc SchemaTestListsContainingMaybe(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnList(\"List__String\",\n\t\t\"String\", false))\n\tts.Accumulate(schema.SpawnList(\"List__nullableString\",\n\t\t\"String\", true))\n\tengine.Init(t, ts)\n\n\tt.Run(\"non-nullable\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"List__String\")\n\t\tnrp := engine.PrototypeByName(\"List__String.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildList(np, 2, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().AssignString(\"1\")\n\t\t\t\tla.AssembleValue().AssignString(\"2\")\n\t\t\t}).(schema.TypedNode)\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(2))\n\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByIndex(0))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByIndex(1))), qt.Equals, \"2\")\n\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupBySegment(datamodel.PathSegmentOfInt(0)))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByNode(basicnode.NewInt(0)))), qt.Equals, \"1\")\n\n\t\t\t\t_, err := n.LookupByIndex(3)\n\t\t\t\tqt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{})\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, nr.Length(), qt.Equals, int64(2))\n\n\t\t\t\tqt.Check(t, must.String(must.Node(nr.LookupByIndex(0))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.String(must.Node(nr.LookupByIndex(1))), qt.Equals, \"2\")\n\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupBySegment(datamodel.PathSegmentOfInt(0)))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByNode(basicnode.NewInt(0)))), qt.Equals, \"1\")\n\n\t\t\t\t_, err := n.LookupByIndex(3)\n\t\t\t\tqt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{})\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuildList(nrp, 2, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().AssignString(\"1\")\n\t\t\t\tla.AssembleValue().AssignString(\"2\")\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t})\n\tt.Run(\"nullable\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"List__nullableString\")\n\t\tnrp := engine.PrototypeByName(\"List__nullableString.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildList(np, 2, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().AssignString(\"1\")\n\t\t\t\tla.AssembleValue().AssignNull()\n\t\t\t}).(schema.TypedNode)\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByIndex(0))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.Node(n.LookupByIndex(1)), qt.Equals, datamodel.Null)\n\t\t\t\t_, err := n.LookupByIndex(3)\n\t\t\t\tqt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{})\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, nr.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByIndex(0))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.Node(n.LookupByIndex(1)), qt.Equals, datamodel.Null)\n\t\t\t\t_, err := n.LookupByIndex(3)\n\t\t\t\tqt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{})\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuildList(nrp, 2, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().AssignString(\"1\")\n\t\t\t\tla.AssembleValue().AssignNull()\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t})\n}\n\n// TestListsContainingLists is probing *two* things:\n//   - that lists can nest, obviously\n//   - that representation semantics are held correctly when we recurse, both in builders and in reading\n//\n// To cover that latter situation, this depends on structs (so we can use rename directives on the representation to make it distinctive).\nfunc SchemaTestListsContainingLists(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnStruct(\"Frub\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"field\", \"String\", false, false), // plain field.\n\t\t},\n\t\tschema.SpawnStructRepresentationMap(map[string]string{\n\t\t\t\"field\": \"encoded\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnList(\"List__Frub\",\n\t\t\"Frub\", false))\n\tts.Accumulate(schema.SpawnList(\"List__List__Frub\",\n\t\t\"List__Frub\", true))\n\tengine.Init(t, ts)\n\n\tnp := engine.PrototypeByName(\"List__List__Frub\")\n\tnrp := engine.PrototypeByName(\"List__List__Frub.Repr\")\n\tvar n schema.TypedNode\n\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\tn = fluent.MustBuildList(np, 3, func(la fluent.ListAssembler) {\n\t\t\tla.AssembleValue().CreateList(3, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(\"field\").AssignString(\"11\") })\n\t\t\t\tla.AssembleValue().CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(\"field\").AssignString(\"12\") })\n\t\t\t\tla.AssembleValue().CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(\"field\").AssignString(\"13\") })\n\t\t\t})\n\t\t\tla.AssembleValue().CreateList(1, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(\"field\").AssignString(\"21\") })\n\t\t\t})\n\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(\"field\").AssignString(\"31\") })\n\t\t\t\tla.AssembleValue().CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(\"field\").AssignString(\"32\") })\n\t\t\t})\n\t\t}).(schema.TypedNode)\n\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\tqt.Assert(t, n.Length(), qt.Equals, int64(3))\n\t\t\tqt.Assert(t, must.Node(n.LookupByIndex(0)).Length(), qt.Equals, int64(3))\n\t\t\tqt.Assert(t, must.Node(n.LookupByIndex(1)).Length(), qt.Equals, int64(1))\n\t\t\tqt.Assert(t, must.Node(n.LookupByIndex(2)).Length(), qt.Equals, int64(2))\n\n\t\t\tqt.Check(t, must.String(must.Node(must.Node(must.Node(n.LookupByIndex(0)).LookupByIndex(0)).LookupByString(\"field\"))), qt.Equals, \"11\")\n\t\t\tqt.Check(t, must.String(must.Node(must.Node(must.Node(n.LookupByIndex(0)).LookupByIndex(2)).LookupByString(\"field\"))), qt.Equals, \"13\")\n\t\t\tqt.Check(t, must.String(must.Node(must.Node(must.Node(n.LookupByIndex(1)).LookupByIndex(0)).LookupByString(\"field\"))), qt.Equals, \"21\")\n\t\t\tqt.Check(t, must.String(must.Node(must.Node(must.Node(n.LookupByIndex(2)).LookupByIndex(1)).LookupByString(\"field\"))), qt.Equals, \"32\")\n\t\t})\n\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\tnr := n.Representation()\n\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\tqt.Assert(t, nr.Length(), qt.Equals, int64(3))\n\t\t\tqt.Assert(t, must.Node(nr.LookupByIndex(0)).Length(), qt.Equals, int64(3))\n\t\t\tqt.Assert(t, must.Node(nr.LookupByIndex(1)).Length(), qt.Equals, int64(1))\n\t\t\tqt.Assert(t, must.Node(nr.LookupByIndex(2)).Length(), qt.Equals, int64(2))\n\n\t\t\tqt.Check(t, must.String(must.Node(must.Node(must.Node(nr.LookupByIndex(0)).LookupByIndex(0)).LookupByString(\"encoded\"))), qt.Equals, \"11\")\n\t\t\tqt.Check(t, must.String(must.Node(must.Node(must.Node(nr.LookupByIndex(0)).LookupByIndex(2)).LookupByString(\"encoded\"))), qt.Equals, \"13\")\n\t\t\tqt.Check(t, must.String(must.Node(must.Node(must.Node(nr.LookupByIndex(1)).LookupByIndex(0)).LookupByString(\"encoded\"))), qt.Equals, \"21\")\n\t\t\tqt.Check(t, must.String(must.Node(must.Node(must.Node(nr.LookupByIndex(2)).LookupByIndex(1)).LookupByString(\"encoded\"))), qt.Equals, \"32\")\n\t\t})\n\t})\n\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\tnr := fluent.MustBuildList(nrp, 2, func(la fluent.ListAssembler) {\n\t\t\t// This is the same as the type-level create earlier, except note the field names are now all different.\n\t\t\tla.AssembleValue().CreateList(3, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(\"encoded\").AssignString(\"11\") })\n\t\t\t\tla.AssembleValue().CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(\"encoded\").AssignString(\"12\") })\n\t\t\t\tla.AssembleValue().CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(\"encoded\").AssignString(\"13\") })\n\t\t\t})\n\t\t\tla.AssembleValue().CreateList(1, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(\"encoded\").AssignString(\"21\") })\n\t\t\t})\n\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(\"encoded\").AssignString(\"31\") })\n\t\t\t\tla.AssembleValue().CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(\"encoded\").AssignString(\"32\") })\n\t\t\t})\n\t\t})\n\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t})\n}\n"
  },
  {
    "path": "node/tests/schemaMaps.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc SchemaTestMapsContainingMaybe(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnMap(\"Map__String__String\",\n\t\t\"String\", \"String\", false))\n\tts.Accumulate(schema.SpawnMap(\"Map__String__nullableString\",\n\t\t\"String\", \"String\", true))\n\tengine.Init(t, ts)\n\n\tt.Run(\"non-nullable\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"Map__String__String\")\n\t\tnrp := engine.PrototypeByName(\"Map__String__String.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildMap(np, 2, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"one\").AssignString(\"1\")\n\t\t\t\tma.AssembleEntry(\"two\").AssignString(\"2\")\n\t\t\t}).(schema.TypedNode)\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"one\"))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"two\"))), qt.Equals, \"2\")\n\t\t\t\t_, err := n.LookupByString(\"miss\")\n\t\t\t\tqt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{})\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, nr.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(nr.LookupByString(\"one\"))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.String(must.Node(nr.LookupByString(\"two\"))), qt.Equals, \"2\")\n\t\t\t\t_, err := nr.LookupByString(\"miss\")\n\t\t\t\tqt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{})\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuildMap(nrp, 2, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"one\").AssignString(\"1\")\n\t\t\t\tma.AssembleEntry(\"two\").AssignString(\"2\")\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t})\n\tt.Run(\"nullable\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"Map__String__nullableString\")\n\t\tnrp := engine.PrototypeByName(\"Map__String__nullableString.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildMap(np, 2, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"one\").AssignString(\"1\")\n\t\t\t\tma.AssembleEntry(\"none\").AssignNull()\n\t\t\t}).(schema.TypedNode)\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"one\"))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.Node(n.LookupByString(\"none\")), qt.Equals, datamodel.Null)\n\t\t\t\t_, err := n.LookupByString(\"miss\")\n\t\t\t\tqt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{})\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, nr.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(nr.LookupByString(\"one\"))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.Node(nr.LookupByString(\"none\")), qt.Equals, datamodel.Null)\n\t\t\t\t_, err := nr.LookupByString(\"miss\")\n\t\t\t\tqt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{})\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuildMap(nrp, 2, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"one\").AssignString(\"1\")\n\t\t\t\tma.AssembleEntry(\"none\").AssignNull()\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t})\n}\n\n// TestMapsContainingMaps is probing *two* things:\n//   - that maps can nest, obviously\n//   - that representation semantics are held correctly when we recurse, both in builders and in reading\n//\n// To cover that latter situation, this depends on structs (so we can use rename directives on the representation to make it distinctive).\nfunc SchemaTestMapsContainingMaps(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnStruct(\"Frub\", // \"type Frub struct { field String (rename \"encoded\") }\"\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"field\", \"String\", false, false), // plain field.\n\t\t},\n\t\tschema.SpawnStructRepresentationMap(map[string]string{\n\t\t\t\"field\": \"encoded\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnMap(\"Map__String__Frub\", // \"{String:Frub}\"\n\t\t\"String\", \"Frub\", false))\n\tts.Accumulate(schema.SpawnMap(\"Map__String__nullableMap__String__Frub\", // \"{String:nullable {String:Frub}}\"\n\t\t\"String\", \"Map__String__Frub\", true))\n\tengine.Init(t, ts)\n\n\tnp := engine.PrototypeByName(\"Map__String__nullableMap__String__Frub\")\n\tnrp := engine.PrototypeByName(\"Map__String__nullableMap__String__Frub.Repr\")\n\tcreation := func(t *testing.T, np datamodel.NodePrototype, fieldName string) schema.TypedNode {\n\t\treturn fluent.MustBuildMap(np, 3, func(ma fluent.MapAssembler) {\n\t\t\tma.AssembleEntry(\"one\").CreateMap(2, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"zot\").CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(fieldName).AssignString(\"11\") })\n\t\t\t\tma.AssembleEntry(\"zop\").CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(fieldName).AssignString(\"12\") })\n\t\t\t})\n\t\t\tma.AssembleEntry(\"two\").CreateMap(1, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"zim\").CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(fieldName).AssignString(\"21\") })\n\t\t\t})\n\t\t\tma.AssembleEntry(\"none\").AssignNull()\n\t\t}).(schema.TypedNode)\n\t}\n\treading := func(t *testing.T, n datamodel.Node, fieldName string) {\n\t\twithNode(n, func(n datamodel.Node) {\n\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(3))\n\t\t\twithNode(must.Node(n.LookupByString(\"one\")), func(n datamodel.Node) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(2))\n\t\t\t\twithNode(must.Node(n.LookupByString(\"zot\")), func(n datamodel.Node) {\n\t\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(1))\n\t\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(fieldName))), qt.Equals, \"11\")\n\t\t\t\t})\n\t\t\t\twithNode(must.Node(n.LookupByString(\"zop\")), func(n datamodel.Node) {\n\t\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(1))\n\t\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(fieldName))), qt.Equals, \"12\")\n\t\t\t\t})\n\t\t\t})\n\t\t\twithNode(must.Node(n.LookupByString(\"two\")), func(n datamodel.Node) {\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(1))\n\t\t\t\twithNode(must.Node(n.LookupByString(\"zim\")), func(n datamodel.Node) {\n\t\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(1))\n\t\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(fieldName))), qt.Equals, \"21\")\n\t\t\t\t})\n\t\t\t})\n\t\t\twithNode(must.Node(n.LookupByString(\"none\")), func(n datamodel.Node) {\n\t\t\t\tqt.Check(t, n, NodeContentEquals, datamodel.Null)\n\t\t\t})\n\t\t\t_, err := n.LookupByString(\"miss\")\n\t\t\tqt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{})\n\t\t})\n\t}\n\tvar n schema.TypedNode\n\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\tn = creation(t, np, \"field\")\n\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\treading(t, n, \"field\")\n\t\t})\n\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\treading(t, n.Representation(), \"encoded\")\n\t\t})\n\t})\n\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\tnr := creation(t, nrp, \"encoded\")\n\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t})\n}\n\nfunc SchemaTestMapsWithComplexKeys(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnStruct(\"StringyStruct\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"foo\", \"String\", false, false),\n\t\t\tschema.SpawnStructField(\"bar\", \"String\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationStringjoin(\":\"),\n\t))\n\tts.Accumulate(schema.SpawnMap(\"Map__StringyStruct__String\",\n\t\t\"StringyStruct\", \"String\", false))\n\tengine.Init(t, ts)\n\n\tnp := engine.PrototypeByName(\"Map__StringyStruct__String\")\n\tnrp := engine.PrototypeByName(\"Map__StringyStruct__String.Repr\")\n\tvar n schema.TypedNode\n\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\tn = fluent.MustBuildMap(np, 3, func(ma fluent.MapAssembler) {\n\t\t\tma.AssembleKey().CreateMap(2, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"foo\").AssignString(\"a\")\n\t\t\t\tma.AssembleEntry(\"bar\").AssignString(\"b\")\n\t\t\t})\n\t\t\tma.AssembleValue().AssignString(\"1\")\n\t\t\tma.AssembleKey().CreateMap(2, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"foo\").AssignString(\"c\")\n\t\t\t\tma.AssembleEntry(\"bar\").AssignString(\"d\")\n\t\t\t})\n\t\t\tma.AssembleValue().AssignString(\"2\")\n\t\t\tma.AssembleKey().CreateMap(2, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"foo\").AssignString(\"e\")\n\t\t\t\tma.AssembleEntry(\"bar\").AssignString(\"f\")\n\t\t\t})\n\t\t\tma.AssembleValue().AssignString(\"3\")\n\t\t}).(schema.TypedNode)\n\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(3))\n\t\t\tn2 := must.Node(n.LookupByString(\"c:d\"))\n\t\t\tqt.Assert(t, n2.Kind(), qt.Equals, datamodel.Kind_String)\n\t\t\tqt.Check(t, must.String(n2), qt.Equals, \"2\")\n\t\t})\n\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\tnr := n.Representation()\n\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\tqt.Check(t, nr.Length(), qt.Equals, int64(3))\n\t\t\tn2 := must.Node(nr.LookupByString(\"c:d\"))\n\t\t\tqt.Assert(t, n2.Kind(), qt.Equals, datamodel.Kind_String)\n\t\t\tqt.Check(t, must.String(n2), qt.Equals, \"2\")\n\t\t})\n\t})\n\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\tnr := fluent.MustBuildMap(nrp, 3, func(ma fluent.MapAssembler) {\n\t\t\tma.AssembleEntry(\"a:b\").AssignString(\"1\")\n\t\t\tma.AssembleEntry(\"c:d\").AssignString(\"2\")\n\t\t\tma.AssembleEntry(\"e:f\").AssignString(\"3\")\n\t\t})\n\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t})\n}\n"
  },
  {
    "path": "node/tests/schemaScalars.go",
    "content": "package tests\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc assignValue(am datamodel.NodeAssembler, value interface{}) error {\n\tswitch value := value.(type) {\n\tcase bool:\n\t\treturn am.AssignBool(value)\n\tcase int64:\n\t\treturn am.AssignInt(value)\n\tcase float64:\n\t\treturn am.AssignFloat(value)\n\tcase string:\n\t\treturn am.AssignString(value)\n\tcase []byte:\n\t\treturn am.AssignBytes(value)\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"%T\", value))\n\t}\n}\n\nfunc SchemaTestScalars(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\n\tts.Accumulate(schema.SpawnBool(\"Bool\"))\n\tts.Accumulate(schema.SpawnInt(\"Int\"))\n\tts.Accumulate(schema.SpawnFloat(\"Float\"))\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnBytes(\"Bytes\"))\n\tengine.Init(t, ts)\n\n\tvar tests = []struct {\n\t\tname  string\n\t\tkind  datamodel.Kind\n\t\tvalue interface{}\n\t}{\n\t\t{\"Bool\", datamodel.Kind_Bool, true},\n\t\t{\"Int\", datamodel.Kind_Int, int64(23)},\n\t\t{\"Float\", datamodel.Kind_Float, 12.25},\n\t\t{\"String\", datamodel.Kind_String, \"foo\"},\n\t\t{\"Bytes\", datamodel.Kind_Bytes, []byte(\"bar\")},\n\t}\n\n\t// We test each of the five scalar prototypes in subtests.\n\tfor _, testProto := range tests {\n\n\t\t// For both the regular node and its repr version,\n\t\t// getting the right value for the kind should work.\n\t\tfor _, useRepr := range []bool{false, true} {\n\n\t\t\tprotoName := testProto.name\n\t\t\tif useRepr {\n\t\t\t\tprotoName += \".Repr\"\n\t\t\t}\n\t\t\tnp := engine.PrototypeByName(protoName)\n\n\t\t\t// For each prototype, we try assigning all scalar values.\n\t\t\tfor _, testAssign := range tests {\n\n\t\t\t\t// We try both AssignKind and AssignNode.\n\t\t\t\tfor _, useAssignNode := range []bool{false, true} {\n\t\t\t\t\ttestName := fmt.Sprintf(\"%s-Assign%s\", protoName, testAssign.name)\n\t\t\t\t\tif useAssignNode {\n\t\t\t\t\t\ttestName = fmt.Sprintf(\"%s-AssignNode-%s\", protoName, testAssign.name)\n\t\t\t\t\t}\n\t\t\t\t\tt.Run(testName, func(t *testing.T) {\n\t\t\t\t\t\tnb := np.NewBuilder()\n\n\t\t\t\t\t\t// Assigning null, a list, or a map, should always fail.\n\t\t\t\t\t\terr := nb.AssignNull()\n\t\t\t\t\t\tqt.Check(t, err, qt.Not(qt.IsNil))\n\t\t\t\t\t\t_, err = nb.BeginMap(-1)\n\t\t\t\t\t\tqt.Check(t, err, qt.Not(qt.IsNil))\n\t\t\t\t\t\t_, err = nb.BeginList(-1)\n\t\t\t\t\t\tqt.Check(t, err, qt.Not(qt.IsNil))\n\n\t\t\t\t\t\t// Assigning the right value for the kind should succeed.\n\t\t\t\t\t\tif useAssignNode {\n\t\t\t\t\t\t\tnp2 := engine.PrototypeByName(testAssign.name)\n\t\t\t\t\t\t\tnb2 := np2.NewBuilder()\n\t\t\t\t\t\t\tqt.Check(t, assignValue(nb2, testAssign.value), qt.IsNil)\n\t\t\t\t\t\t\tn2 := nb2.Build()\n\n\t\t\t\t\t\t\terr = nb.AssignNode(n2)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\terr = assignValue(nb, testAssign.value)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif testAssign.kind == testProto.kind {\n\t\t\t\t\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tqt.Check(t, err, qt.Not(qt.IsNil))\n\n\t\t\t\t\t\t\t// Assign something anyway, just so we can Build later.\n\t\t\t\t\t\t\terr := assignValue(nb, testProto.value)\n\t\t\t\t\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tn := nb.Build()\n\n\t\t\t\t\t\tvar gotValue interface{}\n\t\t\t\t\t\terr = nil\n\t\t\t\t\t\tswitch testAssign.kind {\n\t\t\t\t\t\tcase datamodel.Kind_Bool:\n\t\t\t\t\t\t\tgotValue, err = n.AsBool()\n\t\t\t\t\t\tcase datamodel.Kind_Int:\n\t\t\t\t\t\t\tgotValue, err = n.AsInt()\n\t\t\t\t\t\tcase datamodel.Kind_Float:\n\t\t\t\t\t\t\tgotValue, err = n.AsFloat()\n\t\t\t\t\t\tcase datamodel.Kind_String:\n\t\t\t\t\t\t\tgotValue, err = n.AsString()\n\t\t\t\t\t\tcase datamodel.Kind_Bytes:\n\t\t\t\t\t\t\tgotValue, err = n.AsBytes()\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tt.Fatal(testAssign.kind)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif testAssign.kind == testProto.kind {\n\t\t\t\t\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\t\t\t\t\tqt.Check(t, gotValue, qt.DeepEquals, testAssign.value)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tqt.Check(t, err, qt.Not(qt.IsNil))\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Using Node methods which should never\n\t\t\t\t\t\t// work on scalar kinds.\n\n\t\t\t\t\t\t_, err = n.LookupByString(\"foo\")\n\t\t\t\t\t\tqt.Check(t, err, qt.Not(qt.IsNil))\n\t\t\t\t\t\t_, err = n.LookupByIndex(3)\n\t\t\t\t\t\tqt.Check(t, err, qt.Not(qt.IsNil))\n\t\t\t\t\t\tqt.Check(t, n.MapIterator(), qt.IsNil)\n\t\t\t\t\t\tqt.Check(t, n.ListIterator(), qt.IsNil)\n\t\t\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(-1))\n\t\t\t\t\t\tqt.Check(t, n.IsAbsent(), qt.IsFalse)\n\t\t\t\t\t\tqt.Check(t, n.IsNull(), qt.IsFalse)\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "node/tests/schemaStruct.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc SchemaTestRequiredFields(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnStruct(\"StructOne\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"a\", \"String\", false, false),\n\t\t\tschema.SpawnStructField(\"b\", \"String\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationMap(map[string]string{\n\t\t\t// no renames.  we expect a simpler error message in this case.\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"StructTwo\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"a\", \"String\", false, false),\n\t\t\tschema.SpawnStructField(\"b\", \"String\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationMap(map[string]string{\n\t\t\t\"b\": \"z\",\n\t\t}),\n\t))\n\tengine.Init(t, ts)\n\n\tt.Run(\"building-type-without-required-fields-errors\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"StructOne\")\n\n\t\tnb := np.NewBuilder()\n\t\tma, _ := nb.BeginMap(0)\n\t\terr := ma.Finish()\n\n\t\tqt.Check(t, err, qt.ErrorAs, &schema.ErrMissingRequiredField{})\n\t\tqt.Check(t, err.Error(), qt.Equals, `missing required fields: a,b`)\n\t})\n\tt.Run(\"building-representation-without-required-fields-errors\", func(t *testing.T) {\n\t\tnrp := engine.PrototypeByName(\"StructOne.Repr\")\n\n\t\tnb := nrp.NewBuilder()\n\t\tma, _ := nb.BeginMap(0)\n\t\terr := ma.Finish()\n\n\t\tqt.Check(t, err, qt.ErrorAs, &schema.ErrMissingRequiredField{})\n\t\tqt.Check(t, err.Error(), qt.Equals, `missing required fields: a,b`)\n\t})\n\tt.Run(\"building-representation-with-renames-without-required-fields-errors\", func(t *testing.T) {\n\t\tnrp := engine.PrototypeByName(\"StructTwo.Repr\")\n\n\t\tnb := nrp.NewBuilder()\n\t\tma, _ := nb.BeginMap(0)\n\t\terr := ma.Finish()\n\n\t\tqt.Check(t, err, qt.ErrorAs, &schema.ErrMissingRequiredField{})\n\t\tqt.Check(t, err.Error(), qt.Equals, `missing required fields: a,b (serial:\"z\")`)\n\t})\n}\n\nfunc SchemaTestStructNesting(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnStruct(\"SmolStruct\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"s\", \"String\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationMap(map[string]string{\n\t\t\t\"s\": \"q\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"GulpoStruct\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"x\", \"SmolStruct\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationMap(map[string]string{\n\t\t\t\"x\": \"r\",\n\t\t}),\n\t))\n\tengine.Init(t, ts)\n\n\tnp := engine.PrototypeByName(\"GulpoStruct\")\n\tnrp := engine.PrototypeByName(\"GulpoStruct.Repr\")\n\tvar n schema.TypedNode\n\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\tn = fluent.MustBuildMap(np, 1, func(ma fluent.MapAssembler) {\n\t\t\tma.AssembleEntry(\"x\").CreateMap(1, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"s\").AssignString(\"woo\")\n\t\t\t})\n\t\t}).(schema.TypedNode)\n\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(1))\n\n\t\t\tn2 := must.Node(n.LookupByString(\"x\"))\n\t\t\tqt.Assert(t, n2.Kind(), qt.Equals, datamodel.Kind_Map)\n\n\t\t\tn2Seg := must.Node(n.LookupBySegment(datamodel.PathSegmentOfString(\"x\")))\n\t\t\tqt.Check(t, n2, NodeContentEquals, n2Seg)\n\n\t\t\tn2Node := must.Node(n.LookupByNode(basicnode.NewString(\"x\")))\n\t\t\tqt.Check(t, n2, NodeContentEquals, n2Node)\n\n\t\t\tqt.Check(t, must.String(must.Node(n2.LookupByString(\"s\"))), qt.Equals, \"woo\")\n\t\t})\n\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\tnr := n.Representation()\n\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\tqt.Check(t, nr.Length(), qt.Equals, int64(1))\n\n\t\t\tn2 := must.Node(nr.LookupByString(\"r\"))\n\t\t\tqt.Assert(t, n2.Kind(), qt.Equals, datamodel.Kind_Map)\n\n\t\t\tn2Seg := must.Node(nr.LookupBySegment(datamodel.PathSegmentOfString(\"r\")))\n\t\t\tqt.Check(t, n2, NodeContentEquals, n2Seg)\n\n\t\t\tn2Node := must.Node(nr.LookupByNode(basicnode.NewString(\"r\")))\n\t\t\tqt.Check(t, n2, NodeContentEquals, n2Node)\n\n\t\t\tqt.Check(t, must.String(must.Node(n2.LookupByString(\"q\"))), qt.Equals, \"woo\")\n\t\t})\n\t})\n\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\tnr := fluent.MustBuildMap(nrp, 1, func(ma fluent.MapAssembler) {\n\t\t\tma.AssembleEntry(\"r\").CreateMap(1, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"q\").AssignString(\"woo\")\n\t\t\t})\n\t\t})\n\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t})\n}\n"
  },
  {
    "path": "node/tests/schemaStructReprListpairs.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc SchemaTestStructReprListPairs(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnList(\"List__String\", \"String\", false))\n\tts.Accumulate(schema.SpawnStruct(\"OneListPair\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"field\", \"String\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationListPairs(),\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"FourListPairs\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"foo\", \"String\", false, true),\n\t\t\tschema.SpawnStructField(\"bar\", \"String\", true, true),\n\t\t\tschema.SpawnStructField(\"baz\", \"String\", true, false),\n\t\t\tschema.SpawnStructField(\"qux\", \"List__String\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationListPairs(),\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"NestedListPairs\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"str\", \"String\", false, false),\n\t\t\tschema.SpawnStructField(\"lp\", \"OneListPair\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationListPairs(),\n\t))\n\tengine.Init(t, ts)\n\n\tt.Run(\"onelistpair works\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"OneListPair\")\n\t\tnrp := engine.PrototypeByName(\"OneListPair.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildMap(np, 1, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"field\").AssignString(\"valoo\")\n\t\t\t}).(schema.TypedNode)\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(1))\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"field\"))), qt.Equals, \"valoo\")\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, nr.Length(), qt.Equals, int64(1))\n\t\t\t\tkv := must.Node(nr.LookupByIndex(0))\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, kv.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(0))), qt.Equals, \"field\")\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(1))), qt.Equals, \"valoo\")\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuildList(nrp, 1, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"field\")\n\t\t\t\t\tla.AssembleValue().AssignString(\"valoo\")\n\t\t\t\t})\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t})\n\n\tt.Run(\"fourlistpairs works\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"FourListPairs\")\n\t\tnrp := engine.PrototypeByName(\"FourListPairs.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildMap(np, 4, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"foo\").AssignString(\"0\")\n\t\t\t\tma.AssembleEntry(\"bar\").AssignString(\"1\")\n\t\t\t\tma.AssembleEntry(\"baz\").AssignString(\"2\")\n\t\t\t\tma.AssembleEntry(\"qux\").CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"3\")\n\t\t\t\t\tla.AssembleValue().AssignString(\"4\")\n\t\t\t\t})\n\t\t\t}).(schema.TypedNode)\n\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(4))\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"foo\"))), qt.Equals, \"0\")\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"bar\"))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"baz\"))), qt.Equals, \"2\")\n\t\t\t\tqux := must.Node(n.LookupByString(\"qux\"))\n\t\t\t\tqt.Assert(t, qux.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, qux.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(qux.LookupByIndex(0))), qt.Equals, \"3\")\n\t\t\t\tqt.Check(t, must.String(must.Node(qux.LookupByIndex(1))), qt.Equals, \"4\")\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, nr.Length(), qt.Equals, int64(4))\n\t\t\t\tkv := must.Node(nr.LookupByIndex(0))\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, kv.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(0))), qt.Equals, \"foo\")\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(1))), qt.Equals, \"0\")\n\t\t\t\tkv = must.Node(nr.LookupByIndex(1))\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, kv.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(0))), qt.Equals, \"bar\")\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(1))), qt.Equals, \"1\")\n\t\t\t\tkv = must.Node(nr.LookupByIndex(2))\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, kv.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(0))), qt.Equals, \"baz\")\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(1))), qt.Equals, \"2\")\n\t\t\t\tkv = must.Node(nr.LookupByIndex(3))\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, kv.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(0))), qt.Equals, \"qux\")\n\t\t\t\tqux := must.Node(kv.LookupByIndex(1))\n\t\t\t\tqt.Assert(t, qux.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, qux.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(qux.LookupByIndex(0))), qt.Equals, \"3\")\n\t\t\t\tqt.Check(t, must.String(must.Node(qux.LookupByIndex(1))), qt.Equals, \"4\")\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuildList(nrp, 4, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"foo\")\n\t\t\t\t\tla.AssembleValue().AssignString(\"0\")\n\t\t\t\t})\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"bar\")\n\t\t\t\t\tla.AssembleValue().AssignString(\"1\")\n\t\t\t\t})\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"baz\")\n\t\t\t\t\tla.AssembleValue().AssignString(\"2\")\n\t\t\t\t})\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"qux\")\n\t\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\t\tla.AssembleValue().AssignString(\"3\")\n\t\t\t\t\t\tla.AssembleValue().AssignString(\"4\")\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t\tt.Run(\"repr-create out-of-order\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuildList(nrp, 4, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"bar\")\n\t\t\t\t\tla.AssembleValue().AssignString(\"1\")\n\t\t\t\t})\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"foo\")\n\t\t\t\t\tla.AssembleValue().AssignString(\"0\")\n\t\t\t\t})\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"qux\")\n\t\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\t\tla.AssembleValue().AssignString(\"3\")\n\t\t\t\t\t\tla.AssembleValue().AssignString(\"4\")\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"baz\")\n\t\t\t\t\tla.AssembleValue().AssignString(\"2\")\n\t\t\t\t})\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t})\n\n\tt.Run(\"fourlistpairs with absents\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"FourListPairs\")\n\t\tnrp := engine.PrototypeByName(\"FourListPairs.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildMap(np, 2, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"foo\").AssignNull()\n\t\t\t\tma.AssembleEntry(\"qux\").CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"1\")\n\t\t\t\t\tla.AssembleValue().AssignString(\"2\")\n\t\t\t\t})\n\t\t\t}).(schema.TypedNode)\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(4))\n\t\t\t\tqt.Check(t, must.Node(n.LookupByString(\"foo\")), qt.Equals, datamodel.Null)\n\t\t\t\tqt.Check(t, must.Node(n.LookupByString(\"bar\")), qt.Equals, datamodel.Absent)\n\t\t\t\tqt.Check(t, must.Node(n.LookupByString(\"baz\")), qt.Equals, datamodel.Absent)\n\t\t\t\tqux := must.Node(n.LookupByString(\"qux\"))\n\t\t\t\tqt.Assert(t, qux.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, qux.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(qux.LookupByIndex(0))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.String(must.Node(qux.LookupByIndex(1))), qt.Equals, \"2\")\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, nr.Length(), qt.Equals, int64(2))\n\t\t\t\tkv := must.Node(nr.LookupByIndex(0))\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, kv.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(0))), qt.Equals, \"foo\")\n\t\t\t\tqt.Check(t, must.Node(kv.LookupByIndex(1)), qt.Equals, datamodel.Null)\n\t\t\t\tkv = must.Node(nr.LookupByIndex(1))\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, kv.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(0))), qt.Equals, \"qux\")\n\t\t\t\tqux := must.Node(kv.LookupByIndex(1))\n\t\t\t\tqt.Assert(t, qux.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, qux.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(qux.LookupByIndex(0))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.String(must.Node(qux.LookupByIndex(1))), qt.Equals, \"2\")\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuildList(nrp, 2, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"foo\")\n\t\t\t\t\tla.AssembleValue().AssignNull()\n\t\t\t\t})\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"qux\")\n\t\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\t\tla.AssembleValue().AssignString(\"1\")\n\t\t\t\t\t\tla.AssembleValue().AssignString(\"2\")\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t\tt.Run(\"repr-create with AssignNode\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuildList(basicnode.Prototype.Any, 2, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"foo\")\n\t\t\t\t\tla.AssembleValue().AssignNull()\n\t\t\t\t})\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"qux\")\n\t\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\t\tla.AssembleValue().AssignString(\"1\")\n\t\t\t\t\t\tla.AssembleValue().AssignString(\"2\")\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t\tbuilder := nrp.NewBuilder()\n\t\t\terr := builder.AssignNode(nr)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tanr := builder.Build()\n\t\t\tqt.Check(t, n, NodeContentEquals, anr)\n\t\t})\n\t})\n\n\tt.Run(\"nestedlistpairs works\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"NestedListPairs\")\n\t\tnrp := engine.PrototypeByName(\"NestedListPairs.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildMap(np, 1, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"str\").AssignString(\"boop\")\n\t\t\t\tma.AssembleEntry(\"lp\").CreateMap(1, func(ma fluent.MapAssembler) {\n\t\t\t\t\tma.AssembleEntry(\"field\").AssignString(\"valoo\")\n\t\t\t\t})\n\t\t\t}).(schema.TypedNode)\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"str\"))), qt.Equals, \"boop\")\n\t\t\t\tlp := must.Node(n.LookupByString(\"lp\"))\n\t\t\t\tqt.Check(t, lp.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, must.String(must.Node(lp.LookupByString(\"field\"))), qt.Equals, \"valoo\")\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, nr.Length(), qt.Equals, int64(2))\n\t\t\t\tkv := must.Node(nr.LookupByIndex(0))\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, kv.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(0))), qt.Equals, \"str\")\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(1))), qt.Equals, \"boop\")\n\t\t\t\tkv = must.Node(nr.LookupByIndex(1))\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, kv.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(0))), qt.Equals, \"lp\")\n\t\t\t\tlp := must.Node(kv.LookupByIndex(1))\n\t\t\t\tqt.Check(t, lp.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tkv = must.Node(lp.LookupByIndex(0))\n\t\t\t\tqt.Check(t, kv.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(0))), qt.Equals, \"field\")\n\t\t\t\tqt.Check(t, must.String(must.Node(kv.LookupByIndex(1))), qt.Equals, \"valoo\")\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuildList(nrp, 1, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"str\")\n\t\t\t\t\tla.AssembleValue().AssignString(\"boop\")\n\t\t\t\t})\n\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\tla.AssembleValue().AssignString(\"lp\")\n\t\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\t\tla.AssembleValue().CreateList(2, func(la fluent.ListAssembler) {\n\t\t\t\t\t\t\tla.AssembleValue().AssignString(\"field\")\n\t\t\t\t\t\t\tla.AssembleValue().AssignString(\"valoo\")\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "node/tests/schemaStructReprStringjoin.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// TestStructReprStringjoin exercises... well, what it says on the tin.\n//\n// These should pass even if the natural map representation doesn't.\n// No maybes are exercised.\nfunc SchemaTestStructReprStringjoin(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnStruct(\"StringyStruct\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"field\", \"String\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationStringjoin(\":\"),\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"ManystringStruct\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"foo\", \"String\", false, false),\n\t\t\tschema.SpawnStructField(\"bar\", \"String\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationStringjoin(\":\"),\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"Recurzorator\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"foo\", \"String\", false, false),\n\t\t\tschema.SpawnStructField(\"zap\", \"ManystringStruct\", false, false),\n\t\t\tschema.SpawnStructField(\"bar\", \"String\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationStringjoin(\"-\"),\n\t))\n\tengine.Init(t, ts)\n\n\tt.Run(\"single field works\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"StringyStruct\")\n\t\tnrp := engine.PrototypeByName(\"StringyStruct.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildMap(np, 1, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"field\").AssignString(\"valoo\")\n\t\t\t}).(schema.TypedNode)\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(1))\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"field\"))), qt.Equals, \"valoo\")\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_String)\n\t\t\t\tqt.Check(t, must.String(nr), qt.Equals, \"valoo\")\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuild(nrp, func(na fluent.NodeAssembler) {\n\t\t\t\tna.AssignString(\"valoo\")\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t})\n\n\tt.Run(\"several fields work\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"ManystringStruct\")\n\t\tnrp := engine.PrototypeByName(\"ManystringStruct.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildMap(np, 2, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"foo\").AssignString(\"v1\")\n\t\t\t\tma.AssembleEntry(\"bar\").AssignString(\"v2\")\n\t\t\t}).(schema.TypedNode)\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"foo\"))), qt.Equals, \"v1\")\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"bar\"))), qt.Equals, \"v2\")\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_String)\n\t\t\t\tqt.Check(t, must.String(nr), qt.Equals, \"v1:v2\")\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuild(nrp, func(na fluent.NodeAssembler) {\n\t\t\t\tna.AssignString(\"v1:v2\")\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t})\n\n\tt.Run(\"first field empty string works\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"ManystringStruct\")\n\t\tnrp := engine.PrototypeByName(\"ManystringStruct.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildMap(np, 2, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"foo\").AssignString(\"\")\n\t\t\t\tma.AssembleEntry(\"bar\").AssignString(\"v2\")\n\t\t\t}).(schema.TypedNode)\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"foo\"))), qt.Equals, \"\")\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"bar\"))), qt.Equals, \"v2\")\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_String)\n\t\t\t\tqt.Check(t, must.String(nr), qt.Equals, \":v2\") // Note the leading colon is still present.\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuild(nrp, func(na fluent.NodeAssembler) {\n\t\t\t\tna.AssignString(\":v2\")\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t})\n\n\tt.Run(\"nested stringjoin structs work\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"Recurzorator\")\n\t\tnrp := engine.PrototypeByName(\"Recurzorator.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildMap(np, 3, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"foo\").AssignString(\"v1\")\n\t\t\t\tma.AssembleEntry(\"zap\").CreateMap(2, func(ma fluent.MapAssembler) {\n\t\t\t\t\tma.AssembleEntry(\"foo\").AssignString(\"v2\")\n\t\t\t\t\tma.AssembleEntry(\"bar\").AssignString(\"v3\")\n\t\t\t\t})\n\t\t\t\tma.AssembleEntry(\"bar\").AssignString(\"v4\")\n\t\t\t}).(schema.TypedNode)\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(3))\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"foo\"))), qt.Equals, \"v1\")\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"bar\"))), qt.Equals, \"v4\")\n\t\t\t\tn2 := must.Node(n.LookupByString(\"zap\"))\n\t\t\t\tqt.Check(t, n2.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(n2.LookupByString(\"foo\"))), qt.Equals, \"v2\")\n\t\t\t\tqt.Check(t, must.String(must.Node(n2.LookupByString(\"bar\"))), qt.Equals, \"v3\")\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_String)\n\t\t\t\tqt.Check(t, must.String(nr), qt.Equals, \"v1-v2:v3-v4\")\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuild(nrp, func(na fluent.NodeAssembler) {\n\t\t\t\tna.AssignString(\"v1-v2:v3-v4\")\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "node/tests/schemaStructReprTuple.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc SchemaTestStructReprTuple(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnStruct(\"OneTuple\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"field\", \"String\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationTuple(),\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"FourTuple\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"foo\", \"String\", false, false),\n\t\t\tschema.SpawnStructField(\"bar\", \"String\", false, true),\n\t\t\tschema.SpawnStructField(\"baz\", \"String\", true, true),\n\t\t\tschema.SpawnStructField(\"qux\", \"String\", true, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationTuple(),\n\t))\n\tengine.Init(t, ts)\n\n\tt.Run(\"onetuple works\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"OneTuple\")\n\t\tnrp := engine.PrototypeByName(\"OneTuple.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildMap(np, 1, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"field\").AssignString(\"valoo\")\n\t\t\t}).(schema.TypedNode)\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(1))\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"field\"))), qt.Equals, \"valoo\")\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, nr.Length(), qt.Equals, int64(1))\n\t\t\t\tqt.Check(t, must.String(must.Node(nr.LookupByIndex(0))), qt.Equals, \"valoo\")\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuildList(nrp, 1, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().AssignString(\"valoo\")\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t})\n\n\tt.Run(\"fourtuple works\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"FourTuple\")\n\t\tnrp := engine.PrototypeByName(\"FourTuple.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildMap(np, 4, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"foo\").AssignString(\"0\")\n\t\t\t\tma.AssembleEntry(\"bar\").AssignString(\"1\")\n\t\t\t\tma.AssembleEntry(\"baz\").AssignString(\"2\")\n\t\t\t\tma.AssembleEntry(\"qux\").AssignString(\"3\")\n\t\t\t}).(schema.TypedNode)\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(4))\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"foo\"))), qt.Equals, \"0\")\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"bar\"))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"baz\"))), qt.Equals, \"2\")\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"qux\"))), qt.Equals, \"3\")\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, nr.Length(), qt.Equals, int64(4))\n\t\t\t\tqt.Check(t, must.String(must.Node(nr.LookupByIndex(0))), qt.Equals, \"0\")\n\t\t\t\tqt.Check(t, must.String(must.Node(nr.LookupByIndex(1))), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, must.String(must.Node(nr.LookupByIndex(2))), qt.Equals, \"2\")\n\t\t\t\tqt.Check(t, must.String(must.Node(nr.LookupByIndex(3))), qt.Equals, \"3\")\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuildList(nrp, 4, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().AssignString(\"0\")\n\t\t\t\tla.AssembleValue().AssignString(\"1\")\n\t\t\t\tla.AssembleValue().AssignString(\"2\")\n\t\t\t\tla.AssembleValue().AssignString(\"3\")\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t})\n\n\tt.Run(\"fourtuple with absents\", func(t *testing.T) {\n\t\tnp := engine.PrototypeByName(\"FourTuple\")\n\t\tnrp := engine.PrototypeByName(\"FourTuple.Repr\")\n\t\tvar n schema.TypedNode\n\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\tn = fluent.MustBuildMap(np, 2, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"foo\").AssignString(\"0\")\n\t\t\t\tma.AssembleEntry(\"bar\").AssignNull()\n\t\t\t}).(schema.TypedNode)\n\t\t\tt.Run(\"typed-read\", func(t *testing.T) {\n\t\t\t\tqt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t\t\tqt.Check(t, n.Length(), qt.Equals, int64(4))\n\t\t\t\tqt.Check(t, must.String(must.Node(n.LookupByString(\"foo\"))), qt.Equals, \"0\")\n\t\t\t\tqt.Check(t, must.Node(n.LookupByString(\"bar\")), qt.Equals, datamodel.Null)\n\t\t\t\tqt.Check(t, must.Node(n.LookupByString(\"baz\")), qt.Equals, datamodel.Absent)\n\t\t\t\tqt.Check(t, must.Node(n.LookupByString(\"qux\")), qt.Equals, datamodel.Absent)\n\t\t\t})\n\t\t\tt.Run(\"repr-read\", func(t *testing.T) {\n\t\t\t\tnr := n.Representation()\n\t\t\t\tqt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t\t\tqt.Check(t, nr.Length(), qt.Equals, int64(2))\n\t\t\t\tqt.Check(t, must.String(must.Node(nr.LookupByIndex(0))), qt.Equals, \"0\")\n\t\t\t\tqt.Check(t, must.Node(nr.LookupByIndex(1)), qt.Equals, datamodel.Null)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\tnr := fluent.MustBuildList(nrp, 4, func(la fluent.ListAssembler) {\n\t\t\t\tla.AssembleValue().AssignString(\"0\")\n\t\t\t\tla.AssembleValue().AssignNull()\n\t\t\t})\n\t\t\tqt.Check(t, n, NodeContentEquals, nr)\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "node/tests/schemaStructsContainingMaybe.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// TestStructsContainingMaybe checks all the variations of \"nullable\" and \"optional\" on struct fields.\n// It does this twice: once for the child maybes being implemented with pointers,\n// and once with maybes implemented as embeds.\n// The child values are scalars.\n//\n// Both type-level generic build and access as well as representation build and access are exercised;\n// the representation used is map (the native representation for structs).\nfunc SchemaTestStructsContainingMaybe(t *testing.T, engine Engine) {\n\t// Type declarations.\n\t//  The tests here will all be targetted against this \"Stroct\" type.\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnStruct(\"Stroct\",\n\t\t[]schema.StructField{\n\t\t\t// Every field in this struct (including their order) is exercising an interesting case...\n\t\t\tschema.SpawnStructField(\"f1\", \"String\", false, false), // plain field.\n\t\t\tschema.SpawnStructField(\"f2\", \"String\", true, false),  // optional; later we have more than one optional field, nonsequentially.\n\t\t\tschema.SpawnStructField(\"f3\", \"String\", false, true),  // nullable; but required.\n\t\t\tschema.SpawnStructField(\"f4\", \"String\", true, true),   // optional and nullable; trailing optional.\n\t\t\tschema.SpawnStructField(\"f5\", \"String\", true, false),  // optional; and the second one in a row, trailing.\n\t\t},\n\t\tschema.SpawnStructRepresentationMap(map[string]string{\n\t\t\t\"f1\": \"r1\",\n\t\t\t\"f2\": \"r2\",\n\t\t\t\"f3\": \"r3\",\n\t\t\t\"f4\": \"r4\",\n\t\t}),\n\t))\n\tengine.Init(t, ts)\n\n\t// There's a lot of cases to cover so a shorthand code labels each case for clarity:\n\t//  - 'v' -- value in that entry\n\t//  - 'n' -- null in that entry\n\t//  - 'z' -- absent entry\n\t// There's also a semantic description of the main detail being probed suffixed to the shortcode.\n\tspecs := []testcase{\n\t\t{\n\t\t\tname:     \"vvvvv-AllFieldsSet\",\n\t\t\ttypeJson: `{\"f1\":\"a\",\"f2\":\"b\",\"f3\":\"c\",\"f4\":\"d\",\"f5\":\"e\"}`,\n\t\t\treprJson: `{\"f5\":\"e\",\"r1\":\"a\",\"r2\":\"b\",\"r3\":\"c\",\"r4\":\"d\"}`,\n\t\t\ttypePoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"f1\", \"a\"},\n\t\t\t\t{\"f2\", \"b\"},\n\t\t\t\t{\"f3\", \"c\"},\n\t\t\t\t{\"f4\", \"d\"},\n\t\t\t\t{\"f5\", \"e\"},\n\t\t\t},\n\t\t\treprPoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"r1\", \"a\"},\n\t\t\t\t{\"r2\", \"b\"},\n\t\t\t\t{\"r3\", \"c\"},\n\t\t\t\t{\"r4\", \"d\"},\n\t\t\t\t{\"f5\", \"e\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"vvnnv-Nulls\",\n\t\t\ttypeJson: `{\"f1\":\"a\",\"f2\":\"b\",\"f3\":null,\"f4\":null,\"f5\":\"e\"}`,\n\t\t\treprJson: `{\"f5\":\"e\",\"r1\":\"a\",\"r2\":\"b\",\"r3\":null,\"r4\":null}`,\n\t\t\ttypePoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"f1\", \"a\"},\n\t\t\t\t{\"f2\", \"b\"},\n\t\t\t\t{\"f3\", datamodel.Null},\n\t\t\t\t{\"f4\", datamodel.Null},\n\t\t\t\t{\"f5\", \"e\"},\n\t\t\t},\n\t\t\treprPoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"r1\", \"a\"},\n\t\t\t\t{\"r2\", \"b\"},\n\t\t\t\t{\"r3\", datamodel.Null},\n\t\t\t\t{\"r4\", datamodel.Null},\n\t\t\t\t{\"f5\", \"e\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"vzvzv-AbsentOptionals\",\n\t\t\ttypeJson: `{\"f1\":\"a\",\"f3\":\"c\",\"f5\":\"e\"}`,\n\t\t\treprJson: `{\"f5\":\"e\",\"r1\":\"a\",\"r3\":\"c\"}`,\n\t\t\ttypePoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"f1\", \"a\"},\n\t\t\t\t{\"f2\", datamodel.Absent},\n\t\t\t\t{\"f3\", \"c\"},\n\t\t\t\t{\"f4\", datamodel.Absent},\n\t\t\t\t{\"f5\", \"e\"},\n\t\t\t},\n\t\t\treprPoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"r1\", \"a\"},\n\t\t\t\t//{\"r2\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t\t{\"r3\", \"c\"},\n\t\t\t\t//{\"r4\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t\t{\"f5\", \"e\"},\n\t\t\t},\n\t\t\ttypeItr: []entry{\n\t\t\t\t{\"f1\", \"a\"},\n\t\t\t\t{\"f2\", datamodel.Absent},\n\t\t\t\t{\"f3\", \"c\"},\n\t\t\t\t{\"f4\", datamodel.Absent},\n\t\t\t\t{\"f5\", \"e\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"vvnzz-AbsentTrailingOptionals\",\n\t\t\ttypeJson: `{\"f1\":\"a\",\"f2\":\"b\",\"f3\":null}`,\n\t\t\treprJson: `{\"r1\":\"a\",\"r2\":\"b\",\"r3\":null}`,\n\t\t\ttypePoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"f1\", \"a\"},\n\t\t\t\t{\"f2\", \"b\"},\n\t\t\t\t{\"f3\", datamodel.Null},\n\t\t\t\t{\"f4\", datamodel.Absent},\n\t\t\t\t{\"f5\", datamodel.Absent},\n\t\t\t},\n\t\t\treprPoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"r1\", \"a\"},\n\t\t\t\t{\"r2\", \"b\"},\n\t\t\t\t{\"r3\", datamodel.Null},\n\t\t\t\t//{\"r4\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t\t//{\"f5\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t},\n\t\t\ttypeItr: []entry{\n\t\t\t\t{\"f1\", \"a\"},\n\t\t\t\t{\"f2\", \"b\"},\n\t\t\t\t{\"f3\", datamodel.Null},\n\t\t\t\t{\"f4\", datamodel.Absent},\n\t\t\t\t{\"f5\", datamodel.Absent},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tcase := range specs {\n\t\ttcase.Test(t, engine.PrototypeByName(\"Stroct\"), engine.PrototypeByName(\"Stroct.Repr\"))\n\t}\n}\n"
  },
  {
    "path": "node/tests/schemaUnions.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc SchemaTestUnionKeyed(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnString(\"Strung\"))\n\tts.Accumulate(schema.SpawnUnion(\"StrStr\",\n\t\t[]schema.TypeName{\n\t\t\t\"String\",\n\t\t\t\"Strung\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{\n\t\t\t\"a\": \"String\",\n\t\t\t\"b\": \"Strung\",\n\t\t}),\n\t))\n\tengine.Init(t, ts)\n\n\tspecs := []testcase{\n\t\t{\n\t\t\tname:     \"InhabitantA\",\n\t\t\ttypeJson: `{\"String\":\"whee\"}`,\n\t\t\treprJson: `{\"a\":\"whee\"}`,\n\t\t\ttypePoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"String\", \"whee\"},\n\t\t\t\t//{\"Strung\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t},\n\t\t\treprPoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"a\", \"whee\"},\n\t\t\t\t//{\"b\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"InhabitantB\",\n\t\t\ttypeJson: `{\"Strung\":\"whee\"}`,\n\t\t\treprJson: `{\"b\":\"whee\"}`,\n\t\t\ttypePoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t//{\"String\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t\t{\"Strung\", \"whee\"},\n\t\t\t},\n\t\t\treprPoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t//{\"a\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t\t{\"b\", \"whee\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tnp := engine.PrototypeByName(\"StrStr\")\n\tnrp := engine.PrototypeByName(\"StrStr.Repr\")\n\tfor _, tcase := range specs {\n\t\ttcase.Test(t, np, nrp)\n\t}\n}\n\n// Test keyed unions again, but this time with more complex types as children.\n//\n// The previous tests used scalar types as the children; this exercises most things,\n// but also has a couple (extremely non-obvious) simplifications:\n// namely, because the default representation for strings are \"natural\" representations,\n// the ReprAssemblers are actually aliases of the type-level Assemblers!\n// Aaaand that makes a few things \"work\" by coincidence that wouldn't otherwise fly.\nfunc SchemaTestUnionKeyedComplexChildren(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnStruct(\"SmolStruct\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"s\", \"String\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationMap(map[string]string{\n\t\t\t\"s\": \"q\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnUnion(\"WheeUnion\",\n\t\t[]schema.TypeName{\n\t\t\t\"String\",\n\t\t\t\"SmolStruct\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{\n\t\t\t\"a\": \"String\",\n\t\t\t\"b\": \"SmolStruct\",\n\t\t}),\n\t))\n\tengine.Init(t, ts)\n\n\tspecs := []testcase{\n\t\t{\n\t\t\tname:     \"InhabitantA\",\n\t\t\ttypeJson: `{\"String\":\"whee\"}`,\n\t\t\treprJson: `{\"a\":\"whee\"}`,\n\t\t\ttypePoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"String\", \"whee\"},\n\t\t\t\t//{\"SmolStruct\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t},\n\t\t\treprPoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"a\", \"whee\"},\n\t\t\t\t//{\"b\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"InhabitantB\",\n\t\t\ttypeJson: `{\"SmolStruct\":{\"s\":\"whee\"}}`,\n\t\t\treprJson: `{\"b\":{\"q\":\"whee\"}}`,\n\t\t\ttypePoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t//{\"String\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t\t{\"SmolStruct\", datamodel.Kind_Map},\n\t\t\t\t{\"SmolStruct/s\", \"whee\"},\n\t\t\t},\n\t\t\treprPoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t//{\"a\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t\t{\"b\", datamodel.Kind_Map},\n\t\t\t\t{\"b/q\", \"whee\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tnp := engine.PrototypeByName(\"WheeUnion\")\n\tnrp := engine.PrototypeByName(\"WheeUnion.Repr\")\n\tfor _, tcase := range specs {\n\t\ttcase.Test(t, np, nrp)\n\t}\n}\n\n// TestUnionKeyedReset puts a union inside a list, so that we can use the list's reuse of assembler as a test of the assembler's reset feature.\n// The value inside the union is also more complex than a scalar value so that we test resetting gets passed down, too.\nfunc SchemaTestUnionKeyedReset(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnStruct(\"SmolStruct\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"s\", \"String\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationMap(map[string]string{\n\t\t\t\"s\": \"q\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnUnion(\"WheeUnion\",\n\t\t[]schema.TypeName{\n\t\t\t\"String\",\n\t\t\t\"SmolStruct\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{\n\t\t\t\"a\": \"String\",\n\t\t\t\"b\": \"SmolStruct\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnList(\"OuterList\",\n\t\t\"WheeUnion\", false,\n\t))\n\tengine.Init(t, ts)\n\n\tspecs := []testcase{\n\t\t{\n\t\t\ttypeJson: `[{\"SmolStruct\":{\"s\":\"one\"}}, {\"SmolStruct\":{\"s\":\"two\"}}, {\"String\":\"three\"}]`,\n\t\t\treprJson: `[{\"b\":{\"q\":\"one\"}}, {\"b\":{\"q\":\"two\"}}, {\"a\":\"three\"}]`,\n\t\t\ttypePoints: []testcasePoint{\n\t\t\t\t{\"0/SmolStruct/s\", \"one\"},\n\t\t\t\t{\"1/SmolStruct/s\", \"two\"},\n\t\t\t\t{\"2/String\", \"three\"},\n\t\t\t},\n\t\t\treprPoints: []testcasePoint{\n\t\t\t\t{\"0/b/q\", \"one\"},\n\t\t\t\t{\"1/b/q\", \"two\"},\n\t\t\t\t{\"2/a\", \"three\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tnp := engine.PrototypeByName(\"OuterList\")\n\tnrp := engine.PrototypeByName(\"OuterList.Repr\")\n\tfor _, tcase := range specs {\n\t\ttcase.Test(t, np, nrp)\n\t}\n}\n"
  },
  {
    "path": "node/tests/schemaUnionsKinded.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc SchemaTestUnionKinded(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnStruct(\"SmolStruct\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"s\", \"String\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationMap(map[string]string{\n\t\t\t\"s\": \"q\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnUnion(\"WheeUnion\",\n\t\t[]schema.TypeName{\n\t\t\t\"String\",\n\t\t\t\"SmolStruct\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationKinded(map[datamodel.Kind]schema.TypeName{\n\t\t\tdatamodel.Kind_String: \"String\",\n\t\t\tdatamodel.Kind_Map:    \"SmolStruct\",\n\t\t}),\n\t))\n\tengine.Init(t, ts)\n\n\t// These are the same *type-level* as in TestUnionKeyedComplexChildren,\n\t//  but (of course) have very different representations.\n\tspecs := []testcase{\n\t\t{\n\t\t\tname:     \"InhabitantA\",\n\t\t\ttypeJson: `{\"String\":\"whee\"}`,\n\t\t\treprJson: `\"whee\"`,\n\t\t\ttypePoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"String\", \"whee\"},\n\t\t\t\t//{\"SmolStruct\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t},\n\t\t\treprPoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_String},\n\t\t\t\t{\"\", \"whee\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"InhabitantB\",\n\t\t\ttypeJson: `{\"SmolStruct\":{\"s\":\"whee\"}}`,\n\t\t\treprJson: `{\"q\":\"whee\"}`,\n\t\t\ttypePoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t//{\"String\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t\t{\"SmolStruct\", datamodel.Kind_Map},\n\t\t\t\t{\"SmolStruct/s\", \"whee\"},\n\t\t\t},\n\t\t\treprPoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"q\", \"whee\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tnp := engine.PrototypeByName(\"WheeUnion\")\n\tnrp := engine.PrototypeByName(\"WheeUnion.Repr\")\n\tfor _, tcase := range specs {\n\t\ttcase.Test(t, np, nrp)\n\t}\n}\n"
  },
  {
    "path": "node/tests/schemaUnionsStringprefix.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc SchemaTestUnionStringprefix(t *testing.T, engine Engine) {\n\tts := schema.TypeSystem{}\n\tts.Init()\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnStruct(\"SmolStruct\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"a\", \"String\", false, false),\n\t\t\tschema.SpawnStructField(\"b\", \"String\", false, false),\n\t\t},\n\t\tschema.SpawnStructRepresentationStringjoin(\":\"),\n\t))\n\tts.Accumulate(schema.SpawnUnion(\"WheeUnion\",\n\t\t[]schema.TypeName{\n\t\t\t\"String\",\n\t\t\t\"SmolStruct\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationStringprefix(\n\t\t\t\":\",\n\t\t\tmap[string]schema.TypeName{\n\t\t\t\t\"simple\":  \"String\",\n\t\t\t\t\"complex\": \"SmolStruct\",\n\t\t\t},\n\t\t),\n\t))\n\tengine.Init(t, ts)\n\n\t// These are the same *type-level* as in TestUnionKeyedComplexChildren,\n\t//  but (of course) have very different representations.\n\tspecs := []testcase{\n\t\t{\n\t\t\tname:     \"InhabitantA\",\n\t\t\ttypeJson: `{\"String\":\"whee\"}`,\n\t\t\treprJson: `\"simple:whee\"`,\n\t\t\ttypePoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t{\"String\", \"whee\"},\n\t\t\t\t//{\"SmolStruct\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t},\n\t\t\treprPoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_String},\n\t\t\t\t{\"\", \"simple:whee\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"InhabitantB\",\n\t\t\ttypeJson: `{\"SmolStruct\":{\"a\":\"whee\",\"b\":\"woo\"}}`,\n\t\t\treprJson: `\"complex:whee:woo\"`,\n\t\t\ttypePoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_Map},\n\t\t\t\t//{\"String\", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.\n\t\t\t\t{\"SmolStruct\", datamodel.Kind_Map},\n\t\t\t\t{\"SmolStruct/a\", \"whee\"},\n\t\t\t\t{\"SmolStruct/b\", \"woo\"},\n\t\t\t},\n\t\t\treprPoints: []testcasePoint{\n\t\t\t\t{\"\", datamodel.Kind_String},\n\t\t\t\t{\"\", \"complex:whee:woo\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tnp := engine.PrototypeByName(\"WheeUnion\")\n\tnrp := engine.PrototypeByName(\"WheeUnion.Repr\")\n\tfor _, tcase := range specs {\n\t\ttcase.Test(t, np, nrp)\n\t}\n}\n"
  },
  {
    "path": "node/tests/stringSpecs.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\nfunc SpecTestString(t *testing.T, np datamodel.NodePrototype) {\n\tt.Run(\"string node\", func(t *testing.T) {\n\t\tnb := np.NewBuilder()\n\t\terr := nb.AssignString(\"asdf\")\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tn := nb.Build()\n\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_String)\n\t\tqt.Check(t, n.IsNull(), qt.IsFalse)\n\t\tx, err := n.AsString()\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, x, qt.Equals, \"asdf\")\n\t})\n}\n"
  },
  {
    "path": "node/tests/testEngine.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// Engine describes the interface that can be supplied to run tests on schemas.\n//\n// The PrototypeByName function can get its job done using only interface types\n// that we already know from outside any generated code, so you can write tests\n// that have no _compile time_ dependency on the generated code.  This makes it\n// easier for IDEs and suchlike to help you write and check the test functions.\n//\n// Ask for prototypes using the type name alone (no package prefix);\n// their representation prototypes can be obtained by appending \".Repr\".\ntype Engine interface {\n\tInit(t *testing.T, ts schema.TypeSystem)\n\tPrototypeByName(name string) datamodel.NodePrototype\n}\n"
  },
  {
    "path": "node/tests/testcase.go",
    "content": "package tests\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/polydawn/refmt/json\"\n\t\"github.com/polydawn/refmt/shared\"\n\n\t\"github.com/ipld/go-ipld-prime/codec\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/traversal\"\n)\n\n// This file introduces a testcase struct and a bunch of functions around it.\n//  This structure can be used to specify many test scenarios easily, using json as a shorthand for the fixtures.\n//  Not everything can be tested this way (in particular, there's some fun details around maps with complex keys, and structs with absent fields), but it covers a lot.\n\n/*\ntestcase contains data for directing a sizable number of tests against a NodePrototype\n(or more specifically, a pair of them -- one for the type-level node, one for the representation),\nall of which are applied by calling the testcase.Test method:\n\n  - Creation of values using the type-level builder is tested.\n  - This is done using a json input as a convenient shorthand.\n  - n.b. this is optional, because it won't work for maps with complex keys.\n  - In things that behave as maps: this tests the AssembleEntry path (rather than AssembleKey+AssembleValue; this is the case because this is implemented using unmarshal codepaths).\n  - If this is expected to fail, an expected error may be specified (which will also make all other tests after creation inapplicable to this testcase).\n  - Creation of values using the repr-level builder is tested.\n  - This is (again) done using a json input as a convenient shorthand.\n  - At least *one* of this or the json for type-level must be present.  If neither: the testcase spec is broken.\n  - As for the type-level test: in things that behave as maps, this tests the AssembleEntry path.\n  - If this is expected to fail, an expected error may be specified (which will also make all other tests after creation inapplicable to this testcase).\n  - If both forms of creation were exercised: check that the result nodes are deep-equal.\n  - A list of \"point\" observations may be provided, which can probe positions in the data tree for expected values (or just type kind, etc).\n  - This tests that direct lookups work.  (It doesn't test iterators; that'll come in another step, later.)\n  - Pathing (a la traversal.Get) is used for this this, so it's ready to inspect deep structures.\n  - The field for expected value is just `interface{}`; it handles nodes, some primitives, and will also allow asserting an error.\n  - The node is *copied*, and deep-equal checked again.\n  - The purpose of this is to exercise the AssembleKey+AssembleValue path (as opposed to AssembleEntry (which is already exercised by our creation tests, since they use unmarshal codepaths)).\n  - Access of type-level data via iterators is tested in one of two ways:\n  - A list of expected key+values expected of the iterator can be provided explicitly;\n  - If an explicit list isn't provided, but type-level json is provided, the type-level data will be marshalled and compared to the json fixture.\n  - Most things can use the json path -- those that can't (e.g. maps with complex keys; structs with absent values -- neither is marshallable) use the explicit key+value system instead.\n  - Access of the representation-level data via interators is tested via marshalling, and asserting it against the json fixture data (if present).\n  - There's no explicit key+value list alternative here -- it's not needed; there is no data that is unmarshallable, by design!\n\nThis system should cover a lot of things, but doesn't cover everything.\n\n  - Good coverage for \"reset\" pathways is reached somewhat indirectly...\n  - Tests for recursive types containing nontrivial reset methods exercise both the child type's assembler reset method, and that the parent calls it correctly.\n  - Maps with complex keys are tricky to handle, as already noted above.\n  - But you should be able to do it, with some care.\n  - This whole system depends on json parsers and serializers already working.\n  - This is arguably an uncomfortably large and complex dependency for a test system.  However, the json systems are tested by using basicnode; there's no cycle here.\n  - \"Unhappy paths\" in creation are a bit tricky to test.\n  - It can be done, but for map-like things, only for the AssembleEntry path.\n  - PRs welcome if someone's got a clever idea for a good way to exercise AssembleKey+AssembleValue.  (A variant of unmarshaller implementation?  Would do it; just verbose.)\n  - No support yet for checking properties like Length.\n  - Future: we could add another type-hinted special case to the testcasePoint.expect for this, i suppose.\n*/\ntype testcase struct {\n\tname                string          // name for the testcase.\n\ttypeJson            string          // json that will be fed to unmarshal together with a type-level assembler.  marshal output will also be checked for equality.  may be absent.\n\treprJson            string          // json that will be fed to unmarshal together with a representational assembler.  marshal output will also be checked for equality.\n\texpectUnmarshalFail error           // if present, this error will be expected from the unmarshal process (and implicitly, marshal tests will not be applicable for this testcase).\n\ttypePoints          []testcasePoint // inspections that will be made by traversing the type-level nodes.\n\treprPoints          []testcasePoint // inspections that will be made by traversing the representation nodes.\n\ttypeItr             []entry         // if set, the type will be iterated in this way.  The remarshalling and checking against typeJson will not be tested.  This is used to probe for correct iteration over Absent values in structs (which needs special handling, because they are unserializable).\n\t// there's really no need for an 'expectFail' that applies to marshal, because it shouldn't be possible to create data that's unmarshallable!  (excepting data which is not marshallable by some *codec* due to incompleteness of that codec.  But that's not what we're testing, here.)\n\t// there's no need for a reprItr because the marshalling to reprJson always covers that; unlike with the type level, neither absents nor complex keys can throw a wrench in serialization, so it's always available to us to exercise the iteration code.\n}\n\ntype testcasePoint struct {\n\tpath   string\n\texpect interface{} // if primitive: we'll AsFoo and assert equal on that; if an error, we'll expect an error and compare error types; if a kind, we'll check that the thing reached simply has that kind.\n}\n\ntype entry struct {\n\tkey   interface{} // (mostly string.  not yet defined how this will handle maps with complex keys.)\n\tvalue interface{} // same rules as testcasePoint.expect\n}\n\nfunc (tcase testcase) Test(t *testing.T, np, npr datamodel.NodePrototype) {\n\tt.Run(tcase.name, func(t *testing.T) {\n\t\t// We'll produce either one or two nodes, depending on the fixture; if two, we'll be expecting them to be equal.\n\t\tvar n, n2 datamodel.Node\n\n\t\t// Attempt to produce a node by using unmarshal on type-level fixture data and the type-level NodePrototype.\n\t\t//  This exercises creating a value using the AssembleEntry path (but note, not AssembleKey+AssembleValue path).\n\t\t//  This test section is optional because we can't use it for some types (namely, maps with complex keys -- which simply need custom tests).\n\t\tif tcase.typeJson != \"\" {\n\t\t\tt.Run(\"typed-create\", func(t *testing.T) {\n\t\t\t\tn = testUnmarshal(t, np, tcase.typeJson, tcase.expectUnmarshalFail)\n\t\t\t})\n\t\t}\n\n\t\t// Attempt to produce a node by using unmarshal on repr-level fixture data and the repr-level NodePrototype.\n\t\t//  This exercises creating a value using the AssembleEntry path (but note, not AssembleKey+AssembleValue path).\n\t\t//  This test section is optional simply because it's nice to be able to omit it when writing a new system and not wanting to test representation yet.\n\t\tif tcase.reprJson != \"\" {\n\t\t\tt.Run(\"repr-create\", func(t *testing.T) {\n\t\t\t\tn3 := testUnmarshal(t, npr, tcase.reprJson, tcase.expectUnmarshalFail)\n\t\t\t\tif n == nil {\n\t\t\t\t\tn = n3\n\t\t\t\t} else {\n\t\t\t\t\tn2 = n3\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\t// If unmarshalling was expected to fail, the rest of the tests are inapplicable.\n\t\tif tcase.expectUnmarshalFail != nil {\n\t\t\treturn\n\t\t}\n\n\t\t// Check the nodes are equal, if there's two of them.  (Or holler, if none.)\n\t\tif n == nil {\n\t\t\tt.Fatalf(\"invalid fixture: need one of either typeJson or reprJson provided\")\n\t\t}\n\t\tif n2 != nil {\n\t\t\tt.Run(\"type-create and repr-create match\", func(t *testing.T) {\n\t\t\t\tqt.Check(t, n, NodeContentEquals, n2)\n\t\t\t})\n\t\t}\n\n\t\t// Perform all the point inspections on the type-level node.\n\t\tif tcase.typePoints != nil {\n\t\t\tt.Run(\"type-level inspection\", func(t *testing.T) {\n\t\t\t\tfor _, point := range tcase.typePoints {\n\t\t\t\t\twishPoint(t, n, point)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\t// Perform all the point inspections on the repr-level node.\n\t\tif tcase.reprPoints != nil {\n\t\t\tt.Run(\"repr-level inspection\", func(t *testing.T) {\n\t\t\t\tfor _, point := range tcase.reprPoints {\n\t\t\t\t\twishPoint(t, n.(schema.TypedNode).Representation(), point)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\t// Serialize the type-level node, and check that we get the original json again.\n\t\t//  This exercises iterators on the type-level node.\n\t\t//  OR, if typeItr is present, do that instead (this is necessary when handling maps with complex keys or handling structs with absent values, since both of those are unserializable).\n\t\tif tcase.typeItr != nil {\n\t\t\t// This can unconditionally assume we're going to handle maps,\n\t\t\t//  because the only kind of thing that needs this style of testing are some instances of maps and some instances of structs.\n\t\t\titr := n.MapIterator()\n\t\t\tfor _, entry := range tcase.typeItr {\n\t\t\t\tqt.Check(t, itr.Done(), qt.IsFalse)\n\t\t\t\tk, v, err := itr.Next()\n\t\t\t\tqt.Check(t, k, closeEnough, entry.key)\n\t\t\t\tqt.Check(t, v, closeEnough, entry.value)\n\t\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\t}\n\t\t\tqt.Check(t, itr.Done(), qt.IsTrue)\n\t\t\tk, v, err := itr.Next()\n\t\t\tqt.Check(t, k, qt.IsNil)\n\t\t\tqt.Check(t, v, qt.IsNil)\n\t\t\tqt.Check(t, err, qt.Equals, datamodel.ErrIteratorOverread{})\n\t\t} else if tcase.typeJson != \"\" {\n\t\t\tt.Run(\"type-marshal\", func(t *testing.T) {\n\t\t\t\ttestMarshal(t, n, tcase.typeJson)\n\t\t\t})\n\t\t}\n\n\t\t// Serialize the repr-level node, and check that we get the original json again.\n\t\t//  This exercises iterators on the repr-level node.\n\t\tif tcase.reprJson != \"\" {\n\t\t\tt.Run(\"repr-marshal\", func(t *testing.T) {\n\t\t\t\ttestMarshal(t, n.(schema.TypedNode).Representation(), tcase.reprJson)\n\t\t\t})\n\t\t}\n\n\t\t// Copy the node.  If it's a map-like.\n\t\t//  This exercises the AssembleKey+AssembleValue path for maps (or things that act as maps, such as structs and unions),\n\t\t//   as opposed to the AssembleEntry path (which is what was exercised by the creation via unmarshal).\n\t\t// Assumes that the iterators are working correctly.\n\t\tif n.Kind() == datamodel.Kind_Map {\n\t\t\tt.Run(\"type-create with AK+AV\", func(t *testing.T) {\n\t\t\t\tn3, err := shallowCopyMap(np, n)\n\t\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\t\tqt.Check(t, n, NodeContentEquals, n3)\n\t\t\t})\n\t\t}\n\n\t\t// Copy the node, now at repr level.  Again, this is for exercising AssembleKey+AssembleValue paths.\n\t\t// Assumes that the iterators are working correctly.\n\t\tif n.(schema.TypedNode).Representation().Kind() == datamodel.Kind_Map {\n\t\t\tt.Run(\"repr-create with AK+AV\", func(t *testing.T) {\n\t\t\t\tn3, err := shallowCopyMap(npr, n.(schema.TypedNode).Representation())\n\t\t\t\tqt.Check(t, err, qt.IsNil)\n\t\t\t\tqt.Check(t, n3, NodeContentEquals, n)\n\t\t\t})\n\t\t}\n\n\t})\n}\n\nfunc shallowCopyMap(np datamodel.NodePrototype, n datamodel.Node) (datamodel.Node, error) {\n\tnb := np.NewBuilder()\n\tma, err := nb.BeginMap(n.Length())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor itr := n.MapIterator(); !itr.Done(); {\n\t\tk, v, err := itr.Next()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif v.IsAbsent() {\n\t\t\tcontinue\n\t\t}\n\t\tif err := ma.AssembleKey().AssignNode(k); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := ma.AssembleValue().AssignNode(v); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif err := ma.Finish(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn nb.Build(), nil\n}\n\nfunc testUnmarshal(t *testing.T, np datamodel.NodePrototype, data string, expectFail error) datamodel.Node {\n\tt.Helper()\n\tnb := np.NewBuilder()\n\terr := dagjson.Decode(nb, strings.NewReader(data))\n\tswitch {\n\tcase expectFail == nil && err != nil:\n\t\tt.Fatalf(\"fixture parse failed: %s\", err)\n\tcase expectFail == nil && err == nil:\n\t\t// carry on\n\tcase expectFail != nil && err != nil:\n\t\tqt.Check(t, err, qt.ErrorAs, expectFail)\n\tcase expectFail != nil && err == nil:\n\t\tt.Errorf(\"expected creation to fail with a %T error, but got no error\", expectFail)\n\t}\n\treturn nb.Build()\n}\n\nfunc testMarshal(t *testing.T, n datamodel.Node, data string) {\n\tt.Helper()\n\t// We'll marshal with \"pretty\" linebreaks and indents (and re-format the fixture to the same) for better diffing.\n\tprettyprint := json.EncodeOptions{Line: []byte{'\\n'}, Indent: []byte{'\\t'}}\n\tvar buf bytes.Buffer\n\terr := dagjson.Marshal(n, json.NewEncoder(&buf, prettyprint), dagjson.EncodeOptions{\n\t\tEncodeLinks: true,\n\t\tEncodeBytes: true,\n\t\tMapSortMode: codec.MapSortMode_Lexical,\n\t})\n\tif err != nil {\n\t\tt.Errorf(\"marshal failed: %s\", err)\n\t}\n\tqt.Check(t, buf.String(), qt.Equals, reformat(data, prettyprint))\n}\n\nfunc wishPoint(t *testing.T, n datamodel.Node, point testcasePoint) {\n\tt.Helper()\n\treached, err := traversal.Get(n, datamodel.ParsePath(point.path))\n\tswitch point.expect.(type) {\n\tcase error:\n\t\tqt.Check(t, err, qt.ErrorAs, point.expect)\n\t\tqt.Check(t, err, qt.Equals, point.expect)\n\tdefault:\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tif reached == nil {\n\t\t\treturn\n\t\t}\n\t\tqt.Check(t, reached, closeEnough, point.expect)\n\t}\n}\n\n// closeEnough conforms to quicktest.Checker (so we can use it in quicktest invocations),\n// and lets Nodes be compared to primitives in convenient ways.\n//\n// If the expected value is a primitive string, it'll AsStrong on the Node; etc.\n//\n// Using a datamodel.Kind value is also possible, which will just check the kind and not the value contents.\n//\n// If a datamodel.Node is the expected value, a full deep qt.Equals is used as normal.\nvar closeEnough = &closeEnoughChecker{}\n\nvar _ qt.Checker = (*closeEnoughChecker)(nil)\n\ntype closeEnoughChecker struct{}\n\nfunc (c *closeEnoughChecker) ArgNames() []string {\n\treturn []string{\"got\", \"want\"}\n}\n\nfunc (c *closeEnoughChecker) Check(actual interface{}, args []interface{}, note func(key string, value interface{})) (err error) {\n\texpected := args[0]\n\tif expected == nil {\n\t\treturn qt.IsNil.Check(actual, args, note)\n\t}\n\ta, ok := actual.(datamodel.Node)\n\tif !ok {\n\t\treturn errors.New(\"this checker only supports checking datamodel.Node values\")\n\t}\n\tswitch expected.(type) {\n\tcase datamodel.Kind:\n\t\treturn qt.Equals.Check(a.Kind(), args, note)\n\tcase string:\n\t\tif a.Kind() != datamodel.Kind_String {\n\t\t\treturn fmt.Errorf(\"expected something with kind string, got kind %s\", a.Kind())\n\t\t}\n\t\tx, _ := a.AsString()\n\t\treturn qt.Equals.Check(x, args, note)\n\tcase int:\n\t\tif a.Kind() != datamodel.Kind_Int {\n\t\t\treturn fmt.Errorf(\"expected something with kind int, got kind %s\", a.Kind())\n\t\t}\n\t\tx, _ := a.AsInt()\n\t\treturn qt.Equals.Check(x, args, note)\n\tcase datamodel.Node:\n\t\treturn qt.Equals.Check(actual, args, note)\n\tdefault:\n\t\treturn fmt.Errorf(\"this checker doesn't support an expected value of type %T\", expected)\n\t}\n}\n\nfunc reformat(x string, opts json.EncodeOptions) string {\n\tvar buf bytes.Buffer\n\tif err := (shared.TokenPump{\n\t\tTokenSource: json.NewDecoder(strings.NewReader(x)),\n\t\tTokenSink:   json.NewEncoder(&buf, opts),\n\t}).Run(); err != nil {\n\t\tpanic(err)\n\t}\n\treturn buf.String()\n}\n"
  },
  {
    "path": "node/tests/testutil.go",
    "content": "package tests\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// This file is full of helper functions.  Most are moderately embarassing.\n//\n// We should probably turn half of this into Wish Checkers;\n//  they'd probably be much less fragile and give better error messages that way.\n//  On the other hand, the functions for condensing two-arg returns wouldn't go away anyway.\n\n// various benchmarks assign their final result here,\n// in order to defuse the possibility of their work being elided.\nvar sink interface{} //lint:ignore U1000 used by benchmarks\n\n// purely to syntactically flip large inline closures so we can see the argument at the top rather than the bottom of the block.\nfunc withNode(n datamodel.Node, cb func(n datamodel.Node)) {\n\tcb(n)\n}\n"
  },
  {
    "path": "node/tests/traversalBenchmarks.go",
    "content": "package tests\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/tests/corpus\"\n\t\"github.com/ipld/go-ipld-prime/traversal\"\n)\n\nfunc BenchmarkSpec_Walk_Map3StrInt(b *testing.B, np datamodel.NodePrototype) {\n\tnode := mustNodeFromJsonString(np, corpus.Map3StrInt())\n\tsel := mustSelectorFromJsonString(np, `{\"a\":{\">\":{\".\":{}}}}`)\n\tb.ResetTimer()\n\n\tvar visitCountSanityCheck int\n\tfor i := 0; i < b.N; i++ {\n\t\tvisitCountSanityCheck = 0\n\t\ttraversal.WalkMatching(node, sel, func(tp traversal.Progress, n datamodel.Node) error {\n\t\t\tvisitCountSanityCheck++ // this sanity check is sufficiently cheap to be worth it\n\t\t\treturn nil              // no need to do anything here; just care about exercising the walk internals.\n\t\t})\n\t}\n\tif visitCountSanityCheck != 3 {\n\t\tb.Fatalf(\"visitCountSanityCheck should be 3, got %d\", visitCountSanityCheck)\n\t}\n}\n\nfunc BenchmarkSpec_Walk_MapNStrMap3StrInt(b *testing.B, np datamodel.NodePrototype) {\n\tsel := mustSelectorFromJsonString(np, `{\"a\":{\">\":{\"a\":{\">\":{\".\":{}}}}}}`)\n\n\tfor _, n := range []int{0, 1, 2, 4, 8, 16, 32} {\n\t\tb.Run(fmt.Sprintf(\"n=%d\", n), func(b *testing.B) {\n\t\t\tnode := mustNodeFromJsonString(np, corpus.MapNStrMap3StrInt(n))\n\t\t\tb.ResetTimer()\n\n\t\t\tvar visitCountSanityCheck int\n\t\t\tfor i := 0; i < b.N; i++ {\n\t\t\t\tvisitCountSanityCheck = 0\n\t\t\t\ttraversal.WalkMatching(node, sel, func(tp traversal.Progress, n datamodel.Node) error {\n\t\t\t\t\tvisitCountSanityCheck++ // this sanity check is sufficiently cheap to be worth it\n\t\t\t\t\treturn nil              // no need to do anything here; just care about exercising the walk internals.\n\t\t\t\t})\n\t\t\t}\n\t\t\tif visitCountSanityCheck != 3*n {\n\t\t\t\tb.Fatalf(\"visitCountSanityCheck should be %d, got %d\", n*3, visitCountSanityCheck)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "node/tests/unmarshalBenchmarks.go",
    "content": "package tests\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/codec/json\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/tests/corpus\"\n)\n\n// All of the marshalling and unmarshalling benchmark specs use JSON.\n// This does mean we're measuring a bunch of stuff that has nothing to do\n//  with the core operations of the Node/NodeBuilder interface.\n// We do this so that:\n// - we get a reasonable picture of how much time is spent in the IPLD Data Model\n//    versus how much time is spent in the serialization efforts;\n// - we can make direct comparisons to the standard library json marshalling\n//    and unmarshalling, thus having a back-of-the-envelope baseline to compare.\n\nfunc BenchmarkSpec_Unmarshal_Map3StrInt(b *testing.B, np datamodel.NodePrototype) {\n\tvar err error\n\tfor i := 0; i < b.N; i++ {\n\t\tnb := np.NewBuilder()\n\t\terr = json.Decode(nb, strings.NewReader(`{\"whee\":1,\"woot\":2,\"waga\":3}`))\n\t\tsink = nb.Build()\n\t}\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc BenchmarkSpec_Unmarshal_MapNStrMap3StrInt(b *testing.B, np datamodel.NodePrototype) {\n\tfor _, n := range []int{0, 1, 2, 4, 8, 16, 32} {\n\t\tb.Run(fmt.Sprintf(\"n=%d\", n), func(b *testing.B) {\n\t\t\tmsg := corpus.MapNStrMap3StrInt(n)\n\t\t\tb.ResetTimer()\n\n\t\t\tvar node datamodel.Node\n\t\t\tvar err error\n\t\t\tnb := np.NewBuilder()\n\t\t\tfor i := 0; i < b.N; i++ {\n\t\t\t\terr = json.Decode(nb, strings.NewReader(msg))\n\t\t\t\tnode = nb.Build()\n\t\t\t\tnb.Reset()\n\t\t\t}\n\n\t\t\tb.StopTimer()\n\t\t\tif err != nil {\n\t\t\t\tb.Fatalf(\"decode errored: %s\", err)\n\t\t\t}\n\t\t\tvar buf bytes.Buffer\n\t\t\tjson.Encode(node, &buf)\n\t\t\tif buf.String() != msg {\n\t\t\t\tb.Fatalf(\"re-encode result didn't match corpus\")\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "node/tests/util.go",
    "content": "package tests\n\nimport (\n\t\"strings\"\n\n\t\"github.com/ipld/go-ipld-prime/codec/json\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/traversal/selector\"\n)\n\nfunc mustNodeFromJsonString(np datamodel.NodePrototype, str string) datamodel.Node {\n\tnb := np.NewBuilder()\n\tmust.NotError(json.Decode(nb, strings.NewReader(str)))\n\treturn nb.Build()\n}\n\nfunc mustSelectorFromJsonString(np datamodel.NodePrototype, str string) selector.Selector {\n\t// Needing an 'ns' parameter here is sort of off-topic, to be honest.\n\t//  Someday the selector package will probably contain codegen'd nodes of its own schema, and we'll use those unconditionally.\n\t//  For now... we'll just use whatever node you're already testing, because it oughta work\n\t//   (and because it avoids hardcoding any other implementation that might cause import cycle funtimes.).\n\tseldefn := mustNodeFromJsonString(np, str)\n\tsel, err := selector.ParseSelector(seldefn)\n\tmust.NotError(err)\n\treturn sel\n}\n"
  },
  {
    "path": "operations.go",
    "content": "package ipld\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// DeepEqual reports whether x and y are \"deeply equal\" as IPLD nodes.\n// This is similar to reflect.DeepEqual, but based around the Node interface.\n//\n// This is exactly equivalent to the datamodel.DeepEqual function.\nfunc DeepEqual(x, y Node) bool {\n\treturn datamodel.DeepEqual(x, y)\n}\n"
  },
  {
    "path": "printer/doc.go",
    "content": "/*\nPrinter provides features for printing out IPLD nodes and their contained data in a human-readable diagnostic format.\n\nOutputs should look like...\n\n\tmap{\n\t\tstring{\"foo\"}: string{\"bar\"}\n\t\tstring{\"zot\"}: struct<Foobar>{\n\t\t\tsomeFieldName: list{\n\t\t\t\t0: string{\"this list is untyped\"}\n\t\t\t\t1: string{\"and contains a mixture of kinds of values\"}\n\t\t\t\t2: int{400}\n\t\t\t\t3: bool{true}\n\t\t\t}\n\t\t\totherField: list<ANamedListType>{\n\t\t\t\t0: string<String>{\"mind you: 'ANamedListType' is the name of the *list type*.\"}\n\t\t\t\t1: string<String>{\"it is not the name of the types of the value.\"}\n\t\t\t\t2: string<String>{\"you'd have to look at the schema for that information.\"}\n\t\t\t\t3: string<String>{\"or, of course, you can see it at the start of each of these entries, since they are also each annotated.\"}\n\t\t\t}\n\t\t\tmoreField: list<[nullable String]>{\n\t\t\t\t0: string<String>{\"this is a typed list\"}\n\t\t\t\t1: string<String>{\"but anonymous (meaning you see the value type in the 'name' of it)\"}\n\t\t\t\t2: null\n\t\t\t}\n\t\t}\n\t\tstring{\"frog\"}: map<{String:String}>{\n\t\t\tstring<String>{\"as you have probably imagined\"}: string<String>{\"this is a typed (but anonymous type) map\"}\n\t\t}\n\t\tstring{\"numbers\"}: int{1}\n\t\tstring{\"binary\"}: bytes{ABCDEF0123456789}\n\t\tstring{\"typed numbers\"}: int<MyNamedTypeInt>{9000}\n\t\tstring{\"typed string\"}: string<MyNamedTypeString>{\"okay, this one needed some marker prefixes.\"}\n\t\tstring{\"map with typed keys\"}: map<{MyNamedTypeString:MyNamedTypeString}>{\n\t\t\tstring<MyNamedStringType>{\"work just fine\"}: string<MyNamedTypeString>{\"there's no ambiguity\"}\n\t\t\tstring<MyNamedStringType>{\"you could elide key type info\"}: string<MyNamedTypeString>{\"as long as its a string kind, anyway\"}\n\t\t\tstring<MyNamedStringType>{\"but we don't by default\"}: string<MyNamedTypeString>{\"explicit is good, especially in a debug tool!\"}\n\t\t}\n\t\tstring{\"structs\"}: struct<FooBar>{\n\t\t\tfoo: string<String>{\"do not need to have quoted field names\"}\n\t\t\tbar: string<String>{\"because (unlike map keys) their character range is already restricted\"}\n\t\t}\n\t\tstring{\"unit types\"}: unit<TheTypeName>\n\t\tstring{\"notice unit types\"}: string{\"have no braces at all, because they have literally no further details.  they're all type info.\"}\n\t\tstring{\"unions\"}: union<TheUnionName>{string<TheInhabitant>{\n\t\t\t\"that was wild, wasn't it.  Check out these double closing braces, coming up, too!  also the string got forced to a new line, even though it usually would've clung closer to its type and kind marker.\"\n\t\t}}\n\t\tstring{\"enums\"}: enum<TheEnumName>{\"inhabitant name\"}\n\t\tstring{\"typed bools\"}: bool<TheBoolName>{true}\n\t\tstring{\"map with struct keys\"{: map<{FooBar:String}>{\n\t\t\tstruct<FooBar>{foo:\"foo\", bar:\"bar\"}: string<String>{\"that one probably surprised you, didn't it?\"}\n\t\t\tstruct<FooBar>{foo:\"hmmm\", bar:\"maybe\"}: string<String>{\"we might be able to get away without the kind+type marker, actually.  but we need the one-liner struct content printing, at least, for sure.\"}\n\t\t}\n\t\tstring{\"map with really wicked keys\"}: map<{WickedNestedUnion:String}>{\n\t\t\tunion<WickedNestedUnion>{union<AnotherUnion>{string<TheInhabitant>{\"wow\"}}}: \"yeah, that happens sometimes\"\n\t\t}\n\t}\n\nThe pattern is a preamble saying what kind the value is (and what type, if applicable), followed by the actual value content, in braces.\nFor untyped nodes, this means `kindname{\"value\"}` (so: `string{\"foo\"}` and `int{12}` and `bool{true}` etc),\nor for typed nodes, we get `typekindname<TheTypeName>{\"value\"}`.\nIn addition to the example above, you can check out the tests for a few more examples of how it looks.\n\nSome configuration options are available to elide some information.\nFor example, some configuration can reduce the amount of annotational weight around strings\n(which is possible to do without getting completely vague because the quotation markings for strings already are syntactically distinctive).\nNot all things can be configured for elision, however.\nFor example, for the various number kinds, the kind preambles are always required.  (Number parsers are otherwise often an annoying lookahead problem.)\nSimilarly, for bytes, the kind preamble is always required.  (Among other things, the hexadecimal up until the first letter could be confused with an integer, if we didn't label both of them.)\nAnything that's typed also gets a preamble with the type and kind information, even if its kind is something we'd otherwise elide, like string.\n\nNotice that struct fields aren't quoted.  (It's not necessary, because field names are already constrained.)\nBut map keys are.  (They need quoting because they can be any string.)\n\nNote that the output of printer is NOT INTENDED TO BE PARSABLE.\nIt is NOT an IPLD codec!\nIt is a diagnostic format only.\nMuch of the information included (especially about schema type information)\nis _more_ information than the IPLD data model holds alone,\nso trying to re-parse the printer output would be a strange choice.\n\nThe diagnostic format emitted by printer is not formally specified,\nand is not necessarily language-agnostic.\nIt may not even remain stable across releases of this library.\nIt is intended to be used for diagnostics only.\n*/\npackage printer\n\n/*\nHow to print ADLs is not yet clear.\n\nPerhaps something like `<!TheADLName>` will do;\nthis would also stack reasonably clearly with types as `<TheTypeName!TheADLName>`;\nthis style would have the downside of making ADLs look *very* different than other mere representation strategies,\nwhich may be totally reasonable or mildly questionable depending on how purist you feel about that.\n*/\n"
  },
  {
    "path": "printer/printer.go",
    "content": "package printer\n\nimport (\n\t\"encoding/hex\"\n\t\"io\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// Print emits a textual description of the node tree straight to stdout.\n// All printer configuration will be the default;\n// links will be printed, and will not be traversed.\nfunc Print(n datamodel.Node) {\n\tConfig{}.Print(n)\n}\n\n// Sprint returns a textual description of the node tree.\n// All printer configuration will be the default;\n// links will be printed, and will not be traversed.\nfunc Sprint(n datamodel.Node) string {\n\treturn Config{}.Sprint(n)\n}\n\n// Fprint accepts an io.Writer to which a textual description of the node tree will be written.\n// All printer configuration will be the default;\n// links will be printed, and will not be traversed.\nfunc Fprint(w io.Writer, n datamodel.Node) {\n\tConfig{}.Fprint(w, n)\n}\n\n// Print emits a textual description of the node tree straight to stdout.\n// The configuration structure this method is attached to can be used to specified details for how the printout will be formatted.\nfunc (cfg Config) Print(n datamodel.Node) {\n\tcfg.Fprint(os.Stdout, n)\n}\n\n// Sprint returns a textual description of the node tree.\n// The configuration structure this method is attached to can be used to specified details for how the printout will be formatted.\nfunc (cfg Config) Sprint(n datamodel.Node) string {\n\tvar buf strings.Builder\n\tcfg.Fprint(&buf, n)\n\treturn buf.String()\n}\n\n// Fprint accepts an io.Writer to which a textual description of the node tree will be written.\n// The configuration structure this method is attached to can be used to specified details for how the printout will be formatted.\nfunc (cfg Config) Fprint(w io.Writer, n datamodel.Node) {\n\tpr := printBuf{w, cfg}\n\tpr.Config.init()\n\tpr.doString(0, printState_normal, n)\n}\n\ntype Config struct {\n\t// If true, long strings and long byte sequences will truncated, and will include ellipses instead.\n\t//\n\t// Not yet supported.\n\tAbbreviate bool\n\n\t// If set, the indentation to use.\n\t// If nil, it will be treated as a default \"\\t\".\n\tIndentation []byte\n\n\t// Probably does exactly what you think it does.\n\tStartingIndent []byte\n\n\t// Set to true if you like verbosity, I guess.\n\t// If false, strings will only have kind+type markings if they're typed.\n\t//\n\t// Not yet supported.\n\tAlwaysMarkStrings bool\n\n\t// Set to true if you want type info to be skipped for any type that's in the Prelude\n\t// (e.g. instead of `string<String>{` seeing only `string{` is preferred, etc).\n\t//\n\t// Not yet supported.\n\tElidePreludeTypeInfo bool\n\n\t// Set to true if you want maps to use \"complex\"-style printouts:\n\t// meaning they will print their keys on separate lines than their values,\n\t// and keys may spread across multiple lines if appropriate.\n\t//\n\t// If not set, a heuristic will be used based on if the map is known to\n\t// have keys that are complex enough that rendering them as oneline seems likely to overload.\n\t// See Config.useCmplxKeys for exactly how that's determined.\n\tUseMapComplexStyleAlways bool\n\n\t// For maps to use \"complex\"-style printouts (or not) per type.\n\t// See docs on UseMapComplexStyleAlways for the overview of what \"complex\"-style means.\n\tUseMapComplexStyleOnType map[schema.TypeName]bool\n}\n\nfunc (cfg *Config) init() {\n\tif cfg.Indentation == nil {\n\t\tcfg.Indentation = []byte{'\\t'}\n\t}\n}\n\n// oneline decides if a value should be flatted into printing on a single,\n// or if it's allowed to spread out over multiple lines.\n// Note that this will not be asked if something outside of a value has already declared it's\n// doing a oneline rendering; that railroads everything within it into that mode too.\nfunc (cfg Config) oneline(typ schema.Type, isInKey bool) bool {\n\treturn isInKey // Future: this could become customizable, with some kind of Always|OnlyInKeys|Never option enum per type.\n}\n\n/* TODO: not implemented or used\n// useRepr decides if a value should be printed using its representation.\n// Sometimes configuring this to be true for structs or unions with stringy representations\n// will cause map printouts using them as keys to become drastically more readable\n// (if with some loss of informativeness, or at least loss of explicitness).\nfunc (cfg Config) useRepr(typ schema.Type, isInKey bool) bool {\n\treturn false\n}\n*/\n\n// useCmplxKeys decides if a map should print itself using a multi-line and extra-indented style for keys.\nfunc (cfg Config) useCmplxKeys(mapn datamodel.Node) bool {\n\tif cfg.UseMapComplexStyleAlways {\n\t\treturn true\n\t}\n\ttn, ok := mapn.(schema.TypedNode)\n\tif !ok {\n\t\treturn false\n\t}\n\ttnt := tn.Type()\n\tif tnt == nil {\n\t\treturn false\n\t}\n\tforce, ok := cfg.UseMapComplexStyleOnType[tnt.Name()]\n\tif ok {\n\t\treturn force\n\t}\n\tti, ok := tnt.(*schema.TypeMap)\n\tif !ok { // Probably should never even have been asked, then?\n\t\tpanic(\"how did you get here?\")\n\t}\n\treturn !cfg.oneline(ti.KeyType(), true)\n}\n\n// FUTURE: one could imagine putting an optional LinkSystem param into the Config, too, and some recursion control.\n// It's definitely going to be the default to do zero recursion across links, though,\n// as doing that requires creating graph visualizations, and that is both possible, yet to do well becomes rather nontrivial.\n// Also, often a single node's tree visualization has been enough to get started debugging whatever I need to debug so far.\n\ntype printBuf struct {\n\twr io.Writer\n\n\tConfig\n}\n\nfunc (z *printBuf) writeString(s string) {\n\tz.wr.Write([]byte(s))\n}\n\nfunc (z *printBuf) doIndent(indentLevel int) {\n\tz.wr.Write(z.Config.StartingIndent)\n\tfor i := 0; i < indentLevel; i++ {\n\t\tz.wr.Write(z.Config.Indentation)\n\t}\n}\n\nconst (\n\tprintState_normal       uint8 = iota\n\tprintState_isKey              // may sometimes entersen or stringify things harder.\n\tprintState_isValue            // signals that we're continuing a line that started with a key (so, don't emit indent).\n\tprintState_isCmplxKey         // used to ask something to use multiline form, and an extra indent -- the opposite of what isKey does.\n\tprintState_isCmplxValue       // we're continuing a line (so don't emit indent), and we're stuck in complex mode (so keep telling your children to stay in this state too).\n)\n\nfunc (z *printBuf) doString(indentLevel int, printState uint8, n datamodel.Node) {\n\t// First: indent.\n\tswitch printState {\n\tcase printState_normal, printState_isKey, printState_isCmplxKey:\n\t\tz.doIndent(indentLevel)\n\t}\n\t// Second: the typekind and type name; or, just the kind, if there's no type.\n\t//  Note: this can be somewhat overbearing -- for example, typed strings are going to get called out as `string<String>{\"value\"}`.\n\t//   This is rather agonizingly verbose, but also accurate; I'm not sure if we'd want to elide information about typed-vs-untyped entirely.\n\tif tn, ok := n.(schema.TypedNode); ok {\n\t\tvar tnk schema.TypeKind\n\t\tvar tntName string\n\t\t// Defensively check for nil node type\n\t\tif tnt := tn.Type(); tnt == nil {\n\t\t\ttntName = \"?!nil\"\n\t\t\ttnk = schema.TypeKind_Invalid\n\t\t} else {\n\t\t\ttntName = tnt.Name()\n\t\t\ttnk = tnt.TypeKind()\n\t\t}\n\t\tz.writeString(tnk.String())\n\t\tz.writeString(\"<\")\n\t\tz.writeString(tntName)\n\t\tz.writeString(\">\")\n\t\tswitch tnk {\n\t\tcase schema.TypeKind_Invalid:\n\t\t\tz.writeString(\"{?!}\")\n\t\tcase schema.TypeKind_Map:\n\t\t\t// continue -- the data-model driven behavior is sufficient to handle the content.\n\t\tcase schema.TypeKind_List:\n\t\t\t// continue -- the data-model driven behavior is sufficient to handle the content.\n\t\tcase schema.TypeKind_Unit:\n\t\t\treturn // that's it!  there's no content data for a unit type.\n\t\tcase schema.TypeKind_Bool:\n\t\t\t// continue -- the data-model driven behavior is sufficient to handle the content.\n\t\tcase schema.TypeKind_Int:\n\t\t\t// continue -- the data-model driven behavior is sufficient to handle the content.\n\t\tcase schema.TypeKind_Float:\n\t\t\t// continue -- the data-model driven behavior is sufficient to handle the content.\n\t\tcase schema.TypeKind_String:\n\t\t\t// continue -- the data-model driven behavior is sufficient to handle the content.\n\t\tcase schema.TypeKind_Bytes:\n\t\t\t// continue -- the data-model driven behavior is sufficient to handle the content.\n\t\tcase schema.TypeKind_Link:\n\t\t\t// continue -- the data-model driven behavior is sufficient to handle the content.\n\t\tcase schema.TypeKind_Struct:\n\t\t\t// Very similar to a map, but keys aren't quoted.\n\t\t\t// Also, because it's possible for structs to be keys in a map themselves, they potentially need oneline emission.\n\t\t\t// Or, to customize emission in another direction if being a key in a map that's printing in \"complex\" mode.\n\t\t\t// FUTURE: there should also probably be some way to configure instructions to use their representation form instead.\n\t\t\toneline :=\n\t\t\t\tprintState == printState_isCmplxValue ||\n\t\t\t\t\tprintState != printState_isCmplxKey && z.Config.oneline(tn.Type(), printState == printState_isKey)\n\t\t\tdeepen := 1\n\t\t\tif printState == printState_isCmplxKey {\n\t\t\t\tdeepen = 2\n\t\t\t}\n\t\t\tchildState := printState_isValue\n\t\t\tif oneline {\n\t\t\t\tchildState = printState_isCmplxValue\n\t\t\t}\n\t\t\tz.writeString(\"{\")\n\t\t\tif !oneline && n.Length() > 0 {\n\t\t\t\tz.writeString(\"\\n\")\n\t\t\t}\n\t\t\tfor itr := n.MapIterator(); !itr.Done(); {\n\t\t\t\tk, v, _ := itr.Next()\n\t\t\t\tif !oneline {\n\t\t\t\t\tz.doIndent(indentLevel + deepen)\n\t\t\t\t}\n\t\t\t\tfn, _ := k.AsString()\n\t\t\t\tz.writeString(fn)\n\t\t\t\tz.writeString(\": \")\n\t\t\t\tz.doString(indentLevel+deepen, childState, v)\n\t\t\t\tif oneline {\n\t\t\t\t\tif !itr.Done() {\n\t\t\t\t\t\tz.writeString(\", \")\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tz.writeString(\"\\n\")\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !oneline {\n\t\t\t\tz.doIndent(indentLevel)\n\t\t\t}\n\t\t\tz.writeString(\"}\")\n\t\t\treturn\n\t\tcase schema.TypeKind_Union:\n\t\t\t// There will only be one thing in it, but we still have to use an iterator\n\t\t\t//  to figure out what that is if we're doing this generically.\n\t\t\t//  We can ignore the key and just look at the value type again though (even though those are the same in practice).\n\t\t\t_, v, _ := n.MapIterator().Next()\n\t\t\tz.writeString(\"{\")\n\t\t\tz.doString(indentLevel, printState_isValue, v)\n\t\t\tz.writeString(\"}\")\n\t\t\treturn\n\t\tcase schema.TypeKind_Enum:\n\t\t\tpanic(\"TODO\")\n\t\tdefault:\n\t\t\tpanic(\"unreachable\")\n\t\t}\n\t} else {\n\t\tif n.IsAbsent() {\n\t\t\tz.writeString(\"absent\")\n\t\t\treturn\n\t\t}\n\t\tz.writeString(n.Kind().String())\n\t}\n\t// Third: all the actual content.\n\t// FUTURE: this is probably gonna become... somewhat more conditional, and may end up being a sub-function to be reasonably wieldy.\n\tswitch n.Kind() {\n\tcase datamodel.Kind_Map:\n\t\t// Maps have to decide if they have complex keys and want to use an additionally-intended pattern to make that readable.\n\t\t// \"Complex\" here means roughly: if you try to cram them into one line, it doesn't look good.\n\t\t// This choice starts at the map but is mostly executed during the printing of the key:\n\t\t//  the key will start itself at normal indentation,\n\t\t//  but should then doubly indent all its nested values (assuming it has any).\n\t\tcmplxKeys := z.Config.useCmplxKeys(n)\n\t\tchildKeyState := printState_isKey\n\t\tif cmplxKeys {\n\t\t\tchildKeyState = printState_isCmplxKey\n\t\t}\n\t\tz.writeString(\"{\")\n\t\tif n.Length() > 0 {\n\t\t\tz.writeString(\"\\n\")\n\t\t} else {\n\t\t\tz.writeString(\"}\")\n\t\t\treturn\n\t\t}\n\t\tfor itr := n.MapIterator(); !itr.Done(); {\n\t\t\tk, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\tz.doIndent(indentLevel + 1)\n\t\t\t\tz.writeString(\"!! map iteration step yielded error: \")\n\t\t\t\tz.writeString(err.Error())\n\t\t\t\tz.writeString(\"\\n\")\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tz.doString(indentLevel+1, childKeyState, k)\n\t\t\tz.writeString(\": \")\n\t\t\tz.doString(indentLevel+1, printState_isValue, v)\n\t\t\tz.writeString(\"\\n\")\n\t\t}\n\t\tz.doIndent(indentLevel)\n\t\tz.writeString(\"}\")\n\tcase datamodel.Kind_List:\n\t\tz.writeString(\"{\")\n\t\tif n.Length() > 0 {\n\t\t\tz.writeString(\"\\n\")\n\t\t} else {\n\t\t\tz.writeString(\"}\")\n\t\t\treturn\n\t\t}\n\t\tfor itr := n.ListIterator(); !itr.Done(); {\n\t\t\tidx, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\tz.doIndent(indentLevel + 1)\n\t\t\t\tz.writeString(\"!! list iteration step yielded error: \")\n\t\t\t\tz.writeString(err.Error())\n\t\t\t\tz.writeString(\"\\n\")\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tz.doIndent(indentLevel + 1)\n\t\t\tz.writeString(strconv.FormatInt(idx, 10))\n\t\t\tz.writeString(\": \")\n\t\t\tz.doString(indentLevel+1, printState_isValue, v)\n\t\t\tz.writeString(\"\\n\")\n\t\t}\n\t\tz.doIndent(indentLevel)\n\t\tz.writeString(\"}\")\n\tcase datamodel.Kind_Null:\n\t\t// nothing: we already wrote the word \"null\" when we wrote the kind info prefix.\n\tcase datamodel.Kind_Bool:\n\t\tz.writeString(\"{\")\n\t\tif b, _ := n.AsBool(); b {\n\t\t\tz.writeString(\"true\")\n\t\t} else {\n\t\t\tz.writeString(\"false\")\n\t\t}\n\t\tz.writeString(\"}\")\n\tcase datamodel.Kind_Int:\n\t\tx, _ := n.AsInt()\n\t\tz.writeString(\"{\")\n\t\tz.writeString(strconv.FormatInt(x, 10))\n\t\tz.writeString(\"}\")\n\tcase datamodel.Kind_Float:\n\t\tx, _ := n.AsFloat()\n\t\tz.writeString(\"{\")\n\t\tz.writeString(strconv.FormatFloat(x, 'f', -1, 64))\n\t\tz.writeString(\"}\")\n\tcase datamodel.Kind_String:\n\t\tx, _ := n.AsString()\n\t\tz.writeString(\"{\")\n\t\tz.writeString(strconv.QuoteToGraphic(x))\n\t\tz.writeString(\"}\")\n\tcase datamodel.Kind_Bytes:\n\t\tx, _ := n.AsBytes()\n\t\tz.writeString(\"{\")\n\t\tdst := make([]byte, hex.EncodedLen(len(x)))\n\t\thex.Encode(dst, x)\n\t\tz.writeString(string(dst))\n\t\tz.writeString(\"}\")\n\tcase datamodel.Kind_Link:\n\t\tx, _ := n.AsLink()\n\t\tz.writeString(\"{\")\n\t\tz.writeString(x.String())\n\t\tz.writeString(\"}\")\n\t}\n}\n"
  },
  {
    "path": "printer/printer_test.go",
    "content": "package printer\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent/qp\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/testutil\"\n)\n\nvar testLink = func() datamodel.Link {\n\tsomeCid, _ := cid.Cast([]byte{1, 85, 0, 5, 0, 1, 2, 3, 4})\n\treturn cidlink.Link{Cid: someCid}\n}()\n\nfunc TestSimpleData(t *testing.T) {\n\tt.Run(\"nested-maps\", func(t *testing.T) {\n\t\tn, _ := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {\n\t\t\tqp.MapEntry(ma, \"some key\", qp.String(\"some value\"))\n\t\t\tqp.MapEntry(ma, \"another key\", qp.String(\"another value\"))\n\t\t\tqp.MapEntry(ma, \"nested map\", qp.Map(2, func(ma datamodel.MapAssembler) {\n\t\t\t\tqp.MapEntry(ma, \"deeper entries\", qp.String(\"deeper values\"))\n\t\t\t\tqp.MapEntry(ma, \"more deeper entries\", qp.String(\"more deeper values\"))\n\t\t\t}))\n\t\t\tqp.MapEntry(ma, \"nested list\", qp.List(2, func(la datamodel.ListAssembler) {\n\t\t\t\tqp.ListEntry(la, qp.Int(1))\n\t\t\t\tqp.ListEntry(la, qp.Int(2))\n\t\t\t}))\n\t\t\tqp.MapEntry(ma, \"list with float\", qp.List(1, func(la datamodel.ListAssembler) {\n\t\t\t\tqp.ListEntry(la, qp.Float(3.4))\n\t\t\t}))\n\t\t})\n\t\tqt.Check(t, Sprint(n), qt.CmpEquals(), testutil.Dedent(`\n\t\tmap{\n\t\t\tstring{\"some key\"}: string{\"some value\"}\n\t\t\tstring{\"another key\"}: string{\"another value\"}\n\t\t\tstring{\"nested map\"}: map{\n\t\t\t\tstring{\"deeper entries\"}: string{\"deeper values\"}\n\t\t\t\tstring{\"more deeper entries\"}: string{\"more deeper values\"}\n\t\t\t}\n\t\t\tstring{\"nested list\"}: list{\n\t\t\t\t0: int{1}\n\t\t\t\t1: int{2}\n\t\t\t}\n\t\t\tstring{\"list with float\"}: list{\n\t\t\t\t0: float{3.4}\n\t\t\t}\n\t\t}`,\n\t\t))\n\t})\n\n\tt.Run(\"map-with-link-and-bytes\", func(t *testing.T) {\n\t\tn, _ := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {\n\t\t\tqp.MapEntry(ma, \"some key\", qp.Link(testLink))\n\t\t\tqp.MapEntry(ma, \"another key\", qp.String(\"another value\"))\n\t\t\tqp.MapEntry(ma, \"nested map\", qp.Map(2, func(ma datamodel.MapAssembler) {\n\t\t\t\tqp.MapEntry(ma, \"deeper entries\", qp.String(\"deeper values\"))\n\t\t\t\tqp.MapEntry(ma, \"more deeper entries\", qp.Link(testLink))\n\t\t\t\tqp.MapEntry(ma, \"yet another deeper entries\", qp.Bytes([]byte(\"fish\")))\n\t\t\t}))\n\t\t\tqp.MapEntry(ma, \"nested list\", qp.List(2, func(la datamodel.ListAssembler) {\n\t\t\t\tqp.ListEntry(la, qp.Bytes([]byte(\"ghoti\")))\n\t\t\t\tqp.ListEntry(la, qp.Int(1))\n\t\t\t\tqp.ListEntry(la, qp.Link(testLink))\n\t\t\t}))\n\t\t})\n\t\tqt.Check(t, Sprint(n), qt.CmpEquals(), testutil.Dedent(`\n\t\tmap{\n\t\t\tstring{\"some key\"}: link{bafkqabiaaebagba}\n\t\t\tstring{\"another key\"}: string{\"another value\"}\n\t\t\tstring{\"nested map\"}: map{\n\t\t\t\tstring{\"deeper entries\"}: string{\"deeper values\"}\n\t\t\t\tstring{\"more deeper entries\"}: link{bafkqabiaaebagba}\n\t\t\t\tstring{\"yet another deeper entries\"}: bytes{66697368}\n\t\t\t}\n\t\t\tstring{\"nested list\"}: list{\n\t\t\t\t0: bytes{67686f7469}\n\t\t\t\t1: int{1}\n\t\t\t\t2: link{bafkqabiaaebagba}\n\t\t\t}\n\t\t}`,\n\t\t))\n\t})\n}\n\nfunc TestTypedData(t *testing.T) {\n\tt.Run(\"structs\", func(t *testing.T) {\n\t\ttype FooBar struct {\n\t\t\tFoo  string\n\t\t\tBar  string\n\t\t\tBaz  []byte\n\t\t\tJazz datamodel.Link\n\t\t}\n\t\tts := schema.MustTypeSystem(\n\t\t\tschema.SpawnString(\"String\"),\n\t\t\tschema.SpawnBytes(\"Bytes\"),\n\t\t\tschema.SpawnLink(\"Link\"),\n\t\t\tschema.SpawnStruct(\"FooBar\", []schema.StructField{\n\t\t\t\tschema.SpawnStructField(\"foo\", \"String\", false, false),\n\t\t\t\tschema.SpawnStructField(\"bar\", \"String\", false, false),\n\t\t\t\tschema.SpawnStructField(\"baz\", \"Bytes\", false, false),\n\t\t\t\tschema.SpawnStructField(\"jazz\", \"Link\", false, false),\n\t\t\t}, nil),\n\t\t)\n\t\tn := bindnode.Wrap(&FooBar{\"x\", \"y\", []byte(\"zed\"), testLink}, ts.TypeByName(\"FooBar\"))\n\t\tqt.Check(t, Sprint(n), qt.CmpEquals(), testutil.Dedent(`\n\t\t\tstruct<FooBar>{\n\t\t\t\tfoo: string<String>{\"x\"}\n\t\t\t\tbar: string<String>{\"y\"}\n\t\t\t\tbaz: bytes<Bytes>{7a6564}\n\t\t\t\tjazz: link<Link>{bafkqabiaaebagba}\n\t\t\t}`,\n\t\t))\n\t})\n\tt.Run(\"map-with-struct-keys\", func(t *testing.T) {\n\t\ttype FooBar struct {\n\t\t\tFoo string\n\t\t\tBar string\n\t\t}\n\t\ttype WowMap struct {\n\t\t\tKeys   []FooBar\n\t\t\tValues map[FooBar]string\n\t\t}\n\t\tts := schema.MustTypeSystem(\n\t\t\tschema.SpawnString(\"String\"),\n\t\t\tschema.SpawnStruct(\"FooBar\", []schema.StructField{\n\t\t\t\tschema.SpawnStructField(\"foo\", \"String\", false, false),\n\t\t\t\tschema.SpawnStructField(\"bar\", \"String\", false, false),\n\t\t\t}, schema.SpawnStructRepresentationStringjoin(\":\")),\n\t\t\tschema.SpawnMap(\"WowMap\", \"FooBar\", \"String\", false),\n\t\t)\n\t\tn := bindnode.Wrap(&WowMap{\n\t\t\tKeys: []FooBar{{\"x\", \"y\"}, {\"z\", \"z\"}},\n\t\t\tValues: map[FooBar]string{\n\t\t\t\t{\"x\", \"y\"}: \"a\",\n\t\t\t\t{\"z\", \"z\"}: \"b\",\n\t\t\t},\n\t\t}, ts.TypeByName(\"WowMap\"))\n\t\tqt.Check(t, Sprint(n), qt.CmpEquals(), testutil.Dedent(`\n\t\t\tmap<WowMap>{\n\t\t\t\tstruct<FooBar>{foo: string<String>{\"x\"}, bar: string<String>{\"y\"}}: string<String>{\"a\"}\n\t\t\t\tstruct<FooBar>{foo: string<String>{\"z\"}, bar: string<String>{\"z\"}}: string<String>{\"b\"}\n\t\t\t}`,\n\t\t))\n\t})\n\tt.Run(\"map-with-nested-struct-keys\", func(t *testing.T) {\n\t\ttype Baz struct {\n\t\t\tBaz string\n\t\t}\n\t\ttype FooBar struct {\n\t\t\tFoo string\n\t\t\tBar Baz\n\t\t\tBaz Baz\n\t\t}\n\t\ttype WowMap struct {\n\t\t\tKeys   []FooBar\n\t\t\tValues map[FooBar]Baz\n\t\t}\n\t\tts := schema.MustTypeSystem(\n\t\t\tschema.SpawnString(\"String\"),\n\t\t\tschema.SpawnStruct(\"FooBar\", []schema.StructField{\n\t\t\t\tschema.SpawnStructField(\"foo\", \"String\", false, false),\n\t\t\t\tschema.SpawnStructField(\"bar\", \"Baz\", false, false),\n\t\t\t\tschema.SpawnStructField(\"baz\", \"Baz\", false, false),\n\t\t\t}, schema.SpawnStructRepresentationStringjoin(\":\")),\n\t\t\tschema.SpawnStruct(\"Baz\", []schema.StructField{\n\t\t\t\tschema.SpawnStructField(\"baz\", \"String\", false, false),\n\t\t\t}, schema.SpawnStructRepresentationStringjoin(\":\")),\n\t\t\tschema.SpawnMap(\"WowMap\", \"FooBar\", \"Baz\", false),\n\t\t)\n\t\tn := bindnode.Wrap(&WowMap{\n\t\t\tKeys: []FooBar{{\"x\", Baz{\"y\"}, Baz{\"y\"}}, {\"z\", Baz{\"z\"}, Baz{\"z\"}}},\n\t\t\tValues: map[FooBar]Baz{\n\t\t\t\t{\"x\", Baz{\"y\"}, Baz{\"y\"}}: {\"a\"},\n\t\t\t\t{\"z\", Baz{\"z\"}, Baz{\"z\"}}: {\"b\"},\n\t\t\t},\n\t\t}, ts.TypeByName(\"WowMap\"))\n\t\tt.Run(\"complex-keys-in-effect\", func(t *testing.T) {\n\t\t\tcfg := Config{\n\t\t\t\tUseMapComplexStyleAlways: true,\n\t\t\t}\n\t\t\tqt.Check(t, cfg.Sprint(n), qt.CmpEquals(), testutil.Dedent(`\n\t\t\t\tmap<WowMap>{\n\t\t\t\t\tstruct<FooBar>{\n\t\t\t\t\t\t\tfoo: string<String>{\"x\"}\n\t\t\t\t\t\t\tbar: struct<Baz>{\n\t\t\t\t\t\t\t\tbaz: string<String>{\"y\"}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbaz: struct<Baz>{\n\t\t\t\t\t\t\t\tbaz: string<String>{\"y\"}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}: struct<Baz>{\n\t\t\t\t\t\tbaz: string<String>{\"a\"}\n\t\t\t\t\t}\n\t\t\t\t\tstruct<FooBar>{\n\t\t\t\t\t\t\tfoo: string<String>{\"z\"}\n\t\t\t\t\t\t\tbar: struct<Baz>{\n\t\t\t\t\t\t\t\tbaz: string<String>{\"z\"}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbaz: struct<Baz>{\n\t\t\t\t\t\t\t\tbaz: string<String>{\"z\"}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}: struct<Baz>{\n\t\t\t\t\t\tbaz: string<String>{\"b\"}\n\t\t\t\t\t}\n\t\t\t\t}`,\n\t\t\t))\n\t\t})\n\t\tt.Run(\"complex-keys-in-disabled\", func(t *testing.T) {\n\t\t\tcfg := Config{\n\t\t\t\tUseMapComplexStyleOnType: map[schema.TypeName]bool{\n\t\t\t\t\t\"WowMap\": false,\n\t\t\t\t},\n\t\t\t}\n\t\t\tqt.Check(t, cfg.Sprint(n), qt.CmpEquals(), testutil.Dedent(`\n\t\t\t\tmap<WowMap>{\n\t\t\t\t\tstruct<FooBar>{foo: string<String>{\"x\"}, bar: struct<Baz>{baz: string<String>{\"y\"}}, baz: struct<Baz>{baz: string<String>{\"y\"}}}: struct<Baz>{\n\t\t\t\t\t\tbaz: string<String>{\"a\"}\n\t\t\t\t\t}\n\t\t\t\t\tstruct<FooBar>{foo: string<String>{\"z\"}, bar: struct<Baz>{baz: string<String>{\"z\"}}, baz: struct<Baz>{baz: string<String>{\"z\"}}}: struct<Baz>{\n\t\t\t\t\t\tbaz: string<String>{\"b\"}\n\t\t\t\t\t}\n\t\t\t\t}`,\n\t\t\t))\n\t\t})\n\t})\n\tt.Run(\"invalid-nil-typed-node\", func(t *testing.T) {\n\t\tqt.Check(t, Sprint(&nilTypedNode{datamodel.Kind_Invalid}), qt.CmpEquals(), \"invalid<?!nil>{?!}\")\n\t})\n\tt.Run(\"invalid-nil-typed-node-with-map-kind\", func(t *testing.T) {\n\t\tqt.Check(t, Sprint(&nilTypedNode{datamodel.Kind_Map}), qt.CmpEquals(), \"invalid<?!nil>{?!}{}\")\n\t})\n}\n\nvar _ schema.TypedNode = (*nilTypedNode)(nil)\n\ntype nilTypedNode struct {\n\tkind datamodel.Kind\n}\n\nfunc (n *nilTypedNode) Kind() datamodel.Kind {\n\treturn n.kind\n}\n\nfunc (n nilTypedNode) LookupByString(key string) (datamodel.Node, error) {\n\treturn nil, nil\n}\n\nfunc (n nilTypedNode) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn nil, nil\n}\n\nfunc (n nilTypedNode) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn nil, nil\n}\n\nfunc (n nilTypedNode) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn nil, nil\n}\n\nfunc (n nilTypedNode) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\n\nfunc (n nilTypedNode) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\n\nfunc (n nilTypedNode) Length() int64 {\n\treturn 0\n}\n\nfunc (n nilTypedNode) IsAbsent() bool {\n\treturn false\n}\n\nfunc (n nilTypedNode) IsNull() bool {\n\treturn false\n}\n\nfunc (n nilTypedNode) AsBool() (bool, error) {\n\tpanic(\"nil-typed-node\")\n}\n\nfunc (n nilTypedNode) AsInt() (int64, error) {\n\tpanic(\"nil-typed-node\")\n}\n\nfunc (n nilTypedNode) AsFloat() (float64, error) {\n\tpanic(\"nil-typed-node\")\n}\n\nfunc (n nilTypedNode) AsString() (string, error) {\n\tpanic(\"nil-typed-node\")\n}\n\nfunc (n nilTypedNode) AsBytes() ([]byte, error) {\n\tpanic(\"nil-typed-node\")\n}\n\nfunc (n nilTypedNode) AsLink() (datamodel.Link, error) {\n\tpanic(\"nil-typed-node\")\n}\n\nfunc (n nilTypedNode) Prototype() datamodel.NodePrototype {\n\treturn nil\n}\n\nfunc (n nilTypedNode) Type() schema.Type {\n\treturn nil\n}\n\nfunc (n nilTypedNode) Representation() datamodel.Node {\n\treturn nil\n}\n"
  },
  {
    "path": "schema/dmt/compile.go",
    "content": "package schemadmt\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// Compile transforms a description of a schema in raw data model (\"dmt\") form\n// into a compiled schema.TypeSystem, which is the ready-to-use form.\n//\n// The first parameter is mutated by this process,\n// and the second parameter is the data source.\n//\n// The compilation process includes first inserting the \"prelude\" types into the\n// schema.TypeSystem -- that is, the \"type Bool bool\" and \"type String string\", etc,\n// which are generally presumed to be present in any type system.\n//\n// The compilation process attempts to check the validity of the schema at a logical level as it goes.\n// For example, references to type names not present elsewhere in the same schema are now an error\n// (even though that has been easily representable in the dmt.Schema form up until this point).\n//\n// Note that this API is EXPERIMENTAL and will likely change.\n// It supports many features of IPLD Schemas,\n// but it may yet not support all of them.\n// It supports several validations for logical coherency of schemas,\n// but may not yet successfully reject all invalid schemas.\nfunc Compile(ts *schema.TypeSystem, node *Schema) error {\n\t// Add basic types\n\tschema.SpawnDefaultBasicTypes(ts)\n\n\t// Add the schema types\n\terr := SpawnSchemaTypes(ts, node)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// TODO: if this fails and the user forgot to check Compile's returned error,\n\t// we can leave the TypeSystem in an unfortunate broken state:\n\t// they can obtain types out of the TypeSystem and they are non-nil,\n\t// but trying to use them in any way may result in panics.\n\t// Consider making that less prone to misuse, such as making it illegal to\n\t// call TypeByName until ValidateGraph is happy.\n\tif errs := ts.ValidateGraph(); errs != nil {\n\t\t// Return the first error.\n\t\tfor _, err := range errs {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// SpawnSchemaTypes is a lighter verion of compile that doesn't add basic types and doesn't validate the graph --\n// for use when you want to build a type system from multiple sources and validate later\nfunc SpawnSchemaTypes(ts *schema.TypeSystem, node *Schema) error {\n\n\tfor _, name := range node.Types.Keys {\n\t\tdefn := node.Types.Values[name]\n\n\t\t// TODO: once ./schema supports anonymous/inline types, remove the ts argument.\n\t\ttyp, err := spawnType(ts, name, defn)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tts.Accumulate(typ)\n\t}\n\n\treturn nil\n}\n\n// Note that the parser and compiler support defaults. We're lacking support in bindnode.\nfunc todoFromImplicitlyFalseBool(b *bool) bool {\n\tif b == nil {\n\t\treturn false\n\t}\n\treturn *b\n}\n\nfunc anonTypeName(nameOrDefn TypeNameOrInlineDefn) string {\n\tif nameOrDefn.TypeName != nil {\n\t\treturn *nameOrDefn.TypeName\n\t}\n\tdefn := *nameOrDefn.InlineDefn\n\tswitch {\n\tcase defn.TypeDefnMap != nil:\n\t\tdefn := defn.TypeDefnMap\n\t\treturn fmt.Sprintf(\"Map__%s__%s\", defn.KeyType, anonTypeName(defn.ValueType))\n\tcase defn.TypeDefnList != nil:\n\t\tdefn := defn.TypeDefnList\n\t\treturn fmt.Sprintf(\"List__%s\", anonTypeName(defn.ValueType))\n\tcase defn.TypeDefnLink != nil:\n\t\treturn anonLinkName(*defn.TypeDefnLink)\n\tdefault:\n\t\tpanic(fmt.Errorf(\"%#v\", defn))\n\t}\n}\n\nfunc anonLinkName(defn TypeDefnLink) string {\n\tif defn.ExpectedType != nil {\n\t\treturn fmt.Sprintf(\"Link__%s\", *defn.ExpectedType)\n\t}\n\treturn \"Link__Link\"\n}\n\nfunc parseKind(s string) datamodel.Kind {\n\tswitch s {\n\tcase \"map\":\n\t\treturn datamodel.Kind_Map\n\tcase \"list\":\n\t\treturn datamodel.Kind_List\n\tcase \"null\":\n\t\treturn datamodel.Kind_Null\n\tcase \"bool\":\n\t\treturn datamodel.Kind_Bool\n\tcase \"int\":\n\t\treturn datamodel.Kind_Int\n\tcase \"float\":\n\t\treturn datamodel.Kind_Float\n\tcase \"string\":\n\t\treturn datamodel.Kind_String\n\tcase \"bytes\":\n\t\treturn datamodel.Kind_Bytes\n\tcase \"link\":\n\t\treturn datamodel.Kind_Link\n\tdefault:\n\t\treturn datamodel.Kind_Invalid\n\t}\n}\n\nfunc spawnType(ts *schema.TypeSystem, name schema.TypeName, defn TypeDefn) (schema.Type, error) {\n\tswitch {\n\t// Scalar types without parameters.\n\tcase defn.TypeDefnBool != nil:\n\t\treturn schema.SpawnBool(name), nil\n\tcase defn.TypeDefnString != nil:\n\t\treturn schema.SpawnString(name), nil\n\tcase defn.TypeDefnBytes != nil:\n\t\treturn schema.SpawnBytes(name), nil\n\tcase defn.TypeDefnInt != nil:\n\t\treturn schema.SpawnInt(name), nil\n\tcase defn.TypeDefnFloat != nil:\n\t\treturn schema.SpawnFloat(name), nil\n\n\tcase defn.TypeDefnList != nil:\n\t\ttyp := defn.TypeDefnList\n\t\ttname := \"\"\n\t\tif typ.ValueType.TypeName != nil {\n\t\t\ttname = *typ.ValueType.TypeName\n\t\t} else if tname = anonTypeName(typ.ValueType); ts.TypeByName(tname) == nil {\n\t\t\tanonDefn := TypeDefn{\n\t\t\t\tTypeDefnMap:  typ.ValueType.InlineDefn.TypeDefnMap,\n\t\t\t\tTypeDefnList: typ.ValueType.InlineDefn.TypeDefnList,\n\t\t\t\tTypeDefnLink: typ.ValueType.InlineDefn.TypeDefnLink,\n\t\t\t}\n\t\t\tanonType, err := spawnType(ts, tname, anonDefn)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tts.Accumulate(anonType)\n\t\t}\n\t\tswitch {\n\t\tcase typ.Representation == nil ||\n\t\t\ttyp.Representation.ListRepresentation_List != nil:\n\t\t\t// default behavior\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"TODO: support other list repr in schema package\")\n\t\t}\n\t\treturn schema.SpawnList(name,\n\t\t\ttname,\n\t\t\ttodoFromImplicitlyFalseBool(typ.ValueNullable),\n\t\t), nil\n\tcase defn.TypeDefnMap != nil:\n\t\ttyp := defn.TypeDefnMap\n\t\ttname := \"\"\n\t\tif typ.ValueType.TypeName != nil {\n\t\t\ttname = *typ.ValueType.TypeName\n\t\t} else if tname = anonTypeName(typ.ValueType); ts.TypeByName(tname) == nil {\n\t\t\tanonDefn := TypeDefn{\n\t\t\t\tTypeDefnMap:  typ.ValueType.InlineDefn.TypeDefnMap,\n\t\t\t\tTypeDefnList: typ.ValueType.InlineDefn.TypeDefnList,\n\t\t\t\tTypeDefnLink: typ.ValueType.InlineDefn.TypeDefnLink,\n\t\t\t}\n\t\t\tanonType, err := spawnType(ts, tname, anonDefn)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tts.Accumulate(anonType)\n\t\t}\n\t\tswitch {\n\t\tcase typ.Representation == nil ||\n\t\t\ttyp.Representation.MapRepresentation_Map != nil:\n\t\t\t// default behavior\n\t\tcase typ.Representation.MapRepresentation_Stringpairs != nil:\n\t\t\treturn nil, fmt.Errorf(\"TODO: support stringpairs map repr in schema package\")\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"TODO: support other map repr in schema package\")\n\t\t}\n\t\treturn schema.SpawnMap(name,\n\t\t\ttyp.KeyType,\n\t\t\ttname,\n\t\t\ttodoFromImplicitlyFalseBool(typ.ValueNullable),\n\t\t), nil\n\tcase defn.TypeDefnStruct != nil:\n\t\ttyp := defn.TypeDefnStruct\n\t\tvar fields []schema.StructField\n\t\tfor _, fname := range typ.Fields.Keys {\n\t\t\tfield := typ.Fields.Values[fname]\n\t\t\ttname := \"\"\n\t\t\tif field.Type.TypeName != nil {\n\t\t\t\ttname = *field.Type.TypeName\n\t\t\t} else if tname = anonTypeName(field.Type); ts.TypeByName(tname) == nil {\n\t\t\t\t// Note that TypeDefn and InlineDefn aren't the same enum.\n\t\t\t\tanonDefn := TypeDefn{\n\t\t\t\t\tTypeDefnMap:  field.Type.InlineDefn.TypeDefnMap,\n\t\t\t\t\tTypeDefnList: field.Type.InlineDefn.TypeDefnList,\n\t\t\t\t\tTypeDefnLink: field.Type.InlineDefn.TypeDefnLink,\n\t\t\t\t}\n\t\t\t\tanonType, err := spawnType(ts, tname, anonDefn)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tts.Accumulate(anonType)\n\t\t\t}\n\t\t\tfields = append(fields, schema.SpawnStructField(fname,\n\t\t\t\ttname,\n\t\t\t\ttodoFromImplicitlyFalseBool(field.Optional),\n\t\t\t\ttodoFromImplicitlyFalseBool(field.Nullable),\n\t\t\t))\n\t\t}\n\t\tvar repr schema.StructRepresentation\n\t\tswitch {\n\t\tcase typ.Representation.StructRepresentation_Map != nil:\n\t\t\trp := typ.Representation.StructRepresentation_Map\n\t\t\tif rp.Fields == nil {\n\t\t\t\trepr = schema.SpawnStructRepresentationMap2(nil, nil)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\trenames := make(map[string]string, len(rp.Fields.Keys))\n\t\t\timplicits := make(map[string]schema.ImplicitValue, len(rp.Fields.Keys))\n\t\t\tfor _, name := range rp.Fields.Keys {\n\t\t\t\tdetails := rp.Fields.Values[name]\n\t\t\t\tif details.Rename != nil {\n\t\t\t\t\trenames[name] = *details.Rename\n\t\t\t\t}\n\t\t\t\tif imp := details.Implicit; imp != nil {\n\t\t\t\t\tvar sumVal schema.ImplicitValue\n\t\t\t\t\tswitch {\n\t\t\t\t\tcase imp.Bool != nil:\n\t\t\t\t\t\tsumVal = schema.ImplicitValue_Bool(*imp.Bool)\n\t\t\t\t\tcase imp.String != nil:\n\t\t\t\t\t\tsumVal = schema.ImplicitValue_String(*imp.String)\n\t\t\t\t\tcase imp.Int != nil:\n\t\t\t\t\t\tsumVal = schema.ImplicitValue_Int(*imp.Int)\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tpanic(\"TODO: implicit value kind\")\n\t\t\t\t\t}\n\t\t\t\t\timplicits[name] = sumVal\n\t\t\t\t}\n\n\t\t\t}\n\t\t\trepr = schema.SpawnStructRepresentationMap2(renames, implicits)\n\t\tcase typ.Representation.StructRepresentation_Tuple != nil:\n\t\t\trp := typ.Representation.StructRepresentation_Tuple\n\t\t\tif rp.FieldOrder == nil {\n\t\t\t\trepr = schema.SpawnStructRepresentationTuple()\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"TODO: support for tuples with field orders in the schema package\")\n\t\tcase typ.Representation.StructRepresentation_Stringjoin != nil:\n\t\t\tjoin := typ.Representation.StructRepresentation_Stringjoin.Join\n\t\t\tif join == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"stringjoin has empty join value\")\n\t\t\t}\n\t\t\trepr = schema.SpawnStructRepresentationStringjoin(join)\n\t\tcase typ.Representation.StructRepresentation_Listpairs != nil:\n\t\t\trepr = schema.SpawnStructRepresentationListPairs()\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"TODO: support other struct repr in schema package\")\n\t\t}\n\t\treturn schema.SpawnStruct(name,\n\t\t\tfields,\n\t\t\trepr,\n\t\t), nil\n\tcase defn.TypeDefnUnion != nil:\n\t\ttyp := defn.TypeDefnUnion\n\t\tvar members []schema.TypeName\n\t\tfor _, member := range typ.Members {\n\t\t\tif member.TypeName != nil {\n\t\t\t\tmembers = append(members, *member.TypeName)\n\t\t\t} else {\n\t\t\t\ttname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink)\n\t\t\t\tmembers = append(members, tname)\n\t\t\t\tif ts.TypeByName(tname) == nil {\n\t\t\t\t\tanonDefn := TypeDefn{\n\t\t\t\t\t\tTypeDefnLink: member.UnionMemberInlineDefn.TypeDefnLink,\n\t\t\t\t\t}\n\t\t\t\t\tanonType, err := spawnType(ts, tname, anonDefn)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tts.Accumulate(anonType)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tremainingMembers := make(map[string]bool)\n\t\tfor _, memberName := range members {\n\t\t\tremainingMembers[memberName] = true\n\t\t}\n\t\tvalidMember := func(memberName string) error {\n\t\t\tswitch remaining, known := remainingMembers[memberName]; {\n\t\t\tcase remaining:\n\t\t\t\tremainingMembers[memberName] = false\n\t\t\t\treturn nil\n\t\t\tcase !known:\n\t\t\t\treturn fmt.Errorf(\"%q is not a valid member of union %q\", memberName, name)\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"%q is duplicate in the union repr of %q\", memberName, name)\n\t\t\t}\n\t\t}\n\n\t\tvar repr schema.UnionRepresentation\n\t\tswitch {\n\t\tcase typ.Representation.UnionRepresentation_Kinded != nil:\n\t\t\trp := typ.Representation.UnionRepresentation_Kinded\n\t\t\ttable := make(map[datamodel.Kind]schema.TypeName, len(rp.Keys))\n\t\t\tfor _, kindStr := range rp.Keys {\n\t\t\t\tkind := parseKind(kindStr)\n\t\t\t\tmember := rp.Values[kindStr]\n\t\t\t\tswitch {\n\t\t\t\tcase member.TypeName != nil:\n\t\t\t\t\tmemberName := *member.TypeName\n\t\t\t\t\tif err := validMember(memberName); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\ttable[kind] = memberName\n\t\t\t\tcase member.UnionMemberInlineDefn != nil:\n\t\t\t\t\ttname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink)\n\t\t\t\t\tif err := validMember(tname); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\ttable[kind] = tname\n\t\t\t\t}\n\t\t\t}\n\t\t\trepr = schema.SpawnUnionRepresentationKinded(table)\n\t\tcase typ.Representation.UnionRepresentation_Keyed != nil:\n\t\t\trp := typ.Representation.UnionRepresentation_Keyed\n\t\t\ttable := make(map[string]schema.TypeName, len(rp.Keys))\n\t\t\tfor _, key := range rp.Keys {\n\t\t\t\tmember := rp.Values[key]\n\t\t\t\tswitch {\n\t\t\t\tcase member.TypeName != nil:\n\t\t\t\t\tmemberName := *member.TypeName\n\t\t\t\t\tif err := validMember(memberName); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\ttable[key] = memberName\n\t\t\t\tcase member.UnionMemberInlineDefn != nil:\n\t\t\t\t\ttname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink)\n\t\t\t\t\tif err := validMember(tname); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\ttable[key] = tname\n\t\t\t\t}\n\t\t\t}\n\t\t\trepr = schema.SpawnUnionRepresentationKeyed(table)\n\t\tcase typ.Representation.UnionRepresentation_StringPrefix != nil:\n\t\t\tprefixes := typ.Representation.UnionRepresentation_StringPrefix.Prefixes\n\t\t\tfor _, key := range prefixes.Keys {\n\t\t\t\tif err := validMember(prefixes.Values[key]); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t\trepr = schema.SpawnUnionRepresentationStringprefix(\"\", prefixes.Values)\n\t\tcase typ.Representation.UnionRepresentation_Inline != nil:\n\t\t\trp := typ.Representation.UnionRepresentation_Inline\n\t\t\tif rp.DiscriminantKey == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"inline union has empty discriminantKey value\")\n\t\t\t}\n\t\t\tif rp.DiscriminantTable.Keys == nil || rp.DiscriminantTable.Values == nil {\n\t\t\t\treturn nil, fmt.Errorf(\"inline union has empty discriminantTable\")\n\t\t\t}\n\t\t\tfor _, key := range rp.DiscriminantTable.Keys {\n\t\t\t\tif err := validMember(rp.DiscriminantTable.Values[key]); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t\trepr = schema.SpawnUnionRepresentationInline(rp.DiscriminantKey, rp.DiscriminantTable.Values)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"TODO: support other union repr in schema package\")\n\t\t}\n\t\tfor memberName, remaining := range remainingMembers {\n\t\t\tif remaining {\n\t\t\t\treturn nil, fmt.Errorf(\"%q is not present in the union repr of %q\", memberName, name)\n\t\t\t}\n\t\t}\n\t\treturn schema.SpawnUnion(name,\n\t\t\tmembers,\n\t\t\trepr,\n\t\t), nil\n\tcase defn.TypeDefnEnum != nil:\n\t\ttyp := defn.TypeDefnEnum\n\t\tvar repr schema.EnumRepresentation\n\n\t\t// TODO: we should probably also reject duplicates.\n\t\tvalidMember := func(name string) bool {\n\t\t\tfor _, memberName := range typ.Members {\n\t\t\t\tif memberName == name {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\t\tswitch {\n\t\tcase typ.Representation.EnumRepresentation_String != nil:\n\t\t\trp := typ.Representation.EnumRepresentation_String\n\t\t\tfor memberName := range rp.Values {\n\t\t\t\tif !validMember(memberName) {\n\t\t\t\t\treturn nil, fmt.Errorf(\"%q is not a valid member of enum %q\", memberName, name)\n\t\t\t\t}\n\t\t\t}\n\t\t\trepr = schema.EnumRepresentation_String(rp.Values)\n\t\tcase typ.Representation.EnumRepresentation_Int != nil:\n\t\t\trp := typ.Representation.EnumRepresentation_Int\n\t\t\tfor memberName := range rp.Values {\n\t\t\t\tif !validMember(memberName) {\n\t\t\t\t\treturn nil, fmt.Errorf(\"%q is not a valid member of enum %q\", memberName, name)\n\t\t\t\t}\n\t\t\t}\n\t\t\trepr = schema.EnumRepresentation_Int(rp.Values)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"TODO: support other enum repr in schema package\")\n\t\t}\n\t\treturn schema.SpawnEnum(name,\n\t\t\ttyp.Members,\n\t\t\trepr,\n\t\t), nil\n\tcase defn.TypeDefnLink != nil:\n\t\ttyp := defn.TypeDefnLink\n\t\tif typ.ExpectedType == nil {\n\t\t\treturn schema.SpawnLink(name), nil\n\t\t}\n\t\treturn schema.SpawnLinkReference(name, *typ.ExpectedType), nil\n\tcase defn.TypeDefnAny != nil:\n\t\treturn schema.SpawnAny(name), nil\n\tdefault:\n\t\tpanic(fmt.Errorf(\"%#v\", defn))\n\t}\n}\n"
  },
  {
    "path": "schema/dmt/doc.go",
    "content": "/*\nPackage schema/dmt contains types and functions for dealing with the data model form of IPLD Schemas.\n\n(DMT is short for \"data model tree\" -- see https://ipld.io/glossary/#dmt .)\n\nAs with anything that's IPLD data model, this data can be serialized or deserialized into a wide variety of codecs.\n\nTo contrast this package with some of its neighbors and with some various formats for the data this package describes:\nSchemas also have a DSL (a domain-specific language -- something that's meant to look nice, and be easy for humans to read and write),\nwhich are parsed by the `schema/dsl` package, and produce a DMT form (defined by and handled by this package).\nSchemas also have a compiled form, which is the in-memory structure that this library uses when working with them;\nthis compiled form differs from the DMT because it can use pointers (and that includes cyclic pointers, which is something the DMT form cannot contain).\nWe use the DMT form (this package) to produce the compiled form (which is the `schema` package).\n\nCreating a Compiled schema either flows from DSL(text)->`schema/dsl`->`schema/dmt`->`schema`,\nor just (some codec, e.g. JSON or CBOR or etc)->`schema/dmt`->`schema`.\n\nThe `dmt.Schema` type describes the data found at the root of an IPLD Schema document.\nThe `Compile` function turns such data into a `schema.TypeSystem` that is ready to be used.\nThe `dmt.Prototype.Schema` value is a NodePrototype that can be used to handle IPLD Schemas in DMT form as regular IPLD Nodes.\n\nTypically this package is imported aliased as \"schemadmt\",\nsince \"dmt\" is a fairly generic term in the IPLD ecosystem\n(see https://ipld.io/glossary/#dmt ).\n\nMany types in this package lack documentation directly on the type;\ngenerally, these are structs that match the IPLD schema-schema,\nand so you can find descriptions of them in documentation for the schema-schema.\n*/\npackage schemadmt\n"
  },
  {
    "path": "schema/dmt/gen.go",
    "content": "//go:build ignore\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\tschemadmt \"github.com/ipld/go-ipld-prime/schema/dmt\"\n)\n\nfunc main() {\n\tf, err := os.Create(\"types.go\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Fprintf(f, \"package schemadmt\\n\\n\")\n\tif err := bindnode.ProduceGoTypes(f, schemadmt.TypeSystem); err != nil {\n\t\tpanic(err)\n\t}\n\tif err := f.Close(); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "schema/dmt/operations.go",
    "content": "package schemadmt\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n)\n\n// ConcatenateSchemas returns a new schema DMT object containing the\n// type declarations from both.\n//\n// As is usual for DMT form data, there is no check about the validity\n// of the result yet; you'll need to apply `Compile` on the produced value\n// to produce a usable compiled typesystem or to become certain that\n// all references in the DMT are satisfied, etc.\nfunc ConcatenateSchemas(a, b *Schema) *Schema {\n\t// The joy of having an intermediate form that's just regular data model:\n\t// we can implement this by simply using data model \"copy\" operations,\n\t// and the result is correct.\n\tnb := Prototypes.Schema.NewBuilder()\n\tif err := datamodel.Copy(bindnode.Wrap(a, Prototypes.Schema.Type()), nb); err != nil {\n\t\tpanic(err)\n\t}\n\tif err := datamodel.Copy(bindnode.Wrap(b, Prototypes.Schema.Type()), nb); err != nil {\n\t\tpanic(err)\n\t}\n\treturn bindnode.Unwrap(nb.Build()).(*Schema)\n}\n"
  },
  {
    "path": "schema/dmt/roundtrip_test.go",
    "content": "package schemadmt_test\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\n\tipldjson \"github.com/ipld/go-ipld-prime/codec/json\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\tschemadmt \"github.com/ipld/go-ipld-prime/schema/dmt\"\n\n\tqt \"github.com/frankban/quicktest\"\n)\n\nfunc TestRoundtripSchemaSchema(t *testing.T) {\n\tt.Parallel()\n\n\tinput := \"../../.ipld/specs/schemas/schema-schema.ipldsch.json\"\n\n\tsrc, err := os.ReadFile(input)\n\tqt.Assert(t, err, qt.IsNil)\n\ttestRoundtrip(t, string(src), func(updated string) {\n\t\terr := os.WriteFile(input, []byte(updated), 0o777)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t})\n}\n\nfunc testRoundtrip(t *testing.T, want string, updateFn func(string)) {\n\tt.Helper()\n\n\tcrre := regexp.MustCompile(`\\r?\\n`)\n\twant = crre.ReplaceAllString(want, \"\\n\")\n\tnb := schemadmt.Prototypes.Schema.Representation().NewBuilder()\n\terr := ipldjson.Decode(nb, strings.NewReader(want))\n\tqt.Assert(t, err, qt.IsNil)\n\tnode := nb.Build().(schema.TypedNode)\n\n\t// Ensure the decoded schema compiles as expected.\n\t{\n\t\tsch := bindnode.Unwrap(node).(*schemadmt.Schema)\n\n\t\tvar ts schema.TypeSystem\n\t\tts.Init()\n\t\terr := schemadmt.Compile(&ts, sch)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\ttypeStruct := ts.TypeByName(\"TypeDefnStruct\")\n\t\tif typeStruct == nil {\n\t\t\tt.Fatal(\"TypeStruct not found\")\n\t\t}\n\t}\n\n\t// Ensure we can re-encode the schema as dag-json,\n\t// and that it results in the same bytes as prettified by encoding/json.\n\t{\n\t\tvar buf bytes.Buffer\n\t\terr := ipldjson.Encode(node.Representation(), &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tgot := buf.String()\n\t\tqt.Assert(t, got, qt.Equals, want)\n\t}\n\n\t// For the sake of completeness, check that we can encode the non-repr node.\n\t// This just ensures we don't panic or error.\n\t{\n\t\tvar buf bytes.Buffer\n\t\terr := ipldjson.Encode(node, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t}\n}\n"
  },
  {
    "path": "schema/dmt/schema.go",
    "content": "package schemadmt\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// Prototypes contains some schema.TypedPrototype values which match\n// the IPLD schema-schema -- that is, the schema that describes IPLD schemas.\n// These prototypes create an in-memory representation that is backed by\n// structs in this package and bindnode.\nvar Prototypes struct {\n\tSchema schema.TypedPrototype\n}\n\n//go:generate go run -tags=schemadmtgen gen.go\n\n// TypeSystem is a compiled equivalent of the IPLD schema-schema -- that is, the schema that describes IPLD schemas.\n//\n// The IPLD schema-schema can be found at https://ipld.io/specs/schemas/schema-schema.ipldsch .\nvar TypeSystem schema.TypeSystem\n\n// In this init function, we manually create a type system that *matches* the IPLD schema-schema.\n// This manual work is unfortunate, and also must be kept in-sync manually,\n// but is important because breaks a cyclic dependency --\n// we use the compiled schema-schema produced by this to parse other schema documents.\n// We would also use it to parse... the IPLD schema-schema... if that weren't a cyclic dependency.\nfunc init() {\n\tvar ts schema.TypeSystem\n\tts.Init()\n\n\t// I've elided all references to Advancedlayouts stuff for the moment.\n\t// (Not because it's particularly hard or problematic; I just want to draw a slightly smaller circle first.)\n\n\t// Prelude\n\tts.Accumulate(schema.SpawnString(\"String\"))\n\tts.Accumulate(schema.SpawnBool(\"Bool\"))\n\tts.Accumulate(schema.SpawnInt(\"Int\"))\n\tts.Accumulate(schema.SpawnFloat(\"Float\"))\n\tts.Accumulate(schema.SpawnBytes(\"Bytes\"))\n\n\t// Schema-schema!\n\t// In the same order as the spec's ipldsch file.\n\t// Note that ADL stuff is excluded for now, as per above.\n\tts.Accumulate(schema.SpawnString(\"TypeName\"))\n\tts.Accumulate(schema.SpawnStruct(\"Schema\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"types\", \"Map__TypeName__TypeDefn\", false, false),\n\t\t\t// also: `advanced AdvancedDataLayoutMap`, but as commented above, we'll pursue this later.\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnMap(\"Map__TypeName__TypeDefn\",\n\t\t\"TypeName\", \"TypeDefn\", false,\n\t))\n\tts.Accumulate(schema.SpawnUnion(\"TypeDefn\",\n\t\t[]schema.TypeName{\n\t\t\t\"TypeDefnBool\",\n\t\t\t\"TypeDefnString\",\n\t\t\t\"TypeDefnBytes\",\n\t\t\t\"TypeDefnInt\",\n\t\t\t\"TypeDefnFloat\",\n\t\t\t\"TypeDefnMap\",\n\t\t\t\"TypeDefnList\",\n\t\t\t\"TypeDefnLink\",\n\t\t\t\"TypeDefnUnion\",\n\t\t\t\"TypeDefnStruct\",\n\t\t\t\"TypeDefnEnum\",\n\t\t\t\"TypeDefnUnit\",\n\t\t\t\"TypeDefnAny\",\n\t\t\t\"TypeDefnCopy\",\n\t\t},\n\t\t// TODO: spec uses inline repr.\n\t\tschema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{\n\t\t\t\"bool\":   \"TypeDefnBool\",\n\t\t\t\"string\": \"TypeDefnString\",\n\t\t\t\"bytes\":  \"TypeDefnBytes\",\n\t\t\t\"int\":    \"TypeDefnInt\",\n\t\t\t\"float\":  \"TypeDefnFloat\",\n\t\t\t\"map\":    \"TypeDefnMap\",\n\t\t\t\"list\":   \"TypeDefnList\",\n\t\t\t\"link\":   \"TypeDefnLink\",\n\t\t\t\"union\":  \"TypeDefnUnion\",\n\t\t\t\"struct\": \"TypeDefnStruct\",\n\t\t\t\"enum\":   \"TypeDefnEnum\",\n\t\t\t\"unit\":   \"TypeDefnUnit\",\n\t\t\t\"any\":    \"TypeDefnAny\",\n\t\t\t\"copy\":   \"TypeDefnCopy\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnUnion(\"TypeNameOrInlineDefn\",\n\t\t[]schema.TypeName{\n\t\t\t\"TypeName\",\n\t\t\t\"InlineDefn\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationKinded(map[datamodel.Kind]schema.TypeName{\n\t\t\tdatamodel.Kind_String: \"TypeName\",\n\t\t\tdatamodel.Kind_Map:    \"InlineDefn\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnUnion(\"InlineDefn\",\n\t\t[]schema.TypeName{\n\t\t\t\"TypeDefnMap\",\n\t\t\t\"TypeDefnList\",\n\t\t\t\"TypeDefnLink\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{\n\t\t\t\"map\":  \"TypeDefnMap\",\n\t\t\t\"list\": \"TypeDefnList\",\n\t\t\t\"link\": \"TypeDefnLink\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"TypeDefnBool\",\n\t\t[]schema.StructField{},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"TypeDefnString\",\n\t\t[]schema.StructField{},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"TypeDefnBytes\",\n\t\t[]schema.StructField{},\n\t\t// No BytesRepresentation, since we omit ADL stuff.\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"TypeDefnInt\",\n\t\t[]schema.StructField{},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"TypeDefnFloat\",\n\t\t[]schema.StructField{},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"TypeDefnMap\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"keyType\", \"TypeName\", false, false),\n\t\t\tschema.SpawnStructField(\"valueType\", \"TypeNameOrInlineDefn\", false, false),\n\t\t\tschema.SpawnStructField(\"valueNullable\", \"Bool\", true, false),               // TODO: wants to use the \"implicit\" feature, but not supported yet\n\t\t\tschema.SpawnStructField(\"representation\", \"MapRepresentation\", true, false), // XXXXXX\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnUnion(\"MapRepresentation\",\n\t\t[]schema.TypeName{\n\t\t\t\"MapRepresentation_Map\",\n\t\t\t\"MapRepresentation_Stringpairs\",\n\t\t\t\"MapRepresentation_Listpairs\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{\n\t\t\t\"map\":         \"MapRepresentation_Map\",\n\t\t\t\"stringpairs\": \"MapRepresentation_Stringpairs\",\n\t\t\t\"listpairs\":   \"MapRepresentation_Listpairs\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"MapRepresentation_Map\",\n\t\t[]schema.StructField{},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"MapRepresentation_Stringpairs\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"innerDelim\", \"String\", false, false),\n\t\t\tschema.SpawnStructField(\"entryDelim\", \"String\", false, false),\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"MapRepresentation_Listpairs\",\n\t\t[]schema.StructField{},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"TypeDefnList\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"valueType\", \"TypeNameOrInlineDefn\", false, false),\n\t\t\tschema.SpawnStructField(\"valueNullable\", \"Bool\", true, false),                // TODO: wants to use the \"implicit\" feature, but not supported yet\n\t\t\tschema.SpawnStructField(\"representation\", \"ListRepresentation\", true, false), // XXXXXX\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnUnion(\"ListRepresentation\",\n\t\t[]schema.TypeName{\n\t\t\t\"ListRepresentation_List\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{\n\t\t\t\"list\": \"ListRepresentation_List\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"ListRepresentation_List\",\n\t\t[]schema.StructField{},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"TypeDefnUnion\",\n\t\t[]schema.StructField{\n\t\t\t// n.b. we could conceivably allow TypeNameOrInlineDefn here rather than just TypeName.  but... we'd rather not: imagine what that means about the type-level behavior of the union: the name munge for the anonymous type would suddenly become load-bearing.  would rather not.\n\t\t\tschema.SpawnStructField(\"members\", \"List__UnionMember\", false, false),\n\t\t\tschema.SpawnStructField(\"representation\", \"UnionRepresentation\", false, false),\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnList(\"List__UnionMember\",\n\t\t\"UnionMember\", false,\n\t))\n\tts.Accumulate(schema.SpawnUnion(\"UnionMember\",\n\t\t[]schema.TypeName{\n\t\t\t\"TypeName\",\n\t\t\t\"UnionMemberInlineDefn\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationKinded(map[datamodel.Kind]schema.TypeName{\n\t\t\tdatamodel.Kind_String: \"TypeName\",\n\t\t\tdatamodel.Kind_Map:    \"UnionMemberInlineDefn\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnUnion(\"UnionMemberInlineDefn\",\n\t\t[]schema.TypeName{\n\t\t\t\"TypeDefnLink\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{\n\t\t\t\"link\": \"TypeDefnLink\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnList(\"List__TypeName\", // todo: this is a slight hack: should be an anon inside TypeDefnUnion.members.\n\t\t\"TypeName\", false,\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"TypeDefnLink\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"expectedType\", \"TypeName\", true, false), // todo: this uses an implicit with a value of 'any' in the schema-schema, but that's been questioned before.  maybe it should simply be an optional.\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnUnion(\"UnionRepresentation\",\n\t\t[]schema.TypeName{\n\t\t\t\"UnionRepresentation_Kinded\",\n\t\t\t\"UnionRepresentation_Keyed\",\n\t\t\t\"UnionRepresentation_Envelope\",\n\t\t\t\"UnionRepresentation_Inline\",\n\t\t\t\"UnionRepresentation_StringPrefix\",\n\t\t\t\"UnionRepresentation_BytesPrefix\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{\n\t\t\t\"kinded\":       \"UnionRepresentation_Kinded\",\n\t\t\t\"keyed\":        \"UnionRepresentation_Keyed\",\n\t\t\t\"envelope\":     \"UnionRepresentation_Envelope\",\n\t\t\t\"inline\":       \"UnionRepresentation_Inline\",\n\t\t\t\"stringprefix\": \"UnionRepresentation_StringPrefix\",\n\t\t\t\"byteprefix\":   \"UnionRepresentation_BytesPrefix\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnMap(\"UnionRepresentation_Kinded\",\n\t\t\"RepresentationKind\", \"UnionMember\", false,\n\t))\n\tts.Accumulate(schema.SpawnMap(\"UnionRepresentation_Keyed\",\n\t\t\"String\", \"UnionMember\", false,\n\t))\n\tts.Accumulate(schema.SpawnMap(\"Map__String__UnionMember\",\n\t\t\"TypeName\", \"TypeDefn\", false,\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"UnionRepresentation_Envelope\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"discriminantKey\", \"String\", false, false),\n\t\t\tschema.SpawnStructField(\"contentKey\", \"String\", false, false),\n\t\t\tschema.SpawnStructField(\"discriminantTable\", \"Map__String__UnionMember\", false, false),\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"UnionRepresentation_Inline\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"discriminantKey\", \"String\", false, false),\n\t\t\tschema.SpawnStructField(\"discriminantTable\", \"Map__String__TypeName\", false, false),\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"UnionRepresentation_StringPrefix\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"prefixes\", \"Map__String__TypeName\", false, false),\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"UnionRepresentation_BytesPrefix\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"prefixes\", \"Map__HexString__TypeName\", false, false),\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnMap(\"Map__HexString__TypeName\",\n\t\t\"String\", \"TypeName\", false,\n\t))\n\tts.Accumulate(schema.SpawnString(\"HexString\"))\n\tts.Accumulate(schema.SpawnMap(\"Map__String__TypeName\",\n\t\t\"String\", \"TypeName\", false,\n\t))\n\tts.Accumulate(schema.SpawnMap(\"Map__TypeName__Int\",\n\t\t\"String\", \"Int\", false,\n\t))\n\tts.Accumulate(schema.SpawnString(\"RepresentationKind\")) // todo: RepresentationKind is supposed to be an enum, but we're putting it to a string atm.\n\tts.Accumulate(schema.SpawnStruct(\"TypeDefnStruct\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"fields\", \"Map__FieldName__StructField\", false, false), // todo: dodging inline defn's again.\n\t\t\tschema.SpawnStructField(\"representation\", \"StructRepresentation\", false, false),\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnMap(\"Map__FieldName__StructField\",\n\t\t\"FieldName\", \"StructField\", false,\n\t))\n\tts.Accumulate(schema.SpawnString(\"FieldName\"))\n\tts.Accumulate(schema.SpawnStruct(\"StructField\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"type\", \"TypeNameOrInlineDefn\", false, false),\n\t\t\tschema.SpawnStructField(\"optional\", \"Bool\", true, false), // todo: wants to use the \"implicit\" feature, but not supported yet\n\t\t\tschema.SpawnStructField(\"nullable\", \"Bool\", true, false), // todo: wants to use the \"implicit\" feature, but not supported yet\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnUnion(\"StructRepresentation\",\n\t\t[]schema.TypeName{\n\t\t\t\"StructRepresentation_Map\",\n\t\t\t\"StructRepresentation_Tuple\",\n\t\t\t\"StructRepresentation_Stringpairs\",\n\t\t\t\"StructRepresentation_Stringjoin\",\n\t\t\t\"StructRepresentation_Listpairs\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{\n\t\t\t\"map\":         \"StructRepresentation_Map\",\n\t\t\t\"tuple\":       \"StructRepresentation_Tuple\",\n\t\t\t\"stringpairs\": \"StructRepresentation_Stringpairs\",\n\t\t\t\"stringjoin\":  \"StructRepresentation_Stringjoin\",\n\t\t\t\"listpairs\":   \"StructRepresentation_Listpairs\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"StructRepresentation_Map\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"fields\", \"Map__FieldName__StructRepresentation_Map_FieldDetails\", true, false), // todo: dodging inline defn's again.\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnMap(\"Map__FieldName__StructRepresentation_Map_FieldDetails\",\n\t\t\"FieldName\", \"StructRepresentation_Map_FieldDetails\", false,\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"StructRepresentation_Map_FieldDetails\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"rename\", \"String\", true, false),\n\t\t\tschema.SpawnStructField(\"implicit\", \"AnyScalar\", true, false),\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"StructRepresentation_Tuple\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"fieldOrder\", \"List__FieldName\", true, false), // todo: dodging inline defn's again.\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnList(\"List__FieldName\",\n\t\t\"FieldName\", false,\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"StructRepresentation_Stringpairs\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"innerDelim\", \"String\", false, false),\n\t\t\tschema.SpawnStructField(\"entryDelim\", \"String\", false, false),\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"StructRepresentation_Stringjoin\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"join\", \"String\", false, false),               // review: \"delim\" would seem more consistent with others -- but this is currently what the schema-schema says.\n\t\t\tschema.SpawnStructField(\"fieldOrder\", \"List__FieldName\", true, false), // todo: dodging inline defn's again.\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"StructRepresentation_Listpairs\",\n\t\t[]schema.StructField{},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"TypeDefnEnum\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"members\", \"List__EnumMember\", false, false),\n\t\t\tschema.SpawnStructField(\"representation\", \"EnumRepresentation\", false, false),\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"Unit\", // todo: we should formalize the introdution of unit as first class type kind.\n\t\t[]schema.StructField{},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnList(\"List__EnumMember\",\n\t\t\"EnumMember\", false,\n\t))\n\tts.Accumulate(schema.SpawnString(\"EnumMember\"))\n\tts.Accumulate(schema.SpawnUnion(\"EnumRepresentation\",\n\t\t[]schema.TypeName{\n\t\t\t\"EnumRepresentation_String\",\n\t\t\t\"EnumRepresentation_Int\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{\n\t\t\t\"string\": \"EnumRepresentation_String\",\n\t\t\t\"int\":    \"EnumRepresentation_Int\",\n\t\t}),\n\t))\n\tts.Accumulate(schema.SpawnMap(\"EnumRepresentation_String\",\n\t\t\"EnumMember\", \"String\", false,\n\t))\n\tts.Accumulate(schema.SpawnMap(\"EnumRepresentation_Int\",\n\t\t\"EnumMember\", \"Int\", false,\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"TypeDefnUnit\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"representation\", \"UnitRepresentation\", false, false),\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnString(\"UnitRepresentation\")) // TODO: enum\n\tts.Accumulate(schema.SpawnStruct(\"TypeDefnAny\",\n\t\t[]schema.StructField{},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnStruct(\"TypeDefnCopy\",\n\t\t[]schema.StructField{\n\t\t\tschema.SpawnStructField(\"fromType\", \"TypeName\", false, false),\n\t\t},\n\t\tschema.StructRepresentation_Map{},\n\t))\n\tts.Accumulate(schema.SpawnUnion(\"AnyScalar\",\n\t\t[]schema.TypeName{\n\t\t\t\"Bool\",\n\t\t\t\"String\",\n\t\t\t\"Bytes\",\n\t\t\t\"Int\",\n\t\t\t\"Float\",\n\t\t},\n\t\tschema.SpawnUnionRepresentationKinded(map[datamodel.Kind]schema.TypeName{\n\t\t\tdatamodel.Kind_Bool:   \"Bool\",\n\t\t\tdatamodel.Kind_String: \"String\",\n\t\t\tdatamodel.Kind_Bytes:  \"Bytes\",\n\t\t\tdatamodel.Kind_Int:    \"Int\",\n\t\t\tdatamodel.Kind_Float:  \"Float\",\n\t\t}),\n\t))\n\n\tif errs := ts.ValidateGraph(); errs != nil {\n\t\tfor _, err := range errs {\n\t\t\tfmt.Printf(\"- %s\\n\", err)\n\t\t}\n\t\tpanic(\"not happening\")\n\t}\n\n\tTypeSystem = ts\n\n\tPrototypes.Schema = bindnode.Prototype(\n\t\t(*Schema)(nil),\n\t\tTypeSystem.TypeByName(\"Schema\"),\n\t)\n}\n"
  },
  {
    "path": "schema/dmt/types.go",
    "content": "package schemadmt\n\ntype Schema struct {\n\tTypes Map__TypeName__TypeDefn\n}\ntype Map__TypeName__TypeDefn struct {\n\tKeys   []string\n\tValues map[string]TypeDefn\n}\ntype TypeDefn struct {\n\tTypeDefnBool   *TypeDefnBool\n\tTypeDefnString *TypeDefnString\n\tTypeDefnBytes  *TypeDefnBytes\n\tTypeDefnInt    *TypeDefnInt\n\tTypeDefnFloat  *TypeDefnFloat\n\tTypeDefnMap    *TypeDefnMap\n\tTypeDefnList   *TypeDefnList\n\tTypeDefnLink   *TypeDefnLink\n\tTypeDefnUnion  *TypeDefnUnion\n\tTypeDefnStruct *TypeDefnStruct\n\tTypeDefnEnum   *TypeDefnEnum\n\tTypeDefnUnit   *TypeDefnUnit\n\tTypeDefnAny    *TypeDefnAny\n\tTypeDefnCopy   *TypeDefnCopy\n}\ntype TypeNameOrInlineDefn struct {\n\tTypeName   *string\n\tInlineDefn *InlineDefn\n}\ntype InlineDefn struct {\n\tTypeDefnMap  *TypeDefnMap\n\tTypeDefnList *TypeDefnList\n\tTypeDefnLink *TypeDefnLink\n}\ntype TypeDefnBool struct {\n}\ntype TypeDefnString struct {\n}\ntype TypeDefnBytes struct {\n}\ntype TypeDefnInt struct {\n}\ntype TypeDefnFloat struct {\n}\ntype TypeDefnMap struct {\n\tKeyType        string\n\tValueType      TypeNameOrInlineDefn\n\tValueNullable  *bool\n\tRepresentation *MapRepresentation\n}\ntype MapRepresentation struct {\n\tMapRepresentation_Map         *MapRepresentation_Map\n\tMapRepresentation_Stringpairs *MapRepresentation_Stringpairs\n\tMapRepresentation_Listpairs   *MapRepresentation_Listpairs\n}\ntype MapRepresentation_Map struct {\n}\ntype MapRepresentation_Stringpairs struct {\n\tInnerDelim string\n\tEntryDelim string\n}\ntype MapRepresentation_Listpairs struct {\n}\ntype TypeDefnList struct {\n\tValueType      TypeNameOrInlineDefn\n\tValueNullable  *bool\n\tRepresentation *ListRepresentation\n}\ntype ListRepresentation struct {\n\tListRepresentation_List *ListRepresentation_List\n}\ntype ListRepresentation_List struct {\n}\ntype TypeDefnUnion struct {\n\tMembers        List__UnionMember\n\tRepresentation UnionRepresentation\n}\ntype List__UnionMember []UnionMember\ntype UnionMember struct {\n\tTypeName              *string\n\tUnionMemberInlineDefn *UnionMemberInlineDefn\n}\ntype UnionMemberInlineDefn struct {\n\tTypeDefnLink *TypeDefnLink\n}\ntype List__TypeName []string\ntype TypeDefnLink struct {\n\tExpectedType *string\n}\ntype UnionRepresentation struct {\n\tUnionRepresentation_Kinded       *UnionRepresentation_Kinded\n\tUnionRepresentation_Keyed        *UnionRepresentation_Keyed\n\tUnionRepresentation_Envelope     *UnionRepresentation_Envelope\n\tUnionRepresentation_Inline       *UnionRepresentation_Inline\n\tUnionRepresentation_StringPrefix *UnionRepresentation_StringPrefix\n\tUnionRepresentation_BytesPrefix  *UnionRepresentation_BytesPrefix\n}\ntype UnionRepresentation_Kinded struct {\n\tKeys   []string\n\tValues map[string]UnionMember\n}\ntype UnionRepresentation_Keyed struct {\n\tKeys   []string\n\tValues map[string]UnionMember\n}\ntype Map__String__UnionMember struct {\n\tKeys   []string\n\tValues map[string]TypeDefn\n}\ntype UnionRepresentation_Envelope struct {\n\tDiscriminantKey   string\n\tContentKey        string\n\tDiscriminantTable Map__String__UnionMember\n}\ntype UnionRepresentation_Inline struct {\n\tDiscriminantKey   string\n\tDiscriminantTable Map__String__TypeName\n}\ntype UnionRepresentation_StringPrefix struct {\n\tPrefixes Map__String__TypeName\n}\ntype UnionRepresentation_BytesPrefix struct {\n\tPrefixes Map__HexString__TypeName\n}\ntype Map__HexString__TypeName struct {\n\tKeys   []string\n\tValues map[string]string\n}\ntype Map__String__TypeName struct {\n\tKeys   []string\n\tValues map[string]string\n}\ntype Map__TypeName__Int struct {\n\tKeys   []string\n\tValues map[string]int\n}\ntype TypeDefnStruct struct {\n\tFields         Map__FieldName__StructField\n\tRepresentation StructRepresentation\n}\ntype Map__FieldName__StructField struct {\n\tKeys   []string\n\tValues map[string]StructField\n}\ntype StructField struct {\n\tType     TypeNameOrInlineDefn\n\tOptional *bool\n\tNullable *bool\n}\ntype StructRepresentation struct {\n\tStructRepresentation_Map         *StructRepresentation_Map\n\tStructRepresentation_Tuple       *StructRepresentation_Tuple\n\tStructRepresentation_Stringpairs *StructRepresentation_Stringpairs\n\tStructRepresentation_Stringjoin  *StructRepresentation_Stringjoin\n\tStructRepresentation_Listpairs   *StructRepresentation_Listpairs\n}\ntype StructRepresentation_Map struct {\n\tFields *Map__FieldName__StructRepresentation_Map_FieldDetails\n}\ntype Map__FieldName__StructRepresentation_Map_FieldDetails struct {\n\tKeys   []string\n\tValues map[string]StructRepresentation_Map_FieldDetails\n}\ntype StructRepresentation_Map_FieldDetails struct {\n\tRename   *string\n\tImplicit *AnyScalar\n}\ntype StructRepresentation_Tuple struct {\n\tFieldOrder *List__FieldName\n}\ntype List__FieldName []string\ntype StructRepresentation_Stringpairs struct {\n\tInnerDelim string\n\tEntryDelim string\n}\ntype StructRepresentation_Stringjoin struct {\n\tJoin       string\n\tFieldOrder *List__FieldName\n}\ntype StructRepresentation_Listpairs struct {\n}\ntype TypeDefnEnum struct {\n\tMembers        List__EnumMember\n\tRepresentation EnumRepresentation\n}\ntype Unit struct {\n}\ntype List__EnumMember []string\ntype EnumRepresentation struct {\n\tEnumRepresentation_String *EnumRepresentation_String\n\tEnumRepresentation_Int    *EnumRepresentation_Int\n}\ntype EnumRepresentation_String struct {\n\tKeys   []string\n\tValues map[string]string\n}\ntype EnumRepresentation_Int struct {\n\tKeys   []string\n\tValues map[string]int\n}\ntype TypeDefnUnit struct {\n\tRepresentation string\n}\ntype TypeDefnAny struct {\n}\ntype TypeDefnCopy struct {\n\tFromType string\n}\ntype AnyScalar struct {\n\tBool   *bool\n\tString *string\n\tBytes  *[]uint8\n\tInt    *int\n\tFloat  *float64\n}\n"
  },
  {
    "path": "schema/dsl/parse.go",
    "content": "package schemadsl\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\n\tdmt \"github.com/ipld/go-ipld-prime/schema/dmt\"\n)\n\nvar globalTrue = true\n\n// TODO: fuzz testing\n\nfunc ParseBytes(src []byte) (*dmt.Schema, error) {\n\treturn Parse(\"\", bytes.NewReader(src))\n}\n\nfunc ParseFile(path string) (*dmt.Schema, error) {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer f.Close()\n\treturn Parse(path, f)\n}\n\nfunc Parse(name string, r io.Reader) (*dmt.Schema, error) {\n\tp := &parser{\n\t\tpath: name,\n\t\tbr:   bufio.NewReader(r),\n\t\tline: 1,\n\t\tcol:  1,\n\t}\n\n\tsch := &dmt.Schema{}\n\tsch.Types.Values = make(map[string]dmt.TypeDefn)\n\n\tfor {\n\t\ttok, err := p.consumeToken()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\n\t\tswitch tok {\n\t\tcase \"type\":\n\t\t\tname, err := p.consumeName()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tdefn, err := p.typeDefn()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tmapAppend(&sch.Types, name, defn)\n\t\tcase \"advanced\":\n\t\t\treturn nil, p.errf(\"TODO: advanced\")\n\t\tdefault:\n\t\t\treturn nil, p.errf(\"unexpected token: %q\", tok)\n\t\t}\n\t}\n\treturn sch, nil\n}\n\nfunc mapAppend(mapPtr, k, v interface{}) {\n\t// TODO: delete with generics\n\t// TODO: error on dupes\n\n\tmval := reflect.ValueOf(mapPtr).Elem()\n\tkval := reflect.ValueOf(k)\n\tvval := reflect.ValueOf(v)\n\n\tkeys := mval.FieldByName(\"Keys\")\n\tkeys.Set(reflect.Append(keys, kval))\n\n\tvalues := mval.FieldByName(\"Values\")\n\tif values.IsNil() {\n\t\tvalues.Set(reflect.MakeMap(values.Type()))\n\t}\n\tvalues.SetMapIndex(kval, vval)\n}\n\ntype parser struct {\n\tpath string\n\tbr   *bufio.Reader\n\n\tpeekedToken string\n\n\tline, col int\n}\n\nfunc (p *parser) forwardError(err error) error {\n\tvar prefix string\n\tif p.path != \"\" {\n\t\tprefix = p.path + \":\"\n\t}\n\treturn fmt.Errorf(\"%s%d:%d: %s\", prefix, p.line, p.col, err)\n}\n\nfunc (p *parser) errf(format string, args ...interface{}) error {\n\treturn p.forwardError(fmt.Errorf(format, args...))\n}\n\nfunc (p *parser) consumeToken() (string, error) {\n\tif tok := p.peekedToken; tok != \"\" {\n\t\tp.peekedToken = \"\"\n\t\treturn tok, nil\n\t}\n\tfor {\n\t\t// TODO: use runes for better unicode support\n\t\tb, err := p.br.ReadByte()\n\t\tif err == io.EOF {\n\t\t\treturn \"\", err // TODO: ErrUnexpectedEOF?\n\t\t}\n\t\tif err != nil {\n\t\t\treturn \"\", p.forwardError(err)\n\t\t}\n\t\tp.col++\n\t\tswitch b {\n\t\tcase ' ', '\\t', '\\r': // skip whitespace\n\t\t\tcontinue\n\t\tcase '\\n': // skip newline\n\t\t\t// TODO: should we require a newline after each type def, struct field, etc?\n\t\t\tp.line++\n\t\t\tp.col = 1\n\t\t\tcontinue\n\t\tcase '\"': // quoted string\n\t\t\tquoted, err := p.br.ReadString('\"')\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", p.forwardError(err)\n\t\t\t}\n\t\t\treturn \"\\\"\" + quoted, nil\n\t\tcase '{', '}', '[', ']', '(', ')', ':', '&': // simple token\n\t\t\treturn string(b), nil\n\t\tcase '#': // comment\n\t\t\t_, err := p.br.ReadString('\\n')\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", p.forwardError(err)\n\t\t\t}\n\t\t\t// tokenize the newline\n\t\t\tif err := p.br.UnreadByte(); err != nil {\n\t\t\t\tpanic(err) // should never happen\n\t\t\t}\n\t\t\tcontinue\n\t\tdefault: // string token or name\n\t\t\tvar sb strings.Builder\n\t\t\tsb.WriteByte(b)\n\t\t\tfor {\n\t\t\t\tb, err := p.br.ReadByte()\n\t\t\t\tif err == io.EOF {\n\t\t\t\t\t// Token ends at the end of the whole input.\n\t\t\t\t\treturn sb.String(), nil\n\t\t\t\t}\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", p.forwardError(err)\n\t\t\t\t}\n\t\t\t\t// TODO: should probably allow unicode letters and numbers, like Go?\n\t\t\t\tswitch {\n\t\t\t\tcase b >= 'a' && b <= 'z', b >= 'A' && b <= 'Z':\n\t\t\t\tcase b >= '0' && b <= '9':\n\t\t\t\tcase b == '_':\n\t\t\t\tdefault:\n\t\t\t\t\tif err := p.br.UnreadByte(); err != nil {\n\t\t\t\t\t\tpanic(err) // should never happen\n\t\t\t\t\t}\n\t\t\t\t\treturn sb.String(), nil\n\t\t\t\t}\n\t\t\t\tsb.WriteByte(b)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (p *parser) consumePeeked() {\n\tif p.peekedToken == \"\" {\n\t\tpanic(\"consumePeeked requires a peeked token to be present\")\n\t}\n\tp.peekedToken = \"\"\n}\n\nfunc (p *parser) peekToken() (string, error) {\n\tif tok := p.peekedToken; tok != \"\" {\n\t\treturn tok, nil\n\t}\n\ttok, err := p.consumeToken()\n\tif err != nil {\n\t\tif err == io.EOF {\n\t\t\t// peekToken is often used when a token is optional.\n\t\t\t// If we hit io.EOF, that's not an error.\n\t\t\t// TODO: consider making peekToken just not return an error?\n\t\t\treturn \"\", nil\n\t\t}\n\t\treturn \"\", err\n\t}\n\tp.peekedToken = tok\n\treturn tok, nil\n}\n\nfunc (p *parser) consumeName() (string, error) {\n\ttok, err := p.consumeToken()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tswitch tok {\n\tcase \"\\\"\", \"{\", \"}\", \"[\", \"]\", \"(\", \")\", \":\":\n\t\treturn \"\", p.errf(\"expected a name, got %q\", tok)\n\t}\n\tif tok[0] == '\"' {\n\t\treturn \"\", p.errf(\"expected a name, got string %s\", tok)\n\t}\n\treturn tok, nil\n}\n\nfunc (p *parser) consumeString() (string, error) {\n\ttok, err := p.consumeToken()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif tok[0] != '\"' {\n\t\treturn \"\", p.errf(\"expected a string, got %q\", tok)\n\t}\n\t// Unquote, too.\n\treturn tok[1 : len(tok)-1], nil\n}\n\nfunc (p *parser) consumeStringMap() (map[string]string, error) {\n\tresult := map[string]string{}\nloop:\n\tfor {\n\t\ttok, err := p.peekToken()\n\t\tif err != nil {\n\t\t\treturn result, err\n\t\t}\n\t\tswitch tok {\n\t\tcase \"{\":\n\t\t\tp.consumePeeked()\n\t\tcase \"}\":\n\t\t\tp.consumePeeked()\n\t\t\tbreak loop\n\t\tdefault:\n\t\t\tkey, err := p.consumeName()\n\t\t\tif err != nil {\n\t\t\t\treturn result, err\n\t\t\t}\n\t\t\tvalue, err := p.consumeString()\n\t\t\tif err != nil {\n\t\t\t\treturn result, err\n\t\t\t}\n\t\t\tresult[key] = value\n\t\t}\n\t}\n\treturn result, nil\n}\n\nfunc (p *parser) consumeRequired(tok string) error {\n\tgot, err := p.consumeToken()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif got != tok {\n\t\treturn p.errf(\"expected %q, got %q\", tok, got)\n\t}\n\treturn nil\n}\n\nfunc (p *parser) typeDefn() (dmt.TypeDefn, error) {\n\tvar defn dmt.TypeDefn\n\tkind, err := p.consumeToken()\n\tif err != nil {\n\t\treturn defn, err\n\t}\n\n\tswitch kind {\n\tcase \"struct\":\n\t\tif err := p.consumeRequired(\"{\"); err != nil {\n\t\t\treturn defn, err\n\t\t}\n\t\tdefn.TypeDefnStruct, err = p.typeStruct()\n\tcase \"union\":\n\t\tif err := p.consumeRequired(\"{\"); err != nil {\n\t\t\treturn defn, err\n\t\t}\n\t\tdefn.TypeDefnUnion, err = p.typeUnion()\n\tcase \"enum\":\n\t\tif err := p.consumeRequired(\"{\"); err != nil {\n\t\t\treturn defn, err\n\t\t}\n\t\tdefn.TypeDefnEnum, err = p.typeEnum()\n\tcase \"bool\":\n\t\tdefn.TypeDefnBool = &dmt.TypeDefnBool{}\n\tcase \"bytes\":\n\t\tdefn.TypeDefnBytes = &dmt.TypeDefnBytes{}\n\tcase \"float\":\n\t\tdefn.TypeDefnFloat = &dmt.TypeDefnFloat{}\n\tcase \"int\":\n\t\tdefn.TypeDefnInt = &dmt.TypeDefnInt{}\n\tcase \"link\":\n\t\tdefn.TypeDefnLink = &dmt.TypeDefnLink{}\n\tcase \"any\":\n\t\tdefn.TypeDefnAny = &dmt.TypeDefnAny{}\n\tcase \"&\":\n\t\ttarget, err := p.consumeName()\n\t\tif err != nil {\n\t\t\treturn defn, err\n\t\t}\n\t\tdefn.TypeDefnLink = &dmt.TypeDefnLink{ExpectedType: &target}\n\tcase \"string\":\n\t\tdefn.TypeDefnString = &dmt.TypeDefnString{}\n\tcase \"{\":\n\t\tdefn.TypeDefnMap, err = p.typeMap()\n\tcase \"[\":\n\t\tdefn.TypeDefnList, err = p.typeList()\n\tcase \"=\":\n\t\tfrom, err := p.consumeName()\n\t\tif err != nil {\n\t\t\treturn defn, err\n\t\t}\n\t\tdefn.TypeDefnCopy = &dmt.TypeDefnCopy{FromType: from}\n\tdefault:\n\t\terr = p.errf(\"unknown type keyword: %q\", kind)\n\t}\n\n\treturn defn, err\n}\n\nfunc (p *parser) typeStruct() (*dmt.TypeDefnStruct, error) {\n\trepr := &dmt.StructRepresentation_Map{}\n\trepr.Fields = &dmt.Map__FieldName__StructRepresentation_Map_FieldDetails{}\n\n\tdefn := &dmt.TypeDefnStruct{}\n\tfor {\n\t\ttok, err := p.consumeToken()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif tok == \"}\" {\n\t\t\tbreak\n\t\t}\n\t\tname := tok\n\n\t\tvar field dmt.StructField\n\tloop:\n\t\tfor {\n\t\t\ttok, err := p.peekToken()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tswitch tok {\n\t\t\tcase \"optional\":\n\t\t\t\tif field.Optional != nil {\n\t\t\t\t\treturn nil, p.errf(\"multiple optional keywords\")\n\t\t\t\t}\n\t\t\t\tfield.Optional = &globalTrue\n\t\t\t\tp.consumePeeked()\n\t\t\tcase \"nullable\":\n\t\t\t\tif field.Nullable != nil {\n\t\t\t\t\treturn nil, p.errf(\"multiple nullable keywords\")\n\t\t\t\t}\n\t\t\t\tfield.Nullable = &globalTrue\n\t\t\t\tp.consumePeeked()\n\t\t\tdefault:\n\t\t\t\tvar err error\n\t\t\t\tfield.Type, err = p.typeNameOrInlineDefn()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tbreak loop\n\t\t\t}\n\t\t}\n\t\ttok, err = p.peekToken()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif tok == \"(\" {\n\t\t\tdetails := dmt.StructRepresentation_Map_FieldDetails{}\n\t\t\tp.consumePeeked()\n\t\tparenLoop:\n\t\t\tfor {\n\t\t\t\ttok, err = p.consumeToken()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tswitch tok {\n\t\t\t\tcase \")\":\n\t\t\t\t\tbreak parenLoop\n\t\t\t\tcase \"rename\":\n\t\t\t\t\tstr, err := p.consumeString()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tdetails.Rename = &str\n\t\t\t\tcase \"implicit\":\n\t\t\t\t\tscalar, err := p.consumeToken()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tvar anyScalar dmt.AnyScalar\n\t\t\t\t\tswitch {\n\t\t\t\t\tcase scalar[0] == '\"': // string\n\t\t\t\t\t\ts, err := strconv.Unquote(scalar)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn nil, p.forwardError(err)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tanyScalar.String = &s\n\t\t\t\t\tcase scalar == \"true\", scalar == \"false\": // bool\n\t\t\t\t\t\tt := scalar == \"true\"\n\t\t\t\t\t\tanyScalar.Bool = &t\n\t\t\t\t\tcase scalar[0] >= '0' && scalar[0] <= '0':\n\t\t\t\t\t\tn, err := strconv.Atoi(scalar)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn nil, p.forwardError(err)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tanyScalar.Int = &n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn nil, p.errf(\"unsupported implicit scalar: %s\", scalar)\n\t\t\t\t\t}\n\n\t\t\t\t\tdetails.Implicit = &anyScalar\n\t\t\t\t}\n\t\t\t}\n\t\t\tmapAppend(repr.Fields, name, details)\n\t\t}\n\n\t\tmapAppend(&defn.Fields, name, field)\n\t}\n\n\treprName := \"map\" // default repr\n\tif tok, err := p.peekToken(); err == nil && tok == \"representation\" {\n\t\tp.consumePeeked()\n\t\tname, err := p.consumeName()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treprName = name\n\t}\n\tif reprName != \"map\" && len(repr.Fields.Keys) > 0 {\n\t\treturn nil, p.errf(\"rename and implicit are only supported for struct map representations\")\n\t}\n\tswitch reprName {\n\tcase \"map\":\n\t\tif len(repr.Fields.Keys) == 0 {\n\t\t\t// Fields is optional; omit it if empty.\n\t\t\trepr.Fields = nil\n\t\t}\n\t\tdefn.Representation.StructRepresentation_Map = repr\n\t\treturn defn, nil\n\tcase \"tuple\":\n\t\tdefn.Representation.StructRepresentation_Tuple = &dmt.StructRepresentation_Tuple{}\n\t\treturn defn, nil\n\t\t// TODO: support custom fieldorder\n\tcase \"stringjoin\":\n\t\toptMap, err := p.consumeStringMap()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tjoin, hasJoin := optMap[\"join\"]\n\t\tif !hasJoin {\n\t\t\treturn nil, p.errf(\"no join value provided for stringjoin repr\")\n\t\t}\n\t\tdefn.Representation.StructRepresentation_Stringjoin = &dmt.StructRepresentation_Stringjoin{\n\t\t\tJoin: join,\n\t\t}\n\t\treturn defn, nil\n\tcase \"listpairs\":\n\t\tdefn.Representation.StructRepresentation_Listpairs = &dmt.StructRepresentation_Listpairs{}\n\t\treturn defn, nil\n\tdefault:\n\t\treturn nil, p.errf(\"unknown struct repr: %q\", reprName)\n\t}\n}\n\nfunc (p *parser) typeNameOrInlineDefn() (dmt.TypeNameOrInlineDefn, error) {\n\tvar typ dmt.TypeNameOrInlineDefn\n\ttok, err := p.consumeToken()\n\tif err != nil {\n\t\treturn typ, err\n\t}\n\n\tswitch tok {\n\tcase \"&\":\n\t\texpectedName, err := p.consumeName()\n\t\tif err != nil {\n\t\t\treturn typ, err\n\t\t}\n\t\ttyp.InlineDefn = &dmt.InlineDefn{TypeDefnLink: &dmt.TypeDefnLink{ExpectedType: &expectedName}}\n\tcase \"[\":\n\t\ttlist, err := p.typeList()\n\t\tif err != nil {\n\t\t\treturn typ, err\n\t\t}\n\t\ttyp.InlineDefn = &dmt.InlineDefn{TypeDefnList: tlist}\n\tcase \"{\":\n\t\ttmap, err := p.typeMap()\n\t\tif err != nil {\n\t\t\treturn typ, err\n\t\t}\n\t\ttyp.InlineDefn = &dmt.InlineDefn{TypeDefnMap: tmap}\n\tdefault:\n\t\ttyp.TypeName = &tok\n\t}\n\treturn typ, nil\n}\n\nfunc (p *parser) typeList() (*dmt.TypeDefnList, error) {\n\tdefn := &dmt.TypeDefnList{}\n\ttok, err := p.peekToken()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif tok == \"nullable\" {\n\t\tdefn.ValueNullable = &globalTrue\n\t\tp.consumePeeked()\n\t}\n\n\tdefn.ValueType, err = p.typeNameOrInlineDefn()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := p.consumeRequired(\"]\"); err != nil {\n\t\treturn defn, err\n\t}\n\n\t// TODO: repr\n\treturn defn, nil\n}\n\nfunc (p *parser) typeMap() (*dmt.TypeDefnMap, error) {\n\tdefn := &dmt.TypeDefnMap{}\n\n\tvar err error\n\tdefn.KeyType, err = p.consumeName()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := p.consumeRequired(\":\"); err != nil {\n\t\treturn defn, err\n\t}\n\n\ttok, err := p.peekToken()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif tok == \"nullable\" {\n\t\tdefn.ValueNullable = &globalTrue\n\t\tp.consumePeeked()\n\t}\n\n\tdefn.ValueType, err = p.typeNameOrInlineDefn()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := p.consumeRequired(\"}\"); err != nil {\n\t\treturn defn, err\n\t}\n\n\treturn defn, nil\n}\n\nfunc (p *parser) typeUnion() (*dmt.TypeDefnUnion, error) {\n\tdefn := &dmt.TypeDefnUnion{}\n\tvar reprKeys []string\n\n\tfor {\n\t\ttok, err := p.consumeToken()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif tok == \"}\" {\n\t\t\tbreak\n\t\t}\n\t\tif tok != \"|\" {\n\t\t\treturn nil, p.errf(\"expected %q or %q, got %q\", \"}\", \"|\", tok)\n\t\t}\n\t\tvar member dmt.UnionMember\n\t\tnameOrInline, err := p.typeNameOrInlineDefn()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif nameOrInline.TypeName != nil {\n\t\t\tmember.TypeName = nameOrInline.TypeName\n\t\t} else {\n\t\t\tif nameOrInline.InlineDefn.TypeDefnLink != nil {\n\t\t\t\tmember.UnionMemberInlineDefn = &dmt.UnionMemberInlineDefn{TypeDefnLink: nameOrInline.InlineDefn.TypeDefnLink}\n\t\t\t} else {\n\t\t\t\treturn nil, p.errf(\"expected a name or inline link, got neither\")\n\t\t\t}\n\t\t}\n\t\tdefn.Members = append(defn.Members, member)\n\n\t\tkey, err := p.consumeToken()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treprKeys = append(reprKeys, key)\n\t}\n\tif err := p.consumeRequired(\"representation\"); err != nil {\n\t\treturn nil, err\n\t}\n\treprName, err := p.consumeName()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch reprName {\n\tcase \"keyed\":\n\t\trepr := &dmt.UnionRepresentation_Keyed{}\n\t\tfor i, keyStr := range reprKeys {\n\t\t\tkey, err := strconv.Unquote(keyStr)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, p.forwardError(err)\n\t\t\t}\n\t\t\tmapAppend(repr, key, defn.Members[i])\n\t\t}\n\t\tdefn.Representation.UnionRepresentation_Keyed = repr\n\tcase \"kinded\":\n\t\trepr := &dmt.UnionRepresentation_Kinded{}\n\t\t// TODO: verify keys are valid kinds? enum should do it for us?\n\t\tfor i, key := range reprKeys {\n\t\t\tmapAppend(repr, key, defn.Members[i])\n\t\t}\n\t\tdefn.Representation.UnionRepresentation_Kinded = repr\n\tcase \"stringprefix\":\n\t\trepr := &dmt.UnionRepresentation_StringPrefix{\n\t\t\tPrefixes: dmt.Map__String__TypeName{\n\t\t\t\tValues: map[string]string{},\n\t\t\t},\n\t\t}\n\t\tfor i, key := range reprKeys {\n\t\t\t// unquote prefix string\n\t\t\tif len(key) < 2 || key[0] != '\"' || key[len(key)-1] != '\"' {\n\t\t\t\treturn nil, p.errf(\"invalid stringprefix %q\", key)\n\t\t\t}\n\t\t\tkey = key[1 : len(key)-1]\n\n\t\t\t// add prefix to prefixes map\n\t\t\trepr.Prefixes.Keys = append(repr.Prefixes.Keys, key)\n\t\t\trepr.Prefixes.Values[key] = *defn.Members[i].TypeName\n\t\t}\n\t\tdefn.Representation.UnionRepresentation_StringPrefix = repr\n\tcase \"inline\":\n\t\toptMap, err := p.consumeStringMap()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdiscriminantKey, hasDiscriminantKey := optMap[\"discriminantKey\"]\n\t\tif !hasDiscriminantKey {\n\t\t\treturn nil, p.errf(\"no discriminantKey value provided for inline repr\")\n\t\t}\n\t\trepr := &dmt.UnionRepresentation_Inline{\n\t\t\tDiscriminantKey: discriminantKey,\n\t\t\tDiscriminantTable: dmt.Map__String__TypeName{\n\t\t\t\tValues: map[string]string{},\n\t\t\t},\n\t\t}\n\t\t// TODO: verify member types all have map representation\n\t\tfor i, qkey := range reprKeys {\n\t\t\tkey, err := strconv.Unquote(qkey)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid discriminant key %q: %w\", key, err)\n\t\t\t}\n\t\t\trepr.DiscriminantTable.Keys = append(repr.DiscriminantTable.Keys, key)\n\t\t\trepr.DiscriminantTable.Values[key] = *defn.Members[i].TypeName\n\t\t}\n\t\tdefn.Representation.UnionRepresentation_Inline = repr\n\tdefault:\n\t\treturn nil, p.errf(\"TODO: union repr %q\", reprName)\n\t}\n\treturn defn, nil\n}\n\nfunc (p *parser) typeEnum() (*dmt.TypeDefnEnum, error) {\n\tdefn := &dmt.TypeDefnEnum{}\n\tvar reprKeys []string\n\n\tfor {\n\t\ttok, err := p.consumeToken()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif tok == \"}\" {\n\t\t\tbreak\n\t\t}\n\t\tif tok != \"|\" {\n\t\t\treturn nil, p.errf(\"expected %q or %q, got %q\", \"}\", \"|\", tok)\n\t\t}\n\t\tname, err := p.consumeToken()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdefn.Members = append(defn.Members, name)\n\n\t\tif tok, err := p.peekToken(); err == nil && tok == \"(\" {\n\t\t\tp.consumePeeked()\n\t\t\tkey, err := p.consumeToken()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treprKeys = append(reprKeys, key)\n\t\t\tif err := p.consumeRequired(\")\"); err != nil {\n\t\t\t\treturn defn, err\n\t\t\t}\n\t\t} else {\n\t\t\treprKeys = append(reprKeys, \"\")\n\t\t}\n\t}\n\n\treprName := \"string\" // default repr\n\tif tok, err := p.peekToken(); err == nil && tok == \"representation\" {\n\t\tp.consumePeeked()\n\t\tname, err := p.consumeName()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treprName = name\n\t}\n\tswitch reprName {\n\tcase \"string\":\n\t\trepr := &dmt.EnumRepresentation_String{}\n\t\tfor i, key := range reprKeys {\n\t\t\tif key == \"\" {\n\t\t\t\tcontinue // no key; defaults to the name\n\t\t\t}\n\t\t\tif key[0] != '\"' {\n\t\t\t\treturn nil, p.errf(\"enum string representation used with non-string key: %s\", key)\n\t\t\t}\n\t\t\tunquoted, err := strconv.Unquote(key)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, p.forwardError(err)\n\t\t\t}\n\t\t\tmapAppend(repr, defn.Members[i], unquoted)\n\t\t}\n\t\tdefn.Representation.EnumRepresentation_String = repr\n\tcase \"int\":\n\t\trepr := &dmt.EnumRepresentation_Int{}\n\t\tfor i, key := range reprKeys {\n\t\t\tif key[0] != '\"' {\n\t\t\t\treturn nil, p.errf(\"enum int representation used with non-string key: %s\", key)\n\t\t\t}\n\t\t\tunquoted, err := strconv.Unquote(key)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, p.forwardError(err)\n\t\t\t}\n\t\t\tparsed, err := strconv.Atoi(unquoted)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, p.forwardError(err)\n\t\t\t}\n\t\t\tmapAppend(repr, defn.Members[i], parsed)\n\t\t}\n\t\tdefn.Representation.EnumRepresentation_Int = repr\n\tdefault:\n\t\treturn nil, p.errf(\"unknown enum repr: %q\", reprName)\n\t}\n\treturn defn, nil\n}\n"
  },
  {
    "path": "schema/dsl/parse_test.go",
    "content": "package schemadsl_test\n\nimport (\n\t\"bytes\"\n\t\"flag\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\n\tipldjson \"github.com/ipld/go-ipld-prime/codec/json\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\tschemadmt \"github.com/ipld/go-ipld-prime/schema/dmt\"\n\tschemadsl \"github.com/ipld/go-ipld-prime/schema/dsl\"\n\t\"gopkg.in/yaml.v2\"\n\n\tqt \"github.com/frankban/quicktest\"\n)\n\nvar update = flag.Bool(\"update\", false, \"update testdata files in-place\")\n\nfunc TestParseSchemaSchema(t *testing.T) {\n\tt.Parallel()\n\n\tinputSchema := \"../../.ipld/specs/schemas/schema-schema.ipldsch\"\n\tinputJSON := \"../../.ipld/specs/schemas/schema-schema.ipldsch.json\"\n\n\tsrc, err := os.ReadFile(inputSchema)\n\tqt.Assert(t, err, qt.IsNil)\n\n\tsrcJSON, err := os.ReadFile(inputJSON)\n\tqt.Assert(t, err, qt.IsNil)\n\n\ttestParse(t, string(src), string(srcJSON), func(updated string) {\n\t\terr := os.WriteFile(inputJSON, []byte(updated), 0o777)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t})\n}\n\ntype yamlFixture struct {\n\tSchema          string\n\tCanonical       string `yaml:\",omitempty\"`\n\tExpected        string\n\tExpectedParsed  interface{}        `yaml:\",omitempty\"`\n\tBlocks          []yamlFixtureBlock `yaml:\",omitempty\"`\n\tBadBlocks       []string           `yaml:\"badBlocks,omitempty\"`\n\tBadBlocksParsed []interface{}      `yaml:\",omitempty\"`\n}\n\ntype yamlFixtureBlock struct {\n\tActual         string      `yaml:\",omitempty\"`\n\tActualParsed   interface{} `yaml:\",omitempty\"`\n\tExpected       string      `yaml:\",omitempty\"`\n\tExpectedParsed interface{} `yaml:\",omitempty\"`\n}\n\nfunc TestParse(t *testing.T) {\n\tt.Parallel()\n\n\tmatches, err := filepath.Glob(\"../../.ipld/specs/schemas/tests/*.yml\")\n\tqt.Assert(t, err, qt.IsNil)\n\tqt.Assert(t, matches, qt.Not(qt.HasLen), 0)\n\n\tfor _, ymlPath := range matches {\n\t\tymlPath := ymlPath // do not reuse range var\n\t\tname := filepath.Base(ymlPath)\n\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tdata, err := os.ReadFile(ymlPath)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\t\tvar fixt yamlFixture\n\t\t\terr = yaml.Unmarshal(data, &fixt)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\t\ttestParse(t, fixt.Schema, fixt.Expected, func(updated string) {\n\t\t\t\tupdated = strings.Replace(updated, \"\\t\", \"  \", -1)\n\t\t\t\tfixt.Expected = updated\n\n\t\t\t\tdata, err = yaml.Marshal(&fixt)\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\t\t\t// Note that this will strip comments.\n\t\t\t\t// Probably don't commit its changes straight away.\n\t\t\t\terr = os.WriteFile(ymlPath, data, 0o777)\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t})\n\t\t})\n\t}\n}\n\nfunc testParse(t *testing.T, inSchema, inJSON string, updateFn func(string)) {\n\tt.Helper()\n\n\tinJSON = strings.Replace(inJSON, \"  \", \"\\t\", -1) // fix non-tab indenting\n\tcrre := regexp.MustCompile(`\\r?\\n`)\n\tinJSON = crre.ReplaceAllString(inJSON, \"\\n\") // fix windows carriage-return\n\n\tsch, err := schemadsl.ParseBytes([]byte(inSchema))\n\tqt.Assert(t, err, qt.IsNil)\n\n\t// Ensure the parsed schema compiles as expected.\n\t{\n\t\tvar ts schema.TypeSystem\n\t\tts.Init()\n\t\terr := schemadmt.Compile(&ts, sch)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\tqt.Assert(t, ts.Names(), qt.Not(qt.HasLen), 0)\n\t}\n\n\t// Ensure we can encode the schema as the json codec,\n\t// and that it results in the same bytes as the ipldsch.json file.\n\t{\n\t\tnode := bindnode.Wrap(sch, schemadmt.Prototypes.Schema.Type())\n\n\t\tvar buf bytes.Buffer\n\t\terr := ipldjson.Encode(node.Representation(), &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\t// If we're updating, write to the file.\n\t\t// Otherwise, expect the files to be equal.\n\t\tgot := buf.String()\n\t\tif *update {\n\t\t\tupdateFn(got)\n\t\t\treturn\n\t\t}\n\t\tqt.Assert(t, got, qt.Equals, inJSON,\n\t\t\tqt.Commentf(\"run 'go test -update' to write to the iplsch.json file\"))\n\t}\n\n\t// TODO: ensure that doing a json codec decode results in the same Schema Go\n\t// value that we got by parsing the DSL.\n}\n"
  },
  {
    "path": "schema/errors.go",
    "content": "package schema\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// TODO: errors in this package remain somewhat slapdash.\n//\n//  - datamodel.ErrUnmatchable is used as a catch-all in some places, and contains who-knows-what values wrapped in the Reason field.\n//    - sometimes this wraps things like strconv errors... and on the one hand, i'm kinda okay with that; on the other, maybe saying a bit more with types before getting to that kind of shrug would be nice.\n//  - we probably want to use `Type` values, right?\n//    - or do we: because then we probably need a `Repr bool` next to it, or lots of messages would be nonsensical.\n//    - this is *currently* problematic because we don't actually generate type info consts yet.  Hopefully soon; but the pain, meanwhile, is... substantial.\n//      - \"substantial\" is an understatement.  it makes incremental development almost impossible because stringifying error reports turn into nil pointer crashes!\n//    - other ipld-wide errors like `datamodel.ErrWrongKind` *sometimes* refer to a TypeName... but don't *have* to, because they also arise at the merely-datamodel level; what would we do with these?\n//      - it's undesirable (not to mention intensely forbidden for import cycle reasons) for those error types to refer to schema.Type.\n//        - if we must have TypeName treated stringily in some cases, is it really useful to use full type info in other cases -- inconsistently?\n//    - regardless of where we end up with this, some sort of an embed for helping deal with munging and printing this would probably be wise.\n//  - generally, whether you should expect an \"datamodel.Err*\" or a \"schema.Err*\" from various methods is quite unclear.\n//  - it's possible that we should wrap *all* schema-level errors in a single \"datamodel.ErrSchemaNoMatch\" error of some kind, to fix the above.  (and maybe that's what ErrUnmatchable really is.)  as yet undecided.\n\n// ErrUnmatchable is the error raised when processing data with IPLD Schemas and\n// finding data which cannot be matched into the schema.\n// It will be returned by NodeAssemblers and NodeBuilders when they are fed unmatchable data.\n// As a result, it will also often be seen returned from unmarshalling\n// when unmarshalling into schema-constrained NodeAssemblers.\n//\n// ErrUnmatchable provides the name of the type in the schema that data couldn't be matched to,\n// and wraps another error as the more detailed reason.\ntype ErrUnmatchable struct {\n\t// TypeName will indicate the named type of a node the function was called on.\n\tTypeName string\n\n\t// Reason must always be present.  ErrUnmatchable doesn't say much otherwise.\n\tReason error\n}\n\nfunc (e ErrUnmatchable) Error() string {\n\treturn fmt.Sprintf(\"matching data to schema of %s rejected: %s\", e.TypeName, e.Reason)\n}\n\n// Reasonf returns a new ErrUnmatchable with a Reason field set to the Errorf of the arguments.\n// It's a helper function for creating untyped error reasons without importing the fmt package.\nfunc (e ErrUnmatchable) Reasonf(format string, a ...interface{}) ErrUnmatchable {\n\treturn ErrUnmatchable{e.TypeName, fmt.Errorf(format, a...)}\n}\n\n// Is provides support for Go's standard errors.Is function so that\n// errors.Is(yourError, ErrUnmatchable) may be used to match the type of error.\nfunc (e ErrUnmatchable) Is(err error) bool {\n\t_, ok := err.(ErrUnmatchable)\n\treturn ok\n}\n\n// ErrMissingRequiredField is returned when calling 'Finish' on a NodeAssembler\n// for a Struct that has not has all required fields set.\ntype ErrMissingRequiredField struct {\n\tMissing []string\n}\n\nfunc (e ErrMissingRequiredField) Error() string {\n\treturn \"missing required fields: \" + strings.Join(e.Missing, \",\")\n}\n\n// Is provides support for Go's standard errors.Is function so that\n// errors.Is(yourError, ErrMissingRequiredField) may be used to match the type of error.\nfunc (e ErrMissingRequiredField) Is(err error) bool {\n\t_, ok := err.(ErrMissingRequiredField)\n\treturn ok\n}\n\n// ErrInvalidKey indicates a key is invalid for some reason.\n//\n// This is only possible for typed nodes; specifically, it may show up when\n// handling struct types, or maps with interesting key types.\n// (Other kinds of key invalidity that happen for untyped maps\n// fall under ErrRepeatedMapKey or ErrWrongKind.)\n// (Union types use ErrInvalidUnionDiscriminant instead of ErrInvalidKey,\n// even when their representation strategy is maplike.)\ntype ErrInvalidKey struct {\n\t// TypeName will indicate the named type of a node the function was called on.\n\tTypeName string\n\n\t// Key is the key that was rejected.\n\tKey datamodel.Node\n\n\t// Reason, if set, may provide details (for example, the reason a key couldn't be converted to a type).\n\t// If absent, it'll be presumed \"no such field\".\n\t// ErrUnmatchable may show up as a reason for typed maps with complex keys.\n\tReason error\n}\n\nfunc (e ErrInvalidKey) Error() string {\n\tif e.Reason == nil {\n\t\treturn fmt.Sprintf(\"invalid key for map %s: %q: no such field\", e.TypeName, e.Key)\n\t} else {\n\t\treturn fmt.Sprintf(\"invalid key for map %s: %q: %s\", e.TypeName, e.Key, e.Reason)\n\t}\n}\n\n// Is provides support for Go's standard errors.Is function so that\n// errors.Is(yourError, ErrInvalidKey) may be used to match the type of error.\nfunc (e ErrInvalidKey) Is(err error) bool {\n\t_, ok := err.(ErrInvalidKey)\n\treturn ok\n}\n\n// ErrNoSuchField may be returned from lookup functions on the Node\n// interface when a field is requested which doesn't exist,\n// or from assigning data into on a MapAssembler for a struct\n// when the key doesn't match a field name in the structure\n// (or, when assigning data into a ListAssembler and the list size has\n// reached out of bounds, in case of a struct with list-like representations!).\ntype ErrNoSuchField struct {\n\tType Type\n\n\tField datamodel.PathSegment\n}\n\nfunc (e ErrNoSuchField) Error() string {\n\tif e.Type == nil {\n\t\treturn fmt.Sprintf(\"no such field: {typeinfomissing}.%s\", e.Field)\n\t}\n\treturn fmt.Sprintf(\"no such field: %s.%s\", e.Type.Name(), e.Field)\n}\n\n// Is provides support for Go's standard errors.Is function so that\n// errors.Is(yourError, ErrNoSuchField) may be used to match the type of error.\nfunc (e ErrNoSuchField) Is(err error) bool {\n\t_, ok := err.(ErrNoSuchField)\n\treturn ok\n}\n\n// ErrNotUnionStructure means data was fed into a union assembler that can't match the union.\n//\n// This could have one of several reasons, which are explained in the detail text:\n//\n//   - there are too many entries in the map;\n//   - the keys of critical entries aren't found;\n//   - keys are found that aren't any of the expected critical keys;\n//   - etc.\n//\n// TypeName is currently a string... see comments at the top of this file for\n// remarks on the issues we need to address about these identifiers in errors in general.\ntype ErrNotUnionStructure struct {\n\tTypeName string\n\n\tDetail string\n}\n\nfunc (e ErrNotUnionStructure) Error() string {\n\treturn fmt.Sprintf(\"cannot match schema: union structure constraints for %s caused rejection: %s\", e.TypeName, e.Detail)\n}\n\n// Is provides support for Go's standard errors.Is function so that\n// errors.Is(yourError, ErrNotUnionStructure) may be used to match the type of error.\nfunc (e ErrNotUnionStructure) Is(err error) bool {\n\t_, ok := err.(ErrNotUnionStructure)\n\treturn ok\n}\n"
  },
  {
    "path": "schema/gen/go/HACKME.md",
    "content": "hacking gengo\n=============\n\nWhat the heck?\n--------------\n\nWe're doing code generation.\n\nThe name of the game is \"keep it simple\".\nMost of this is implemented as string templating.\nNo, we didn't use the Go AST system.  We could have; we didn't.\nImplementing this as string templating seemed easier to mentally model,\nand the additional value provided by use of AST libraries seems minimal\nsince we feed the outputs into a compiler for verification immediately anyway.\n\nSome things seem significantly redundant.\nThat's probably because they are.\nIn general, if there's a choice between apparent redundancy in the generator itself\nversus almost any other tradeoff which affects the outputs, we prioritize the outputs.\n(This may be especially noticeable when it comes to error messages: we emit a lot\nof them... while making sure they contain very specific references.  This leads\nto some seemingly redundant code, but good error messages are worth it.)\n\nSee [README_behaviors](README_behaviors.md) for notes about the behaviors of the code output by the generator;\nthis document is about the generator code itself and the design thereof.\n\n\nEntrypoints\n-----------\n\nThe most important intefaces are all in [`generators.go`](generators.go).\n\nThe function you're most likely looking for that \"does the thing\" is the\n`Generate(outputPath string, pkgName string, schema.TypeSystem, *AdjunctCfg)` method,\nwhich can be found in the [`generate.go`](generate.go) file.\nYou can take any of the functions inside of that and use them as well,\nif you want more granular control over what content ends up in which files.\n\nThe eventual plan is be able to drive this whole apparatus around via a CLI\nwhich consumes IPLD Schema files.\nImplementing this can come after more of the core is done.\n(Seealso the `schema/tmpBuilders.go` file a couple directories up for why\nthis is currently filed as nontrivial/do-later.)\n\n\nOrganization\n------------\n\n### How many things are generated, anyway?\n\nThere are roughly *seven* categories of API to generate per type:\n\n- 1: the readonly thing a native caller uses\n- 2: the builder thing a native caller uses\n- 3: the readonly typed node\n- 4: the builder/assembler for typed node\n- 5: the readonly representation node\n- 6: the builder/assembler via representation\n- 7: and a maybe wrapper\n\n(And these are just the ones nominally visible in the exported API surface!\nThere are several more concrete types than this implied by some parts of that list,\nsuch as iterators for the nodes, internal parts of builders, and so forth.)\n\nThese numbers will be used to describe some further organization.\n\n### How are the generator components grouped?\n\nThere are three noteworthy types of generator internals:\n\n- `TypeGenerator`\n- `NodeGenerator`\n- `NodebuilderGenerator`\n\nThe first one is where you start; the latter two do double duty for each type.\n\nExported types for purpose 1, 2, 3, and 7 are emitted from `TypeGenerator` (3 from the embedded `NodeGenerator`).\n\nThe exported type for purpose 5 is emitted from another `NodeGenerator` instance.\n\nThe exported types for purposes 4 and 6 are emitted from two distinct `NodebuilderGenerator` instances.\n\nFor every variation in type kind and representation strategy for that type kind,\none type implementing `TypeGenerator` is composed, and it has functions which\nyield all the other interfaces for addressing the various purposes.\n\n### How are files and their contents grouped?\n\nMost of the files in this package are following a pattern:\n\n- for each kind:\n\t- `gen{Kind}.go` -- has emitters for the native type parts (1, 2, 7) and type-level node behaviors (3, 4).\n\t- for each representation that kind can have:\n\t\t- `gen{Kind}Repr{ReprStrat}.go` -- has emitters for (5, 6).\n\nA `mixins` sub-package contains some code which is used and embedded in the generators in this package.\nThese features are mostly per-kind -- representation kind, not type-level kind.\nFor example, you'll see \"map\" behaviors from the mixins package added to \"struct\" generators.\n\n### What are all these abbreviations?\n\nSee [HACKME_abbrevs.md](HACKME_abbrevs.md).\n\n### Code architecture\n\nSee [HACKME_tradeoffs.md](HACKME_tradeoffs.md) for an overview of tradeoffs,\nand which priorities we selected in this package.\n(There are *many* tradeoffs.)\n\nSee [HACKME_memorylayout.md](HACKME_memorylayout.md) for a (large) amount of\nexposition on how this code is designed in order to be allocation-avoidant\nand fast in general.\n\nSee [HACKME_templates.md](HACKME_templates.md) for some overview on how we've\nused templates, and what forms of reuse and abstraction there are.\n\nSee [HACKME_scalars.md](HACKME_scalars.md) for some discussion of scalars\nand (why we generate more of them than you might expect).\n\nSee [HACKME_maybe.md](HACKME_maybe.md) for notes how how the 'maybe' feature\n(how we describe `nullable` and `optional` schema features in generated golang code)\nhas evolved.\n\n\nTesting\n-------\n\nSee [HACKME_testing.md](HACKME_testing.md) for some details about how this works.\n\nIn general, try to copy some of the existing tests and get things to suit.\n\nBe advised that we use the golang plugin feature, and that has some additional\nrequirements of your development environment than is usual in golang.\n(Namely, you have to be on linux and you have to have a c compiler!)\n\n"
  },
  {
    "path": "schema/gen/go/HACKME_abbrevs.md",
    "content": "abbreviations\n=============\n\nA lot of abbreviations are used the generated code in the interest of minimizing the size of the output.\n\nThis is a short index of the most common ones:\n\n- `n` -- **n**ode, of course -- the accessor functions on node implementations usually refer to their 'this' as 'n'.\n- `na` -- **n**ode **a**ssembler\n\t- `la` or `ma` may also be seen for **l**ist and **m**ap in some contexts (but may refer to same type being called `na` in other contexts).\n- `w` -- **w**ork-in-progress node -- you'll see this in nearly every assembler (e.g. `na.w` is a very common string).\n\ninside nodes:\n\n- `x` -- a placeholder for \"the thing\" for types that contain only one element of data (e.g., the string inside a codegen'd node of string kind).\n- `t` -- **t**able -- the slice inside most map nodes that is used for alloc amortizations and maintaining order.\n- `m` -- **m**ap -- the actual map inside most map nodes (seealso `t`, which is usually a sibling).\n\ninside assemblers:\n\n- `va` -- **v**alue **a**ssembler -- an assembler for values in lists or maps (often embedded in the node assembler, e.g. `ma.va` and `la.va` are common strings).\n- `ka` -- **k**ey **a**ssembler -- an assembler for keys in maps (often embedded in the node assembler, e.g. `ma.ka` is a common string).\n- `ca_*` -- **c**hild **a**ssembler -- the same concept as `ka` and `va`, but appearing in structs and other types that have differentiated children.\n- `cm` -- **c**hild **m**aybe -- a piece of memory sometimes found in a node assembler for statekeeping for child assemblers.\n- `m` -- **m**aybe pointer -- a pointer to where an assembler should put a mark when it's finished.  (this is often a pointer to a parent structure's 'cm'!)\n"
  },
  {
    "path": "schema/gen/go/HACKME_dry.md",
    "content": "HACKME: \"don't repeat yourself\": how-to (and, limits of that goal)\n==================================================================\n\nWhich kind of extraction applies?\n---------------------------------\n\nThings vary in how identical they are.\n\n- **Textually identical**: Some code is textually identical between different types,\n  varying only in the most simple and obvious details, like the actual type name it's attached to.\n\t- These cases can often be extracted on the generation side...\n\t\t- We tend to put them in `genparts{*}.go` files.\n\t- But the output is still pretty duplicacious.\n\n- **Textually identical minus simple variations**: Some code is textually *nearly* identical,\n  but varies in relatively minor ways (such as whether or not the \"Repr\" is part of munges, and \"Representation()\" calls are made, etc).\n\t- These cases can often be extracted on the generation side...\n\t\t- We tend to put them in `genparts{*}.go` files.\n\t\t- There's just a bit more `{{ various templating }}` injected in them, compared to other textually identical templates.\n\t- But the output is still pretty duplicacious.\n\n- **Linkologically identical**: When code is not _only_ textually identical,\n  but also refers to identical types.\n\t- These cases can be extracted on the generation side...\n\t\t- but it may be questionable to do so: if its terse enough in the output, there's that much less incentive to make a template-side shorthand for it.\n\t- The output in this case can actually be deduplicated!\n\t\t- It's possible we haven't bothered yet.  **That doesn't mean it's not worth it**; we probably just haven't had time yet.  PRs welcome.\n\t\t- How?\n\t\t\t- functions?  This is the most likely to apply.\n\t\t\t- embedded types?  We haven't seen many cases where this can help, yet (unfortunately?).\n\t\t\t- shared constants?\n\t\t- It's not always easy to do this.\n\t\t\t- We usually put something in the \"minima\" file.\n\t\t\t- We don't currently have a way to toggle whether whole features or shared constants are emitted in the minima file.  Todo?\n\t\t\t\t- This requires keeping state that records what's necessary as we go, so that we can do them all together at the end.\n\t\t\t\t- May also require varying the imports at the top of the minima file.  (But: by doing it only here, we can avoid that complexity in every other file.)\n\t- **This is actually pretty rare**.  _Things that are textually identical are not necessarily linkologically identical_.\n\t\t- One can generally turn things that are textually identical into linkologically identical by injecting an interface into the types...\n\t\t\t- ... but this isn't always a *good* idea:\n\t\t\t\t- if this would cause more allocations?  Yeah, very no.\n\t\t\t\t- even if this can be done without a heap allocation, it probably means inlining and other optimizations will become impossible for the compiler to perform, and often, we're not okay with the performance implications of that either.\n\n- **Identical if it wasn't for debugability**: In some cases, code varies only by some small constants...\n  and really, those constants could be removed entirely.  If... we didn't care about debugging.  Which we do.\n\t- This is really the same as \"textually identical minus simple variations\", but worth talking about briefly just because of the user story around it.\n\t- A bunch of the error-thunking methods on Node and NodeAssemblers exemplify this.\n\t\t- It's really annoying that we can't remove this boilerplate entirely from the generated code.\n\t\t- It's also basically impossible, because we *want* information that varies per type in those error messages.\n\n\nWhat mechanism of extraction should be used?\n--------------------------------------------\n\n- (for gen-side dry) gen-side functions\n\t- this is most of what we've done so far\n- (for gen-side dry) sub-templates\n\t- we currently don't really use this at all\n- (for gen-side dry) template concatenation\n\t- some of this: kinded union representations do this\n- (for output-side dry) output side functions\n\t- some of this: see \"minima\" file.\n- (for output-side dry) output side embeds\n\t- we currently don't really use this at all (it hasn't really turned out applicable in any cases yet).\n\n\nDon't overdo it\n---------------\n\nI'd rather have longer templates than harder-to-read and harder-to-maintain templates.\n\nThere's a balance to this and it's tricky to pick out.\n\nA good heuristic to consider might be: are we extracting this thing because we can?\nOr because if we made changes to this thing in the future, we'd expect to need to make that change in every single place we've extracted it from,\nwhich therefore makes the extraction a net win for maintainability?\nIf it's the latter: then yes, extract it.\nIf it's not clear: maybe let it be.\n\n(It may be the case that the preferable balance for DRYing changes over time as we keep maintaining things.\nWe'll see; but it's certainly the case that the first draft of this package has favored length heavily.\nThere was a lot of \"it's not clear\" when the maintainability heuristic was applied during the first writing of this;\nthat may change!  If so, that's great.)\n"
  },
  {
    "path": "schema/gen/go/HACKME_maybe.md",
    "content": "How do maybe/nullable/optional work?\n====================================\n\n(No, this document is not about things that we should \"maybe\" hack on.\nIt's about the feature we use to describe `nullable` and `optional` fields\nin generated golang code.)\n\nbackground\n----------\n\nYou'll need to understand what the `nullable` and `optional` modifiers in IPLD schemas mean.\nThe https://specs.datamodel.io/ site has more content about that.\n\n### how this works outside of schemas\n\nThere are concepts of null and of absent present in the core `Node` and `NodeAssembler` interfaces.\n`Node` specifies `IsNull() bool` and `IsAbsent() bool` predicates;\nand `NodeAssembler` specifies an `AssignNull` function.\n\nThere are also singleton values available called `datamodel.Null` and `datamodel.Absent`\nwhich report true for `IsNull` and `IsAbsent`, respectively.\nThese singletons can be used by an function that need to return a null or absence indicator.\n\nThere's really no reason for any package full of `Node` implementations need to make their own types for these values,\nsince the singletons are always fine to use.\nHowever, there's also nothing stopping a `Node` implementation from doing interesting\ncustom internal memory layouts to describe whether they contain nulls, etc --\nand there's nothing particularly blessed about the `datamodel.Null` singleton.\nAny value reporting `IsNull` to be `true` must be treated indistinguishably from `datamodel.Null`.\n\nThis indistinguishability is bidirectional.\nFor example, if you have some `myFancyNodeType`, and it answers `IsNull` as `true`,\nand you insert this into a `basicnode.Map`, then ask for that value back from the map later...\nyou're very likely to get `datamodel.Null`, and not your concrete value of `myFancyNodeType` back again.\n(This contract is important because some node implementations may compress\nthe concept of null into a bitmask, or otherwise similarly optimize things internally.)\n\n#### null\n\nThe concept of \"null\" has a Kind in the IPLD Data Model.\nIt's implemented by the `datamodel.nullNode` type (which has no fields -- it's a \"unit\" type),\nand is exposed as the `datamodel.Null` singleton value.\n\n(More generally, `datamodel.Node` can be null by having its `Kind()` method return `datamodel.Kind_Null`,\nand having the `IsNull()` method return `true`.\nHowever, most code prefers to return the `datamodel.Null` singleton value whenever it can.)\n\nNull values can be easily produced: the `AssignNull()` method on `datamodel.NodeAssembler` produces nulls;\nand many codecs have some concept of null, meaning deserialization can produce them.\n\nNull values work essentially the same way in both the plain Data Model and when working with Schemas.\n\n#### absent\n\nThere's also a concept of \"absent\".\n\"Absent\" is separate and distinct from the concept of \"null\" -- null is still a _value_; absent just means _nothing there_.\n\n(Those familiar with javascript might note that javascript also has concepts of \"null\" versus \"undefined\".\nIt's the same idea -- we just call it \"absent\" instead of \"undefined\".)\n\nAbsent is implemented by the `datamodel.absentNode` type (which has no fields -- it's a \"unit\" type),\nand is exposed as the `datamodel.Absent` singleton value.\n\n(More generally, an `datamodel.Node` can describe itself as containing \"absent\" by having the `IsAbsent()` method return `true`.\n(The `Kind()` method still returns `datamodel.Kind_Null`, for lack of better option.)\nHowever, most code prefers to return the `datamodel.Absent` singleton value whenever it can.)\n\nAbsent values aren't really used at the Data Model level.\nIf you ask for a map key that isn't present in the map, the lookup method will return `nil` and `ErrNotExists`.\n\nAbsent values *do* show up at the Schema level, however.\nSpecifically, in structs: a struct can have a field which is `optional`,\none of the values such an optional field may report itself as having is `datamodel.Absent`.\nThis represents when a value *wasn't present* in the serialized form of the struct,\neven though the schema lets us know that it could be, and that it's part of the struct's type.\n(Accordingly, no `ErrNotExists` is returned for a lookup of that field --\nthe field is always considered to _exist_... the value is just _absent_.)\nIterators will also return the field name key, together with `datamodel.Absent` as the value.\n\nHowever, absent values can't really be *created*.\nThere's no such thing as an `AssignAbsent` or `AssignAbsent` method on the `datamodel.NodeAssembler` interface.\nCodecs similarly can't produce absent as a value (obviously -- codecs work over `datamodel.NodeAssembler`, so how could they?).\nAbsent values are just produced by implication, when a field is defined, but its value isn't set.\n\nDespite absent values not being used or produced at the Data Model, we still have methods like `IsAbsent` specified\nas part of the `datamodel.Node` interface so that it's possible to write code which is generic over\neither plain Data Model or Schema data while using just that interface.\n\n### the above is all regarding generic interfaces\n\nAs long as we're talking about the `datamodel.Node` _interface_,\nwe talk about the `datamodel.Null` and `datamodel.Absent` singletons, and their contracts in terms of the interface.\n\n(Part of the reason this works is because an interface, in golang,\ncomes in two parts: a pointer to the typeinfo of the inhabitant value,\nand a pointer to the value itself.\nThis means anywhere we have an `datamodel.Node` return type, we can toss `datamodel.Null`\nor `datamodel.Absent` into it with no additional overhead!)\n\nWhen we talk about concrete types, rather than the `datamodel.Node` _interface_ --\nas we're going to, in codegen -- it's a different scenario.\nWe can't just return `datamodel.Null` pointers for a `genresult.Foo` value;\nif `genresult.Foo` is a concrete type, that's just flat out a compile error.\n\nSo what shall we do?\n\nWe introduce the \"maybe\" types.\n\n\n\nthe maybe types\n---------------\n\nThe general rule of \"return `datamodel.Null` whenever you have a null value\"\nholds up only as long as our API is returning monomorphized `datamodel.Node` interfaces --\nin that situation, `datamodel.Null` fits within `datamodel.Node`, and there's no trouble.\n\nThis doesn't hold up when we get to codegen.\nOr rather, more specifically, it even holds up for codegen...\nas long as we're still returning monomorphized `datamodel.Node` interfaces (and a decent amount of the API surface still does so).\nAt the moment we want to return a concrete native type, it breaks.\n\nWe call methods created by codegen that use specific types\n(e.g., methods that you _couldn't have_ without codegen)\n\"speciated\" methods.  And we do want them!\n\nSo we have to decide how to handle null and absent for these speciated methods.\n\n### goals of the maybe types\n\nThere are a couple of things we want to accomplish with the maybe types:\n\n- Be able to have speciated methods that return a specific type (for doc, editor autocomplete, etc purposes).\n- Be able to have speciated methods that return specific *concrete* type (i.e. not only do we want to be more specific than `datamodel.Node`, we don't want an interface _at all_ -- so that the compiler can do inlining and optimization and so forth).\n- Make reading and writing code that uses speciated methods and handles nullable or optional fields be reasonably ergonomic (and as always, this may vary by \"taste\").\n\nAnd we'll consider one more fourth, bonus goal:\n\n- It would be nice if the maybe types can clearly discuss whether the type is `(null|value)` vs `(absent|value)` vs `(absent|null|value)`, because this would let the golang compiler help check more of our logical correctness in code written using optionals and nullables.\n\n### there is only one type generated for each maybe\n\nFor every type generated, there is one maybe type also generated.\n(At least this much is clearly necessary to satisfy the goals about \"specific types\".)\n\nThis means *we dropped the bonus goal* above.\nMaking `(null|value)` vs `(absent|value)` vs `(absent|null|value)` distinguishable to the golang compiler\nwould require three *additional* generated types (for obvious reasons) for each type specified by the Schema.\nWe decided that's simply too onerous.\n\n(A different codegen project could certainly make a different choice here, though.)\n\n### the symbol for maybe types\n\nFor some type named `T` generated into a package named `gen`...\n\n- the main type symbol is `gen.T`;\n- the maybe for that type is `gen.MaybeT`;\n\nBeware that this may spell trouble if your schema contains any types\nwith names starting in \"Maybe\".\n(You can use adjunct config to change symbols for those types, if necessary.)\n\n(There are also internal symbols for the same things,\nbut these are prefixed in such a way as to make collision not a concern.)\n\n### maybe types don't implement the full Node interface\n\nThe \"maybe\" types don't implement the full `datamodel.Node` interface.\nThey could have!  They don't.\n\nArguments that went in favor of implementing `Node`:\n\n- generally \"seem fine\"\n- certainly makes sense to be able to 'IsNull' on it like any other Node.\n- if in practice the maybe is embedded, we can return an internal pointer to it just fine, so there's no obvious runtime perf reason not to.\n\nArguments against:\n\n- it's another type with a ton of methods.  or two, or four.\n\t- may increase the binary size.  possibly by a significant constant multiplier.\n\t- definitely increases the gsloc size, significantly.\n- would it have a 'Type' accessor on it?\n\t- if so, what does it say?\n- simply not sure how useful this is!\n\t- istm one will often either be passing the MaybeT to other speciated functions, or, fairly immediately de-maybing it.\n\t\t- if this is true, the number of times anyone wants to treat it as a Node in practice are near zero.\n- does this imply the existence of a _MaybeT__Assembler type, as well?\n\t- binary and gsloc size still drifting up; this needs to justify itself and provide value to be worth it.\n\t- what would be the expected behavior of handing a _MaybeT__Assembler to something like unmarshalling?\n\t\t- if you have a null in the root, you can describe this with a kinded union, and probably would be better off for it.\n\t\t- if you have can absent value in the root of a document you're unmarshalling... what?  That's called \"EOF\".\n\t- does a _MaybeT__Assembler show up usefully in the middle of a tree?\n\t\t- it does not!  there's always a _P_ValueAssembler type involved there anyway (this is needed for parent state machine purposes), and it largely delegates to the _T__Assembler, but is already a perfect position to add on the \"maybe\" semantics if the P type has them for its children.\n\nThe arguments against carried the day.\n\n### the maybe type is emebbedable\n\nIt's important that the \"maybe\" types be embeddable, for all the same reasons that\n[we normally want embeddable types](./HACKME_memorylayout.md#embed-by-default).\n\nIt's interesting to consider the alternatives, though:\n\nWe could've bitpacked the isAbsent or isNull flags for a field into one word at the top of a struct, for example.\nBut, there are numerous drawbacks to this:\n\n- the complexity of this is high.\n- it would be exposed to anyone who writes addntl code in-package, which is asking for errors.\n- the only thing this buys us is *slightly* less resident memory size.\n\t- and long story short: if you look at how many other programming language do this, pareto-wise, no one in the world at large appears to care.\n- it only applies to structs!  maps or lists would require yet more custom bitpacking of a different arrangement.\n\nIf someone wants to do another codegen project someday, or make PRs to this one, which does choose bitpacking,\nit would probably be neat.  It's just a lot of effort for a payout that doesn't seem to often be worth it.\n\n(We also ended up using pointers to a field with a `schema.Maybe` type _heavily_\nin the internals of our codegen outputs, in order to let child and parent assemblers coordinate.\nRebuilding this to work with a bitpacking alignment and yet still be composable enough to do its job... uufdah.  Tricky.\nIt might be possible to use the current system in the assembler state, but flip it bitpack in the resulting immutable nodes,\nand thereby get the best of both worlds.  If you who reads this is enthusiastic, feel free to explore it.)\n\n### ...but the user is only exposed to the pointer form\n\nThis is the same story as for the main types: it's covered in\n[unexported implementations, exported aliases](./HACKME_memorylayout.md#unexported-implementations-exported-aliases).\n\nGenenerally, this \"shielded\" type means you can only have a MaybeT with valid contents,\nbecause no one can ever produce the uninitialized \"zero\" value of the type.\nThis means there's no \"invalid\" state which can kick you in the shins at runtime,\nand we generally regard that as a good thing.\n\nIt also just keeps things syntactically simple.\nOne always refers to \"MaybeT\"; never with a star.\n\n### whether or not the maybe's inhabitant type is embedded is based on adjunct config\n\nAlthough the maybe type itself is embeddable, its _inhabitant_ may be\neither embedded in the maybe type or be a pointer, at your option.\n\nThis is clearest to explain in code: you can have either:\n\n```go\ntype MaybeFoo struct {\n\tm schema.Maybe // enum bit for present|absent|null\n\tv Foo          // the inhabitant (here, embedded)\n}\n```\n\nor:\n\n```go\ntype MaybeFoo struct {\n\tm schema.Maybe // enum bit for present|absent|null\n\tv *Foo         // the inhabitant (here, a pointer!)\n}\n```\n\n(Yes, we're talking about a one-character difference in the code.)\n\nWhich of these two forms is generated can be selected by adjunct config.\n(\"Adjunct\" config just means: it's not part of the schema; it's part of the\nconfig for this codegen tool.)\n\nThere are advantages to each:\n\n- the embedded form is ([as usual](./HACKME_memorylayout.md#embed-by-default)), faster for workloads where the value is usually present (it provokes fewer allocations).\n- the pointer form may use less memory when the value is absent; it works for cyclic structures; and if assigning a whole subtree at once, it allows faster assignment.\n\nAlso, for cyclic structures, such as `type Foo {String:nullable Foo}`, or `type Bar struct{ recurse optional Bar }`, the pointer form is *required*.\n(Otherwise... how big of a slab of memory would we be allocating?  Infinite?  Nope; compile error.)\n\nBy default, we generate the pointer form.\nHowever, your application may experience significant performance improvements by selectively using the embed form.\nCheck it out and tune for what's right for your application.\n\n(FUTURE: we should make more clever defaults: it's reasonable to default to embed form for any type that is of scalar kind.)\n\n\n\nimplementation detail notes\n---------------------------\n\n### how state machines and maybes work\n\nAssemblers for recursive stuff have state machines that are used to insure\norderly transitions between each key and value assembly,\nand that a complete entry has been assembled before the next entry or the finish.\n(For example, you can't go key-then-key in a map,\nnor start a value and then start another value before finishing the first one in a list,\nnor finish a map when you've just inserted a key and no value, and so forth.)\n\nOne part of this is straightforward: we simply implement state machines,\nusing bog-standard patterns around a typed uint and logical transition guards\nin all the relevant functions.  Done and done.  Except...\n\nHow do child assemblers signal to their parent that they've become finished?\nTheoretically, easy; in practice, to work efficiently...\nThis poses a bit of an implementation challenge.\n\nOne obvious solution is to put a callback field in assemblers, and have\nthe parent assembler supply the child assembler with a callback that can\nupdate the parent's state machine when the child becomes finished.\nThis is logically correct, but practically, problematic and Not Fast:\nit requires generating a closure of some kind which composes the function\npointer with the pointer to that parent assembler: and since this is two words\nof memory, it implies an allocation and (unfortunately) a heap escape.\nAn allocation per child key and value in a recursive structure is unacceptable;\nwe want to set a _much_ higher bar for performance here.\n\nSo, we move on to less obvious solutions: we're all in the same package here,\nso we can twiddle the bits of our neighboring structures quite directly, yes?\nWhat if we just have assemblers contain pointers to a state machine uint,\nand they do a fixed-value compare-and-swap when they're done?\nThis is terrifyingly direct and has no abstractions, yes indeed: but\nwe do generally assume control all the code in this package for any of our\ncorrectness constraints, so this is in-bounds (if admittedly uncomfortable).\n\nNow let's combine that with one more concern: nullables.  When an assembler\nis not at the root of a document, it may need to accept null values.\nWe could do this by generating distinct assembler types for use in positions\nwhere nulls are allowed; but though such an approach would work, it is bulky.\nWe'd much rather be able to reuse assembler types in either scenario.\n\nSo, let's have assemblers contain two pointers:\nthe already-familiar 'w' pointer, and also an 'm' pointer.\nThe 'm' pointer effectively communicates up whether the child has become finished\nwhen it becomes either 'Maybe_Null' or 'Maybe_Value'.\n\nWe add a few new states to the 'm' value, and use it to hint in both directions:\nassemblers will assume nulls are not an acceptable transition *unless* the 'm'\nvalue comes initialized with a hint that we are in a situation where they work.\n\nThe costs here are \"some\": it's another pointer indirection and memory set.\nHowever, compared to the alternatives, it's pretty good: versus an allocation\n(in the callback approach), this is a huge win; and we're even pretty safe to\nbet that that pointer indirection is going to land in a cache line already hot.\n\nYou can find the additional magic consts crammed into `schema.Maybe` fields\nfor this statekeeping during assembly defined in the \"minima\" file in codegen output.\nThey are named `midvalue` and `allowNull`.\n\n\n\nthis could have been different\n------------------------------\n\nThere are many ways this design could've been different:\n\n### we could have every maybe type implement Node\n\nAs already discussed above, it would cause a lot of extra boilerplate methods,\nincreasing both the generated code source size and binary size;\nbut on the plus side, it would've been in some ways arguably more consistent.\n\nWe didn't.\n\n### we could've generated three maybes per type\n\nAlready discussed above.\n\nWe didn't.\n\n### we could've designed schemas differently\n\nA lot of the twists of the design originate from the fact that both `optional`\nand `nullable` are both rather special as well as very contextual in IPLD Schemas\n(e.g., `optional` is only permitted in a very few special places in a schema).\nIf we had built a very different type system, maybe things would come out differently.\n\nSome of this has some exploration in some gists:\n\n- https://gist.github.com/warpfork/9dd8b68deff2b90f96167c900ea31eec#dubious-soln-drop-nullable-completely-make-inline-anonymous-union-syntax-instead\n- https://gist.github.com/warpfork/9dd8b68deff2b90f96167c900ea31eec#soln-change-how-schemas-regard-nullable-and-optional\n- https://gist.github.com/warpfork/9dd8b68deff2b90f96167c900ea31eec#soln-support-absent-as-a-discriminator-in-kinded-unions\n\nBut suffice to say, that's a very big topic.\n\nOptionals and nullables are the way they are because they seemed like useful\nconcepts for describing the structure of data which has serial forms;\nhow they map onto any particular programming language (such as Go) was a secondary concern.\nThis design for a golang library is trying to do its best within that.\n\n### we could've done X with technique Y\n\nProbably, yes :)\n\nThis is just one implementation of codegen for Golang for IPLD Schemas.\nCompeting implementations that make different choices are absolutely welcome :)\n\n\n\n"
  },
  {
    "path": "schema/gen/go/HACKME_memorylayout.md",
    "content": "about memory layout\n===================\n\nMemory layout is important when designing a system for going fast.\nIt also shows up in exported types (whether or not they're pointers, etc).\n\nFor the most part, we try to hide these details;\nor, failing that, at least make them appear consistent.\nThere's some deeper logic required to *pick* which way we do things, though.\n\nThis document was written to describe codegen and all of the tradeoffs here,\nbut much of it (particularly the details about embedding and internal pointers)\nalso strongly informed the design of the core NodeAssembler semantics,\nand thus also may be useful reading to understand some of the forces that\nshaped even the various un-typed node implementations.\n\n\n\nPrerequisite understandings\n---------------------------\n\nThe following headings contain brief summaries of information that's important\nto know in order to understand how we designed the IPLD data structure\nmemory layouts (and how to tune them).\n\nMost of these concepts are common to many programming languages, so you can\nlikely skim those sections if you know them.  Others are fairly golang-specific.\n\n### heap vs stack\n\nThe concept of heap vs stack in Golang is pretty similar to the concept\nin most other languages with garbage collection, so we won't cover it\nin great detail here.\n\nThe key concept to know: the *count* of allocations which are made on\nthe heap significantly affects performance.  Allocations on the heap\nconsume CPU time both when made, and later, as part of GC.\n\nThe *size* of the allocations affects the total memory needed, but\ndoes *not* significantly affect the speed of execution.\n\nAllocations which are made on the stack are (familiarly) effectively free.\n\n### escape analysis\n\n\"Escape Analysis\" refers to the efforts the compiler makes to figure out if some\npiece of memory can be kept on the stack or if it must \"escape\" to the heap.\nIf escape analysis finds that some memory can be kept on the stack,\nit will prefer to do so (and this is faster/preferable because it both means\nallocation is simple and that no 'garbage' is generated to collect later).\n\nSince whether things are allocated on the stack or the heap affects performance,\nthe concept of escape analysis is important.  The details (fortunately) are not:\nFor the purposes of what we need to do in in our IPLD data structures,\nour goal with our code is to A) flunk out and escape to heap\nas soon as possible, but B) do that in one big chunk of memory at once\n(because we'll be able to use [internal pointers](#internal-pointers)\nthereafter).\n\nOne implication of escape analysis that's both useful and easy to note is that\nwhether or not you use a struct literal (`Foo{}`) or a pointer (`&Foo{}`)\n*does not determine* whether that memory gets allocated on the heap or stack.\nIf you use a pointer, the escape analysis can still prove that the pointer\nnever escapes, it will still end up allocated on the stack.\n\nAnother way to thing about this is: use pointers freely!  By using pointers,\nyou're in effect giving the compiler *more* freedom to decide where memory resides;\nin contrast, avoiding the use of pointers in method signitures, etc, will\ngive the compiler *less* choice about where the memory should reside,\nand typically forces copying.  Giving the compiler more freedom generally\nhas better results.\n\n**pro-tip**: you can compile a program with the arguments `-gcflags \"-m -m\"` to\nget lots of information about the escape analysis the compiler performs.\n\n### embed vs pointer\n\nStructs can be embedded -- e.g. `type Foo struct { field Otherstruct }` --\nor referenced by a pointer -- e.g. `type Foo struct { field *Otherstruct }`.\n\nThe difference is substantial.\n\nWhen structs are embedded, the layout in memory of the larger struct is simply\na concatenation of the embedded structs.  This means the amount of memory\nthat structure takes is the sum of the size of all of the embedded things;\nand by the other side of the same coint, the *count* of allocations needed\n(remember! the *count* affects performance more than the *size*, as we briefly\ndiscussed in the [heap-vs-stack](#heap-vs-stack) section) is exactly *one*.\n\nWhen pointers are used instead of embedding, the parent struct is typically\nsmaller (pointers are one word of memory, whereas the embedded thing can often\nbe larger), and null values can be used... but if fields are assigned to some\nother value than null, there's a very high likelihood that heap allocations\nwill start cropping up in the process of creating values to take pointers\nto before then assigning the pointer field!  (This can be subverted by\neither [escape analysis](#escape-analysis) (though it's fairly uncommon),\nor by [internal pointers](#internal-pointers) (which are going to turn out\nvery important, and will be discussed later)... but it's wise to default\nto worrying about it until you can prove that one of the two will save you.)\n\nWhen setting fields, another difference appears: a pointer field takes one\ninstruction (assuming the value already exists, and we're not invoking heap\nallocation to get the pointer!) to assign,\nwhereas an embedded field generally signifies a memcopy, which\nmay take several instructions if the embedded value is large.\n\nYou can see how the choice between use of pointers and embeds results\nin significantly different memory usage and performance characteristics!\n\n(Quick mention in passing: \"cache lines\", etc, are also potential concerns that\ncan be addressed by embedding choices.  However, it's probably wise to attend\nto GC first.  While cache alignment *can* be important, it's almost always going\nto be a winning bet that GC will be a much higher impact concern.)\n\nIt is an unfortunate truth that whether or not a field can be null in Golang\nand whether or not it's a pointer are two properties that are conflated --\nyou can't choose one independently of the other.  (The reasoning for this is\nbased on intuitions around mechanical sympathy -- but it's worth mentioning that\na sufficiently smart compiler *could* address both the logical separation\nand simultaneously have the compiler solve for the mechanical sympathy concerns\nin order to reach good performance in many cases; Golang just doesn't do so.)\n\n### interfaces are two words and may cause implicit allocation\n\nInterfaces in Golang are always two words in size.  The first word is a pointer\nto the type information for what the interface contains.  The second word is\na pointer to the data itself.\n\nThis means if some data is assigned into an interface value, it *must* become\na pointer -- the compiler will do this implicitly; and this is the case even if\nthe type info in the first word retains a claim that the data is not a pointer.\nIn practice, this also almost guarantees in practice that the data in question\nwill escape to the heap.\n\n(This applies even to primitives that are one word in size!  At least, as of\ngolang version 1.13 -- keep an eye on on the `runtime.convT32` functions\nif you want to look into this further; the `mallocgc` call is clear to see.\nThere's a special case inside `malloc` which causes zero values to get a\nfree pass (!), but in all other cases, allocation will occur.)\n\nKnowing this, you probably can conclude a general rule of thumb: if your\napplication is going to put a value in an interface, and *especially* if it's\ngoing to do that more than once, you're probably best off explicitly handling\nit as a pointer rather than a value.  Any other approach will be very likely to\nprovoke unnecessary copy behavior and/or multiple unnecessary heap allocations\nas the value moves in and out of pointer form.\n\n(Fun note: if attempting to probe this by microbenchmarking experiments, be\ncareful to avoid using zero values!  Zero values get special treatment and avoid\nallocations in ways that aren't general.)\n\n### internal pointers\n\n\"Internal pointers\" refer to any pointer taken to some position in a piece\nof memory that was already allocated somewhere.\n\nFor example, given some `type Foo struct { a, b, c Otherstruct }`, the\nvalue of `f := &Foo{}` and `b := &f.b` will be very related: they will\ndiffer by the size of `Otherstruct`!\n\nThe main consequence of this is: using internal pointers can allow you to\nconstruct large structure containing many pointers... *without* using a\ncorrespondingly large *count of allocations*.  This unlocks a lot of potential\nchoices for how to build data structures in memory while minimizing allocs!\n\nInternal pointers are not without their tradeoffs, however: in particular,\ninternal pointers have an interesting relationship with garbage collection.\nWhen there's an internal pointer to some field in a large struct, that pointer\nwill cause the *entire* containing struct to be still considered to be\nreferenced for garbage collection purposes -- that is, *it won't be collected*.\nSo, in our example above, keeping a reference to `&f.b` will in fact cause\nmemory of the size of *three* `Otherstruct`s to be uncollectable, not one.\n\nYou can find more information about internal pointers in this talk:\nhttps://blog.golang.org/ismmkeynote\n\n### inlining functions\n\nFunction inlining is an important compiler optimization.\n\nInlining optimizes in two regards: one, can remove some of the overhead of\nfunction calls; and two, it can enable *other* optimizations by getting the\nrelevant instruction blocks to be located together and thus rearrangeable.\n(Inlining does increase the compiled binary size, so it's not all upside.)\n\nCalling a function has some fixed overhead -- shuffling arguments from registers\ninto calling convention order on the stack; potentially growing the stack; etc.\nWhile these overheads are small in practice... if the function is called many\n(many) times, this overhead can still add up.  Inlining can remove these costs!\n\nMore interestingly, function inlining can also enable *other* optimizations.\nFor example, a function that *would* have caused escape analysis to flunk\nsomething out to the heap *if* that function as called was alone... can\npotentially be inlined in such a way that in its contextual usage,\nthe escape analysis flunking can actually disappear entirely.\nMany other kinds of optimizations can similarly be enabled by inlining.\nThis makes designing library code to be inline-friendly a potentially\nhigh-impact concern -- sometimes even more so than can be easily seen.\n\nThe exact mechanisms used by the compiler to determine what can (and should)\nbe inlined may vary significantly from version to version of the Go compiler,\nwhich means one should be cautious of spending too much time in the details.\nHowever, we *can* make useful choices around things that will predictably\nobstruct inlining -- such as [virtual function calls](#virtual-function-calls).\nOccasionally there are positive stories in teasing the inliner to do well,\nsuch as https://blog.filippo.io/efficient-go-apis-with-the-inliner/ (but these\nseem to generally require a lot of thought and probably aren't the first stop\non most optimization quests).\n\n### virtual function calls\n\nFunction calls which are intermediated by interfaces are called \"virtual\"\nfunction calls.  (You may also encounter the term \"v-table\" in compiler\nand runtime design literature -- this 'v' stands for \"virtual\".)\n\nVirtual function calls generally can't be inlined.  This can have significant\neffects, as described in the [inlining functions](#inlining-functions) section --\nit both means function call overhead can't be removed, and it can have cascading\nconsequences by making other potential optimizations unreachable.\n\n\n\nResultant Design Features\n-------------------------\n\n### concrete implementations\n\nWe generate a concrete type for each type in the schema.\n\nUsing a concrete type means methods on it are possible to inline.\nThis is important to us because most of the methods are \"accessors\" -- that is,\na style of function that has a small body and does little work -- and these\nare precisely the sort of function where inlining can add up.\n\n### natively-typed methods in addition to the general interface\n\nWe generate two sets of methods: **both** the general interface methods to\ncomply with Node and NodeBuilder interfaces, **and** also natively-typed\nvariants of the same methods (e.g. a `Lookup` method for maps that takes\nthe concrete type key and returns the concrete type value, rather than\ntaking and returning `Node` interfaces).\n\nWhile both sets of methods can accomplish the same end goals, both are needed.\nThere are two distinct advantages to natively-typed methods;\nand at the same time, the need for the general methods is system critical.\n\nFirstly, to programmers writing code that can use the concrete types, the\nnatively-typed methods provide more value in the form of compile-time type\nchecking, autocompletion and other tooling assist opportunities, and\nless verbosity.\n\nSecondly, natively-typed functions on concrete types can be higher performance:\nsince they're not [virtual function calls](#virtual-function-calls), we\ncan expect [inlining](#inlining-functions) to work.  We might expect this to\nbe particularly consequential in builders and in accessor methods, since these\ninvolve numerous calls to methods with small bodies -- precisely the sort of\nsituation that often substantially benefits from inlining.\n\nAt the same time, it goes without saying that we need the general Node and\nNodeBuilder interfaces to be satisfied, so that we can write generic library\ncode such as reusable traversals, etc.  It is not possible to satisfy both\nneeds with a single set of methods with the Golang typesystem; therefore,\nwe generate both.\n\n### embed by default\n\nEmbedded structs amortizes the count of memory allocations.\nThis addresses what is typically our biggest concern.\n\nThe increase in size is generally not consequential.  We expect most fields\nend up filled anyway, so reserving that memory up front is reasonable.\n(Indeed, unfilled fields are only possible for nullable or optional fields\nwhich are implemented as embedded.)\n\nIf assigning whole sub-trees at once, assignment into embedded fields\nincurs the cost of a memcopy (whereas by contrast, if fields were pointers,\nassigning them would be cheap... it's just that we would've had to pay\na (possibly _extra_) allocation cost elsewhere earlier.)\nHowever, this is usually a worthy trade.\nLinear memcpy in practice can be significantly cheaper than extra allocations\n(especially if it's one long memcpy vs many allocations);\nand if we assume a balance of use cases such as \"unmarshal happens more often\nthan sub-tree-assignment\", then it's pretty clear we should prioritize getting\nallocation minimization for unmarshal rather than fret sub-tree assignment.\n\n### nodebuilders point to the concrete type\n\nWe generate NodeBuilder types which contain a pointer to the type they build.\n\nThis means we can hold onto the Node pointer when its building is completed,\nand discard the NodeBuilder.  (Or, reset and reuse the NodeBuilder.)\nGarbage collection can apply on the NodeBuilder independently of the lifespan\nof the Node it built.\n\nThis means a single NodeBuilder and its produced Node will require\n**two** allocations -- one for the NodeBuilder, and a separate one for the Node.\n\n(An alternative would be to embed the concrete Node value in the NodeBuilder,\nand return a pointer to when finalizing the creation of the Node;\nhowever, because due to the garbage collection semantics around\n[internal pointers](#internal-pointers), such a design would cause the entirety\nof the memory needed in the NodeBuilder to remain uncollectable as long as\ncompleted Node is reachable!  This would be an unfortunate trade.)\n\nWhile we pay two allocations for the Node and its Builder, we earn that back\nin spades via our approach to recursion with\n[NodeAssemblers](#nodeassemblers-accumulate-mutations), and specifically, how\n[NodeAssemblers embed more NodeAssemblers](#nodeassemblers-embed-nodeassemblers).\nLong story short: we pay two allocations, yes.  But it's *fixed* at two,\nno matter how large and complex the structure is.\n\n### nodeassemblers accumulate mutations\n\nThe NodeBuilder type is only used at the root of construction of a value.\nAfter that, recursion works with an interface called NodeAssembler instead.\n\nA NodeAssembler is essentially the same thing as a NodeBuilder, except\n_it doesn't return a Node_.\n\nThis means we can use the NodeAssembler interface to describe constructing\nthe data in the middle of some complex value, and we're not burdened by the\nneed to be able to return the finished product.  (Sufficient state-keeping\nand defensive checks to ensure we don't leak mutable references would not\ncome for free; reducing the number of points we might need to do this makes\nit possible to create a more efficient system overall.)\n\nThe documentation on the datamodel.NodeAssembler type gives some general\ndescription of this.\n\nNodeBuilder types end up being just a NodeAssembler embed, plus a few methods\nfor exposing the final results and optionally resetting the whole system.\n\n### nodeassemblers embed nodeassemblers\n\nIn addition to each NodeAssembler containing a pointer to the value they modify\n(the same as [NodeBuilders](#nodebuilders-point-to-the-concrete-type))...\nfor assemblers that work with recursive structures, they also embed another\nNodeAssembler for each of their child values.\n\nThis lets us amortize the allocations for all the *assemblers* in the same way\nas embedding in the actual value structs let us amortized allocations there.\n\nThe code for this gets a little complex, and the result also carries several\nadditional limitations to the usage, but it does keep the allocations finite,\nand thus makes the overall performance fast.\n\n(To be more specific, for recursive types that are infinite (namely, maps and\nlists; whereas structs and unions are finite), the NodeAssembler embeds\n*one* NodeAssembler for all values.  (Obviously, we can't embed an infinite\nnumber of them, right?)  This leads to a restriction: you can't assemble\nmultiple children of an infinite recursive value simultaneously.)\n\n### nullable and optional struct fields embed too\n\nTODO intro\n\nThere is some chance of over-allocation in the event of nullable or optional\nfields.  We support tuning that via adjunct configuration to the code generator\nwhich allows you to opt in to using pointers for fields; choosing to do this\nwill of course cause you to lose out on alloc amortization features in exchange.\n\nTODO also resolve the loops note, at bottom\n\n### unexported implementations, exported aliases\n\nOur concrete types are unexported.  For those that need to be exported,\nwe export an alias to the pointer type.\n\nThis has an interesting set of effects:\n\n- copy-by-value from outside the package becomes impossible;\n- creating zero values from outside the package becomes impossible;\n- and yet referring to the type for type assertions remains possible.\n\nThis addresses one downside to using [concrete implementations](#concrete-implementations):\nif the concrete implementation is an exported symbol, it means any code external\nto the package can produce Golang's natural \"zero\" for the type.\nThis is problematic because it's true even if the Golang \"zero\" value for the\ntype doesn't correspond to a valid value.\nWhile keeping an unexported implementation and an exported interface makes\nexternal fabrication of zero values impossible, it breaks inlining.\nExporting an alias of the pointer type, however, strikes both goals at once:\nexternal fabrication of zero values is blocked, and yet inlining works.\n\n\n\nAmusing Details and Edge Cases\n------------------------------\n\n### looped references\n\n// who's job is it to detect this?\n// the schema validator should check it...\n// but something that breaks the cycle *there* doesn't necessarily do so for the emitted code!  aggh!\n//  ... unless we go back to optional and nullable both making ptrs unconditionally.\n\n\n\nLearning more (the hard way)\n----------------------------\n\nIf this document doesn't provide enough information for you,\nyou've probably graduated to the point where doing experiments is next.  :)\n\nPrototypes and research examples can be found in the\n`go-ipld-prime/_rsrch/` directories.\nIn particular, the \"multihoisting\" and \"nodeassembler\" packages are relevant,\ncontaining research that lead to the drafting of this doc,\nas well as some partially-worked alternative interface drafts.\n(You may have to search back through git history to find these directories;\nthey're removed after some time, when the lessons have been applied.)\n\nTests there include some benchmarks (self-explanitory);\nsome tests based on runtime memory stats inspection;\nand some tests which are simply meant to be disassembled and read thusly.\n\nCompiler flags can provide useful insights:\n\n- `-gcflags '-S'` -- gives you assembler dump.\n\t- read this to see for sure what's inlined and not.\n\t- easy to quickly skim for calls like `runtime.newObject`, etc.\n\t- often critically useful to ensure a benchmark hasn't optimized out the question you meant to ask it!\n\t- generally gives a ground truth which puts an end to guessing.\n- `-gcflags '-m -m'` -- reports escape analysis and other decisions.\n   - note the two m's -- not a typo: this gives you info in stack form,\n\t  which is radically more informative than the single-m output.\n- `-gcflags '-l'` -- disables inlining!\n\t- useful on benchmarks to quickly detect whether inlining is a major part of performance.\n\nThese flags can apply to any command like `go install`... as well as `go test`.\n\nProfiling information collected from live systems in use is of course always\nintensely useful... if you have any on hand.  When handling this, be aware of\nhow data-dependent performance can be when handling serialization systems:\ndifferent workload content can very much lead to different hot spots.\n\nHappy hunting.\n"
  },
  {
    "path": "schema/gen/go/HACKME_scalars.md",
    "content": "What's the deal with scalars, anyway?\n=====================================\n\nTwo sorts of scalars\n--------------------\n\nThere are two sorts of scalars that show up in codegen:\n\n- 1: scalars that are just the plain kind (e.g. \"string\", not even named);\n- 2: scalars that have named types.\n\nPlain scalars can't have any special rules or semantics attached to them.\n\nNamed types with scalar kinds (aka a \"typedef\") **can** have additional rules and semantics attached to them.\n\nLet's talk about named scalars first, because it's clearer that there's fun there.\n\n\n### named scalars\n\nNamed scalars cause a type to be generated.\nThat type information is part of their identity (practically speaking: affects their definition of equality).\n\n#### named scalars are never equal even if their contents are\n\nIt stands to reason that named scalars can't be freely interchanged.\n\nIf you have a schema:\n\n```ipldsch\ntype Foo string\ntype Bar string\n```\n\n... then you'll get codegen output code with an exported type for each:\n\n```go\ntype Foo struct{ x string }\n/*...*/\n\ntype Bar struct{ x string }\n/*...*/\n```\n\n... and clearly, `(Foo{\"asdf\"} == Bar{\"asdf\"}) == false`.\n\n#### named scalars appear in specialized method argument types and return types\n\nJust like any other named type, named scalars will appear in specialized methods\nwhich are exported on codegen'd types.\n\nFor example, if you have a schema:\n\n```ipldsch\ntype Foo string\ntype Bar string\ntype Foomp map {Foo:Bar}\n```\n\n... then you'll get codegen output code which includes a method on Foomp:\n\n```go\nfunc (x *Foomp) LookupByNode(k *Foo) (*Bar) { /*...*/ }\n```\n\nSuch specialized methods are often much shorter, much more efficient to execute,\nand involve much less error handling to use than their more generalized\ncounterparts on the `datamodel.Node` interface.\n\nNote that when named scalars appear in the signitures of specialized methods,\nthey always appear as pointers.  They will never be `nil`, but there is still\na reason that pointers are used here, and it's based on performance.\n(The details don't matter as a user, but: it means if those values need to be\nregarded as the `datamodel.Node` interface again in the future, that boxing is\ninexpensive since we already have a (heap-escaped long ago) pointer.\nBy contrast, copying by value in more places is likely to result in more\nheap escapes and thus additional undesirable new allocation costs in the\n(entirely common!) case that the values end up handled as `datamodel.Node` later.)\n\n#### named scalars have a specialized method which unboxes them to a native primitive unconditionally\n\nEvery named scalar type as a specialized unbox method corresponding to its kind.\n\nFor example, for a `type Foo string`, there will be a `func (f Foo) String() string` method\n(in addition to the `func (f Foo) AsString() (string, error)` method,\nwhich does the same thing but is stuck presenting an error due to interface conformance even though we know that it's statically impossible).\n\n#### named scalars can have additional methods attached to them\n\nIt's possible for users of codegen to attach additional methods to the types\ngenerated for a named scalar.\n\nThis can be either done for purely aesthetic/ergonomic purposes particular\nto the user's exact product, or, as part of some extended library features.\nFor example, we plan support extended features like \"validation\" methods\nvia detecting when a user adds a `Valdiate() error` method to a generated type.\n\n\n### plain scalars\n\nPlain scalars also cause a type to be generated;\none type for each kind in the Data Model is sufficient.\n\nPlain scalars show up in codegen output packages almost exactly as if\nthere was a short preamble in every schema:\n\n```ipldsch\ntype Int int\ntype Bool bool\ntype Float float\ntype String string\ntype Bytes bytes\n```\n\n#### note about schema syntax\n\nThere's an issue about capitalization that's somewhat unresolved in schemas:\nnamely, is `type Fwee struct { someField string }` allowed, or a parse error?\n\nThis syntax is questionable because it means some of the scalar kind identifier\nkeywords are allowed in the same place as type names,\nand it's potentially confusing because when we come to interacting with the\ngenerated output code in golang, we still have `String`-with-a-capital-S\nas a type identifier.\n\nAt any rate, it seems clear that you can mentally capitalize the 's'\nat any time you see this debatable syntax.\n\n(We should resolve this issue in the specs, which are in the `datamodel.specs` repo.)\n\n#### plain scalars appear in specialized method argument types and return types\n\nThis is the same story as for named scalars.\n\nFor example, if you have a schema:\n\n```ipldsch\ntype Foomp map {String:String}\n```\n\n... then you'll get codegen output code which includes a method on Foomp:\n\n```go\nfunc (x *Foomp) LookupByNode(k String) (String) { /*...*/ }\n```\n\n(The exact symbols involved and whether or not they're pointers may vary.)\n\nThe type might carry less semantic information than it does when a\nnamed scalar shows up in the same position, but we still use a generated\ntype (and a pointer) here for two reasons: first of all, and more simply,\nconsistency; but secondly, for the same performance reasons as applied\nto named scalars (if we need to treat this value as an `datamodel.Node` again\nin the future, it's much better if we already have a heap pointer rather\nthan a bare primitive value (`runtime.convT*` functions are often not your\nfavorite thing to see in a pprof flamegraph)).\n\n(FUTURE: this is still worth review.  We might actually want to use\nbare primitives in a lot of these cases, because surely, if you're about\nto want to treat something as an `datamodel.Node` again, then you can use the\ngeneralized methods conforming to `datamodel.Node` which already yield that...?\nWe'll get more information and impressions about this after trying to use\ncodegen in bulk (especially the specialized methods).)\n\n#### plain scalars do not allow additional method attachedments\n\nWhile we can't *stop* developers from modifying the source code emitted by codegen,\nadding a method to any of the plain scalars is intensely discouraged.\nNothing sensible or good can come of trying to attach a \"Validate\" method\nto something like the `String` type.  Don't do it.\n\n\nCode reuse for plain scalars\n----------------------------\n\nWe *always* need some type that can contain a plain scalar while also\nimplementing all the `datamodel.Node` methods.  Even if we didn't export it\nor show it in any method signitures anywhere at all, we'd *still* need it\nfor internal implementation of other types, because it's important those\ntypes be able to return a pointer to their fields in their implements of\nthe `datamodel.Node` contract (otherwise, they'd be terribly slow and alloc-heavy).\n\n### can we reuse another package's plain scalars?\n\nSince there's no functional difference between the plain scalars in a schema\nand the scalars implementation from another package that's untyped in the first place,\ncan we reuse some code from an untyped package in codegen output packages?\n\nNo.\n\n(Or: \"maybe, conditionally, and it would have a lot of caveats and make the\nuntyped package we try to hitch a ride on become significantly weirder, so...\nit's probably not worth it\".)\n\nThe reason to desire this so there's less (admittedly quite duplicative) code\nin the package emitted by using codegen.\n\nHowever, there are *many* \"cons\" which outweigh that single \"pro\":\n\n- This would require the untyped package to export their concrete implementation types.\n\t- This is the *only* reason those implementation types would need to be exported, which is a concerning smell all by itself.\n\t- In the case of we consider using the 'basicnode' package in particular:\n\t\t- Exporting those types allows creation by casting, which exposes an API surface that's not conventional (nor necessarily even possible) for other packages, and will thus be likely to create confusion as well as create multiple ways of doing things which will make refactors harder.\n\t\t\t- We don't like allowing casting for creating values in general for reasons explored well in the go-cid refactors to use wrapper structs: if casting is possible, it's far too easy for an end-user to write shoddy code which dodges all constructors and validation logic.\n\t\t- Exporting those types allows unboxing by casting, which again exposes an API surface that's not conventional (nor necessarily even possible) for other packages, and will thus be likely to create confusion as well as create multiple ways of doing things which will make refactors harder.\n\t\t\t- Since we're talking about scalars and they're essentially copy-by-value (except for bytes -- but we give up and rely on \"lawful\" code for those anyway, since defensive copies are completely nonviable in performance terms), this doesn't create incorrectness issues... but it's still not *good*.\n\t\t\t- Note that while casting to concrete types exported by the output package of codegen is considered acceptable, this is a different beast: you still can't get the raw content out without using at least one more unboxing method; and, if you're casting or doing a type switch with type in a codegen package, it should already instantly be clear that your code is no longer general-purpose, and this will surprise no one.\n\t\t- ...And while the above two are true only because the implementation is by typedefs and they could be fixed by using a wrapper struct... that fix would have exactly the effect of making reuse impossible anyway, since the field in that wrapper struct would need to be unexported (otherwise, immutability would then in turn trivially shatter).\n\t\t- The implementation of the scalar for link kinds can't be reused anyway (it *does* use a wrapper struct already, and needs to; type aliases on an interface don't permit adding methods), adding yet more inconsistency and jagged edges to the picture.\n\t\t- The \"more unnecessarily(-for-end-user-perspectives) exported symbols\" code smell counts about 10x as hard for this package in particular, since it's often one of the first ones a newcomer to this library will see: there shouldn't be weird designs with elaborate and far away justifications poking up here.\n- Reusing concrete types between packages makes it more likely uncautious users could write code that uses native equality on scalars and get away with it *sometimes*.  Since this is still incorrect and would sometimes fail in fully general code, it's better if code like this flunks out as early as possible, which results in a better ecosystem overall.\n- We like it when error messages can include a type name.  It's marginally better for that to be something like \"gendemo.String\" ('gendemo' being consistent with whatever the rest of the package also says) than just bare \"string\".\n\nThere are also a few bits that aren't entirely known (at least, at the time of this writing):\nnamely, how 'any' types are going to be handled in codegen.\nProbably, though, the answer is: it's just treated as 'datamodel.Node',\nand the codegen package doesn't export *any* more types which regard this situation because that's already sufficient.\n\nLong story short?  It's better to have plain scalar types in codegen output,\neven if they look somewhat duplicative,\nbecause trying to do anything fancier either fails outright\nor spawns ridiculously detailed epicycles of complexity.\nEmitting the plain scalar types in codegen output\nis *more consistent* in almost every way,\nwill generate less cognitive load for users,\nand just plain *works unconditionally*.\n"
  },
  {
    "path": "schema/gen/go/HACKME_templates.md",
    "content": "Notes about how Templates are used in this package\n==================================================\n\nThis package makes heavy use of go's `text/template`.\n\nSome of it is not pretty.  But beware of trying to trade elegance for legibility.\n\nAn overview of the choices that got us here:\n\n### string templating is fine\n\nString templating for code is fine, actually.\n\nAn alternative would be to use the golang AST packages.\nWhile those are nice... for our purposes, they're a bit verbose.\nIt's not necessarily helpful to have the visual distance between our\ngeneration code and the actual result _increase_ (at least, without a good reason).\n\n### don't make indirections around uncomplicated munges\n\nDon't make indirections that aren't needed for simple string operations.\n(This goes for both the template funcmap, or in the form of reusable templates.)\n\nOne very common situation is that for some type `T`, there's a related thing to be generated\ncalled `T__Foo`, where \"Foo\" is some kind of modifier that is completely predictable\nand not user-selected nor configurable.\n\nIn this situation: simply conjoining `{{ .T }}__Foo` as string in the template is fine!\nDon't turn it into a shell game with functions that make the reader jump around more to see what's happening.\n(Even when refactoring, it's easy enough to use simple string replace on these patterns;\nextracting a function to enable \"changing it in one place\" doesn't really add much value.)\n\nIf there's something more complicated going on, or it's user-configurable?\nFine, get more functions involved.  But be judicious about it.\n\n(An earlier draft of the code introduced a new method for each modifier form in the example above.\nThe result was... just repeating the modifiers in the function name in the template!\nIt produced more code, yet no additional flexibility.\nIt is advisable to resist making this mistake again ;))\n\n### maintain distinction between **symbol** versus **name**\n\n- **symbol** is what is used in type and function names in code.\n- **name** is the string that comes from the schema; it is never modified nor overridable.\n\nSymbols can change based on adjunct config.\n(In theory, they could also be munged to avoid collisions with language constructs\nor favor certain library conventions... however, this is currently not automatic.)\n\nNames can't change.  They're _exactly_ what was written in in the Schema.\n\nTypes and functions and most of the _code_ part of codegen use Symbols.\nError messages, reflectable type information, etc, use Names.\n\nSymbols may also need to be _generated_ for types that don't have names.\nFor example, `type Foo struct { field {String:Int} }` might result in codegen\ncreating *two* symbols: `Foo`, and `Map__String__Int`.\n\nOne way to check that the goal is being satisfied is to consider that\nsomeone just experiencing error messages from a program should not end up exposed to any information about:\n\n- what language the program is written in,\n- or which codegen tool was used (or even *if* a codegen tool was used),\n- or what adjunct config was present when codegen was performed.\n\n(n.b. this consideration does not include errors with stack traces -- then\nof course you will unavoidably see symbols appear.)\n\n### anything that is configurable goes through adjunctCfg; adjunctCfg is accessed via the template funcmap\n\nFor example, all Symbol processing all pipes through an adjunct configuration object.\nWe make this available in the templates via a funcmap so it's available context-free as a nice tidy pipe syntax.\n\n### there are several kinds of reuse\n\n(Oh, boy.)\n\nIt may be wise to read the [\"values we can balance\"](./HACKME_tradeoffs.md#values-we-can-balance) document before continuing.\nThere's also a _seventh_ tradeoff to consider, in addition to those from that document:\nhow much reuse there is in our _template_ code, and (_eighth!_) how _readable_ and maintainable the template code is.\nAlso, (_ninth!!_) how _fast_ the template code is.\n\nWe've generally favored *all* of the priorities for the output code (speed, size, allocation count, etc) over the niceness of the codegen.\nWe've also _completely_ disregarded speed of the template code (it's always going to be \"fast enough\"; you don't run this in a hot loop!).\nWhen there's a tension between readability and reuse, we've often favored readability.\nThat means sometimes text is outright duplicated, if it seemed like extracting it would make it harder to read the template.\n\nHere's what we've ended up with:\n\n- There are mixins from the `node/mixins` package, which save some amount of code and standardize some behaviors.\n\t- These end up in the final result code.\n\t- It doesn't save *much* code, and they generally don't save *any* binary size (because it all gets inlined).\n\t- The consistency is the main virtue of these.\n\t- These are used mainly for error handling (specifically, returning of errors for methods called on nodes that have the wrong kind for that method).\n- There are mixins from the `schema/gen/go/mixins` package.\n\t- These are in the template code only -- they don't show up in the final result code.\n\t- These attempt to make it easier to create new 'generator' types.  (There's a 'generator' type for each kind-plus-representation.)\n\t- They only attempt to take away some boilerplate, and you don't _have_ to use them.\n- There are functions in the template funcmap.\n\t- ... not many of them, though.\n- There's the idea of using associated templates (templates that are invoked by other templates).\n\t- There's currently none of this in use.  Might it be helpful?  Maybe.\n- There are functions which apply well-known templates to a generator.\n\t- These compose at the golang level, so it's easy to have the compiler check that they're all in order without running them (unlike templates, which have to be exercised in order to detect even basic problems like \"does this named template exist\").\n\t- Many of these assume some pattern of methods on the generator objects.  (Not of all these are super well documented.)\n\t- Generators usually call out to one or more of these from within the methods that their interface requires them to have.\n- The generator types themselves are usually split into two parts: the mechanisms for type-plus-repr, and just mechanisms for the type.\n\t- The mechanisms for the type alone aren't actually a full generator.  The type-plus-repr thing just embeds the type-level semantics in itself.\n\n*Mostly*, it's general aim has been to keep relatively close to the structure of the code being generated.\nWhen reading a generator, one generally has to do *zero* or *one* jump-to-definition in order to see the fulltext of a template -- no more than that.\n(And so far, all those jump-to-definition lookups are on _go code_, not inside the template -- so an IDE can help you.)\n\nBy example: if there are things which turn out common between _representation kinds_,\nthose will probably end up in a function containing a well-known template,\nand that will end up being called from the generator type in one of the functions its required to have per its interface contract.\n\nThis all probably has plenty of room for improvement!\nBut know you know the reasoning that got things to be in the shape they are.\n"
  },
  {
    "path": "schema/gen/go/HACKME_testing.md",
    "content": "Testing Generated Code\n======================\n\nGetting nice testing scenarios for generated code is tricky.\n\nThere are three major phases of testing we can do:\n\n1. unit tests on the codegen tooling itself\n2. tests that the emitted generated code can compile\n3. behavioral tests on the emitted generated code\n\nGroups 1 and 2 are pretty easy (and we don't have a lot of group 1,\nbecause group 2 covers it pretty nicely).\n\nGroup 3, however, is tricky.\nThe rest of the document will talk more about this kind of testing.\n\n\nBehavioral Tests\n----------------\n\n### Behavioral tests are run via plugins\n\nThis package does some fancy footwork with the golang `plugin` system\nand `go build -buildmode=plugin` in order to compile and load the\ngenerated code into the same memory as the test process,\nthereby letting us do behavioral tests on the gen'd code quite seamlessly.\n\nThis does have some downsides -- namely, the `plugin` system requires\nthe use of `cgo`.  This means you'll need more things installed on your\nhost system than just the go toolchain -- you might need `gcc` and friends too.\nThe `plugin` system also (at time of writing) doesn't support windows.\nYou can skip the behavioral tests if this is a problem: see the next section.\n\n### Skipping the behavioral tests\n\nYou can skip behavioral tests by adding a build tag of `\"skipgenbehavtests\"`.\nThey'll also be automatically skipped if you're running in `\"!cgo\"` mode --\nhowever, the `go` tools don't automatically set `\"!cgo\"` just because it\ndoesn't have enough tools, so you'll still need to be explicit about this.\n\nThe ability of the generated code to be compiled will still be checked,\neven if the behavioral tests are skipped.\n\nYou can grep through your test output for \"bhvtest=skip\" to see at-a-glance\nif the behavioral tests are being skipped.\n\n### Plugins don't jive with race detection\n\nLong story short: if running tests with the race detector, skip the gen tests.\nAny `go test -race` is going to need `go test -race -tags 'skipgenbehavtests'`.\n\nThe go plugin system requires the plugin and host process have the same \"runtime\".\nThe way '-race' works makes for an effectively distinct runtime.\n\n### Alternatives to plugins\n\nAre there other ways this could be done?  Well, surely.  There always are.\n\nInvoking 'go test' as a subprocess is usually central to alternative ideas,\nbut this has several downsides I haven't yet figured out how to counter:\n\n- it tends to result in very difficult-to-wrangle output;\n- it ends up imposing a lot of constraints on file organization,\n  which in turn makes writing tests into a very high-friction endeavour;\n- passing down flags to the test process (e.g., '-v' and friends)\n  begins to require additional infrastructure;\n- some flags such as '-run' are even yet more difficult to pass down usefully;\n- every single behavioral test has to have an exported top-level function,\n  making some things that are trivial with closures now difficult...\n- You get the idea.\n\nYou can see some attempts around\ncommit 79de0e26469f0d2899c813a2c70d921fe5946f23 and its halfdozen or so\nparents; remarks can be found in the git commit messages.\n\nThere are probably yet more variations in ways files and functions could\nbe reorganized, particularly to minimize the downsides of the file and\npackage splitting requirements, but if you're looking at this scenario and\nwanting to propose one... Do read those commits to avoid getting into a\nChesterton's Fence situation, and kindly try it before proposing it.\nNot all of the hurdles are immediately obvious.\n\n### Plugins are only used in testing\n\nThis might not need a clarification statement, but just in case it does:\n**plugins** (and by extension, cgo) **are not necessary**\nfor **doing** codegen nor for **using** the resulting generated code.\nThey are _only_ used for our testing of the codegen tooling\n(and specifically, at that, for the behavioral tests).\nWe would not foist a dependency like cgo on codegen users.\n"
  },
  {
    "path": "schema/gen/go/HACKME_tradeoffs.md",
    "content": "tradeoffs and design decisions in codegen\n=========================================\n\nIn creating codegen for IPLD, as with any piece of software,\nthere are design decisions to be made, and tradeoffs to be considered.\n\nSome of these decisions and tradeoffs are particularly interesting\nin IPLD codegen because they're:\n\n- significantly different resolutions and answers than the same decisions for non-codegen Node implementations\n- able to make significantly different choices, expanding the decision space dimentionality, since they have more information before compile-time\n- can reach higher upper bounds of performance, due to that pre-compile-time foothold\n- have correspondingly less flexibility in many ways because of the same.\n\n\nvalues we can balance\n---------------------\n\nLet's enumerate the things we can balance (and give them some short reference codes):\n\n- AS: assembly/binary/final-shipping size, in bytes\n- BM: builder memory, in bytes, used as long as a NodeBuilder is in use\n- SP: execution speed, in seconds, especially of NodeBuilder in deserialization use\n- AC: allocations, in count, needed for operations (though in truth, this is just a proxy for SP due to its outsized impact there)\n- ERG: ergonomics, as an ineffable, ellusive-to-measurement sort of vibe of the thing, and how well it self-explains use and deters erroneous application\n- GLOC: generated lines of code, as a line count or in bytes, of interest because it may be of noticeable cost in version control weight\n\nThis list is in particular regarding concerns that come to light in considering performant deserialization operations...\nhowever, it's fairly representative of general use as well:\ntraversals and serialization are generally easier situations to handle (they essentially get to skip the \"BM\" term);\nand while different operations might encounter different scalars for how much these different values affect them,\nas we'll see in the prioritization coming up in the next section... that turns out not to matter for our priorities.\n\nWe can also other code which knows it's addressing generated code can use special methods,\n  which means we can in a way disregard its effect on this ordering (mostly).\n\nSide note: though \"AC\" is *mostly* just a proxy for SP,\nAC can also count on its own in *addition* to SP because it increases the *variance* in SP.\n(But we don't often regard this; it's a pretty fine detail, and the goal is \"minimize\" either way.)\n\n\nprioritization of those values\n------------------------------\n\nThe designs here emerge from `SP > BM > AS`.\n\nMore fully: `SP|AC > BM > ERG > AS > GLOC`.\n\nIn other words: speed is the overwhelming priority;\nthereafter, we'd like to conserve memory (but will readily sell it for speed);\nergonomics takes a side seat to both of these (the intention being that we can add 'porcelain' layers separately later);\nassembly size is a concern but fourth fiddle (if this is your dominant concern, you may not want to use codegen, or may want a different library implementation that aims at the same specs);\nand generated code size is a concern but we'll trade it away for any of the other priorities\n(because it's a cost that doesn't end up affecting final users of products built with this system!).\n\n(Some caveats: it's still possible to consider it a red flag if ratios on these get wild.\nFor example if BM gets > 2x, it's questionable;\nand at some point we could imagine saying that AS has really gotten out of hand.)\n\n(BM also has some special conditions such that if it increases on recursive kinds, but not on scalars,\nwe regard that as roughly half price, because generally most of a tree is leaves.\n(As it happens, though, this has turned out not to change any results much.))\n\n\"Ergonomics\" remains a tricky to account for.\nIt's true that when push comes to shove, speed and memory economy win.\nBut it's not at all single-dimentional; and with codegen, there are many options\nwhich set a higher bar for all three concerns at the same time.\n(In contrast, there's a stark upper limit to the ergonomic possbilities for\nnon-codegen no-schema handling of data -- code handling the data model has\nthe limits that its monomorphized approach imposes on it, and there's little\nthat can be done to avoid or improve upon that.)\n"
  },
  {
    "path": "schema/gen/go/HACKME_wip.md",
    "content": "\n### absent values\n\nThe handling of absent values is still not consistent.\n\nCurrently:\n\n- reading (via accessors or iterators) yields `datamodel.Absent` values for absent fields\n- putting those datamodel.Absent values via NodeAssembler.AssignNode will result in `ErrWrongKind`.\n- *the recursive copies embedded in AssignNode methods don't handle absents either*.\n\nThe first two are defensible and consistent (if not necessarily ergonomic).\nThe third is downright a bug, and needs to be fixed.\n\nHow we fix it is not entirely settled.\n\n- Option 1: keep the hostility to absent assignment\n- Option 2: *require* explicit absent assignment\n- Option 3: become indifferent to absent assignment when it's valid\n- Option 4: don't yield values that are absent during iteration at all\n\nOption 3 seems the most preferable (and least user-hostile).\n(Options 1 and 2 create work for end users;\nOption 4 has questionable logical consistency.)\n\nUpdating the codegen to do Option 3 needs some work, though.\n\nIt's likely that the way to go about this would involve adding two more valid\nbit states to the extended schema.Maybe values: one for allowAbsent (similar to\nthe existing allowNull), and another for both (for \"nullable optional\" fields).\nEvery NodeAssembler would then have to support that, just as they each support allowNull now.\n\nI think the above design is valid, but it's not implemented nor tested yet.\n\n\n### AssignNode optimality\n\nThe AssignNode methods we generate currently do pretty blithe things with large structures:\nthey iterate over the given node, and hurl entries into the assembler's AssignKey and AssignValue methods.\n\nThis isn't always optimal.\nFor any structure that is more efficient when fed info in an ideal order, we might want to take account of that.\n\nFor example, unions with representation mode \"inline\" are a stellar example of this:\nif the discriminant key comes first, they can work *much, much* more efficiently.\nBy contrast, if the discriminant key shows up late in the object, it is necessary to\nhave buffered *all the other* data, then backtrack to handle it once the discriminant is found and parsed.\n\nAt best, this probably means iterating once, plucking out the discriminant entry,\nand then *getting a new iterator* that starts from the beginning (which shifts\nthe buffer problem to the Node we're consuming data from).\n\nEven more irritatingly: since NodeAssembler has to accept entries in any order\nif it is to accept information streamingly from codecs, the NodeAssembler\n*also* has to be ready to do the buffering work...\nTODO ouch what are the ValueAssembler going to yield for dealing with children?\nTODO we have to hand out dummy ValueAssembler types that buffer... a crazy amount of stuff.  (Reinvent refmt.Tok??  argh.)  cannot avoid???\nTODO this means where errors arise from will be nuts: you can't say if anything is wrong until you figure out the discriminant.  then we replay everything?  your errors for deeper stuff will appear... uh... midway, from a random AssembleValue finishing that happens to be for the discriminant.  that is not pleasant.\n\n... let's leave that thought aside: suffice to say, some assemblers are *really*\nnot happy or performant if they have to accept things in unpleasant orderings.\n\nSo.\n\nWe should flip all this on its head.  The AssignNode methods should lean in\non the knowledge they have about the structure they're building, and assume\nthat the Node we're copying content from supports random access:\npluck the fields that we care most about out first with direct lookups,\nand only use iteration to cover the remaining data that the new structure\ndoesn't care about the ordering of.\n\nPerhaps this only matters for certain styles of unions.\n\n\n### sidenote about codec interfaces\n\nPerhaps we should get used to the idea of codec packages offering two styles of methods:\n\n- `UnmarshalIntoAssembler(io.Reader, datamodel.NodeAssembler) error`\n\t- this is for when you have opinions about what kind of in-memory format should be used\n- `Unmarshal(io.Reader) (datamodel.Node, error)`\n\t- this is for when you want to let the codec pick.\n\nWe might actually end up preferring the latter in a fair number of cases.\n\nLooking at this inline union ordering situation described above:\nthe best path through that (other than saying \"don't fking use inline unions,\nand if you do, put the discriminant in the first fking entry or gtfo\") would probably be\nto do a cbor (or whatever) unmarshal that produces the half-deserialized skip-list nodes\n(which are specialized to the cbor format rather than general purpose, but we want that in this story)...\nand those can then claim to do random access, thereby letting them take on the \"buffering\".\nThis approach would let the serialization-specialized nodes take on the work,\nrather than forcing the union's NodeAssembler to do buffer at a higher level...\nwhich is good because doing that buffering in a structured way at a higher level\nis actually more work and causes more memory fragmentation and allocations.\n\nWhew.\n\nI have not worked out what this implies for multicodecs or other muxes that do compositions of codecs.\n\n\n### enums of union keys\n\nIt's extremely common to have an enum that is the discrimant values of a union.\n\nWe should make a schema syntax for that.\n\nWe tend to generate such an enum in codegen anyway, for various purposes.\nMight as well let people name it outright too, if they have the slightest desire to do so.\n\n(Doesn't apply to kinded unions.)\n\n\n### can reset methods be replaced with duff's device?\n\nYes.  Well, sort of.  Okay, no.\n\nIt's close!  Assemblers were all written such that their zero values are ready to go.\n\nHowever, there's a couple of situations where you *wouldn't* want to blithely zero everything:\nfor example, if an assembler has to do some allocations, but they're reusable,\nyou wouldn't want to turn those other objects into garbage by zeroing the pointer to them.\nSee the following section about new-alloc child assemblers for an example of this.\n\n\n### what's up with new-alloc child assemblers?\n\nMostly, child assemblers are embedded in the assembler for the type that contains them;\nthis is part of our allocation amortization strategy and important to performance.\nHowever, it doesn't always apply:\nSometimes we *need* independently allocated assemblers, even when they're child assemblers:\nrecursive structures need this (otherwise, how big would the slab be?  infinite?  no; halt).\nSometimes we also just *want* them, somewhat more mildly: if a union is one of several things,\nand some of them are uncommonly used but huuuuge, then maybe we'd rather allocate the child assemblers\nindividually on demand rather than pay a large resident memory cost to embed all the possibilities.\n\nThere's a couple things to think about with these:\n\n- resetting assemblers with a duff's device strategy wouldn't recursively reset these;\n  it would just orphan them.  While possibly leaving them pointed into some parts of memory in the parent slab ('cm' in particular comes to mind).\n  This could be a significant correctness issue.\n   - But who's responsibility is it to \"safe\" this?  Nilling 'w' proactively should also make this pretty innocuous, as one option (but we don't currently do this).\n\n- if the parent assembler is being used in some highly reusable situation (e.g. it's a list value or map value),\n  is the parent able to hold onto and re-use the child assembler?  We probably usually still want to do this, even if it's in a separate piece of heap.\n  - For unions, there's a question of if we should hold onto each child assembler, or just the most recent; that's a choice we could make and tune.\n    If the answer is \"most recent only\", we could even crank down the resident size by use of more interfaces instead of concrete types (at the cost of some other runtime performance debufs, most likely).\n\nWe've chosen to discard the possibility of duff's device as an assembler resetting implementation.\nAs a result, we don't have to do proactive 'w'-nil'ing in places we might otherwise have to.\nAnd union assemblers hold on to all child assembler types they've ever needed.\n"
  },
  {
    "path": "schema/gen/go/README.md",
    "content": "gengo\n=====\n\nThis package contains a codegenerator for emitting Golang source code\nfor datastructures based on IPLD Schemas.\n\nIt is reasonably complete.  See the [feature table](#completeness) below for details.\n\nThere is a CLI tool which can be used to run this generator.\nSee https://github.com/ipld/go-ipldtool !\n\nSome features may still requiring writing code to fully configure them.\n(PRs, here or in the go-ipldtool repo, welcome.)\n\nSee [README_behaviors](README_behaviors.md) for notes about the behaviors of the code output by the generator.\n\nCheck out the [HACKME](HACKME.md) document for more info about the internals,\nhow they're organized, and how to hack on this package.\n\n\naims\n----\n\n`gengo` aims to:\n\n- generate native Golang code\n- that faithfully represents the data structuring specified by an IPLD Schema,\n- operating efficiently, both in speed (both creating and inspecting) and memory compactness;\n- producing a better type system for Golang (we've got unions and enums!)\n- that is both powerful and generic (when you need it)\n- and minimalist (when you don't),\n- with immutable data structures,\n- good validation primitives and type-supported safety systems,\n- and is friendly to embellishments of other hand-written Golang code.\n\nSome of these aims should be satisfied.\n\nSome are still a stretch ;)  (we definitely don't have \"minimalist\" outputs, yet.\nMaking this reachable by tuning is a goal, however!)\n\n\ncompleteness\n------------\n\nLegend:\n\n- `✔` - supported!\n- `✘` - not currently supported.\n- `⚠` - not currently supported -- and might not be obvious; be careful.\n- `-` - is not applicable\n- `?` - feature definition needed!  (applies to many of the \"native extras\" rows -- often there's partial features, but also room for more.)\n- ` ` - table is not finished, please refer to the code and help fix the table :)\n\n| feature                          | accessors | builders |\n|:---------------------------------|:---------:|:--------:|\n| structs                          |    ...    |    ...   |\n| ... type level                   |     ✔     |     ✔    |\n| ... native extras                |     ?     |     ?    |\n| ... map representation           |     ✔     |     ✔    |\n| ... ... including optional       |     ✔     |     ✔    |\n| ... ... including renames        |     ✔     |     ✔    |\n| ... ... including implicits      |     ⚠     |     ⚠    |\n| ... tuple representation         |     ✔     |     ✔    |\n| ... ... including optional       |     ✔     |     ✔    |\n| ... ... including renames        |     -     |     -    |\n| ... ... including implicits      |     ⚠     |     ⚠    |\n| ... stringjoin representation    |     ✔     |     ✔    |\n| ... ... including optional       |     -     |     -    |\n| ... ... including renames        |     -     |     -    |\n| ... ... including implicits      |     -     |     -    |\n| ... stringpairs representation   |     ✘     |     ✘    |\n| ... ... including optional       |           |          |\n| ... ... including renames        |           |          |\n| ... ... including implicits      |           |          |\n| ... listpairs representation     |     ✘     |     ✘    |\n| ... ... including optional       |           |          |\n| ... ... including renames        |           |          |\n| ... ... including implicits      |           |          |\n\n| feature                          | accessors | builders |\n|:---------------------------------|:---------:|:--------:|\n| lists                            |    ...    |    ...   |\n| ... type level                   |     ✔     |     ✔    |\n| ... native extras                |     ?     |     ?    |\n| ... list representation          |     ✔     |     ✔    |\n\n| feature                          | accessors | builders |\n|:---------------------------------|:---------:|:--------:|\n| maps                             |    ...    |    ...   |\n| ... type level                   |     ✔     |     ✔    |\n| ... native extras                |     ?     |     ?    |\n| ... map representation           |     ✔     |     ✔    |\n| ... stringpairs representation   |     ✘     |     ✘    |\n| ... listpairs representation     |     ✘     |     ✘    |\n\n| feature                          | accessors | builders |\n|:---------------------------------|:---------:|:--------:|\n| unions                           |    ...    |    ...   |\n| ... type level                   |     ✔     |     ✔    |\n| ... keyed representation         |     ✔     |     ✔    |\n| ... envelope representation      |     ✘     |     ✘    |\n| ... kinded representation        |     ✔     |     ✔    |\n| ... inline representation        |     ✘     |     ✘    |\n| ... stringprefix representation  |     ✔     |     ✔    |\n| ... byteprefix representation    |     ✘     |     ✘    |\n \n| feature                          | accessors | builders |\n|:---------------------------------|:---------:|:--------:|\n| strings                          |     ✔     |     ✔    |\n| bytes                            |     ✔     |     ✔    |\n| ints                             |     ✔     |     ✔    |\n| floats                           |     ✔     |     ✔    |\n| bools                            |     ✔     |     ✔    |\n| links                            |     ✔     |     ✔    |\n\n| feature                          | accessors | builders |\n|:---------------------------------|:---------:|:--------:|\n| enums                            |    ...    |    ...   |\n| ... type level                   |     ✘     |     ✘    |\n| ... string representation        |     ✘     |     ✘    |\n| ... int representation           |     ✘     |     ✘    |\n"
  },
  {
    "path": "schema/gen/go/README_behaviors.md",
    "content": "Behaviors of Generated Types\n============================\n\nTypes generated by `gogen` obey the rules that already exist for the IPLD Data Model,\nand the rules that exist for Schema typed nodes.\n\nThere are some further details of behavior that might be worth noting, though.\n\nSome of these details aren't necessarily programmer-friendly(!),\nand arise from prioritizing performance over other concerns;\nso especially watch out for these as you develop against the code output by this tool.\n\n### retaining assemblers beyond their intended lifespan is not guaranteed to be safe\n\nThere is no promise of nice-to-read errors if you over-hold child assemblers beyond their valid lifespan.\n`NodeAssembler` values should not be retained for any longer than they're actively in use.\n\n- We **do** care about making things fail hard and fast rather than potentially leak inappropriate mutability.\n- We do **not** care about making these errors pretty (it's high cost to do so, and code that hits this path is almost certainly statically (and hopefully fairly obviously) wrong).\n\nIn some cases it may also be the case that a `NodeAssembler` that populates the internals of some large structure\nmay become invalid (because of state transitions that block inappropriate mutability),\nand yet become possible to use again later (because of coincidences of how we reuse memory internally for efficiency reasons).\nWe don't reliably raise errors in some of these situations, for efficiency reasons, but wish we could.\nUsers of the generated code should not rely on these behaviors:\nit results in difficult-to-read code in any case,\nand such internal details should not be considered part of the intended public API (e.g., such details may be subject to change without notice).\n\n### absent values\n\nIterating a type-level node with optional fields will yield the field key and the `datamodel.Absent` constant as a value.\nGetting a such a field will also yield the `datamodel.Absent` constant as a value, and will not return a \"not found\" error.\n\nAttempting to *assign* an `datamodel.Absent` value, however --\nvia the `NodeAssembler.AssignNode` function (none of the other function signatures permit expressing this) --\nwill result in an `datamodel.ErrWrongKind` error.\n\n// Seealso some unresolved todos in the [HACKME_wip](HACKME_wip.md) document regarding how absent values are handled.\n"
  },
  {
    "path": "schema/gen/go/README_wishes.md",
    "content": "wishes and dreams of other things that could be\n===============================================\n\n### minimal gen for regular code\n\n(In other short words: gen without the monomorphization.)\n\nIt'd be neat to have a mode that generates all public fields (shrugging on immutability),\nand can also toggle off generating all the data model Node interface satisfaction methods.\nThis would let us use IPLD Schemas to define types (including enums and unions) and get Golang code out,\nand easily use it in programs even where we don't particularly care about the Node interface.\n(E.g., suppose we want an enum or a union type -- which Go doesn't naturally have -- but aren't going to use it\nfor serialization or anything else.  We've already got a lot of codegen here; why not make it help there too?)\n\nIt's unclear if we can load that much into this gen project, or if it'd be easier to make another one for this.\nThe output code would definitely be substantially structurally different;\nand it would also tend to be useless/silly to generate different parts of a type system in each of the different modes,\nso it's pretty likely that any practical user story would involve different process invocations to use them anyway.\n"
  },
  {
    "path": "schema/gen/go/_test/.gitignore",
    "content": "/*\n"
  },
  {
    "path": "schema/gen/go/adjunctCfg.go",
    "content": "package gengo\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// This entire file is placeholder-quality implementations.\n//\n// The AdjunctCfg struct should be replaced with an IPLD Schema-specified thing!\n// The values in the unionMemlayout field should be an enum;\n// etcetera!\n\ntype FieldTuple struct {\n\tTypeName  schema.TypeName\n\tFieldName string\n}\n\ntype AdjunctCfg struct {\n\ttypeSymbolOverrides       map[schema.TypeName]string\n\tFieldSymbolLowerOverrides map[FieldTuple]string\n\tfieldSymbolUpperOverrides map[FieldTuple]string\n\tmaybeUsesPtr              map[schema.TypeName]bool   // absent uses a heuristic\n\tCfgUnionMemlayout         map[schema.TypeName]string // \"embedAll\"|\"interface\"; maybe more options later, unclear for now.\n\n\t// ... some of these fields have sprouted messy name prefixes so they don't collide with their matching method names.\n\t//  this structure has reached the critical threshold where it due to be cleaned up and taken seriously.\n\n\t// note: PkgName doesn't appear in here, because it's...\n\t//  not adjunct data.  it's a generation invocation parameter.\n\t//   ... this might not hold up in the future though.\n\t//    There are unanswered questions about how (also, tbf, *if*) we'll handle generation of multiple packages which use each other's types.\n}\n\n// TypeSymbol returns the symbol for a type;\n// by default, it's the same string as its name in the schema,\n// but it can be overridden.\n//\n// This is the base, unembellished symbol.\n// It's frequently augmented:\n// prefixing an underscore to make it unexported;\n// suffixing \"__Something\" to make the name of a supporting type;\n// etc.\n// (Most such augmentations are not configurable.)\nfunc (cfg *AdjunctCfg) TypeSymbol(t schema.Type) string {\n\tif x, ok := cfg.typeSymbolOverrides[t.Name()]; ok {\n\t\treturn x\n\t}\n\treturn string(t.Name()) // presumed already upper\n}\n\nfunc (cfg *AdjunctCfg) FieldSymbolLower(f schema.StructField) string {\n\tif x, ok := cfg.FieldSymbolLowerOverrides[FieldTuple{f.Parent().Name(), f.Name()}]; ok {\n\t\treturn x\n\t}\n\treturn f.Name() // presumed already lower\n}\n\nfunc (cfg *AdjunctCfg) FieldSymbolUpper(f schema.StructField) string {\n\tif x, ok := cfg.fieldSymbolUpperOverrides[FieldTuple{f.Type().Name(), f.Name()}]; ok {\n\t\treturn x\n\t}\n\treturn strings.Title(f.Name()) //lint:ignore SA1019 cases.Title doesn't work for this\n}\n\n// Comments returns a bool for whether comments should be included in gen output or not.\nfunc (cfg *AdjunctCfg) Comments() bool {\n\treturn true // FUTURE: okay, maybe this should be configurable :)\n}\n\nfunc (cfg *AdjunctCfg) MaybeUsesPtr(t schema.Type) bool {\n\tif x, ok := cfg.maybeUsesPtr[t.Name()]; ok {\n\t\treturn x\n\t}\n\n\t// As a simple heuristic,\n\t// check how large the Go representation of this type will be.\n\t// If it weighs little, we estimate that a pointer is not worthwhile,\n\t// as storing the data directly will barely take more memory.\n\t// Plus, the resulting code will be shorter and have fewer branches.\n\treturn sizeOfSchemaType(t) > sizeSmallEnoughForInlining\n}\n\nvar (\n\t// The cutoff for \"weighs little\" is any size up to this number.\n\t// It's hasn't been measured with any benchmarks or stats just yet.\n\t// It's possible that, with those, it might increase in the future.\n\t// Intuitively, any type 4x the size of a pointer is fine to inline.\n\t// Adding a pointer will already add 1x overhead, anyway.\n\tsizeSmallEnoughForInlining = 4 * reflect.TypeOf(new(int)).Size()\n\n\tsizeOfTypeKind [128]uintptr\n)\n\nfunc init() {\n\t// Uncomment for debugging.\n\t// fmt.Fprintf(os.Stderr, \"sizeOf(small): %d (4x pointer size)\\n\", sizeSmallEnoughForInlining)\n\n\t// Get the basic node sizes via basicnode.\n\tfor _, tk := range []struct {\n\t\ttypeKind  schema.TypeKind\n\t\tprototype datamodel.NodePrototype\n\t}{\n\t\t{schema.TypeKind_Bool, basicnode.Prototype.Bool},\n\t\t{schema.TypeKind_Int, basicnode.Prototype.Int},\n\t\t{schema.TypeKind_Float, basicnode.Prototype.Float},\n\t\t{schema.TypeKind_String, basicnode.Prototype.String},\n\t\t{schema.TypeKind_Bytes, basicnode.Prototype.Bytes},\n\t\t{schema.TypeKind_List, basicnode.Prototype.List},\n\t\t{schema.TypeKind_Map, basicnode.Prototype.Map},\n\t\t{schema.TypeKind_Link, basicnode.Prototype.Link},\n\t} {\n\t\tnb := tk.prototype.NewBuilder()\n\t\tswitch tk.typeKind {\n\t\tcase schema.TypeKind_List:\n\t\t\tam, err := nb.BeginList(0)\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tif err := am.Finish(); err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\tcase schema.TypeKind_Map:\n\t\t\tam, err := nb.BeginMap(0)\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tif err := am.Finish(); err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t}\n\t\t// Note that the Node interface has a pointer underneath,\n\t\t// so we use Elem to reach the underlying type.\n\t\tsize := reflect.TypeOf(nb.Build()).Elem().Size()\n\t\tsizeOfTypeKind[tk.typeKind] = size\n\n\t\t// Uncomment for debugging.\n\t\t// fmt.Fprintf(os.Stderr, \"sizeOf(%s): %d\\n\", tk.typeKind, size)\n\t}\n}\n\n// sizeOfSchemaType returns the size of a schema type,\n// relative to the size of a pointer in native Go.\n//\n// For example, TypeInt and TypeMap returns 1, but TypeList returns 3, as a\n// slice in Go has a pointer and two integers for length and capacity.\n// Any basic type smaller than a pointer, such as TypeBool, returns 1.\nfunc sizeOfSchemaType(t schema.Type) uintptr {\n\tkind := t.TypeKind()\n\n\t// If this TypeKind is represented by the basicnode package,\n\t// we statically know its size and we can return here.\n\tif size := sizeOfTypeKind[kind]; size > 0 {\n\t\treturn size\n\t}\n\n\t// TODO: handle typekinds like structs, unions, etc.\n\t// For now, return a large size to fall back to using a pointer.\n\treturn 100 * sizeSmallEnoughForInlining\n}\n\n// UnionMemlayout returns a plain string at present;\n// there's a case-switch in the templates that processes it.\n// We validate that it's a known string when this method is called.\n// This should probably be improved in type-safety,\n// and validated more aggressively up front when adjcfg is loaded.\nfunc (cfg *AdjunctCfg) UnionMemlayout(t schema.Type) string {\n\tif t.TypeKind() != schema.TypeKind_Union {\n\t\tpanic(fmt.Errorf(\"%s is not a union\", t.Name()))\n\t}\n\tv, ok := cfg.CfgUnionMemlayout[t.Name()]\n\tif !ok {\n\t\treturn \"embedAll\"\n\t}\n\tswitch v {\n\tcase \"embedAll\", \"interface\":\n\t\treturn v\n\tdefault:\n\t\tpanic(fmt.Errorf(\"invalid config: unionMemlayout values must be either \\\"embedAll\\\" or \\\"interface\\\", not %q\", v))\n\t}\n}\n"
  },
  {
    "path": "schema/gen/go/externUtil.go",
    "content": "package gengo\n\nimport (\n\t\"go/ast\"\n\t\"go/parser\"\n\t\"go/token\"\n\tpath \"path/filepath\"\n\t\"strings\"\n)\n\n// getExternTypes provides a mapping of all types defined in the destination package.\n// It is used by generate to not duplicate defined types to allow overriding of types.\nfunc getExternTypes(pth string) (map[string]struct{}, error) {\n\tset := token.NewFileSet()\n\tpacks, err := parser.ParseDir(set, pth, nil, 0)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttypes := make(map[string]struct{})\n\tfor _, pack := range packs {\n\t\tfor fname, f := range pack.Files {\n\t\t\tif strings.HasPrefix(path.Base(fname), \"ipldsch_\") {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor _, d := range f.Decls {\n\t\t\t\tif t, isType := d.(*ast.GenDecl); isType {\n\t\t\t\t\tif t.Tok == token.TYPE {\n\t\t\t\t\t\tfor _, s := range t.Specs {\n\t\t\t\t\t\t\tts := s.(*ast.TypeSpec)\n\t\t\t\t\t\t\ttypes[ts.Name.Name] = struct{}{}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn types, nil\n}\n"
  },
  {
    "path": "schema/gen/go/genBool.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\ntype boolGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.BoolTraits\n\tPkgName string\n\tType    *schema.TypeBool\n}\n\nfunc (boolGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\n// --- native content and specializations --->\n\nfunc (g boolGenerator) EmitNativeType(w io.Writer) {\n\temitNativeType_scalar(w, g.AdjCfg, g)\n}\nfunc (g boolGenerator) EmitNativeAccessors(w io.Writer) {\n\temitNativeAccessors_scalar(w, g.AdjCfg, g)\n}\nfunc (g boolGenerator) EmitNativeBuilder(w io.Writer) {\n\temitNativeBuilder_scalar(w, g.AdjCfg, g)\n}\n\nfunc (g boolGenerator) EmitNativeMaybe(w io.Writer) {\n\temitNativeMaybe(w, g.AdjCfg, g)\n}\n\n// --- type info --->\n\nfunc (g boolGenerator) EmitTypeConst(w io.Writer) {\n\tdoTemplate(`\n\t\t// TODO EmitTypeConst\n\t`, w, g.AdjCfg, g)\n}\n\n// --- TypedNode interface satisfaction --->\n\nfunc (g boolGenerator) EmitTypedNodeMethodType(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .Type | TypeSymbol }}) Type() schema.Type {\n\t\t\treturn nil /*TODO:typelit*/\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g boolGenerator) EmitTypedNodeMethodRepresentation(w io.Writer) {\n\temitTypicalTypedNodeMethodRepresentation(w, g.AdjCfg, g)\n}\n\n// --- Node interface satisfaction --->\n\nfunc (g boolGenerator) EmitNodeType(w io.Writer) {\n\t// No additional types needed.  Methods all attach to the native type.\n}\nfunc (g boolGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\temitNodeTypeAssertions_typical(w, g.AdjCfg, g)\n}\nfunc (g boolGenerator) EmitNodeMethodAsBool(w io.Writer) {\n\temitNodeMethodAsKind_scalar(w, g.AdjCfg, g)\n}\nfunc (g boolGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\nfunc (g boolGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g boolGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn boolBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.BoolAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype boolBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.BoolAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeBool\n}\n\nfunc (boolBuilderGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\nfunc (g boolBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g boolBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g boolBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\temitNodeAssemblerType_scalar(w, g.AdjCfg, g)\n}\nfunc (g boolBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_scalar(w, g.AdjCfg, g)\n}\nfunc (g boolBuilderGenerator) EmitNodeAssemblerMethodAssignBool(w io.Writer) {\n\temitNodeAssemblerMethodAssignKind_scalar(w, g.AdjCfg, g)\n}\nfunc (g boolBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\temitNodeAssemblerMethodAssignNode_scalar(w, g.AdjCfg, g)\n}\nfunc (g boolBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\t// Nothing needed here for bool kinds.\n}\n"
  },
  {
    "path": "schema/gen/go/genBoolReprBool.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\nvar _ TypeGenerator = &boolReprBoolGenerator{}\n\nfunc NewBoolReprBoolGenerator(pkgName string, typ *schema.TypeBool, adjCfg *AdjunctCfg) TypeGenerator {\n\treturn boolReprBoolGenerator{\n\t\tboolGenerator{\n\t\t\tadjCfg,\n\t\t\tmixins.BoolTraits{\n\t\t\t\tPkgName:    pkgName,\n\t\t\t\tTypeName:   string(typ.Name()),\n\t\t\t\tTypeSymbol: adjCfg.TypeSymbol(typ),\n\t\t\t},\n\t\t\tpkgName,\n\t\t\ttyp,\n\t\t},\n\t}\n}\n\ntype boolReprBoolGenerator struct {\n\tboolGenerator\n}\n\nfunc (g boolReprBoolGenerator) GetRepresentationNodeGen() NodeGenerator {\n\treturn boolReprBoolReprGenerator{\n\t\tg.AdjCfg,\n\t\tg.Type,\n\t}\n}\n\ntype boolReprBoolReprGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tType   *schema.TypeBool\n}\n\nfunc (g boolReprBoolReprGenerator) EmitNodeType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Repr = _{{ .Type | TypeSymbol }}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g boolReprBoolReprGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}\n\t`, w, g.AdjCfg, g)\n}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodKind(io.Writer)            {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodLookupByString(io.Writer)  {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodLookupByNode(io.Writer)    {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodLookupByIndex(io.Writer)   {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodLookupBySegment(io.Writer) {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodMapIterator(io.Writer)     {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodListIterator(io.Writer)    {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodLength(io.Writer)          {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodIsAbsent(io.Writer)        {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodIsNull(io.Writer)          {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodAsBool(io.Writer)          {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodAsInt(io.Writer)           {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodAsFloat(io.Writer)         {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodAsString(io.Writer)        {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodAsBytes(io.Writer)         {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodAsLink(io.Writer)          {}\nfunc (boolReprBoolReprGenerator) EmitNodeMethodPrototype(io.Writer)       {}\nfunc (g boolReprBoolReprGenerator) EmitNodePrototypeType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprPrototype = _{{ .Type | TypeSymbol }}__Prototype\n\t`, w, g.AdjCfg, g)\n}\nfunc (g boolReprBoolReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn boolReprBoolReprBuilderGenerator(g)\n}\n\ntype boolReprBoolReprBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tType   *schema.TypeBool\n}\n\nfunc (boolReprBoolReprBuilderGenerator) EmitNodeBuilderType(io.Writer)    {}\nfunc (boolReprBoolReprBuilderGenerator) EmitNodeBuilderMethods(io.Writer) {}\nfunc (g boolReprBoolReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprAssembler = _{{ .Type | TypeSymbol }}__Assembler\n\t`, w, g.AdjCfg, g)\n}\nfunc (boolReprBoolReprBuilderGenerator) EmitNodeAssemblerMethodBeginMap(io.Writer)     {}\nfunc (boolReprBoolReprBuilderGenerator) EmitNodeAssemblerMethodBeginList(io.Writer)    {}\nfunc (boolReprBoolReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(io.Writer)   {}\nfunc (boolReprBoolReprBuilderGenerator) EmitNodeAssemblerMethodAssignBool(io.Writer)   {}\nfunc (boolReprBoolReprBuilderGenerator) EmitNodeAssemblerMethodAssignInt(io.Writer)    {}\nfunc (boolReprBoolReprBuilderGenerator) EmitNodeAssemblerMethodAssignFloat(io.Writer)  {}\nfunc (boolReprBoolReprBuilderGenerator) EmitNodeAssemblerMethodAssignString(io.Writer) {}\nfunc (boolReprBoolReprBuilderGenerator) EmitNodeAssemblerMethodAssignBytes(io.Writer)  {}\nfunc (boolReprBoolReprBuilderGenerator) EmitNodeAssemblerMethodAssignLink(io.Writer)   {}\nfunc (boolReprBoolReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(io.Writer)   {}\nfunc (boolReprBoolReprBuilderGenerator) EmitNodeAssemblerMethodPrototype(io.Writer)    {}\nfunc (boolReprBoolReprBuilderGenerator) EmitNodeAssemblerOtherBits(io.Writer)          {}\n"
  },
  {
    "path": "schema/gen/go/genBytes.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\ntype bytesGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.BytesTraits\n\tPkgName string\n\tType    *schema.TypeBytes\n}\n\nfunc (bytesGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\n// --- native content and specializations --->\n\nfunc (g bytesGenerator) EmitNativeType(w io.Writer) {\n\temitNativeType_scalar(w, g.AdjCfg, g)\n}\nfunc (g bytesGenerator) EmitNativeAccessors(w io.Writer) {\n\temitNativeAccessors_scalar(w, g.AdjCfg, g)\n}\nfunc (g bytesGenerator) EmitNativeBuilder(w io.Writer) {\n\temitNativeBuilder_scalar(w, g.AdjCfg, g)\n}\n\nfunc (g bytesGenerator) EmitNativeMaybe(w io.Writer) {\n\temitNativeMaybe(w, g.AdjCfg, g)\n}\n\n// --- type info --->\n\nfunc (g bytesGenerator) EmitTypeConst(w io.Writer) {\n\tdoTemplate(`\n\t\t// TODO EmitTypeConst\n\t`, w, g.AdjCfg, g)\n}\n\n// --- TypedNode interface satisfaction --->\n\nfunc (g bytesGenerator) EmitTypedNodeMethodType(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .Type | TypeSymbol }}) Type() schema.Type {\n\t\t\treturn nil /*TODO:typelit*/\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g bytesGenerator) EmitTypedNodeMethodRepresentation(w io.Writer) {\n\temitTypicalTypedNodeMethodRepresentation(w, g.AdjCfg, g)\n}\n\n// --- Node interface satisfaction --->\n\nfunc (g bytesGenerator) EmitNodeType(w io.Writer) {\n\t// No additional types needed.  Methods all attach to the native type.\n}\nfunc (g bytesGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\temitNodeTypeAssertions_typical(w, g.AdjCfg, g)\n}\nfunc (g bytesGenerator) EmitNodeMethodAsBytes(w io.Writer) {\n\temitNodeMethodAsKind_scalar(w, g.AdjCfg, g)\n}\nfunc (g bytesGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\nfunc (g bytesGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g bytesGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn bytesBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.BytesAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype bytesBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.BytesAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeBytes\n}\n\nfunc (bytesBuilderGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\nfunc (g bytesBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g bytesBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g bytesBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\temitNodeAssemblerType_scalar(w, g.AdjCfg, g)\n}\nfunc (g bytesBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_scalar(w, g.AdjCfg, g)\n}\nfunc (g bytesBuilderGenerator) EmitNodeAssemblerMethodAssignBytes(w io.Writer) {\n\temitNodeAssemblerMethodAssignKind_scalar(w, g.AdjCfg, g)\n}\nfunc (g bytesBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\temitNodeAssemblerMethodAssignNode_scalar(w, g.AdjCfg, g)\n}\nfunc (g bytesBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\t// Nothing needed here for bytes kinds.\n}\n"
  },
  {
    "path": "schema/gen/go/genBytesReprBytes.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\nvar _ TypeGenerator = &bytesReprBytesGenerator{}\n\nfunc NewBytesReprBytesGenerator(pkgName string, typ *schema.TypeBytes, adjCfg *AdjunctCfg) TypeGenerator {\n\treturn bytesReprBytesGenerator{\n\t\tbytesGenerator{\n\t\t\tadjCfg,\n\t\t\tmixins.BytesTraits{\n\t\t\t\tPkgName:    pkgName,\n\t\t\t\tTypeName:   string(typ.Name()),\n\t\t\t\tTypeSymbol: adjCfg.TypeSymbol(typ),\n\t\t\t},\n\t\t\tpkgName,\n\t\t\ttyp,\n\t\t},\n\t}\n}\n\ntype bytesReprBytesGenerator struct {\n\tbytesGenerator\n}\n\nfunc (g bytesReprBytesGenerator) GetRepresentationNodeGen() NodeGenerator {\n\treturn bytesReprBytesReprGenerator{\n\t\tg.AdjCfg,\n\t\tg.Type,\n\t}\n}\n\ntype bytesReprBytesReprGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tType   *schema.TypeBytes\n}\n\nfunc (g bytesReprBytesReprGenerator) EmitNodeType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Repr = _{{ .Type | TypeSymbol }}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g bytesReprBytesReprGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}\n\t`, w, g.AdjCfg, g)\n}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodKind(io.Writer)            {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodLookupByString(io.Writer)  {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodLookupByNode(io.Writer)    {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodLookupByIndex(io.Writer)   {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodLookupBySegment(io.Writer) {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodMapIterator(io.Writer)     {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodListIterator(io.Writer)    {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodLength(io.Writer)          {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodIsAbsent(io.Writer)        {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodIsNull(io.Writer)          {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodAsBool(io.Writer)          {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodAsInt(io.Writer)           {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodAsFloat(io.Writer)         {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodAsString(io.Writer)        {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodAsBytes(io.Writer)         {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodAsLink(io.Writer)          {}\nfunc (bytesReprBytesReprGenerator) EmitNodeMethodPrototype(io.Writer)       {}\nfunc (g bytesReprBytesReprGenerator) EmitNodePrototypeType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprPrototype = _{{ .Type | TypeSymbol }}__Prototype\n\t`, w, g.AdjCfg, g)\n}\nfunc (g bytesReprBytesReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn bytesReprBytesReprBuilderGenerator(g)\n}\n\ntype bytesReprBytesReprBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tType   *schema.TypeBytes\n}\n\nfunc (bytesReprBytesReprBuilderGenerator) EmitNodeBuilderType(io.Writer)    {}\nfunc (bytesReprBytesReprBuilderGenerator) EmitNodeBuilderMethods(io.Writer) {}\nfunc (g bytesReprBytesReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprAssembler = _{{ .Type | TypeSymbol }}__Assembler\n\t`, w, g.AdjCfg, g)\n}\nfunc (bytesReprBytesReprBuilderGenerator) EmitNodeAssemblerMethodBeginMap(io.Writer)     {}\nfunc (bytesReprBytesReprBuilderGenerator) EmitNodeAssemblerMethodBeginList(io.Writer)    {}\nfunc (bytesReprBytesReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(io.Writer)   {}\nfunc (bytesReprBytesReprBuilderGenerator) EmitNodeAssemblerMethodAssignBool(io.Writer)   {}\nfunc (bytesReprBytesReprBuilderGenerator) EmitNodeAssemblerMethodAssignInt(io.Writer)    {}\nfunc (bytesReprBytesReprBuilderGenerator) EmitNodeAssemblerMethodAssignFloat(io.Writer)  {}\nfunc (bytesReprBytesReprBuilderGenerator) EmitNodeAssemblerMethodAssignString(io.Writer) {}\nfunc (bytesReprBytesReprBuilderGenerator) EmitNodeAssemblerMethodAssignBytes(io.Writer)  {}\nfunc (bytesReprBytesReprBuilderGenerator) EmitNodeAssemblerMethodAssignLink(io.Writer)   {}\nfunc (bytesReprBytesReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(io.Writer)   {}\nfunc (bytesReprBytesReprBuilderGenerator) EmitNodeAssemblerMethodPrototype(io.Writer)    {}\nfunc (bytesReprBytesReprBuilderGenerator) EmitNodeAssemblerOtherBits(io.Writer)          {}\n"
  },
  {
    "path": "schema/gen/go/genFloat.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\ntype float64Generator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.FloatTraits\n\tPkgName string\n\tType    *schema.TypeFloat\n}\n\nfunc (float64Generator) IsRepr() bool { return false } // hint used in some generalized templates.\n\n// --- native content and specializations --->\n\nfunc (g float64Generator) EmitNativeType(w io.Writer) {\n\temitNativeType_scalar(w, g.AdjCfg, g)\n}\nfunc (g float64Generator) EmitNativeAccessors(w io.Writer) {\n\temitNativeAccessors_scalar(w, g.AdjCfg, g)\n}\nfunc (g float64Generator) EmitNativeBuilder(w io.Writer) {\n\temitNativeBuilder_scalar(w, g.AdjCfg, g)\n}\n\nfunc (g float64Generator) EmitNativeMaybe(w io.Writer) {\n\temitNativeMaybe(w, g.AdjCfg, g)\n}\n\n// --- type info --->\n\nfunc (g float64Generator) EmitTypeConst(w io.Writer) {\n\tdoTemplate(`\n\t\t// TODO EmitTypeConst\n\t`, w, g.AdjCfg, g)\n}\n\n// --- TypedNode interface satisfaction --->\n\nfunc (g float64Generator) EmitTypedNodeMethodType(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .Type | TypeSymbol }}) Type() schema.Type {\n\t\t\treturn nil /*TODO:typelit*/\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g float64Generator) EmitTypedNodeMethodRepresentation(w io.Writer) {\n\temitTypicalTypedNodeMethodRepresentation(w, g.AdjCfg, g)\n}\n\n// --- Node interface satisfaction --->\n\nfunc (g float64Generator) EmitNodeType(w io.Writer) {\n\t// No additional types needed.  Methods all attach to the native type.\n}\nfunc (g float64Generator) EmitNodeTypeAssertions(w io.Writer) {\n\temitNodeTypeAssertions_typical(w, g.AdjCfg, g)\n}\nfunc (g float64Generator) EmitNodeMethodAsFloat(w io.Writer) {\n\temitNodeMethodAsKind_scalar(w, g.AdjCfg, g)\n}\nfunc (g float64Generator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\nfunc (g float64Generator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g float64Generator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn float64BuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.FloatAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype float64BuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.FloatAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeFloat\n}\n\nfunc (float64BuilderGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\nfunc (g float64BuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g float64BuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g float64BuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\temitNodeAssemblerType_scalar(w, g.AdjCfg, g)\n}\nfunc (g float64BuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_scalar(w, g.AdjCfg, g)\n}\nfunc (g float64BuilderGenerator) EmitNodeAssemblerMethodAssignFloat(w io.Writer) {\n\temitNodeAssemblerMethodAssignKind_scalar(w, g.AdjCfg, g)\n}\nfunc (g float64BuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\temitNodeAssemblerMethodAssignNode_scalar(w, g.AdjCfg, g)\n}\nfunc (g float64BuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\t// Nothing needed here for float64 kinds.\n}\n"
  },
  {
    "path": "schema/gen/go/genFloatReprFloat.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\nvar _ TypeGenerator = &float64ReprFloatGenerator{}\n\nfunc NewFloatReprFloatGenerator(pkgName string, typ *schema.TypeFloat, adjCfg *AdjunctCfg) TypeGenerator {\n\treturn float64ReprFloatGenerator{\n\t\tfloat64Generator{\n\t\t\tadjCfg,\n\t\t\tmixins.FloatTraits{\n\t\t\t\tPkgName:    pkgName,\n\t\t\t\tTypeName:   string(typ.Name()),\n\t\t\t\tTypeSymbol: adjCfg.TypeSymbol(typ),\n\t\t\t},\n\t\t\tpkgName,\n\t\t\ttyp,\n\t\t},\n\t}\n}\n\ntype float64ReprFloatGenerator struct {\n\tfloat64Generator\n}\n\nfunc (g float64ReprFloatGenerator) GetRepresentationNodeGen() NodeGenerator {\n\treturn float64ReprFloatReprGenerator{\n\t\tg.AdjCfg,\n\t\tg.Type,\n\t}\n}\n\ntype float64ReprFloatReprGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tType   *schema.TypeFloat\n}\n\nfunc (g float64ReprFloatReprGenerator) EmitNodeType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Repr = _{{ .Type | TypeSymbol }}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g float64ReprFloatReprGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}\n\t`, w, g.AdjCfg, g)\n}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodKind(io.Writer)            {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodLookupByString(io.Writer)  {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodLookupByNode(io.Writer)    {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodLookupByIndex(io.Writer)   {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodLookupBySegment(io.Writer) {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodMapIterator(io.Writer)     {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodListIterator(io.Writer)    {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodLength(io.Writer)          {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodIsAbsent(io.Writer)        {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodIsNull(io.Writer)          {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodAsBool(io.Writer)          {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodAsInt(io.Writer)           {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodAsFloat(io.Writer)         {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodAsString(io.Writer)        {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodAsBytes(io.Writer)         {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodAsLink(io.Writer)          {}\nfunc (float64ReprFloatReprGenerator) EmitNodeMethodPrototype(io.Writer)       {}\nfunc (g float64ReprFloatReprGenerator) EmitNodePrototypeType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprPrototype = _{{ .Type | TypeSymbol }}__Prototype\n\t`, w, g.AdjCfg, g)\n}\nfunc (g float64ReprFloatReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn float64ReprFloatReprBuilderGenerator(g)\n}\n\ntype float64ReprFloatReprBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tType   *schema.TypeFloat\n}\n\nfunc (float64ReprFloatReprBuilderGenerator) EmitNodeBuilderType(io.Writer)    {}\nfunc (float64ReprFloatReprBuilderGenerator) EmitNodeBuilderMethods(io.Writer) {}\nfunc (g float64ReprFloatReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprAssembler = _{{ .Type | TypeSymbol }}__Assembler\n\t`, w, g.AdjCfg, g)\n}\nfunc (float64ReprFloatReprBuilderGenerator) EmitNodeAssemblerMethodBeginMap(io.Writer)     {}\nfunc (float64ReprFloatReprBuilderGenerator) EmitNodeAssemblerMethodBeginList(io.Writer)    {}\nfunc (float64ReprFloatReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(io.Writer)   {}\nfunc (float64ReprFloatReprBuilderGenerator) EmitNodeAssemblerMethodAssignBool(io.Writer)   {}\nfunc (float64ReprFloatReprBuilderGenerator) EmitNodeAssemblerMethodAssignInt(io.Writer)    {}\nfunc (float64ReprFloatReprBuilderGenerator) EmitNodeAssemblerMethodAssignFloat(io.Writer)  {}\nfunc (float64ReprFloatReprBuilderGenerator) EmitNodeAssemblerMethodAssignString(io.Writer) {}\nfunc (float64ReprFloatReprBuilderGenerator) EmitNodeAssemblerMethodAssignBytes(io.Writer)  {}\nfunc (float64ReprFloatReprBuilderGenerator) EmitNodeAssemblerMethodAssignLink(io.Writer)   {}\nfunc (float64ReprFloatReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(io.Writer)   {}\nfunc (float64ReprFloatReprBuilderGenerator) EmitNodeAssemblerMethodPrototype(io.Writer)    {}\nfunc (float64ReprFloatReprBuilderGenerator) EmitNodeAssemblerOtherBits(io.Writer)          {}\n"
  },
  {
    "path": "schema/gen/go/genInt.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\ntype intGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.IntTraits\n\tPkgName string\n\tType    *schema.TypeInt\n}\n\nfunc (intGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\n// --- native content and specializations --->\n\nfunc (g intGenerator) EmitNativeType(w io.Writer) {\n\temitNativeType_scalar(w, g.AdjCfg, g)\n}\nfunc (g intGenerator) EmitNativeAccessors(w io.Writer) {\n\temitNativeAccessors_scalar(w, g.AdjCfg, g)\n}\nfunc (g intGenerator) EmitNativeBuilder(w io.Writer) {\n\temitNativeBuilder_scalar(w, g.AdjCfg, g)\n}\n\nfunc (g intGenerator) EmitNativeMaybe(w io.Writer) {\n\temitNativeMaybe(w, g.AdjCfg, g)\n}\n\n// --- type info --->\n\nfunc (g intGenerator) EmitTypeConst(w io.Writer) {\n\tdoTemplate(`\n\t\t// TODO EmitTypeConst\n\t`, w, g.AdjCfg, g)\n}\n\n// --- TypedNode interface satisfaction --->\n\nfunc (g intGenerator) EmitTypedNodeMethodType(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .Type | TypeSymbol }}) Type() schema.Type {\n\t\t\treturn nil /*TODO:typelit*/\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g intGenerator) EmitTypedNodeMethodRepresentation(w io.Writer) {\n\temitTypicalTypedNodeMethodRepresentation(w, g.AdjCfg, g)\n}\n\n// --- Node interface satisfaction --->\n\nfunc (g intGenerator) EmitNodeType(w io.Writer) {\n\t// No additional types needed.  Methods all attach to the native type.\n}\nfunc (g intGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\temitNodeTypeAssertions_typical(w, g.AdjCfg, g)\n}\nfunc (g intGenerator) EmitNodeMethodAsInt(w io.Writer) {\n\temitNodeMethodAsKind_scalar(w, g.AdjCfg, g)\n}\nfunc (g intGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\nfunc (g intGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g intGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn intBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.IntAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype intBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.IntAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeInt\n}\n\nfunc (intBuilderGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\nfunc (g intBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g intBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g intBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\temitNodeAssemblerType_scalar(w, g.AdjCfg, g)\n}\nfunc (g intBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_scalar(w, g.AdjCfg, g)\n}\nfunc (g intBuilderGenerator) EmitNodeAssemblerMethodAssignInt(w io.Writer) {\n\temitNodeAssemblerMethodAssignKind_scalar(w, g.AdjCfg, g)\n}\nfunc (g intBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\temitNodeAssemblerMethodAssignNode_scalar(w, g.AdjCfg, g)\n}\nfunc (g intBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\t// Nothing needed here for int kinds.\n}\n"
  },
  {
    "path": "schema/gen/go/genIntReprInt.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\nvar _ TypeGenerator = &intReprIntGenerator{}\n\nfunc NewIntReprIntGenerator(pkgName string, typ *schema.TypeInt, adjCfg *AdjunctCfg) TypeGenerator {\n\treturn intReprIntGenerator{\n\t\tintGenerator{\n\t\t\tadjCfg,\n\t\t\tmixins.IntTraits{\n\t\t\t\tPkgName:    pkgName,\n\t\t\t\tTypeName:   string(typ.Name()),\n\t\t\t\tTypeSymbol: adjCfg.TypeSymbol(typ),\n\t\t\t},\n\t\t\tpkgName,\n\t\t\ttyp,\n\t\t},\n\t}\n}\n\ntype intReprIntGenerator struct {\n\tintGenerator\n}\n\nfunc (g intReprIntGenerator) GetRepresentationNodeGen() NodeGenerator {\n\treturn intReprIntReprGenerator{\n\t\tg.AdjCfg,\n\t\tg.Type,\n\t}\n}\n\ntype intReprIntReprGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tType   *schema.TypeInt\n}\n\nfunc (g intReprIntReprGenerator) EmitNodeType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Repr = _{{ .Type | TypeSymbol }}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g intReprIntReprGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}\n\t`, w, g.AdjCfg, g)\n}\nfunc (intReprIntReprGenerator) EmitNodeMethodKind(io.Writer)            {}\nfunc (intReprIntReprGenerator) EmitNodeMethodLookupByString(io.Writer)  {}\nfunc (intReprIntReprGenerator) EmitNodeMethodLookupByNode(io.Writer)    {}\nfunc (intReprIntReprGenerator) EmitNodeMethodLookupByIndex(io.Writer)   {}\nfunc (intReprIntReprGenerator) EmitNodeMethodLookupBySegment(io.Writer) {}\nfunc (intReprIntReprGenerator) EmitNodeMethodMapIterator(io.Writer)     {}\nfunc (intReprIntReprGenerator) EmitNodeMethodListIterator(io.Writer)    {}\nfunc (intReprIntReprGenerator) EmitNodeMethodLength(io.Writer)          {}\nfunc (intReprIntReprGenerator) EmitNodeMethodIsAbsent(io.Writer)        {}\nfunc (intReprIntReprGenerator) EmitNodeMethodIsNull(io.Writer)          {}\nfunc (intReprIntReprGenerator) EmitNodeMethodAsBool(io.Writer)          {}\nfunc (intReprIntReprGenerator) EmitNodeMethodAsInt(io.Writer)           {}\nfunc (intReprIntReprGenerator) EmitNodeMethodAsFloat(io.Writer)         {}\nfunc (intReprIntReprGenerator) EmitNodeMethodAsString(io.Writer)        {}\nfunc (intReprIntReprGenerator) EmitNodeMethodAsBytes(io.Writer)         {}\nfunc (intReprIntReprGenerator) EmitNodeMethodAsLink(io.Writer)          {}\nfunc (intReprIntReprGenerator) EmitNodeMethodPrototype(io.Writer)       {}\nfunc (g intReprIntReprGenerator) EmitNodePrototypeType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprPrototype = _{{ .Type | TypeSymbol }}__Prototype\n\t`, w, g.AdjCfg, g)\n}\nfunc (g intReprIntReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn intReprIntReprBuilderGenerator(g)\n}\n\ntype intReprIntReprBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tType   *schema.TypeInt\n}\n\nfunc (intReprIntReprBuilderGenerator) EmitNodeBuilderType(io.Writer)    {}\nfunc (intReprIntReprBuilderGenerator) EmitNodeBuilderMethods(io.Writer) {}\nfunc (g intReprIntReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprAssembler = _{{ .Type | TypeSymbol }}__Assembler\n\t`, w, g.AdjCfg, g)\n}\nfunc (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodBeginMap(io.Writer)     {}\nfunc (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodBeginList(io.Writer)    {}\nfunc (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(io.Writer)   {}\nfunc (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignBool(io.Writer)   {}\nfunc (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignInt(io.Writer)    {}\nfunc (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignFloat(io.Writer)  {}\nfunc (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignString(io.Writer) {}\nfunc (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignBytes(io.Writer)  {}\nfunc (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignLink(io.Writer)   {}\nfunc (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(io.Writer)   {}\nfunc (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodPrototype(io.Writer)    {}\nfunc (intReprIntReprBuilderGenerator) EmitNodeAssemblerOtherBits(io.Writer)          {}\n"
  },
  {
    "path": "schema/gen/go/genLink.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\ntype linkGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.LinkTraits\n\tPkgName string\n\tType    *schema.TypeLink\n}\n\nfunc (linkGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\n// --- native content and specializations --->\n\nfunc (g linkGenerator) EmitNativeType(w io.Writer) {\n\temitNativeType_scalar(w, g.AdjCfg, g)\n}\nfunc (g linkGenerator) EmitNativeAccessors(w io.Writer) {\n\temitNativeAccessors_scalar(w, g.AdjCfg, g)\n}\nfunc (g linkGenerator) EmitNativeBuilder(w io.Writer) {\n\temitNativeBuilder_scalar(w, g.AdjCfg, g)\n}\n\nfunc (g linkGenerator) EmitNativeMaybe(w io.Writer) {\n\temitNativeMaybe(w, g.AdjCfg, g)\n}\n\n// --- type info --->\n\nfunc (g linkGenerator) EmitTypeConst(w io.Writer) {\n\tdoTemplate(`\n\t\t// TODO EmitTypeConst\n\t`, w, g.AdjCfg, g)\n}\n\n// --- TypedNode interface satisfaction --->\n\nfunc (g linkGenerator) EmitTypedNodeMethodType(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .Type | TypeSymbol }}) Type() schema.Type {\n\t\t\treturn nil /*TODO:typelit*/\n\t\t}\n\t`, w, g.AdjCfg, g)\n\n\t// Bonus feature for some links (conforms to the schema.TypedLinkNode interface):\n\tif g.Type.HasReferencedType() {\n\t\tdoTemplate(`\n\t\t\tfunc ({{ .Type | TypeSymbol }}) LinkTargetNodePrototype() datamodel.NodePrototype {\n\t\t\t\treturn Type.{{ .Type.ReferencedType | TypeSymbol }}__Repr\n\t\t\t}\n\t\t`, w, g.AdjCfg, g)\n\t}\n}\n\nfunc (g linkGenerator) EmitTypedNodeMethodRepresentation(w io.Writer) {\n\temitTypicalTypedNodeMethodRepresentation(w, g.AdjCfg, g)\n}\n\n// --- Node interface satisfaction --->\n\nfunc (g linkGenerator) EmitNodeType(w io.Writer) {\n\t// No additional types needed.  Methods all attach to the native type.\n}\nfunc (g linkGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\temitNodeTypeAssertions_typical(w, g.AdjCfg, g)\n}\nfunc (g linkGenerator) EmitNodeMethodAsLink(w io.Writer) {\n\temitNodeMethodAsKind_scalar(w, g.AdjCfg, g)\n}\nfunc (g linkGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\nfunc (g linkGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g linkGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn linkBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.LinkAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype linkBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.LinkAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeLink\n}\n\nfunc (linkBuilderGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\nfunc (g linkBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g linkBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g linkBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\temitNodeAssemblerType_scalar(w, g.AdjCfg, g)\n}\nfunc (g linkBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_scalar(w, g.AdjCfg, g)\n}\nfunc (g linkBuilderGenerator) EmitNodeAssemblerMethodAssignLink(w io.Writer) {\n\temitNodeAssemblerMethodAssignKind_scalar(w, g.AdjCfg, g)\n}\nfunc (g linkBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\temitNodeAssemblerMethodAssignNode_scalar(w, g.AdjCfg, g)\n}\nfunc (g linkBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\t// Nothing needed here for link kinds.\n}\n"
  },
  {
    "path": "schema/gen/go/genLinkReprLink.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\nvar _ TypeGenerator = &linkReprLinkGenerator{}\n\nfunc NewLinkReprLinkGenerator(pkgName string, typ *schema.TypeLink, adjCfg *AdjunctCfg) TypeGenerator {\n\treturn linkReprLinkGenerator{\n\t\tlinkGenerator{\n\t\t\tadjCfg,\n\t\t\tmixins.LinkTraits{\n\t\t\t\tPkgName:    pkgName,\n\t\t\t\tTypeName:   string(typ.Name()),\n\t\t\t\tTypeSymbol: adjCfg.TypeSymbol(typ),\n\t\t\t},\n\t\t\tpkgName,\n\t\t\ttyp,\n\t\t},\n\t}\n}\n\ntype linkReprLinkGenerator struct {\n\tlinkGenerator\n}\n\nfunc (g linkReprLinkGenerator) GetRepresentationNodeGen() NodeGenerator {\n\treturn linkReprLinkReprGenerator{\n\t\tg.AdjCfg,\n\t\tg.Type,\n\t}\n}\n\ntype linkReprLinkReprGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tType   *schema.TypeLink\n}\n\nfunc (g linkReprLinkReprGenerator) EmitNodeType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Repr = _{{ .Type | TypeSymbol }}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g linkReprLinkReprGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}\n\t`, w, g.AdjCfg, g)\n}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodKind(io.Writer)            {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodLookupByString(io.Writer)  {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodLookupByNode(io.Writer)    {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodLookupByIndex(io.Writer)   {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodLookupBySegment(io.Writer) {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodMapIterator(io.Writer)     {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodListIterator(io.Writer)    {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodLength(io.Writer)          {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodIsAbsent(io.Writer)        {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodIsNull(io.Writer)          {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodAsBool(io.Writer)          {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodAsInt(io.Writer)           {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodAsFloat(io.Writer)         {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodAsString(io.Writer)        {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodAsBytes(io.Writer)         {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodAsLink(io.Writer)          {}\nfunc (linkReprLinkReprGenerator) EmitNodeMethodPrototype(io.Writer)       {}\nfunc (g linkReprLinkReprGenerator) EmitNodePrototypeType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprPrototype = _{{ .Type | TypeSymbol }}__Prototype\n\t`, w, g.AdjCfg, g)\n}\nfunc (g linkReprLinkReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn linkReprLinkReprBuilderGenerator(g)\n}\n\ntype linkReprLinkReprBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tType   *schema.TypeLink\n}\n\nfunc (linkReprLinkReprBuilderGenerator) EmitNodeBuilderType(io.Writer)    {}\nfunc (linkReprLinkReprBuilderGenerator) EmitNodeBuilderMethods(io.Writer) {}\nfunc (g linkReprLinkReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprAssembler = _{{ .Type | TypeSymbol }}__Assembler\n\t`, w, g.AdjCfg, g)\n}\nfunc (linkReprLinkReprBuilderGenerator) EmitNodeAssemblerMethodBeginMap(io.Writer)     {}\nfunc (linkReprLinkReprBuilderGenerator) EmitNodeAssemblerMethodBeginList(io.Writer)    {}\nfunc (linkReprLinkReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(io.Writer)   {}\nfunc (linkReprLinkReprBuilderGenerator) EmitNodeAssemblerMethodAssignBool(io.Writer)   {}\nfunc (linkReprLinkReprBuilderGenerator) EmitNodeAssemblerMethodAssignInt(io.Writer)    {}\nfunc (linkReprLinkReprBuilderGenerator) EmitNodeAssemblerMethodAssignFloat(io.Writer)  {}\nfunc (linkReprLinkReprBuilderGenerator) EmitNodeAssemblerMethodAssignString(io.Writer) {}\nfunc (linkReprLinkReprBuilderGenerator) EmitNodeAssemblerMethodAssignBytes(io.Writer)  {}\nfunc (linkReprLinkReprBuilderGenerator) EmitNodeAssemblerMethodAssignLink(io.Writer)   {}\nfunc (linkReprLinkReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(io.Writer)   {}\nfunc (linkReprLinkReprBuilderGenerator) EmitNodeAssemblerMethodPrototype(io.Writer)    {}\nfunc (linkReprLinkReprBuilderGenerator) EmitNodeAssemblerOtherBits(io.Writer)          {}\n"
  },
  {
    "path": "schema/gen/go/genList.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\ntype listGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.ListTraits\n\tPkgName string\n\tType    *schema.TypeList\n}\n\nfunc (listGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\n// --- native content and specializations --->\n\nfunc (g listGenerator) EmitNativeType(w io.Writer) {\n\t// Lists are a pretty straightforward struct enclosing a slice.\n\tdoTemplate(`\n\t\t{{- if Comments -}}\n\t\t// {{ .Type | TypeSymbol }} matches the IPLD Schema type \"{{ .Type.Name }}\".  It has {{ .Kind }} kind.\n\t\t{{- end}}\n\t\ttype {{ .Type | TypeSymbol }} = *_{{ .Type | TypeSymbol }}\n\t\ttype _{{ .Type | TypeSymbol }} struct {\n\t\t\tx []_{{ .Type.ValueType | TypeSymbol }}{{if .Type.ValueIsNullable }}__Maybe{{end}}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g listGenerator) EmitNativeAccessors(w io.Writer) {\n\t// Generate a speciated Lookup as well as LookupMaybe method.\n\t// The Lookup method returns nil in case of *either* an out-of-range/absent value or a null value,\n\t//  and so should only be used if the list type doesn't allow nullable keys or if the caller doesn't care about the difference.\n\t// The LookupMaybe method returns a MaybeT type for the list value,\n\t//  and is needed if the list allows nullable values and the caller wishes to distinguish between null and out-of-range/absent.\n\t// (The Lookup method should be preferred for lists that have non-nullable keys, because LookupMaybe may incur additional costs;\n\t//   boxing something into a maybe when it wasn't already stored that way costs an alloc(!),\n\t//    and may additionally incur a memcpy if the maybe for the value type doesn't use pointers internally).\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}) Lookup(idx int64) {{ .Type.ValueType | TypeSymbol }} {\n\t\t\tif n.Length() <= idx {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tv := &n.x[idx]\n\t\t\t{{- if .Type.ValueIsNullable }}\n\t\t\tif v.m == schema.Maybe_Null {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn {{ if not (MaybeUsesPtr .Type.ValueType) }}&{{end}}v.v\n\t\t\t{{- else}}\n\t\t\treturn v\n\t\t\t{{- end}}\n\t\t}\n\t\tfunc (n *_{{ .Type | TypeSymbol }}) LookupMaybe(idx int64) Maybe{{ .Type.ValueType | TypeSymbol }} {\n\t\t\tif n.Length() <= idx {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tv := &n.x[idx]\n\t\t\t{{- if .Type.ValueIsNullable }}\n\t\t\treturn v\n\t\t\t{{- else}}\n\t\t\treturn &_{{ .Type.ValueType | TypeSymbol }}__Maybe{\n\t\t\t\tm: schema.Maybe_Value,\n\t\t\t\tv: {{ if not (MaybeUsesPtr .Type.ValueType) }}*{{end}}v,\n\t\t\t}\n\t\t\t{{- end}}\n\t\t}\n\n\t\tvar _{{ .Type | TypeSymbol }}__valueAbsent = _{{ .Type.ValueType | TypeSymbol }}__Maybe{m:schema.Maybe_Absent}\n\t`, w, g.AdjCfg, g)\n\n\t// Generate a speciated iterator.\n\t//  The main advantage of this over the general datamodel.ListIterator is of course keeping types visible (and concrete, to the compiler's eyes in optimizations, too).\n\t//  It also elides the error return from the iterator's Next method.  (Overreads will result in -1 as an index and nil values; this is both easily avoidable, and unambiguous if you do goof and hit it.)\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) Iterator() *{{ .Type | TypeSymbol }}__Itr {\n\t\t\treturn &{{ .Type | TypeSymbol }}__Itr{n, 0}\n\t\t}\n\n\t\ttype {{ .Type | TypeSymbol }}__Itr struct {\n\t\t\tn {{ .Type | TypeSymbol }}\n\t\t\tidx  int\n\t\t}\n\n\t\tfunc (itr *{{ .Type | TypeSymbol }}__Itr) Next() (idx int64, v {{if .Type.ValueIsNullable }}Maybe{{end}}{{ .Type.ValueType | TypeSymbol }}) {\n\t\t\tif itr.idx >= len(itr.n.x) {\n\t\t\t\treturn -1, nil\n\t\t\t}\n\t\t\tidx = int64(itr.idx)\n\t\t\tv = &itr.n.x[itr.idx]\n\t\t\titr.idx++\n\t\t\treturn\n\t\t}\n\t\tfunc (itr *{{ .Type | TypeSymbol }}__Itr) Done() bool {\n\t\t\treturn itr.idx >= len(itr.n.x)\n\t\t}\n\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g listGenerator) EmitNativeBuilder(w io.Writer) {\n\t// FUTURE: come back to this -- not yet clear what exactly might be most worth emitting here.\n}\n\nfunc (g listGenerator) EmitNativeMaybe(w io.Writer) {\n\temitNativeMaybe(w, g.AdjCfg, g)\n}\n\n// --- type info --->\n\nfunc (g listGenerator) EmitTypeConst(w io.Writer) {\n\tdoTemplate(`\n\t\t// TODO EmitTypeConst\n\t`, w, g.AdjCfg, g)\n}\n\n// --- TypedNode interface satisfaction --->\n\nfunc (g listGenerator) EmitTypedNodeMethodType(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .Type | TypeSymbol }}) Type() schema.Type {\n\t\t\treturn nil /*TODO:typelit*/\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g listGenerator) EmitTypedNodeMethodRepresentation(w io.Writer) {\n\temitTypicalTypedNodeMethodRepresentation(w, g.AdjCfg, g)\n}\n\n// --- Node interface satisfaction --->\n\nfunc (g listGenerator) EmitNodeType(w io.Writer) {\n\t// No additional types needed.  Methods all attach to the native type.\n}\n\nfunc (g listGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\temitNodeTypeAssertions_typical(w, g.AdjCfg, g)\n}\n\nfunc (g listGenerator) EmitNodeMethodLookupByIndex(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) LookupByIndex(idx int64) (datamodel.Node, error) {\n\t\t\tif n.Length() <= idx {\n\t\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfInt(idx)}\n\t\t\t}\n\t\t\tv := &n.x[idx]\n\t\t\t{{- if .Type.ValueIsNullable }}\n\t\t\tif v.m == schema.Maybe_Null {\n\t\t\t\treturn datamodel.Null, nil\n\t\t\t}\n\t\t\treturn {{ if not (MaybeUsesPtr .Type.ValueType) }}&{{end}}v.v, nil\n\t\t\t{{- else}}\n\t\t\treturn v, nil\n\t\t\t{{- end}}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g listGenerator) EmitNodeMethodLookupByNode(w io.Writer) {\n\t// LookupByNode will proceed by coercing to int64 if it can; or fail; those are really the only options.\n\t// REVIEW: how much coercion is done by other types varies quite wildly.  so we should figure out if that inconsistency is acceptable, and at least document it if so.\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) LookupByNode(k datamodel.Node) (datamodel.Node, error) {\n\t\t\tidx, err := k.AsInt()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn n.LookupByIndex(idx)\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g listGenerator) EmitNodeMethodListIterator(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) ListIterator() datamodel.ListIterator {\n\t\t\treturn &_{{ .Type | TypeSymbol }}__ListItr{n, 0}\n\t\t}\n\n\t\ttype _{{ .Type | TypeSymbol }}__ListItr struct {\n\t\t\tn {{ .Type | TypeSymbol }}\n\t\t\tidx  int\n\t\t}\n\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__ListItr) Next() (idx int64, v datamodel.Node, _ error) {\n\t\t\tif itr.idx >= len(itr.n.x) {\n\t\t\t\treturn -1, nil, datamodel.ErrIteratorOverread{}\n\t\t\t}\n\t\t\tidx = int64(itr.idx)\n\t\t\tx := &itr.n.x[itr.idx]\n\t\t\t{{- if .Type.ValueIsNullable }}\n\t\t\tswitch x.m {\n\t\t\tcase schema.Maybe_Null:\n\t\t\t\tv = datamodel.Null\n\t\t\tcase schema.Maybe_Value:\n\t\t\t\tv = {{ if not (MaybeUsesPtr .Type.ValueType) }}&{{end}}x.v\n\t\t\t}\n\t\t\t{{- else}}\n\t\t\tv = x\n\t\t\t{{- end}}\n\t\t\titr.idx++\n\t\t\treturn\n\t\t}\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__ListItr) Done() bool {\n\t\t\treturn itr.idx >= len(itr.n.x)\n\t\t}\n\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g listGenerator) EmitNodeMethodLength(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) Length() int64 {\n\t\t\treturn int64(len(n.x))\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g listGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\n\nfunc (g listGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g listGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn listBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.ListAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype listBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.ListAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeList\n}\n\nfunc (listBuilderGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\nfunc (g listBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g listBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g listBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// - 'w' is the \"**w**ip\" pointer.\n\t// - 'm' is the **m**aybe which communicates our completeness to the parent if we're a child assembler.\n\t// - 'state' is what it says on the tin.  this is used for the list state (the broad transitions between null, start-list, and finish are handled by 'm' for consistency with other types).\n\t//\n\t// - 'cm' is **c**hild **m**aybe and is used for the completion message from children.\n\t//    It's only present if list values *aren't* allowed to be nullable, since otherwise they have their own per-value maybe slot we can use.\n\t// - 'va' is the embedded child value assembler.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Assembler struct {\n\t\t\tw *_{{ .Type | TypeSymbol }}\n\t\t\tm *schema.Maybe\n\t\t\tstate laState\n\n\t\t\t{{ if not .Type.ValueIsNullable }}cm schema.Maybe{{end}}\n\t\t\tva _{{ .Type.ValueType | TypeSymbol }}__Assembler\n\t\t}\n\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__Assembler) reset() {\n\t\t\tna.state = laState_initial\n\t\t\tna.va.reset()\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g listBuilderGenerator) EmitNodeAssemblerMethodBeginList(w io.Writer) {\n\temitNodeAssemblerMethodBeginList_listoid(w, g.AdjCfg, g)\n}\nfunc (g listBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_recursive(w, g.AdjCfg, g)\n}\nfunc (g listBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\temitNodeAssemblerMethodAssignNode_listoid(w, g.AdjCfg, g)\n}\nfunc (g listBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\temitNodeAssemblerHelper_listoid_tidyHelper(w, g.AdjCfg, g)\n\temitNodeAssemblerHelper_listoid_listAssemblerMethods(w, g.AdjCfg, g)\n}\n"
  },
  {
    "path": "schema/gen/go/genListReprList.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\nvar _ TypeGenerator = &listReprListGenerator{}\n\nfunc NewListReprListGenerator(pkgName string, typ *schema.TypeList, adjCfg *AdjunctCfg) TypeGenerator {\n\treturn listReprListGenerator{\n\t\tlistGenerator{\n\t\t\tadjCfg,\n\t\t\tmixins.ListTraits{\n\t\t\t\tPkgName:    pkgName,\n\t\t\t\tTypeName:   string(typ.Name()),\n\t\t\t\tTypeSymbol: adjCfg.TypeSymbol(typ),\n\t\t\t},\n\t\t\tpkgName,\n\t\t\ttyp,\n\t\t},\n\t}\n}\n\ntype listReprListGenerator struct {\n\tlistGenerator\n}\n\nfunc (g listReprListGenerator) GetRepresentationNodeGen() NodeGenerator {\n\treturn listReprListReprGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.ListTraits{\n\t\t\tPkgName:    g.PkgName,\n\t\t\tTypeName:   string(g.Type.Name()) + \".Repr\",\n\t\t\tTypeSymbol: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Repr\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype listReprListReprGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.ListTraits\n\tPkgName string\n\tType    *schema.TypeList\n}\n\nfunc (listReprListReprGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g listReprListReprGenerator) EmitNodeType(w io.Writer) {\n\t// Even though this is a \"natural\" representation... we need a new type here,\n\t//  because lists are recursive, and so all our functions that access\n\t//   children need to remember to return the representation node of those child values.\n\t// It's still structurally the same, though (and we'll be able to cast in the methodset pattern).\n\t// Error-thunking methods also have a different string in their error, so those are unique even if they don't seem particularly interesting.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Repr _{{ .Type | TypeSymbol }}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g listReprListReprGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g listReprListReprGenerator) EmitNodeMethodLookupByNode(w io.Writer) {\n\t// Null is also already a branch in the method we're calling; hopefully the compiler inlines and sees this and DTRT.\n\t// REVIEW: these unchecked casts are definitely safe at compile time, but I'm not sure if the compiler considers that provable,\n\t//  so we should investigate if there's any runtime checks injected here that waste time.  If so: write this with more gsloc to avoid :(\n\tdoTemplate(`\n\t\tfunc (nr *_{{ .Type | TypeSymbol }}__Repr) LookupByNode(k datamodel.Node) (datamodel.Node, error) {\n\t\t\tv, err := ({{ .Type | TypeSymbol }})(nr).LookupByNode(k)\n\t\t\tif err != nil || v == datamodel.Null {\n\t\t\t\treturn v, err\n\t\t\t}\n\t\t\treturn v.({{ .Type.ValueType | TypeSymbol}}).Representation(), nil\n\t\t}\n\t`, w, g.AdjCfg, g)\n\n}\n\nfunc (g listReprListReprGenerator) EmitNodeMethodLookupByIndex(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (nr *_{{ .Type | TypeSymbol }}__Repr) LookupByIndex(idx int64) (datamodel.Node, error) {\n\t\t\tv, err := ({{ .Type | TypeSymbol }})(nr).LookupByIndex(idx)\n\t\t\tif err != nil || v == datamodel.Null {\n\t\t\t\treturn v, err\n\t\t\t}\n\t\t\treturn v.({{ .Type.ValueType | TypeSymbol}}).Representation(), nil\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g listReprListReprGenerator) EmitNodeMethodListIterator(w io.Writer) {\n\t// FUTURE: trying to get this to share the preallocated memory if we get iterators wedged into their node slab will be ... fun.\n\tdoTemplate(`\n\t\tfunc (nr *_{{ .Type | TypeSymbol }}__Repr) ListIterator() datamodel.ListIterator {\n\t\t\treturn &_{{ .Type | TypeSymbol }}__ReprListItr{({{ .Type | TypeSymbol }})(nr), 0}\n\t\t}\n\n\t\ttype _{{ .Type | TypeSymbol }}__ReprListItr _{{ .Type | TypeSymbol }}__ListItr\n\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__ReprListItr) Next() (idx int64, v datamodel.Node, err error) {\n\t\t\tidx, v, err = (*_{{ .Type | TypeSymbol }}__ListItr)(itr).Next()\n\t\t\tif err != nil || v == datamodel.Null {\n\t\t\t\treturn\n\t\t\t}\n\t\t\treturn idx, v.({{ .Type.ValueType | TypeSymbol}}).Representation(), nil\n\t\t}\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__ReprListItr) Done() bool {\n\t\t\treturn (*_{{ .Type | TypeSymbol }}__ListItr)(itr).Done()\n\t\t}\n\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g listReprListReprGenerator) EmitNodeMethodLength(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (rn *_{{ .Type | TypeSymbol }}__Repr) Length() int64 {\n\t\t\treturn int64(len(rn.x))\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g listReprListReprGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\n\nfunc (g listReprListReprGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g listReprListReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn listReprListReprBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.ListAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Repr\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype listReprListReprBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.ListAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeList\n}\n\nfunc (listReprListReprBuilderGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g listReprListReprBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g listReprListReprBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g listReprListReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// - 'w' is the \"**w**ip\" pointer.\n\t// - 'm' is the **m**aybe which communicates our completeness to the parent if we're a child assembler.\n\t// - 'state' is what it says on the tin.  this is used for the list state (the broad transitions between null, start-list, and finish are handled by 'm' for consistency with other types).\n\t//\n\t// - 'cm' is **c**hild **m**aybe and is used for the completion message from children.\n\t//    It's only present if list values *aren't* allowed to be nullable, since otherwise they have their own per-value maybe slot we can use.\n\t// - 'va' is the embedded child value assembler.\n\t//\n\t// Note that this textually similar to the type-level assembler, but because it embeds the repr assembler for the child types,\n\t//  it might be *significantly* different in size and memory layout in that trailing part of the struct.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprAssembler struct {\n\t\t\tw *_{{ .Type | TypeSymbol }}\n\t\t\tm *schema.Maybe\n\t\t\tstate laState\n\n\t\t\t{{ if not .Type.ValueIsNullable }}cm schema.Maybe{{end}}\n\t\t\tva _{{ .Type.ValueType | TypeSymbol }}__ReprAssembler\n\t\t}\n\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) reset() {\n\t\t\tna.state = laState_initial\n\t\t\tna.va.reset()\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g listReprListReprBuilderGenerator) EmitNodeAssemblerMethodBeginList(w io.Writer) {\n\temitNodeAssemblerMethodBeginList_listoid(w, g.AdjCfg, g)\n}\nfunc (g listReprListReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_recursive(w, g.AdjCfg, g)\n}\nfunc (g listReprListReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\temitNodeAssemblerMethodAssignNode_listoid(w, g.AdjCfg, g)\n}\nfunc (g listReprListReprBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\temitNodeAssemblerHelper_listoid_tidyHelper(w, g.AdjCfg, g)\n\temitNodeAssemblerHelper_listoid_listAssemblerMethods(w, g.AdjCfg, g)\n}\n"
  },
  {
    "path": "schema/gen/go/genMap.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\ntype mapGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.MapTraits\n\tPkgName string\n\tType    *schema.TypeMap\n}\n\nfunc (mapGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\n// --- native content and specializations --->\n\nfunc (g mapGenerator) EmitNativeType(w io.Writer) {\n\t// Maps do double bookkeeping.\n\t// - 'm' is used for quick lookup.\n\t// - 't' is used for both for order maintenance, and for allocation amortization for both keys and values.\n\t// Note that the key in 'm' is *not* a pointer.\n\t// The value in 'm' is a pointer into 't' (except when it's a maybe; maybes are already pointers).\n\tdoTemplate(`\n\t\t{{- if Comments -}}\n\t\t// {{ .Type | TypeSymbol }} matches the IPLD Schema type \"{{ .Type.Name }}\".  It has {{ .Kind }} kind.\n\t\t{{- end}}\n\t\ttype {{ .Type | TypeSymbol }} = *_{{ .Type | TypeSymbol }}\n\t\ttype _{{ .Type | TypeSymbol }} struct {\n\t\t\tm map[_{{ .Type.KeyType | TypeSymbol }}]{{if .Type.ValueIsNullable }}Maybe{{else}}*_{{end}}{{ .Type.ValueType | TypeSymbol }}\n\t\t\tt []_{{ .Type | TypeSymbol }}__entry\n\t\t}\n\t`, w, g.AdjCfg, g)\n\t// - address of 'k' is used when we return keys as nodes, such as in iterators.\n\t//    Having these in the 't' slice above amortizes moving all of them to heap at once,\n\t//     which makes iterators that have to return them as an interface much (much) lower cost -- no 'runtime.conv*' pain.\n\t// - address of 'v' is used in map values, to return, and of course also in iterators.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__entry struct {\n\t\t\tk _{{ .Type.KeyType | TypeSymbol }}\n\t\t\tv _{{ .Type.ValueType | TypeSymbol }}{{if .Type.ValueIsNullable }}__Maybe{{end}}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g mapGenerator) EmitNativeAccessors(w io.Writer) {\n\t// Generate a speciated Lookup as well as LookupMaybe method.\n\t// The Lookup method returns nil in case of *either* an absent value or a null value,\n\t//  and so should only be used if the map type doesn't allow nullable keys or if the caller doesn't care about the difference.\n\t// The LookupMaybe method returns a MaybeT type for the map value,\n\t//  and is needed if the map allows nullable values and the caller wishes to distinguish between null and absent.\n\t// (The Lookup method should be preferred for maps that have non-nullable keys, because LookupMaybe may incur additional costs;\n\t//   boxing something into a maybe when it wasn't already stored that way costs an alloc(!),\n\t//    and may additionally incur a memcpy if the maybe for the value type doesn't use pointers internally).\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}) Lookup(k {{ .Type.KeyType | TypeSymbol }}) {{ .Type.ValueType | TypeSymbol }} {\n\t\t\tv, exists := n.m[*k]\n\t\t\tif !exists {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\t{{- if .Type.ValueIsNullable }}\n\t\t\tif v.m == schema.Maybe_Null {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn {{ if not (MaybeUsesPtr .Type.ValueType) }}&{{end}}v.v\n\t\t\t{{- else}}\n\t\t\treturn v\n\t\t\t{{- end}}\n\t\t}\n\t\tfunc (n *_{{ .Type | TypeSymbol }}) LookupMaybe(k {{ .Type.KeyType | TypeSymbol }}) Maybe{{ .Type.ValueType | TypeSymbol }} {\n\t\t\tv, exists := n.m[*k]\n\t\t\tif !exists {\n\t\t\t\treturn &_{{ .Type | TypeSymbol }}__valueAbsent\n\t\t\t}\n\t\t\t{{- if .Type.ValueIsNullable }}\n\t\t\treturn v\n\t\t\t{{- else}}\n\t\t\treturn &_{{ .Type.ValueType | TypeSymbol }}__Maybe{\n\t\t\t\tm: schema.Maybe_Value,\n\t\t\t\tv: {{ if not (MaybeUsesPtr .Type.ValueType) }}*{{end}}v,\n\t\t\t}\n\t\t\t{{- end}}\n\t\t}\n\n\t\tvar _{{ .Type | TypeSymbol }}__valueAbsent = _{{ .Type.ValueType | TypeSymbol }}__Maybe{m:schema.Maybe_Absent}\n\t`, w, g.AdjCfg, g)\n\n\t// Generate a speciated iterator.\n\t//  The main advantage of this over the general datamodel.MapIterator is of course keeping types visible (and concrete, to the compiler's eyes in optimizations, too).\n\t//  It also elides the error return from the iterator's Next method.  (Overreads will result in nil keys; this is both easily avoidable, and unambiguous if you do goof and hit it.)\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) Iterator() *{{ .Type | TypeSymbol }}__Itr {\n\t\t\treturn &{{ .Type | TypeSymbol }}__Itr{n, 0}\n\t\t}\n\n\t\ttype {{ .Type | TypeSymbol }}__Itr struct {\n\t\t\tn {{ .Type | TypeSymbol }}\n\t\t\tidx  int\n\t\t}\n\n\t\tfunc (itr *{{ .Type | TypeSymbol }}__Itr) Next() (k {{ .Type.KeyType | TypeSymbol }}, v {{if .Type.ValueIsNullable }}Maybe{{end}}{{ .Type.ValueType | TypeSymbol }}) {\n\t\t\tif itr.idx >= len(itr.n.t) {\n\t\t\t\treturn nil, nil\n\t\t\t}\n\t\t\tx := &itr.n.t[itr.idx]\n\t\t\tk = &x.k\n\t\t\tv = &x.v\n\t\t\titr.idx++\n\t\t\treturn\n\t\t}\n\t\tfunc (itr *{{ .Type | TypeSymbol }}__Itr) Done() bool {\n\t\t\treturn itr.idx >= len(itr.n.t)\n\t\t}\n\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g mapGenerator) EmitNativeBuilder(w io.Writer) {\n\t// Not yet clear what exactly might be most worth emitting here.\n}\n\nfunc (g mapGenerator) EmitNativeMaybe(w io.Writer) {\n\temitNativeMaybe(w, g.AdjCfg, g)\n}\n\n// --- type info --->\n\nfunc (g mapGenerator) EmitTypeConst(w io.Writer) {\n\tdoTemplate(`\n\t\t// TODO EmitTypeConst\n\t`, w, g.AdjCfg, g)\n}\n\n// --- TypedNode interface satisfaction --->\n\nfunc (g mapGenerator) EmitTypedNodeMethodType(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .Type | TypeSymbol }}) Type() schema.Type {\n\t\t\treturn nil /*TODO:typelit*/\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g mapGenerator) EmitTypedNodeMethodRepresentation(w io.Writer) {\n\temitTypicalTypedNodeMethodRepresentation(w, g.AdjCfg, g)\n}\n\n// --- Node interface satisfaction --->\n\nfunc (g mapGenerator) EmitNodeType(w io.Writer) {\n\t// No additional types needed.  Methods all attach to the native type.\n}\n\nfunc (g mapGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\temitNodeTypeAssertions_typical(w, g.AdjCfg, g)\n}\n\nfunc (g mapGenerator) EmitNodeMethodLookupByString(w io.Writer) {\n\t// What should be coercible in which directions (and how surprising that is) is an interesting question.\n\t//  Most of the answer comes from considering what needs to be possible when working with PathSegment:\n\t//   we *must* be able to accept a string in a PathSegment and be able to use it to navigate a map -- even if the map has complex keys.\n\t//   For that to work out, it means if the key type doesn't have a string type kind, we must be willing to reach into its representation and use the fromString there.\n\t//  If the key type *does* have a string kind at the type level, we'll use that; no need to consider going through the representation.\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) LookupByString(k string) (datamodel.Node, error) {\n\t\t\tvar k2 _{{ .Type.KeyType | TypeSymbol }}\n\t\t\t{{- if eq .Type.KeyType.TypeKind.String \"String\" }}\n\t\t\tif err := (_{{ .Type.KeyType | TypeSymbol }}__Prototype{}).fromString(&k2, k); err != nil {\n\t\t\t\treturn nil, err // TODO wrap in some kind of ErrInvalidKey\n\t\t\t}\n\t\t\t{{- else}}\n\t\t\tif err := (_{{ .Type.KeyType | TypeSymbol }}__ReprPrototype{}).fromString(&k2, k); err != nil {\n\t\t\t\treturn nil, err // TODO wrap in some kind of ErrInvalidKey\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\tv, exists := n.m[k2]\n\t\t\tif !exists {\n\t\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(k)}\n\t\t\t}\n\t\t\t{{- if .Type.ValueIsNullable }}\n\t\t\tif v.m == schema.Maybe_Null {\n\t\t\t\treturn datamodel.Null, nil\n\t\t\t}\n\t\t\treturn {{ if not (MaybeUsesPtr .Type.ValueType) }}&{{end}}v.v, nil\n\t\t\t{{- else}}\n\t\t\treturn v, nil\n\t\t\t{{- end}}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g mapGenerator) EmitNodeMethodLookupByNode(w io.Writer) {\n\t// LookupByNode will proceed by cast if it can; or simply error if that doesn't work.\n\t//  There's no attempt to turn the node (or its repr) into a string and then reify that into a key;\n\t//   if you used a Node here, you should've meant it.\n\t// REVIEW: by comparison structs will coerce anything stringish silently...!  so we should figure out if that inconsistency is acceptable, and at least document it if so.\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) LookupByNode(k datamodel.Node) (datamodel.Node, error) {\n\t\t\tk2, ok := k.({{ .Type.KeyType | TypeSymbol }})\n\t\t\tif !ok {\n\t\t\t\tpanic(\"todo invalid key type error\")\n\t\t\t\t// 'schema.ErrInvalidKey{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}\", Key:&_String{k}}' doesn't quite cut it: need room to explain the type, and it's not guaranteed k can be turned into a string at all\n\t\t\t}\n\t\t\tv, exists := n.m[*k2]\n\t\t\tif !exists {\n\t\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(k2.String())}\n\t\t\t}\n\t\t\t{{- if .Type.ValueIsNullable }}\n\t\t\tif v.m == schema.Maybe_Null {\n\t\t\t\treturn datamodel.Null, nil\n\t\t\t}\n\t\t\treturn {{ if not (MaybeUsesPtr .Type.ValueType) }}&{{end}}v.v, nil\n\t\t\t{{- else}}\n\t\t\treturn v, nil\n\t\t\t{{- end}}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g mapGenerator) EmitNodeMethodMapIterator(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) MapIterator() datamodel.MapIterator {\n\t\t\treturn &_{{ .Type | TypeSymbol }}__MapItr{n, 0}\n\t\t}\n\n\t\ttype _{{ .Type | TypeSymbol }}__MapItr struct {\n\t\t\tn {{ .Type | TypeSymbol }}\n\t\t\tidx  int\n\t\t}\n\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__MapItr) Next() (k datamodel.Node, v datamodel.Node, _ error) {\n\t\t\tif itr.idx >= len(itr.n.t) {\n\t\t\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t\t\t}\n\t\t\tx := &itr.n.t[itr.idx]\n\t\t\tk = &x.k\n\t\t\t{{- if .Type.ValueIsNullable }}\n\t\t\tswitch x.v.m {\n\t\t\tcase schema.Maybe_Null:\n\t\t\t\tv = datamodel.Null\n\t\t\tcase schema.Maybe_Value:\n\t\t\t\tv = {{ if not (MaybeUsesPtr .Type.ValueType) }}&{{end}}x.v.v\n\t\t\t}\n\t\t\t{{- else}}\n\t\t\tv = &x.v\n\t\t\t{{- end}}\n\t\t\titr.idx++\n\t\t\treturn\n\t\t}\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__MapItr) Done() bool {\n\t\t\treturn itr.idx >= len(itr.n.t)\n\t\t}\n\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g mapGenerator) EmitNodeMethodLength(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) Length() int64 {\n\t\t\treturn int64(len(n.t))\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g mapGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\n\nfunc (g mapGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g mapGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn mapBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.MapAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype mapBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.MapAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeMap\n}\n\nfunc (mapBuilderGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\nfunc (g mapBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g mapBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g mapBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// - 'w' is the \"**w**ip\" pointer.\n\t// - 'm' is the **m**aybe which communicates our completeness to the parent if we're a child assembler.\n\t// - 'state' is what it says on the tin.  this is used for the map state (the broad transitions between null, start-map, and finish are handled by 'm' for consistency.)\n\t// - there's no equivalent of the 'f' (**f**ocused next) field in struct assemblers -- that's implicitly the last row of the 'w.t'.\n\t//\n\t// - 'cm' is **c**hild **m**aybe and is used for the completion message from children.\n\t//    It's used for values if values aren't allowed to be nullable and thus don't have their own per-value maybe slot we can use.\n\t//    It's always used for key assembly, since keys are never allowed to be nullable and thus etc.\n\t// - 'ka' and 'va' are the key assembler and value assembler respectively.\n\t//    Perhaps surprisingly, we can get away with using the assemblers for each type just straight up, no wrappers necessary;\n\t//     All of the required magic is handled through maybe pointers and some tidy methods used during state transitions.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Assembler struct {\n\t\t\tw *_{{ .Type | TypeSymbol }}\n\t\t\tm *schema.Maybe\n\t\t\tstate maState\n\n\t\t\tcm schema.Maybe\n\t\t\tka _{{ .Type.KeyType | TypeSymbol }}__Assembler\n\t\t\tva _{{ .Type.ValueType | TypeSymbol }}__Assembler\n\t\t}\n\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__Assembler) reset() {\n\t\t\tna.state = maState_initial\n\t\t\tna.ka.reset()\n\t\t\tna.va.reset()\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g mapBuilderGenerator) EmitNodeAssemblerMethodBeginMap(w io.Writer) {\n\temitNodeAssemblerMethodBeginMap_mapoid(w, g.AdjCfg, g)\n}\nfunc (g mapBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_recursive(w, g.AdjCfg, g)\n}\nfunc (g mapBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\temitNodeAssemblerMethodAssignNode_mapoid(w, g.AdjCfg, g)\n}\nfunc (g mapBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\temitNodeAssemblerHelper_mapoid_keyTidyHelper(w, g.AdjCfg, g)\n\temitNodeAssemblerHelper_mapoid_valueTidyHelper(w, g.AdjCfg, g)\n\temitNodeAssemblerHelper_mapoid_mapAssemblerMethods(w, g.AdjCfg, g)\n}\n"
  },
  {
    "path": "schema/gen/go/genMapReprMap.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\nvar _ TypeGenerator = &mapReprMapGenerator{}\n\nfunc NewMapReprMapGenerator(pkgName string, typ *schema.TypeMap, adjCfg *AdjunctCfg) TypeGenerator {\n\treturn mapReprMapGenerator{\n\t\tmapGenerator{\n\t\t\tadjCfg,\n\t\t\tmixins.MapTraits{\n\t\t\t\tPkgName:    pkgName,\n\t\t\t\tTypeName:   string(typ.Name()),\n\t\t\t\tTypeSymbol: adjCfg.TypeSymbol(typ),\n\t\t\t},\n\t\t\tpkgName,\n\t\t\ttyp,\n\t\t},\n\t}\n}\n\ntype mapReprMapGenerator struct {\n\tmapGenerator\n}\n\nfunc (g mapReprMapGenerator) GetRepresentationNodeGen() NodeGenerator {\n\treturn mapReprMapReprGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.MapTraits{\n\t\t\tPkgName:    g.PkgName,\n\t\t\tTypeName:   string(g.Type.Name()) + \".Repr\",\n\t\t\tTypeSymbol: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Repr\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype mapReprMapReprGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.MapTraits\n\tPkgName string\n\tType    *schema.TypeMap\n}\n\nfunc (mapReprMapReprGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g mapReprMapReprGenerator) EmitNodeType(w io.Writer) {\n\t// Even though this is a \"natural\" representation... we need a new type here,\n\t//  because maps are recursive, and so all our functions that access\n\t//   children need to remember to return the representation node of those child values.\n\t// It's still structurally the same, though (and we'll be able to cast in the methodset pattern).\n\t// Error-thunking methods also have a different string in their error, so those are unique even if they don't seem particularly interesting.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Repr _{{ .Type | TypeSymbol }}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g mapReprMapReprGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g mapReprMapReprGenerator) EmitNodeMethodLookupByString(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (nr *_{{ .Type | TypeSymbol }}__Repr) LookupByString(k string) (datamodel.Node, error) {\n\t\t\tv, err := ({{ .Type | TypeSymbol }})(nr).LookupByString(k)\n\t\t\tif err != nil || v == datamodel.Null {\n\t\t\t\treturn v, err\n\t\t\t}\n\t\t\treturn v.({{ .Type.ValueType | TypeSymbol}}).Representation(), nil\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g mapReprMapReprGenerator) EmitNodeMethodLookupByNode(w io.Writer) {\n\t// Null is also already a branch in the method we're calling; hopefully the compiler inlines and sees this and DTRT.\n\t// REVIEW: these unchecked casts are definitely safe at compile time, but I'm not sure if the compiler considers that provable,\n\t//  so we should investigate if there's any runtime checks injected here that waste time.  If so: write this with more gsloc to avoid :(\n\tdoTemplate(`\n\t\tfunc (nr *_{{ .Type | TypeSymbol }}__Repr) LookupByNode(k datamodel.Node) (datamodel.Node, error) {\n\t\t\tv, err := ({{ .Type | TypeSymbol }})(nr).LookupByNode(k)\n\t\t\tif err != nil || v == datamodel.Null {\n\t\t\t\treturn v, err\n\t\t\t}\n\t\t\treturn v.({{ .Type.ValueType | TypeSymbol}}).Representation(), nil\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g mapReprMapReprGenerator) EmitNodeMethodMapIterator(w io.Writer) {\n\t// FUTURE: trying to get this to share the preallocated memory if we get iterators wedged into their node slab will be ... fun.\n\tdoTemplate(`\n\t\tfunc (nr *_{{ .Type | TypeSymbol }}__Repr) MapIterator() datamodel.MapIterator {\n\t\t\treturn &_{{ .Type | TypeSymbol }}__ReprMapItr{({{ .Type | TypeSymbol }})(nr), 0}\n\t\t}\n\n\t\ttype _{{ .Type | TypeSymbol }}__ReprMapItr _{{ .Type | TypeSymbol }}__MapItr\n\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__ReprMapItr) Next() (k datamodel.Node, v datamodel.Node, err error) {\n\t\t\tk, v, err = (*_{{ .Type | TypeSymbol }}__MapItr)(itr).Next()\n\t\t\tif err != nil || v == datamodel.Null {\n\t\t\t\treturn\n\t\t\t}\n\t\t\treturn k, v.({{ .Type.ValueType | TypeSymbol}}).Representation(), nil\n\t\t}\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__ReprMapItr) Done() bool {\n\t\t\treturn (*_{{ .Type | TypeSymbol }}__MapItr)(itr).Done()\n\t\t}\n\n\t`, w, g.AdjCfg, g)\n}\nfunc (g mapReprMapReprGenerator) EmitNodeMethodLength(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (rn *_{{ .Type | TypeSymbol }}__Repr) Length() int64 {\n\t\t\treturn int64(len(rn.t))\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g mapReprMapReprGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\nfunc (g mapReprMapReprGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g mapReprMapReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn mapReprMapReprBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.MapAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Repr\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype mapReprMapReprBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.MapAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeMap\n}\n\nfunc (mapReprMapReprBuilderGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g mapReprMapReprBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g mapReprMapReprBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g mapReprMapReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// - 'w' is the \"**w**ip\" pointer.\n\t// - 'm' is the **m**aybe which communicates our completeness to the parent if we're a child assembler.\n\t// - 'state' is what it says on the tin.  this is used for the map state (the broad transitions between null, start-map, and finish are handled by 'm' for consistency.)\n\t// - there's no equivalent of the 'f' (**f**ocused next) field in struct assemblers -- that's implicitly the last row of the 'w.t'.\n\t//\n\t// - 'cm' is **c**hild **m**aybe and is used for the completion message from children.\n\t//    It's used for values if values aren't allowed to be nullable and thus don't have their own per-value maybe slot we can use.\n\t//    It's always used for key assembly, since keys are never allowed to be nullable and thus etc.\n\t// - 'ka' and 'va' are the key assembler and value assembler respectively.\n\t//    Perhaps surprisingly, we can get away with using the assemblers for each type just straight up, no wrappers necessary;\n\t//     All of the required magic is handled through maybe pointers and some tidy methods used during state transitions.\n\t//\n\t// Note that this textually similar to the type-level assembler, but because it embeds the repr assembler for the child types,\n\t//  it might be *significantly* different in size and memory layout in that trailing part of the struct.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprAssembler struct {\n\t\t\tw *_{{ .Type | TypeSymbol }}\n\t\t\tm *schema.Maybe\n\t\t\tstate maState\n\n\t\t\tcm schema.Maybe\n\t\t\tka _{{ .Type.KeyType | TypeSymbol }}__ReprAssembler\n\t\t\tva _{{ .Type.ValueType | TypeSymbol }}__ReprAssembler\n\t\t}\n\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) reset() {\n\t\t\tna.state = maState_initial\n\t\t\tna.ka.reset()\n\t\t\tna.va.reset()\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g mapReprMapReprBuilderGenerator) EmitNodeAssemblerMethodBeginMap(w io.Writer) {\n\temitNodeAssemblerMethodBeginMap_mapoid(w, g.AdjCfg, g)\n}\nfunc (g mapReprMapReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_recursive(w, g.AdjCfg, g)\n}\nfunc (g mapReprMapReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\temitNodeAssemblerMethodAssignNode_mapoid(w, g.AdjCfg, g)\n}\nfunc (g mapReprMapReprBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\temitNodeAssemblerHelper_mapoid_keyTidyHelper(w, g.AdjCfg, g)\n\temitNodeAssemblerHelper_mapoid_valueTidyHelper(w, g.AdjCfg, g)\n\temitNodeAssemblerHelper_mapoid_mapAssemblerMethods(w, g.AdjCfg, g)\n}\n"
  },
  {
    "path": "schema/gen/go/genString.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\ntype stringGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.StringTraits\n\tPkgName string\n\tType    *schema.TypeString\n}\n\nfunc (stringGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\n// --- native content and specializations --->\n\nfunc (g stringGenerator) EmitNativeType(w io.Writer) {\n\temitNativeType_scalar(w, g.AdjCfg, g)\n}\nfunc (g stringGenerator) EmitNativeAccessors(w io.Writer) {\n\temitNativeAccessors_scalar(w, g.AdjCfg, g)\n}\nfunc (g stringGenerator) EmitNativeBuilder(w io.Writer) {\n\t// Generate a single-step construction function -- this is easy to do for a scalar,\n\t//  and all representations of scalar kind can be expected to have a method like this.\n\t// The function is attached to the NodePrototype for convenient namespacing;\n\t//  it needs no new memory, so it would be inappropriate to attach to the builder or assembler.\n\t// The function is directly used internally by anything else that might involve recursive destructuring on the same scalar kind\n\t//  (for example, structs using stringjoin strategies that have one of this type as a field, etc).\n\t// FUTURE: should engage validation flow.\n\tdoTemplate(`\n\t\tfunc (_{{ .Type | TypeSymbol }}__Prototype) fromString(w *_{{ .Type | TypeSymbol }}, v string) error {\n\t\t\t*w = _{{ .Type | TypeSymbol }}{v}\n\t\t\treturn nil\n\t\t}\n\t`, w, g.AdjCfg, g)\n\t// And generate a publicly exported version of that single-step constructor, too.\n\t//  (Just don't expose the details about allocation, because you can't meaningfully use that from outside the package.)\n\temitNativeBuilder_scalar(w, g.AdjCfg, g)\n}\n\nfunc (g stringGenerator) EmitNativeMaybe(w io.Writer) {\n\temitNativeMaybe(w, g.AdjCfg, g)\n}\n\n// --- type info --->\n\nfunc (g stringGenerator) EmitTypeConst(w io.Writer) {\n\tdoTemplate(`\n\t\t// TODO EmitTypeConst\n\t`, w, g.AdjCfg, g)\n}\n\n// --- TypedNode interface satisfaction --->\n\nfunc (g stringGenerator) EmitTypedNodeMethodType(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .Type | TypeSymbol }}) Type() schema.Type {\n\t\t\treturn nil /*TODO:typelit*/\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g stringGenerator) EmitTypedNodeMethodRepresentation(w io.Writer) {\n\temitTypicalTypedNodeMethodRepresentation(w, g.AdjCfg, g)\n}\n\n// --- Node interface satisfaction --->\n\nfunc (g stringGenerator) EmitNodeType(w io.Writer) {\n\t// No additional types needed.  Methods all attach to the native type.\n}\n\nfunc (g stringGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\temitNodeTypeAssertions_typical(w, g.AdjCfg, g)\n}\nfunc (g stringGenerator) EmitNodeMethodAsString(w io.Writer) {\n\temitNodeMethodAsKind_scalar(w, g.AdjCfg, g)\n}\nfunc (g stringGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\nfunc (g stringGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g stringGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn stringBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.StringAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype stringBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.StringAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeString\n}\n\nfunc (stringBuilderGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\nfunc (g stringBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g stringBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g stringBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\temitNodeAssemblerType_scalar(w, g.AdjCfg, g)\n}\nfunc (g stringBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_scalar(w, g.AdjCfg, g)\n}\nfunc (g stringBuilderGenerator) EmitNodeAssemblerMethodAssignString(w io.Writer) {\n\temitNodeAssemblerMethodAssignKind_scalar(w, g.AdjCfg, g)\n}\nfunc (g stringBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\temitNodeAssemblerMethodAssignNode_scalar(w, g.AdjCfg, g)\n}\nfunc (g stringBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\t// Nothing needed here for string kinds.\n}\n"
  },
  {
    "path": "schema/gen/go/genStringReprString.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\nvar _ TypeGenerator = &stringReprStringGenerator{}\n\nfunc NewStringReprStringGenerator(pkgName string, typ *schema.TypeString, adjCfg *AdjunctCfg) TypeGenerator {\n\treturn stringReprStringGenerator{\n\t\tstringGenerator{\n\t\t\tadjCfg,\n\t\t\tmixins.StringTraits{\n\t\t\t\tPkgName:    pkgName,\n\t\t\t\tTypeName:   string(typ.Name()),\n\t\t\t\tTypeSymbol: adjCfg.TypeSymbol(typ),\n\t\t\t},\n\t\t\tpkgName,\n\t\t\ttyp,\n\t\t},\n\t}\n}\n\ntype stringReprStringGenerator struct {\n\tstringGenerator\n}\n\nfunc (g stringReprStringGenerator) GetRepresentationNodeGen() NodeGenerator {\n\treturn stringReprStringReprGenerator{\n\t\tg.AdjCfg,\n\t\tg.Type,\n\t}\n}\n\ntype stringReprStringReprGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tType   *schema.TypeString\n}\n\nfunc (g stringReprStringReprGenerator) EmitNodeType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Repr = _{{ .Type | TypeSymbol }}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g stringReprStringReprGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}\n\t`, w, g.AdjCfg, g)\n}\nfunc (stringReprStringReprGenerator) EmitNodeMethodKind(io.Writer)            {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodLookupByString(io.Writer)  {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodLookupByNode(io.Writer)    {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodLookupByIndex(io.Writer)   {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodLookupBySegment(io.Writer) {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodMapIterator(io.Writer)     {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodListIterator(io.Writer)    {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodLength(io.Writer)          {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodIsAbsent(io.Writer)        {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodIsNull(io.Writer)          {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodAsBool(io.Writer)          {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodAsInt(io.Writer)           {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodAsFloat(io.Writer)         {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodAsString(io.Writer)        {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodAsBytes(io.Writer)         {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodAsLink(io.Writer)          {}\nfunc (stringReprStringReprGenerator) EmitNodeMethodPrototype(io.Writer)       {}\nfunc (g stringReprStringReprGenerator) EmitNodePrototypeType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprPrototype = _{{ .Type | TypeSymbol }}__Prototype\n\t`, w, g.AdjCfg, g)\n}\nfunc (g stringReprStringReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn stringReprStringReprBuilderGenerator(g)\n}\n\ntype stringReprStringReprBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tType   *schema.TypeString\n}\n\nfunc (stringReprStringReprBuilderGenerator) EmitNodeBuilderType(io.Writer)        {}\nfunc (g stringReprStringReprBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {}\nfunc (g stringReprStringReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// Since this is a \"natural\" representation... there's just a type alias here.\n\t//  No new functions are necessary.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprAssembler = _{{ .Type | TypeSymbol }}__Assembler\n\t`, w, g.AdjCfg, g)\n}\nfunc (stringReprStringReprBuilderGenerator) EmitNodeAssemblerMethodBeginMap(io.Writer)     {}\nfunc (stringReprStringReprBuilderGenerator) EmitNodeAssemblerMethodBeginList(io.Writer)    {}\nfunc (stringReprStringReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(io.Writer)   {}\nfunc (stringReprStringReprBuilderGenerator) EmitNodeAssemblerMethodAssignBool(io.Writer)   {}\nfunc (stringReprStringReprBuilderGenerator) EmitNodeAssemblerMethodAssignInt(io.Writer)    {}\nfunc (stringReprStringReprBuilderGenerator) EmitNodeAssemblerMethodAssignFloat(io.Writer)  {}\nfunc (stringReprStringReprBuilderGenerator) EmitNodeAssemblerMethodAssignString(io.Writer) {}\nfunc (stringReprStringReprBuilderGenerator) EmitNodeAssemblerMethodAssignBytes(io.Writer)  {}\nfunc (stringReprStringReprBuilderGenerator) EmitNodeAssemblerMethodAssignLink(io.Writer)   {}\nfunc (stringReprStringReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(io.Writer)   {}\nfunc (stringReprStringReprBuilderGenerator) EmitNodeAssemblerMethodPrototype(io.Writer)    {}\nfunc (stringReprStringReprBuilderGenerator) EmitNodeAssemblerOtherBits(io.Writer)          {}\n"
  },
  {
    "path": "schema/gen/go/genStruct.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\ntype structGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.MapTraits\n\tPkgName string\n\tType    *schema.TypeStruct\n}\n\nfunc (structGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\n// --- native content and specializations --->\n\nfunc (g structGenerator) EmitNativeType(w io.Writer) {\n\tdoTemplate(`\n\t\t{{- if Comments -}}\n\t\t// {{ .Type | TypeSymbol }} matches the IPLD Schema type \"{{ .Type.Name }}\".  It has {{ .Type.TypeKind }} type-kind, and may be interrogated like {{ .Kind }} kind.\n\t\t{{- end}}\n\t\ttype {{ .Type | TypeSymbol }} = *_{{ .Type | TypeSymbol }}\n\t\ttype _{{ .Type | TypeSymbol }} struct {\n\t\t\t{{- range $field := .Type.Fields}}\n\t\t\t{{ $field | FieldSymbolLower }} _{{ $field.Type | TypeSymbol }}{{if $field.IsMaybe }}__Maybe{{end}}\n\t\t\t{{- end}}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structGenerator) EmitNativeAccessors(w io.Writer) {\n\tdoTemplate(`\n\t\t{{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}}\n\t\t{{- range $field := .Type.Fields }}\n\t\tfunc (n _{{ $type | TypeSymbol }}) Field{{ $field | FieldSymbolUpper }}() {{ if $field.IsMaybe }}Maybe{{end}}{{ $field.Type | TypeSymbol }} {\n\t\t\treturn &n.{{ $field | FieldSymbolLower }}\n\t\t}\n\t\t{{- end}}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structGenerator) EmitNativeBuilder(w io.Writer) {\n\t// Unclear what, if anything, goes here.\n}\n\nfunc (g structGenerator) EmitNativeMaybe(w io.Writer) {\n\temitNativeMaybe(w, g.AdjCfg, g)\n}\n\n// --- type info --->\n\nfunc (g structGenerator) EmitTypeConst(w io.Writer) {\n\tdoTemplate(`\n\t\t// TODO EmitTypeConst\n\t`, w, g.AdjCfg, g)\n}\n\n// --- TypedNode interface satisfaction --->\n\nfunc (g structGenerator) EmitTypedNodeMethodType(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .Type | TypeSymbol }}) Type() schema.Type {\n\t\t\treturn nil /*TODO:typelit*/\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structGenerator) EmitTypedNodeMethodRepresentation(w io.Writer) {\n\temitTypicalTypedNodeMethodRepresentation(w, g.AdjCfg, g)\n}\n\n// --- Node interface satisfaction --->\n\nfunc (g structGenerator) EmitNodeType(w io.Writer) {\n\t// No additional types needed.  Methods all attach to the native type.\n\t// We do, however, want some constants for our fields;\n\t//  they'll make iterators able to work faster.  So let's emit those.\n\tdoTemplate(`\n\t\tvar (\n\t\t\t{{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}}\n\t\t\t{{- range $field := .Type.Fields }}\n\t\t\tfieldName__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }} = _String{\"{{ $field.Name }}\"}\n\t\t\t{{- end }}\n\t\t)\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\temitNodeTypeAssertions_typical(w, g.AdjCfg, g)\n}\n\nfunc (g structGenerator) EmitNodeMethodLookupByString(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) LookupByString(key string) (datamodel.Node, error) {\n\t\t\tswitch key {\n\t\t\t{{- range $field := .Type.Fields }}\n\t\t\tcase \"{{ $field.Name }}\":\n\t\t\t\t{{- if $field.IsOptional }}\n\t\t\t\tif n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Absent {\n\t\t\t\t\treturn datamodel.Absent, nil\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- if $field.IsNullable }}\n\t\t\t\tif n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Null {\n\t\t\t\t\treturn datamodel.Null, nil\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- if $field.IsMaybe }}\n\t\t\t\treturn {{if not (MaybeUsesPtr $field.Type) }}&{{end}}n.{{ $field | FieldSymbolLower }}.v, nil\n\t\t\t\t{{- else}}\n\t\t\t\treturn &n.{{ $field | FieldSymbolLower }}, nil\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\treturn nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: datamodel.PathSegmentOfString(key)}\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structGenerator) EmitNodeMethodLookupByNode(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\t\t\tks, err := key.AsString()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn n.LookupByString(ks)\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structGenerator) EmitNodeMethodMapIterator(w io.Writer) {\n\t// Note that the typed iterator will report absent fields.\n\t//  The representation iterator (if has one) however will skip those.\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) MapIterator() datamodel.MapIterator {\n\t\t\treturn &_{{ .Type | TypeSymbol }}__MapItr{n, 0}\n\t\t}\n\n\t\ttype _{{ .Type | TypeSymbol }}__MapItr struct {\n\t\t\tn {{ .Type | TypeSymbol }}\n\t\t\tidx  int\n\t\t}\n\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__MapItr) Next() (k datamodel.Node, v datamodel.Node, _ error) {\n\t\t\t{{- if not .Type.Fields }}\n\t\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t\t\t{{ else -}}\n\t\t\tif itr.idx >= {{ len .Type.Fields }} {\n\t\t\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t\t\t}\n\t\t\tswitch itr.idx {\n\t\t\t{{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}}\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tcase {{ $i }}:\n\t\t\t\tk = &fieldName__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}\n\t\t\t\t{{- if $field.IsOptional }}\n\t\t\t\tif itr.n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Absent {\n\t\t\t\t\tv = datamodel.Absent\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- if $field.IsNullable }}\n\t\t\t\tif itr.n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Null {\n\t\t\t\t\tv = datamodel.Null\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- if $field.IsMaybe }}\n\t\t\t\tv = {{if not (MaybeUsesPtr $field.Type) }}&{{end}}itr.n.{{ $field | FieldSymbolLower}}.v\n\t\t\t\t{{- else}}\n\t\t\t\tv = &itr.n.{{ $field | FieldSymbolLower}}\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t\titr.idx++\n\t\t\treturn\n\t\t\t{{- end}}\n\t\t}\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__MapItr) Done() bool {\n\t\t\treturn itr.idx >= {{ len .Type.Fields }}\n\t\t}\n\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structGenerator) EmitNodeMethodLength(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .Type | TypeSymbol }}) Length() int64 {\n\t\t\treturn {{ len .Type.Fields }}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\n\nfunc (g structGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g structGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn structBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.MapAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype structBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.MapAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeStruct\n}\n\nfunc (structBuilderGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\nfunc (g structBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g structBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g structBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// - 'w' is the \"**w**ip\" pointer.\n\t// - 'm' is the **m**aybe which communicates our completeness to the parent if we're a child assembler.\n\t// - 'state' is what it says on the tin.  this is used for the map state (the broad transitions between null, start-map, and finish are handled by 'm' for consistency.)\n\t// - 's' is a bitfield for what's been **s**et.\n\t// - 'f' is the **f**ocused field that will be assembled next.\n\t//\n\t// - 'cm' is **c**hild **m**aybe and is used for the completion message from children that aren't allowed to be nullable (for those that are, their own maybe.m is used).\n\t//    ('cm' could be elided for structs where all fields are maybes.  trivial but not yet implemented.)\n\t// - the 'ca_*' fields embed **c**hild **a**ssemblers -- these are embedded so we can yield pointers to them without causing new allocations.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Assembler struct {\n\t\t\tw *_{{ .Type | TypeSymbol }}\n\t\t\tm *schema.Maybe\n\t\t\tstate maState\n\t\t\ts int\n\t\t\tf int\n\n\t\t\tcm schema.Maybe\n\t\t\t{{range $field := .Type.Fields -}}\n\t\t\tca_{{ $field | FieldSymbolLower }} _{{ $field.Type | TypeSymbol }}__Assembler\n\t\t\t{{end -}}\n\t\t}\n\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__Assembler) reset() {\n\t\t\tna.state = maState_initial\n\t\t\tna.s = 0\n\t\t\t{{- range $field := .Type.Fields }}\n\t\t\tna.ca_{{ $field | FieldSymbolLower }}.reset()\n\t\t\t{{- end}}\n\t\t}\n\n\t\tvar (\n\t\t\t{{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}}\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tfieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }} = 1 << {{ $i }}\n\t\t\t{{- end}}\n\t\t\tfieldBits__{{ $type | TypeSymbol }}_sufficient = 0 {{- range $i, $field := .Type.Fields }}{{if not $field.IsOptional }} + 1 << {{ $i }}{{end}}{{end}}\n\t\t)\n\t`, w, g.AdjCfg, g)\n}\nfunc (g structBuilderGenerator) EmitNodeAssemblerMethodBeginMap(w io.Writer) {\n\temitNodeAssemblerMethodBeginMap_strictoid(w, g.AdjCfg, g)\n}\nfunc (g structBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_recursive(w, g.AdjCfg, g)\n}\nfunc (g structBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\t// AssignNode goes through three phases:\n\t// 1. is it null?  Jump over to AssignNull (which may or may not reject it).\n\t// 2. is it our own type?  Handle specially -- we might be able to do efficient things.\n\t// 3. is it the right kind to morph into us?  Do so.\n\t//\n\t// We do not set m=midvalue in phase 3 -- it shouldn't matter unless you're trying to pull off concurrent access, which is wrong and unsafe regardless.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__Assembler) AssignNode(v datamodel.Node) error {\n\t\t\tif v.IsNull() {\n\t\t\t\treturn na.AssignNull()\n\t\t\t}\n\t\t\tif v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok {\n\t\t\t\tswitch *na.m {\n\t\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\t\tcase midvalue:\n\t\t\t\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t\t\t\t}\n\t\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\t\tif na.w == nil {\n\t\t\t\t\tna.w = v2\n\t\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t*na.w = *v2\n\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif v.Kind() != datamodel.Kind_Map {\n\t\t\t\treturn datamodel.ErrWrongKind{TypeName: \"{{ .PkgName }}.{{ .Type.Name }}\", MethodName: \"AssignNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: v.Kind()}\n\t\t\t}\n\t\t\titr := v.MapIterator()\n\t\t\tfor !itr.Done() {\n\t\t\t\tk, v, err := itr.Next()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := na.AssembleKey().AssignNode(k); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn na.Finish()\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g structBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\tg.emitMapAssemblerChildTidyHelper(w)\n\tg.emitMapAssemblerMethods(w)\n\tg.emitKeyAssembler(w)\n}\nfunc (g structBuilderGenerator) emitMapAssemblerChildTidyHelper(w io.Writer) {\n\t// This function attempts to clean up the state machine to acknolwedge child assembly finish.\n\t//  If the child was finished and we just collected it, return true and update state to maState_initial.\n\t//  Otherwise, if it wasn't done, return false;\n\t//   and the caller is almost certain to emit an error momentarily.\n\t// The function will only be called when the current state is maState_midValue.\n\t//  (In general, the idea is that if the user is doing things correctly,\n\t//   this function will only be called when the child is in fact finished.)\n\t// Most of the logic here is about nullables and not optionals,\n\t//  because if you're an optional that's absent, you never got to value assembly.\n\t//  There's still one branch for optionals, though, because they have a different residence for 'm' just as nullables do.\n\t// Child assemblers are expected to control their own state machines;\n\t//  for values that have maybes, we never change their maybe state again, so the usual logic should hold;\n\t//  for values that don't have maybes (and thus share 'cm')...\n\t//   We don't bother to nil their 'm' pointer; the worst that can happen is an over-held assembler for that field\n\t//    can make a bizarre and broken transition for a subsequent field, which will result in very ugly errors, but isn't unsafe per se.\n\t//   We do nil their 'w' pointer, though: we don't want a set to that able to leak in later if we're on the way to Finish!\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__Assembler) valueFinishTidy() bool {\n\t\t\tswitch ma.f {\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tcase {{ $i }}:\n\t\t\t\t{{- if $field.IsNullable }}\n\t\t\t\tswitch ma.w.{{ $field | FieldSymbolLower }}.m {\n\t\t\t\tcase schema.Maybe_Null:\n\t\t\t\t\tma.state = maState_initial\n\t\t\t\t\treturn true\n\t\t\t\tcase schema.Maybe_Value:\n\t\t\t\t\t{{- if (MaybeUsesPtr $field.Type) }}\n\t\t\t\t\tma.w.{{ $field | FieldSymbolLower }}.v = ma.ca_{{ $field | FieldSymbolLower }}.w\n\t\t\t\t\t{{- end}}\n\t\t\t\t\tma.state = maState_initial\n\t\t\t\t\treturn true\n\t\t\t\tdefault:\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\t{{- else if $field.IsOptional }}\n\t\t\t\tswitch ma.w.{{ $field | FieldSymbolLower }}.m {\n\t\t\t\tcase schema.Maybe_Value:\n\t\t\t\t\t{{- if (MaybeUsesPtr $field.Type) }}\n\t\t\t\t\tma.w.{{ $field | FieldSymbolLower }}.v = ma.ca_{{ $field | FieldSymbolLower }}.w\n\t\t\t\t\t{{- end}}\n\t\t\t\t\tma.state = maState_initial\n\t\t\t\t\treturn true\n\t\t\t\tdefault:\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\t{{- else}}\n\t\t\t\tswitch ma.cm {\n\t\t\t\tcase schema.Maybe_Value:\n\t\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.w = nil\n\t\t\t\t\tma.cm = schema.Maybe_Absent\n\t\t\t\t\tma.state = maState_initial\n\t\t\t\t\treturn true\n\t\t\t\tdefault:\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g structBuilderGenerator) emitMapAssemblerMethods(w io.Writer) {\n\t// FUTURE: some of the setup of the child assemblers could probably be DRY'd up.\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__Assembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling another key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\t{{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}}\n\t\t\t{{- if .Type.Fields }}\n\t\t\tswitch k {\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tcase \"{{ $field.Name }}\":\n\t\t\t\tif ma.s & fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }} != 0 {\n\t\t\t\t\treturn nil, datamodel.ErrRepeatedMapKey{Key: &fieldName__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}}\n\t\t\t\t}\n\t\t\t\tma.s += fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}\n\t\t\t\tma.state = maState_midValue\n\t\t\t\tma.f = {{ $i }}\n\t\t\t\t{{- if $field.IsMaybe }}\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.w = {{if not (MaybeUsesPtr $field.Type) }}&{{end}}ma.w.{{ $field | FieldSymbolLower }}.v\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.m = &ma.w.{{ $field | FieldSymbolLower }}.m\n\t\t\t\t{{- if $field.IsNullable }}\n\t\t\t\tma.w.{{ $field | FieldSymbolLower }}.m = allowNull\n\t\t\t\t{{- end}}\n\t\t\t\t{{- else}}\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.w = &ma.w.{{ $field | FieldSymbolLower }}\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.m = &ma.cm\n\t\t\t\t{{- end}}\n\t\t\t\treturn &ma.ca_{{ $field | FieldSymbolLower }}, nil\n\t\t\t{{- end}}\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\treturn nil, schema.ErrInvalidKey{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}\", Key:&_String{k}}\n\t\t}\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__Assembler) AssembleKey() datamodel.NodeAssembler {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling another key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tma.state = maState_midKey\n\t\t\treturn (*_{{ .Type | TypeSymbol }}__KeyAssembler)(ma)\n\t\t}\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__Assembler) AssembleValue() datamodel.NodeAssembler {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when no key is primed\")\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling a key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\t// carry on\n\t\t\tcase maState_midValue:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling another value\")\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tma.state = maState_midValue\n\t\t\tswitch ma.f {\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tcase {{ $i }}:\n\t\t\t\t{{- if $field.IsMaybe }}\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.w = {{if not (MaybeUsesPtr $field.Type) }}&{{end}}ma.w.{{ $field | FieldSymbolLower }}.v\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.m = &ma.w.{{ $field | FieldSymbolLower }}.m\n\t\t\t\t{{- if $field.IsNullable }}\n\t\t\t\tma.w.{{ $field | FieldSymbolLower }}.m = allowNull\n\t\t\t\t{{- end}}\n\t\t\t\t{{- else}}\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.w = &ma.w.{{ $field | FieldSymbolLower }}\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.m = &ma.cm\n\t\t\t\t{{- end}}\n\t\t\t\treturn &ma.ca_{{ $field | FieldSymbolLower }}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t}\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__Assembler) Finish() error {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tif ma.s & fieldBits__{{ $type | TypeSymbol }}_sufficient != fieldBits__{{ $type | TypeSymbol }}_sufficient {\n\t\t\t\terr := schema.ErrMissingRequiredField{Missing: make([]string, 0)}\n\t\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\t\t{{- if not $field.IsMaybe}}\n\t\t\t\tif ma.s & fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }} == 0 {\n\t\t\t\t\terr.Missing = append(err.Missing, \"{{ $field.Name }}\")\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- end}}\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tma.state = maState_finished\n\t\t\t*ma.m = schema.Maybe_Value\n\t\t\treturn nil\n\t\t}\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__Assembler) KeyPrototype() datamodel.NodePrototype {\n\t\t\treturn _String__Prototype{}\n\t\t}\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__Assembler) ValuePrototype(k string) datamodel.NodePrototype {\n\t\t\tpanic(\"todo structbuilder mapassembler valueprototype\")\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g structBuilderGenerator) emitKeyAssembler(w io.Writer) {\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__KeyAssembler _{{ .Type | TypeSymbol }}__Assembler\n\t`, w, g.AdjCfg, g)\n\tstubs := mixins.StringAssemblerTraits{\n\t\tPkgName:       g.PkgName,\n\t\tTypeName:      g.TypeName + \".KeyAssembler\",\n\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Key\",\n\t}\n\t// This key assembler can disregard any idea of complex keys because it's a struct!\n\t//  Struct field names must be strings (and quite simple ones at that).\n\tstubs.EmitNodeAssemblerMethodBeginMap(w)\n\tstubs.EmitNodeAssemblerMethodBeginList(w)\n\tstubs.EmitNodeAssemblerMethodAssignNull(w)\n\tstubs.EmitNodeAssemblerMethodAssignBool(w)\n\tstubs.EmitNodeAssemblerMethodAssignInt(w)\n\tstubs.EmitNodeAssemblerMethodAssignFloat(w)\n\tdoTemplate(`\n\t\tfunc (ka *_{{ .Type | TypeSymbol }}__KeyAssembler) AssignString(k string) error {\n\t\t\tif ka.state != maState_midKey {\n\t\t\t\tpanic(\"misuse: KeyAssembler held beyond its valid lifetime\")\n\t\t\t}\n\t\t\tswitch k {\n\t\t\t{{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}}\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tcase \"{{ $field.Name }}\":\n\t\t\t\tif ka.s & fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }} != 0 {\n\t\t\t\t\treturn datamodel.ErrRepeatedMapKey{Key: &fieldName__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}}\n\t\t\t\t}\n\t\t\t\tka.s += fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}\n\t\t\t\tka.state = maState_expectValue\n\t\t\t\tka.f = {{ $i }}\n\t\t\t\treturn nil\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\treturn schema.ErrInvalidKey{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}\", Key:&_String{k}}\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n\tstubs.EmitNodeAssemblerMethodAssignBytes(w)\n\tstubs.EmitNodeAssemblerMethodAssignLink(w)\n\tdoTemplate(`\n\t\tfunc (ka *_{{ .Type | TypeSymbol }}__KeyAssembler) AssignNode(v datamodel.Node) error {\n\t\t\tif v2, err := v.AsString(); err != nil {\n\t\t\t\treturn err\n\t\t\t} else {\n\t\t\t\treturn ka.AssignString(v2)\n\t\t\t}\n\t\t}\n\t\tfunc (_{{ .Type | TypeSymbol }}__KeyAssembler) Prototype() datamodel.NodePrototype {\n\t\t\treturn _String__Prototype{}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n"
  },
  {
    "path": "schema/gen/go/genStructReprMap.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\t\"strconv\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\nvar _ TypeGenerator = &structReprMapGenerator{}\n\nfunc NewStructReprMapGenerator(pkgName string, typ *schema.TypeStruct, adjCfg *AdjunctCfg) TypeGenerator {\n\treturn structReprMapGenerator{\n\t\tstructGenerator{\n\t\t\tadjCfg,\n\t\t\tmixins.MapTraits{\n\t\t\t\tPkgName:    pkgName,\n\t\t\t\tTypeName:   string(typ.Name()),\n\t\t\t\tTypeSymbol: adjCfg.TypeSymbol(typ),\n\t\t\t},\n\t\t\tpkgName,\n\t\t\ttyp,\n\t\t},\n\t}\n}\n\ntype structReprMapGenerator struct {\n\tstructGenerator\n}\n\nfunc (g structReprMapGenerator) GetRepresentationNodeGen() NodeGenerator {\n\treturn structReprMapReprGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.MapTraits{\n\t\t\tPkgName:    g.PkgName,\n\t\t\tTypeName:   string(g.Type.Name()) + \".Repr\",\n\t\t\tTypeSymbol: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Repr\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype structReprMapReprGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.MapTraits\n\tPkgName string\n\tType    *schema.TypeStruct\n}\n\nfunc (structReprMapReprGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g structReprMapReprGenerator) EmitNodeType(w io.Writer) {\n\t// The type is structurally the same, but will have a different set of methods.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Repr _{{ .Type | TypeSymbol }}\n\t`, w, g.AdjCfg, g)\n\n\t// We do also want some constants for our fields;\n\t//  they'll make iterators able to work faster.\n\t//  These might be the same strings as the type-level field names\n\t//   (in fact, they are, unless renames are used)... but that's fine.\n\t//    We get simpler code by just doing this unconditionally.\n\tdoTemplate(`\n\t\tvar (\n\t\t\t{{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}}\n\t\t\t{{- range $field := .Type.Fields }}\n\t\t\tfieldName__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}_serial = _String{\"{{ $field | $type.RepresentationStrategy.GetFieldKey }}\"}\n\t\t\t{{- end }}\n\t\t)\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structReprMapReprGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structReprMapReprGenerator) EmitNodeMethodLookupByString(w io.Writer) {\n\t// Similar to the type-level method, except any absent fields also return ErrNotExists.\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) LookupByString(key string) (datamodel.Node, error) {\n\t\t\tswitch key {\n\t\t\t{{- range $field := .Type.Fields }}\n\t\t\tcase \"{{ $field | $field.Parent.RepresentationStrategy.GetFieldKey }}\":\n\t\t\t\t{{- if $field.IsOptional }}\n\t\t\t\tif n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Absent {\n\t\t\t\t\treturn datamodel.Absent, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)}\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- if $field.IsNullable }}\n\t\t\t\tif n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Null {\n\t\t\t\t\treturn datamodel.Null, nil\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- if $field.IsMaybe }}\n\t\t\t\treturn n.{{ $field | FieldSymbolLower }}.v.Representation(), nil\n\t\t\t\t{{- else}}\n\t\t\t\treturn n.{{ $field | FieldSymbolLower }}.Representation(), nil\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\treturn nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: datamodel.PathSegmentOfString(key)}\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structReprMapReprGenerator) EmitNodeMethodLookupByNode(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\t\t\tks, err := key.AsString()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn n.LookupByString(ks)\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structReprMapReprGenerator) EmitNodeMethodMapIterator(w io.Writer) {\n\t// The 'idx' int is what field we'll yield next.\n\t// Note that this iterator doesn't mention fields that are absent.\n\t//  This makes things a bit trickier -- especially the 'Done' predicate,\n\t//   since it may have to do lookahead if there's any optionals at the end of the structure!\n\t//  It also means 'idx' can jump ahead by more than one per Next call in order to skip over absent fields.\n\t// TODO : support for implicits is still future work.\n\n\t// First: Determine if there are any optionals at all.\n\t//  If there are none, some control flow symbols need to not be emitted.\n\tfields := g.Type.Fields()\n\thaveOptionals := false\n\tfor _, field := range fields {\n\t\tif field.IsOptional() {\n\t\t\thaveOptionals = true\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// Second: Count how many trailing fields are optional.\n\t//  The 'Done' predicate gets more complex when in the trailing optionals.\n\tfieldCount := len(fields)\n\tbeginTrailingOptionalField := fieldCount\n\tfor i := fieldCount - 1; i >= 0; i-- {\n\t\tif !fields[i].IsOptional() {\n\t\t\tbreak\n\t\t}\n\t\tbeginTrailingOptionalField = i\n\t}\n\thaveTrailingOptionals := beginTrailingOptionalField < fieldCount\n\n\t// Now: finally we can get on with the actual templating.\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) MapIterator() datamodel.MapIterator {\n\t\t\t{{- if .HaveTrailingOptionals }}\n\t\t\tend := {{ len .Type.Fields }}`+\n\t\tfunc() string { // this next part was too silly in templates due to lack of reverse ranging.\n\t\t\tv := \"\\n\"\n\t\t\tfor i := fieldCount - 1; i >= beginTrailingOptionalField; i-- {\n\t\t\t\tv += \"\\t\\t\\tif n.\" + g.AdjCfg.FieldSymbolLower(fields[i]) + \".m == schema.Maybe_Absent {\\n\"\n\t\t\t\tv += \"\\t\\t\\t\\tend = \" + strconv.Itoa(i) + \"\\n\"\n\t\t\t\tv += \"\\t\\t\\t} else {\\n\"\n\t\t\t\tv += \"\\t\\t\\t\\tgoto done\\n\"\n\t\t\t\tv += \"\\t\\t\\t}\\n\"\n\t\t\t}\n\t\t\treturn v\n\t\t}()+`done:\n\t\t\treturn &_{{ .Type | TypeSymbol }}__ReprMapItr{n, 0, end}\n\t\t\t{{- else}}\n\t\t\treturn &_{{ .Type | TypeSymbol }}__ReprMapItr{n, 0}\n\t\t\t{{- end}}\n\t\t}\n\n\t\ttype _{{ .Type | TypeSymbol }}__ReprMapItr struct {\n\t\t\tn   *_{{ .Type | TypeSymbol }}__Repr\n\t\t\tidx int\n\t\t\t{{if .HaveTrailingOptionals }}end int{{end}}\n\t\t}\n\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__ReprMapItr) Next() (k datamodel.Node, v datamodel.Node, _ error) {\n\t\t\t{{- if not .Type.Fields }}\n\t\t\t{{- /* TODO: deduplicate all these methods which just error */ -}}\n\t\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t\t\t{{ else -}}\n\t\t\t{{ if .HaveOptionals }}advance:{{end -}}\n\t\t\tif itr.idx >= {{ len .Type.Fields }} {\n\t\t\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t\t\t}\n\t\t\tswitch itr.idx {\n\t\t\t{{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}}\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tcase {{ $i }}:\n\t\t\t\tk = &fieldName__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}_serial\n\t\t\t\t{{- if $field.IsOptional }}\n\t\t\t\tif itr.n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Absent {\n\t\t\t\t\titr.idx++\n\t\t\t\t\tgoto advance\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- if $field.IsNullable }}\n\t\t\t\tif itr.n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Null {\n\t\t\t\t\tv = datamodel.Null\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- if $field.IsMaybe }}\n\t\t\t\tv = itr.n.{{ $field | FieldSymbolLower}}.v.Representation()\n\t\t\t\t{{- else}}\n\t\t\t\tv = itr.n.{{ $field | FieldSymbolLower}}.Representation()\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t\titr.idx++\n\t\t\treturn\n\t\t\t{{- end}}\n\t\t}\n\t\t{{- if .HaveTrailingOptionals }}\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__ReprMapItr) Done() bool {\n\t\t\treturn itr.idx >= itr.end\n\t\t}\n\t\t{{- else}}\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__ReprMapItr) Done() bool {\n\t\t\treturn itr.idx >= {{ len .Type.Fields }}\n\t\t}\n\t\t{{- end}}\n\t`, w, g.AdjCfg, struct {\n\t\tType                       *schema.TypeStruct\n\t\tHaveOptionals              bool\n\t\tHaveTrailingOptionals      bool\n\t\tBeginTrailingOptionalField int\n\t}{\n\t\tg.Type,\n\t\thaveOptionals,\n\t\thaveTrailingOptionals,\n\t\tbeginTrailingOptionalField,\n\t})\n}\n\nfunc (g structReprMapReprGenerator) EmitNodeMethodLength(w io.Writer) {\n\t// This is fun: it has to count down for any unset optional fields.\n\t// TODO : support for implicits is still future work.\n\tdoTemplate(`\n\t\tfunc (rn *_{{ .Type | TypeSymbol }}__Repr) Length() int64 {\n\t\t\tl := {{ len .Type.Fields }}\n\t\t\t{{- range $field := .Type.Fields }}\n\t\t\t{{- if $field.IsOptional }}\n\t\t\tif rn.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Absent {\n\t\t\t\tl--\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\treturn int64(l)\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structReprMapReprGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\n\nfunc (g structReprMapReprGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g structReprMapReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn structReprMapReprBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.MapAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Repr\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype structReprMapReprBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.MapAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeStruct\n}\n\nfunc (structReprMapReprBuilderGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g structReprMapReprBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g structReprMapReprBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g structReprMapReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// - 'w' is the \"**w**ip\" pointer.\n\t// - 'm' is the **m**aybe which communicates our completeness to the parent if we're a child assembler.\n\t// - 'state' is what it says on the tin.  this is used for the map state (the broad transitions between null, start-map, and finish are handled by 'm' for consistency.)\n\t// - 's' is a bitfield for what's been **s**et.\n\t// - 'f' is the **f**ocused field that will be assembled next.\n\t//\n\t// - 'cm' is **c**hild **m**aybe and is used for the completion message from children that aren't allowed to be nullable (for those that are, their own maybe.m is used).\n\t// - the 'ca_*' fields embed **c**hild **a**ssemblers -- these are embedded so we can yield pointers to them without causing new allocations.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprAssembler struct {\n\t\t\tw *_{{ .Type | TypeSymbol }}\n\t\t\tm *schema.Maybe\n\t\t\tstate maState\n\t\t\ts int\n\t\t\tf int\n\n\t\t\tcm schema.Maybe\n\t\t\t{{range $field := .Type.Fields -}}\n\t\t\tca_{{ $field | FieldSymbolLower }} _{{ $field.Type | TypeSymbol }}__ReprAssembler\n\t\t\t{{end -}}\n\t\t}\n\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) reset() {\n\t\t\tna.state = maState_initial\n\t\t\tna.s = 0\n\t\t\t{{- range $field := .Type.Fields }}\n\t\t\tna.ca_{{ $field | FieldSymbolLower }}.reset()\n\t\t\t{{- end}}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g structReprMapReprBuilderGenerator) EmitNodeAssemblerMethodBeginMap(w io.Writer) {\n\temitNodeAssemblerMethodBeginMap_strictoid(w, g.AdjCfg, g)\n}\nfunc (g structReprMapReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_recursive(w, g.AdjCfg, g)\n}\nfunc (g structReprMapReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\t// AssignNode goes through three phases:\n\t// 1. is it null?  Jump over to AssignNull (which may or may not reject it).\n\t// 2. is it our own type?  Handle specially -- we might be able to do efficient things.\n\t// 3. is it the right kind to morph into us?  Do so.\n\t//\n\t// We do not set m=midvalue in phase 3 -- it shouldn't matter unless you're trying to pull off concurrent access, which is wrong and unsafe regardless.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignNode(v datamodel.Node) error {\n\t\t\tif v.IsNull() {\n\t\t\t\treturn na.AssignNull()\n\t\t\t}\n\t\t\tif v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok {\n\t\t\t\tswitch *na.m {\n\t\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\t\tcase midvalue:\n\t\t\t\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t\t\t\t}\n\t\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\t\tif na.w == nil {\n\t\t\t\t\tna.w = v2\n\t\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t*na.w = *v2\n\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif v.Kind() != datamodel.Kind_Map {\n\t\t\t\treturn datamodel.ErrWrongKind{TypeName: \"{{ .PkgName }}.{{ .Type.Name }}.Repr\", MethodName: \"AssignNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: v.Kind()}\n\t\t\t}\n\t\t\titr := v.MapIterator()\n\t\t\tfor !itr.Done() {\n\t\t\t\tk, v, err := itr.Next()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := na.AssembleKey().AssignNode(k); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn na.Finish()\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g structReprMapReprBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\tg.emitMapAssemblerChildTidyHelper(w)\n\tg.emitMapAssemblerMethods(w)\n\tg.emitKeyAssembler(w)\n}\nfunc (g structReprMapReprBuilderGenerator) emitMapAssemblerChildTidyHelper(w io.Writer) {\n\t// This is exactly the same as the matching method on the type-level assembler;\n\t//  everything that differs happens to be hidden behind the 'f' indirection, which is numeric.\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) valueFinishTidy() bool {\n\t\t\tswitch ma.f {\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tcase {{ $i }}:\n\t\t\t\t{{- if $field.IsNullable }}\n\t\t\t\tswitch ma.w.{{ $field | FieldSymbolLower }}.m {\n\t\t\t\tcase schema.Maybe_Null:\n\t\t\t\t\tma.state = maState_initial\n\t\t\t\t\treturn true\n\t\t\t\tcase schema.Maybe_Value:\n\t\t\t\t\t{{- if (MaybeUsesPtr $field.Type) }}\n\t\t\t\t\tma.w.{{ $field | FieldSymbolLower }}.v = ma.ca_{{ $field | FieldSymbolLower }}.w\n\t\t\t\t\t{{- end}}\n\t\t\t\t\tma.state = maState_initial\n\t\t\t\t\treturn true\n\t\t\t\tdefault:\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\t{{- else if $field.IsOptional }}\n\t\t\t\tswitch ma.w.{{ $field | FieldSymbolLower }}.m {\n\t\t\t\tcase schema.Maybe_Value:\n\t\t\t\t\t{{- if (MaybeUsesPtr $field.Type) }}\n\t\t\t\t\tma.w.{{ $field | FieldSymbolLower }}.v = ma.ca_{{ $field | FieldSymbolLower }}.w\n\t\t\t\t\t{{- end}}\n\t\t\t\t\tma.state = maState_initial\n\t\t\t\t\treturn true\n\t\t\t\tdefault:\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\t{{- else}}\n\t\t\t\tswitch ma.cm {\n\t\t\t\tcase schema.Maybe_Value:\n\t\t\t\t\t{{- /* while defense in depth here might avoid some 'wat' outcomes, it's not strictly necessary for safety */ -}}\n\t\t\t\t\t{{- /* ma.ca_{{ $field | FieldSymbolLower }}.w = nil */ -}}\n\t\t\t\t\t{{- /* ma.ca_{{ $field | FieldSymbolLower }}.m = nil */ -}}\n\t\t\t\t\tma.cm = schema.Maybe_Absent\n\t\t\t\t\tma.state = maState_initial\n\t\t\t\t\treturn true\n\t\t\t\tdefault:\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g structReprMapReprBuilderGenerator) emitMapAssemblerMethods(w io.Writer) {\n\t// FUTURE: some of the setup of the child assemblers could probably be DRY'd up.\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling another key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\t{{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}}\n\t\t\t{{- if .Type.Fields }}\n\t\t\tswitch k {\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tcase \"{{ $field | $type.RepresentationStrategy.GetFieldKey }}\":\n\t\t\t\tif ma.s & fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }} != 0 {\n\t\t\t\t\treturn nil, datamodel.ErrRepeatedMapKey{Key: &fieldName__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}_serial}\n\t\t\t\t}\n\t\t\t\tma.s += fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}\n\t\t\t\tma.state = maState_midValue\n\t\t\t\tma.f = {{ $i }}\n\t\t\t\t{{- if $field.IsMaybe }}\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.w = {{if not (MaybeUsesPtr $field.Type) }}&{{end}}ma.w.{{ $field | FieldSymbolLower }}.v\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.m = &ma.w.{{ $field | FieldSymbolLower }}.m\n\t\t\t\t{{if $field.IsNullable }}ma.w.{{ $field | FieldSymbolLower }}.m = allowNull{{end}}\n\t\t\t\t{{- else}}\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.w = &ma.w.{{ $field | FieldSymbolLower }}\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.m = &ma.cm\n\t\t\t\t{{- end}}\n\t\t\t\treturn &ma.ca_{{ $field | FieldSymbolLower }}, nil\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\treturn nil, schema.ErrInvalidKey{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}.Repr\", Key:&_String{k}}\n\t\t}\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) AssembleKey() datamodel.NodeAssembler {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling another key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tma.state = maState_midKey\n\t\t\treturn (*_{{ .Type | TypeSymbol }}__ReprKeyAssembler)(ma)\n\t\t}\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) AssembleValue() datamodel.NodeAssembler {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when no key is primed\")\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling a key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\t// carry on\n\t\t\tcase maState_midValue:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling another value\")\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tma.state = maState_midValue\n\t\t\tswitch ma.f {\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tcase {{ $i }}:\n\t\t\t\t{{- if $field.IsMaybe }}\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.w = {{if not (MaybeUsesPtr $field.Type) }}&{{end}}ma.w.{{ $field | FieldSymbolLower }}.v\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.m = &ma.w.{{ $field | FieldSymbolLower }}.m\n\t\t\t\t{{if $field.IsNullable }}ma.w.{{ $field | FieldSymbolLower }}.m = allowNull{{end}}\n\t\t\t\t{{- else}}\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.w = &ma.w.{{ $field | FieldSymbolLower }}\n\t\t\t\tma.ca_{{ $field | FieldSymbolLower }}.m = &ma.cm\n\t\t\t\t{{- end}}\n\t\t\t\treturn &ma.ca_{{ $field | FieldSymbolLower }}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t}\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) Finish() error {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tif ma.s & fieldBits__{{ $type | TypeSymbol }}_sufficient != fieldBits__{{ $type | TypeSymbol }}_sufficient {\n\t\t\t\terr := schema.ErrMissingRequiredField{Missing: make([]string, 0)}\n\t\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\t\t{{- if not $field.IsMaybe}}\n\t\t\t\tif ma.s & fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }} == 0 {\n\t\t\t\t\t{{- if $field | $type.RepresentationStrategy.FieldHasRename }}\n\t\t\t\t\terr.Missing = append(err.Missing, \"{{ $field.Name }} (serial:\\\"{{ $field | $type.RepresentationStrategy.GetFieldKey }}\\\")\")\n\t\t\t\t\t{{- else}}\n\t\t\t\t\terr.Missing = append(err.Missing, \"{{ $field.Name }}\")\n\t\t\t\t\t{{- end}}\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- end}}\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tma.state = maState_finished\n\t\t\t*ma.m = schema.Maybe_Value\n\t\t\treturn nil\n\t\t}\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) KeyPrototype() datamodel.NodePrototype {\n\t\t\treturn _String__Prototype{}\n\t\t}\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) ValuePrototype(k string) datamodel.NodePrototype {\n\t\t\tpanic(\"todo structbuilder mapassembler repr valueprototype\")\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g structReprMapReprBuilderGenerator) emitKeyAssembler(w io.Writer) {\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprKeyAssembler _{{ .Type | TypeSymbol }}__ReprAssembler\n\t`, w, g.AdjCfg, g)\n\tstubs := mixins.StringAssemblerTraits{\n\t\tPkgName:       g.PkgName,\n\t\tTypeName:      g.TypeName + \".KeyAssembler\", // \".Repr\" is already in `g.TypeName`, so don't stutter the \"Repr\" part.\n\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__ReprKey\",\n\t}\n\t// This key assembler can disregard any idea of complex keys because it's at the representation level!\n\t//  Map keys must always be plain strings at the representation level.\n\tstubs.EmitNodeAssemblerMethodBeginMap(w)\n\tstubs.EmitNodeAssemblerMethodBeginList(w)\n\tstubs.EmitNodeAssemblerMethodAssignNull(w)\n\tstubs.EmitNodeAssemblerMethodAssignBool(w)\n\tstubs.EmitNodeAssemblerMethodAssignInt(w)\n\tstubs.EmitNodeAssemblerMethodAssignFloat(w)\n\tdoTemplate(`\n\t\tfunc (ka *_{{ .Type | TypeSymbol }}__ReprKeyAssembler) AssignString(k string) error {\n\t\t\tif ka.state != maState_midKey {\n\t\t\t\tpanic(\"misuse: KeyAssembler held beyond its valid lifetime\")\n\t\t\t}\n\t\t\t{{- if .Type.Fields }}\n\t\t\tswitch k {\n\t\t\t{{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}}\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tcase \"{{ $field | $type.RepresentationStrategy.GetFieldKey }}\":\n\t\t\t\tif ka.s & fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }} != 0 {\n\t\t\t\t\treturn datamodel.ErrRepeatedMapKey{Key: &fieldName__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}_serial}\n\t\t\t\t}\n\t\t\t\tka.s += fieldBit__{{ $type | TypeSymbol }}_{{ $field | FieldSymbolUpper }}\n\t\t\t\tka.state = maState_expectValue\n\t\t\t\tka.f = {{ $i }}\n\t\t\t\treturn nil\n\t\t\t{{- end }}\n\t\t\t}\n\t\t\t{{- end }}\n\t\t\treturn schema.ErrInvalidKey{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}.Repr\", Key:&_String{k}}\n\t\t}\n\t`, w, g.AdjCfg, g)\n\tstubs.EmitNodeAssemblerMethodAssignBytes(w)\n\tstubs.EmitNodeAssemblerMethodAssignLink(w)\n\tdoTemplate(`\n\t\tfunc (ka *_{{ .Type | TypeSymbol }}__ReprKeyAssembler) AssignNode(v datamodel.Node) error {\n\t\t\tif v2, err := v.AsString(); err != nil {\n\t\t\t\treturn err\n\t\t\t} else {\n\t\t\t\treturn ka.AssignString(v2)\n\t\t\t}\n\t\t}\n\t\tfunc (_{{ .Type | TypeSymbol }}__ReprKeyAssembler) Prototype() datamodel.NodePrototype {\n\t\t\treturn _String__Prototype{}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n"
  },
  {
    "path": "schema/gen/go/genStructReprStringjoin.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\nvar _ TypeGenerator = &structReprStringjoinGenerator{}\n\nfunc NewStructReprStringjoinGenerator(pkgName string, typ *schema.TypeStruct, adjCfg *AdjunctCfg) TypeGenerator {\n\treturn structReprStringjoinGenerator{\n\t\tstructGenerator{\n\t\t\tadjCfg,\n\t\t\tmixins.MapTraits{\n\t\t\t\tPkgName:    pkgName,\n\t\t\t\tTypeName:   string(typ.Name()),\n\t\t\t\tTypeSymbol: adjCfg.TypeSymbol(typ),\n\t\t\t},\n\t\t\tpkgName,\n\t\t\ttyp,\n\t\t},\n\t}\n}\n\ntype structReprStringjoinGenerator struct {\n\tstructGenerator\n}\n\nfunc (g structReprStringjoinGenerator) GetRepresentationNodeGen() NodeGenerator {\n\treturn structReprStringjoinReprGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.StringTraits{\n\t\t\tPkgName:    g.PkgName,\n\t\t\tTypeName:   string(g.Type.Name()) + \".Repr\",\n\t\t\tTypeSymbol: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Repr\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype structReprStringjoinReprGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.StringTraits\n\tPkgName string\n\tType    *schema.TypeStruct\n}\n\nfunc (structReprStringjoinReprGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g structReprStringjoinReprGenerator) EmitNodeType(w io.Writer) {\n\t// The type is structurally the same, but will have a different set of methods.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Repr _{{ .Type | TypeSymbol }}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structReprStringjoinReprGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structReprStringjoinReprGenerator) EmitNodeMethodAsString(w io.Writer) {\n\t// Prerequisites:\n\t//  - every field must be a string, or have string representation.\n\t//    - this should've been checked when compiling the type system info.\n\t//    - we're willing to imply a base-10 atoi/itoa for ints (but it's not currently supported).\n\t//  - there are NO sanity checks that your value doesn't contain the delimiter\n\t//    - you need to do this in validation hooks or some other way\n\t//  - optional or nullable fields are not supported with this representation strategy.\n\t//    - this should've been checked when compiling the type system info.\n\t//    - if support for this is added in the future, you can bet all optionals\n\t//      will be required to be *either* in a row at the start, or in a row at the end.\n\t//      (a 'direction' property might also be needed, so behavior is defined if every field is optional.)\n\t//\n\t// A speciated String method is also generated here.\n\t//  (Organization questionable: if this was at type level, it'd be in the 'EmitNativeAccessors' block,\n\t//   but we don't have that in the NodeGenerator interface so we don't have it here.  Maybe that's a mistake.)\n\t//\n\t// A String method is *also* generated on the type-level node.\n\t//  This might be worth consistency review...\n\t//  It's a practical necessity in areas like stringifying for key error messages if used in map keys, for example.\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) AsString() (string, error) {\n\t\t\treturn n.String(), nil\n\t\t}\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) String() string {\n\t\t\treturn {{ \"\" }}\n\t\t\t{{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}}\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\t{{- if $i }} + \"{{ $type.RepresentationStrategy.GetDelim }}\" + {{end -}}\n\t\t\t(*_{{ $field.Type | TypeSymbol }}__Repr)(&n.{{ $field | FieldSymbolLower }}).String()\n\t\t\t{{- end}}\n\t\t}\n\t\tfunc (n {{ .Type | TypeSymbol }}) String() string {\n\t\t\treturn (*_{{ .Type | TypeSymbol }}__Repr)(n).String()\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structReprStringjoinReprGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\n\nfunc (g structReprStringjoinReprGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g structReprStringjoinReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn structReprStringjoinReprBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.StringAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Repr\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype structReprStringjoinReprBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.StringAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeStruct\n}\n\nfunc (structReprStringjoinReprBuilderGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g structReprStringjoinReprBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g structReprStringjoinReprBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n\n\t// Generate a single-step construction function -- this is easy to do for a scalar,\n\t//  and all representations of scalar kind can be expected to have a method like this.\n\t// The function is attached to the NodePrototype for convenient namespacing;\n\t//  it needs no new memory, so it would be inappropriate to attach to the builder or assembler.\n\t// The function is directly used internally by anything else that might involve recursive destructuring on the same scalar kind\n\t//  (for example, structs using stringjoin strategies that have one of this type as a field, etc).\n\t// Since we're a representation of scalar kind, and can recurse,\n\t//  we ourselves presume this plain construction method must also exist for all our members.\n\t// REVIEW: We could make an immut-safe version of this and export it on the NodePrototype too, as `FromString(string)`.\n\t// FUTURE: should engage validation flow.\n\tdoTemplate(`\n\t\tfunc (_{{ .Type | TypeSymbol }}__ReprPrototype) fromString(w *_{{ .Type | TypeSymbol }}, v string) error {\n\t\t\tss, err := mixins.SplitExact(v, \"{{ .Type.RepresentationStrategy.GetDelim }}\", {{ len .Type.Fields }})\n\t\t\tif err != nil {\n\t\t\t\treturn schema.ErrUnmatchable{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}.Repr\", Reason: err}\n\t\t\t}\n\t\t\t{{- $dot := . -}} {{- /* ranging modifies dot, unhelpfully */ -}}\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tif err := (_{{ $field.Type | TypeSymbol }}__ReprPrototype{}).fromString(&w.{{ $field | FieldSymbolLower }}, ss[{{ $i }}]); err != nil {\n\t\t\t\treturn schema.ErrUnmatchable{TypeName:\"{{ $dot.PkgName }}.{{ $dot.Type.Name }}.Repr\", Reason: err}\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\treturn nil\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g structReprStringjoinReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprAssembler struct {\n\t\t\tw *_{{ .Type | TypeSymbol }}\n\t\t\tm *schema.Maybe\n\t\t}\n\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) reset() {}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g structReprStringjoinReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_scalar(w, g.AdjCfg, g)\n}\nfunc (g structReprStringjoinReprBuilderGenerator) EmitNodeAssemblerMethodAssignString(w io.Writer) {\n\t// This method contains a branch to support MaybeUsesPtr because new memory may need to be allocated.\n\t//  This allocation only happens if the 'w' ptr is nil, which means we're being used on a Maybe;\n\t//  otherwise, the 'w' ptr should already be set, and we fill that memory location without allocating, as usual.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignString(v string) error {\n\t\t\tswitch *na.m {\n\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\t}\n\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\tif na.w == nil {\n\t\t\t\tna.w = &_{{ .Type | TypeSymbol }}{}\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\tif err := (_{{ .Type | TypeSymbol }}__ReprPrototype{}).fromString(na.w, v); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t*na.m = schema.Maybe_Value\n\t\t\treturn nil\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structReprStringjoinReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\t// AssignNode goes through three phases:\n\t// 1. is it null?  Jump over to AssignNull (which may or may not reject it).\n\t// 2. is it our own type?  Handle specially -- we might be able to do efficient things.\n\t// 3. is it the right kind to morph into us?  Do so.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignNode(v datamodel.Node) error {\n\t\t\tif v.IsNull() {\n\t\t\t\treturn na.AssignNull()\n\t\t\t}\n\t\t\tif v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok {\n\t\t\t\tswitch *na.m {\n\t\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\t\t}\n\t\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\t\tif na.w == nil {\n\t\t\t\t\tna.w = v2\n\t\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t*na.w = *v2\n\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif v2, err := v.AsString(); err != nil {\n\t\t\t\treturn err\n\t\t\t} else {\n\t\t\t\treturn na.AssignString(v2)\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g structReprStringjoinReprBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\t// None for this.\n}\n"
  },
  {
    "path": "schema/gen/go/genStructReprTuple.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\t\"strconv\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\nvar _ TypeGenerator = &structReprTupleGenerator{}\n\n// Optional fields for tuple representation are only allowed at the end, and contiguously.\n// Present fields are matched greedily: if the struct has five fields,\n//  and the last two are optional, and there's four values, then they will be mapped onto the first four fields, period.\n// In theory, it would be possible to support a variety of fancier modes, configurably;\n//  in practice, let's not: the ROI would be atrocious:\n//   few people seem to want this;\n//   the implementation complexity would rise dramatically;\n//   and the next nearest substitutes for such behavior are already available, and cheap (and also sturdier).\n// It would make about as much sense to support implicits as it does trailing optionals,\n//  which means we probably should consider that someday,\n//   but it's not implemented today.\n\nfunc NewStructReprTupleGenerator(pkgName string, typ *schema.TypeStruct, adjCfg *AdjunctCfg) TypeGenerator {\n\treturn structReprTupleGenerator{\n\t\tstructGenerator{\n\t\t\tadjCfg,\n\t\t\tmixins.MapTraits{\n\t\t\t\tPkgName:    pkgName,\n\t\t\t\tTypeName:   string(typ.Name()),\n\t\t\t\tTypeSymbol: adjCfg.TypeSymbol(typ),\n\t\t\t},\n\t\t\tpkgName,\n\t\t\ttyp,\n\t\t},\n\t}\n}\n\ntype structReprTupleGenerator struct {\n\tstructGenerator\n}\n\nfunc (g structReprTupleGenerator) GetRepresentationNodeGen() NodeGenerator {\n\treturn structReprTupleReprGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.ListTraits{\n\t\t\tPkgName:    g.PkgName,\n\t\t\tTypeName:   string(g.Type.Name()) + \".Repr\",\n\t\t\tTypeSymbol: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Repr\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype structReprTupleReprGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.ListTraits\n\tPkgName string\n\tType    *schema.TypeStruct\n}\n\nfunc (structReprTupleReprGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g structReprTupleReprGenerator) EmitNodeType(w io.Writer) {\n\t// The type is structurally the same, but will have a different set of methods.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Repr _{{ .Type | TypeSymbol }}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structReprTupleReprGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structReprTupleReprGenerator) EmitNodeMethodLookupByIndex(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) LookupByIndex(idx int64) (datamodel.Node, error) {\n\t\t\tswitch idx {\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tcase {{ $i }}:\n\t\t\t\t{{- if $field.IsOptional }}\n\t\t\t\tif n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Absent {\n\t\t\t\t\treturn datamodel.Absent, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfInt(idx)}\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- if $field.IsNullable }}\n\t\t\t\tif n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Null {\n\t\t\t\t\treturn datamodel.Null, nil\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- if $field.IsMaybe }}\n\t\t\t\treturn n.{{ $field | FieldSymbolLower }}.v.Representation(), nil\n\t\t\t\t{{- else}}\n\t\t\t\treturn n.{{ $field | FieldSymbolLower }}.Representation(), nil\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\treturn nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: datamodel.PathSegmentOfInt(idx)}\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structReprTupleReprGenerator) EmitNodeMethodLookupByNode(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\t\t\tki, err := key.AsInt()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn n.LookupByIndex(ki)\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structReprTupleReprGenerator) EmitNodeMethodListIterator(w io.Writer) {\n\t// DRY: much of this precalcuation about doneness is common with the map representation.\n\t//  (or at least: it is for now: the addition of support for implicits in the map representation may bamboozle that.)\n\t//  Some of the templating also experiences the `.HaveTrailingOptionals` branching,\n\t//   but not quite as much as the map representation: since we always know those come at the end\n\t//    (and in particular, once we hit one absent, we're done!), some simplifications can be made.\n\n\t// The 'idx' int is what field we'll yield next.\n\t// Note that this iterator doesn't mention fields that are absent.\n\t//  This makes things a bit trickier -- especially the 'Done' predicate,\n\t//   since it may have to do lookahead if there's any optionals at the end of the structure!\n\n\t// Count how many trailing fields are optional.\n\t//  The 'Done' predicate gets more complex when in the trailing optionals.\n\tfields := g.Type.Fields()\n\tfieldCount := len(fields)\n\tbeginTrailingOptionalField := fieldCount\n\tfor i := fieldCount - 1; i >= 0; i-- {\n\t\tif !fields[i].IsOptional() {\n\t\t\tbreak\n\t\t}\n\t\tbeginTrailingOptionalField = i\n\t}\n\thaveTrailingOptionals := beginTrailingOptionalField < fieldCount\n\n\t// Now: finally we can get on with the actual templating.\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) ListIterator() datamodel.ListIterator {\n\t\t\t{{- if .HaveTrailingOptionals }}\n\t\t\tend := {{ len .Type.Fields }}`+\n\t\tfunc() string { // this next part was too silly in templates due to lack of reverse ranging.\n\t\t\tv := \"\\n\"\n\t\t\tfor i := fieldCount - 1; i >= beginTrailingOptionalField; i-- {\n\t\t\t\tv += \"\\t\\t\\tif n.\" + g.AdjCfg.FieldSymbolLower(fields[i]) + \".m == schema.Maybe_Absent {\\n\"\n\t\t\t\tv += \"\\t\\t\\t\\tend = \" + strconv.Itoa(i) + \"\\n\"\n\t\t\t\tv += \"\\t\\t\\t} else {\\n\"\n\t\t\t\tv += \"\\t\\t\\t\\tgoto done\\n\"\n\t\t\t\tv += \"\\t\\t\\t}\\n\"\n\t\t\t}\n\t\t\treturn v\n\t\t}()+`done:\n\t\t\treturn &_{{ .Type | TypeSymbol }}__ReprListItr{n, 0, end}\n\t\t\t{{- else}}\n\t\t\treturn &_{{ .Type | TypeSymbol }}__ReprListItr{n, 0}\n\t\t\t{{- end}}\n\t\t}\n\n\t\ttype _{{ .Type | TypeSymbol }}__ReprListItr struct {\n\t\t\tn   *_{{ .Type | TypeSymbol }}__Repr\n\t\t\tidx int\n\t\t\t{{if .HaveTrailingOptionals }}end int{{end}}\n\t\t}\n\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__ReprListItr) Next() (idx int64, v datamodel.Node, err error) {\n\t\t\tif itr.idx >= {{ len .Type.Fields }} {\n\t\t\t\treturn -1, nil, datamodel.ErrIteratorOverread{}\n\t\t\t}\n\t\t\tswitch itr.idx {\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tcase {{ $i }}:\n\t\t\t\tidx = int64(itr.idx)\n\t\t\t\t{{- if $field.IsOptional }}\n\t\t\t\tif itr.n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Absent {\n\t\t\t\t\treturn -1, nil, datamodel.ErrIteratorOverread{}\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- if $field.IsNullable }}\n\t\t\t\tif itr.n.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Null {\n\t\t\t\t\tv = datamodel.Null\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- if $field.IsMaybe }}\n\t\t\t\tv = itr.n.{{ $field | FieldSymbolLower}}.v.Representation()\n\t\t\t\t{{- else}}\n\t\t\t\tv = itr.n.{{ $field | FieldSymbolLower}}.Representation()\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t\titr.idx++\n\t\t\treturn\n\t\t}\n\t\t{{- if .HaveTrailingOptionals }}\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__ReprListItr) Done() bool {\n\t\t\treturn itr.idx >= itr.end\n\t\t}\n\t\t{{- else}}\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__ReprListItr) Done() bool {\n\t\t\treturn itr.idx >= {{ len .Type.Fields }}\n\t\t}\n\t\t{{- end}}\n\n\t`, w, g.AdjCfg, struct {\n\t\tType                  *schema.TypeStruct\n\t\tHaveTrailingOptionals bool\n\t}{\n\t\tg.Type,\n\t\thaveTrailingOptionals,\n\t})\n}\n\nfunc (g structReprTupleReprGenerator) EmitNodeMethodLength(w io.Writer) {\n\t// This is fun: it has to count down for any unset optional fields.\n\tdoTemplate(`\n\t\tfunc (rn *_{{ .Type | TypeSymbol }}__Repr) Length() int64 {\n\t\t\tl := {{ len .Type.Fields }}\n\t\t\t{{- range $field := .Type.Fields }}\n\t\t\t{{- if $field.IsOptional }}\n\t\t\tif rn.{{ $field | FieldSymbolLower }}.m == schema.Maybe_Absent {\n\t\t\t\tl--\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\treturn int64(l)\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g structReprTupleReprGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\n\nfunc (g structReprTupleReprGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g structReprTupleReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn structReprTupleReprBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.ListAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Repr\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype structReprTupleReprBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.ListAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeStruct\n}\n\nfunc (structReprTupleReprBuilderGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g structReprTupleReprBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g structReprTupleReprBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g structReprTupleReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// - 'w' is the \"**w**ip\" pointer.\n\t// - 'm' is the **m**aybe which communicates our completeness to the parent if we're a child assembler.\n\t// - 'state' is what it says on the tin.  this is used for the list state (the broad transitions between null, start-list, and finish are handled by 'm' for consistency with other types).\n\t// - contrasted to the map representation, there's no 's' bitfield for what's been **s**et -- because we know things must proceed in order, it would be redundant with 'f'.\n\t// - 'f' is the **f**ocused field that will be assembled next.\n\t//\n\t// - 'cm' is **c**hild **m**aybe and is used for the completion message from children that aren't allowed to be nullable (for those that are, their own maybe.m is used).\n\t// - the 'ca_*' fields embed **c**hild **a**ssemblers -- these are embedded so we can yield pointers to them without causing new allocations.\n\t//\n\t// Note that this textually similar to the type-level assembler, but because it embeds the repr assembler for the child types,\n\t//  it might be *significantly* different in size and memory layout in that trailing part of the struct.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprAssembler struct {\n\t\t\tw *_{{ .Type | TypeSymbol }}\n\t\t\tm *schema.Maybe\n\t\t\tstate laState\n\t\t\tf int\n\n\t\t\tcm schema.Maybe\n\t\t\t{{range $field := .Type.Fields -}}\n\t\t\tca_{{ $field | FieldSymbolLower }} _{{ $field.Type | TypeSymbol }}__ReprAssembler\n\t\t\t{{end -}}\n\t\t}\n\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) reset() {\n\t\t\tna.state = laState_initial\n\t\t\tna.f = 0\n\t\t\t{{- range $field := .Type.Fields }}\n\t\t\tna.ca_{{ $field | FieldSymbolLower }}.reset()\n\t\t\t{{- end}}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g structReprTupleReprBuilderGenerator) EmitNodeAssemblerMethodBeginList(w io.Writer) {\n\t// Future: This could do something strict with the sizehint; it currently ignores it.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) BeginList(int64) (datamodel.ListAssembler, error) {\n\t\t\tswitch *na.m {\n\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\tcase midvalue:\n\t\t\t\tpanic(\"invalid state: it makes no sense to 'begin' twice on the same assembler!\")\n\t\t\t}\n\t\t\t*na.m = midvalue\n\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\tif na.w == nil {\n\t\t\t\tna.w = &_{{ .Type | TypeSymbol }}{}\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\treturn na, nil\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g structReprTupleReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_recursive(w, g.AdjCfg, g)\n}\nfunc (g structReprTupleReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\temitNodeAssemblerMethodAssignNode_listoid(w, g.AdjCfg, g)\n}\nfunc (g structReprTupleReprBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\tg.emitListAssemblerChildTidyHelper(w)\n\tg.emitListAssemblerChildListAssemblerMethods(w)\n}\nfunc (g structReprTupleReprBuilderGenerator) emitListAssemblerChildTidyHelper(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (la *_{{ .Type | TypeSymbol }}__ReprAssembler) valueFinishTidy() bool {\n\t\t\tswitch la.f {\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tcase {{ $i }}:\n\t\t\t\t{{- if $field.IsMaybe }}\n\t\t\t\tswitch la.w.{{ $field | FieldSymbolLower }}.m {\n\t\t\t\tcase schema.Maybe_Value:\n\t\t\t\t\t{{- if (MaybeUsesPtr $field.Type) }}\n\t\t\t\t\tla.w.{{ $field | FieldSymbolLower }}.v = la.ca_{{ $field | FieldSymbolLower }}.w\n\t\t\t\t\t{{- end}}\n\t\t\t\t\tla.state = laState_initial\n\t\t\t\t\tla.f++\n\t\t\t\t\treturn true\n\t\t\t\t{{- else}}\n\t\t\t\tswitch la.cm {\n\t\t\t\tcase schema.Maybe_Value:\n\t\t\t\t\tla.cm = schema.Maybe_Absent\n\t\t\t\t\tla.state = laState_initial\n\t\t\t\t\tla.f++\n\t\t\t\t\treturn true\n\t\t\t\t{{- end}}\n\t\t\t\t{{- if $field.IsNullable }}\n\t\t\t\tcase schema.Maybe_Null:\n\t\t\t\t\tla.state = laState_initial\n\t\t\t\t\tla.f++\n\t\t\t\t\treturn true\n\t\t\t\t{{- end}}\n\t\t\t\tdefault:\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g structReprTupleReprBuilderGenerator) emitListAssemblerChildListAssemblerMethods(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (la *_{{ .Type | TypeSymbol }}__ReprAssembler) AssembleValue() datamodel.NodeAssembler {\n\t\t\tswitch la.state {\n\t\t\tcase laState_initial:\n\t\t\t\t// carry on\n\t\t\tcase laState_midValue:\n\t\t\t\tif !la.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when still in the middle of assembling the previous value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase laState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tif la.f >= {{ len .Type.Fields }} {\n\t\t\t\treturn _ErrorThunkAssembler{schema.ErrNoSuchField{Type: nil /*TODO*/, Field: datamodel.PathSegmentOfInt({{ len .Type.Fields }})}}\n\t\t\t}\n\t\t\tla.state = laState_midValue\n\t\t\tswitch la.f {\n\t\t\t{{- range $i, $field := .Type.Fields }}\n\t\t\tcase {{ $i }}:\n\t\t\t\t{{- if $field.IsMaybe }}\n\t\t\t\tla.ca_{{ $field | FieldSymbolLower }}.w = {{if not (MaybeUsesPtr $field.Type) }}&{{end}}la.w.{{ $field | FieldSymbolLower }}.v\n\t\t\t\tla.ca_{{ $field | FieldSymbolLower }}.m = &la.w.{{ $field | FieldSymbolLower }}.m\n\t\t\t\t{{- if $field.IsNullable }}\n\t\t\t\tla.w.{{ $field | FieldSymbolLower }}.m = allowNull\n\t\t\t\t{{- end}}\n\t\t\t\t{{- else}}\n\t\t\t\tla.ca_{{ $field | FieldSymbolLower }}.w = &la.w.{{ $field | FieldSymbolLower }}\n\t\t\t\tla.ca_{{ $field | FieldSymbolLower }}.m = &la.cm\n\t\t\t\t{{- end}}\n\t\t\t\treturn &la.ca_{{ $field | FieldSymbolLower }}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n\t// Surprisingly, the Finish method doesn't have anything to do regarding any trailing optionals:\n\t//  if they weren't assigned yet, their Maybe state is still the zero value: absent.  And that's correct.\n\t// DRY: okay, this finish component is actually identical, both textually and in terms of linking, to lists.  This we should actually extract.\n\tdoTemplate(`\n\t\tfunc (la *_{{ .Type | TypeSymbol }}__ReprAssembler) Finish() error {\n\t\t\tswitch la.state {\n\t\t\tcase laState_initial:\n\t\t\t\t// carry on\n\t\t\tcase laState_midValue:\n\t\t\t\tif !la.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase laState_finished:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tla.state = laState_finished\n\t\t\t*la.m = schema.Maybe_Value\n\t\t\treturn nil\n\t\t}\n\t`, w, g.AdjCfg, g)\n\tdoTemplate(`\n\t\tfunc (la *_{{ .Type | TypeSymbol }}__ReprAssembler) ValuePrototype(_ int64) datamodel.NodePrototype {\n\t\t\tpanic(\"todo structbuilder tuplerepr valueprototype\")\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n"
  },
  {
    "path": "schema/gen/go/genUnion.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\n// The generator for unions is a bit more wild than most others:\n// it has at three major branches for how its internals are laid out:\n//\n//   - all possible children are embedded.\n//   - all possible children are pointers... in which case we collapse to one interface resident.\n//       (n.b. this does give up some inlining potential as well as gives up on alloc amortization, but it does make resident memory size minimal.)\n//   - some children are emebedded and some are pointers, and of the latter set, they may be either in one interface field or several discrete pointers.\n//       (discrete fields of pointer type makes inlining possible in some paths, whereas an interface field blocks it).\n//\n// ... We're not doing that last one at all right now.  The pareto-prevalence of these concerns is extremely low compared to the effort required.\n// But the first two are both very reasonable, and both are often wanted.\n//\n// These choices are made from adjunct config (which should make sense, because they're clearly all \"golang\" details -- not type semantics).\n// We still tackle all the generation for all these strategies this in one file,\n//  because all of the interfaces we export are the same, regardless of the internals (and it just seems easiest to do this way).\n\ntype unionGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.MapTraits\n\tPkgName string\n\tType    *schema.TypeUnion\n}\n\nfunc (unionGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\n// --- native content and specializations --->\n\nfunc (g unionGenerator) EmitNativeType(w io.Writer) {\n\t// We generate *two* types: a struct which acts as the union node,\n\t// and also an interface which covers the members (and has an unexported marker function to make sure the set can't be extended).\n\t//\n\t// The interface *mostly* isn't used... except for in the return type of a speciated function which can be used to do golang-native type switches.\n\t//\n\t// The interface also includes a requirement for an errorless primitive access method (such as `String() string`)\n\t// if our representation strategy is one that has that semantic (e.g., stringprefix repr does).\n\t//\n\t// A note about index: in all cases the index of a member type is used, we increment it by one, to avoid using zero.\n\t// We do this because it's desirable to reserve the zero in the 'tag' field (if we generate one) as a sentinel value\n\t// (see further comments in the EmitNodeAssemblerType function);\n\t// and since we do it in that one case, it's just as well to do it uniformly.\n\tdoTemplate(`\n\t\t{{- if Comments -}}\n\t\t// {{ .Type | TypeSymbol }} matches the IPLD Schema type \"{{ .Type.Name }}\".\n\t\t// {{ .Type | TypeSymbol }} has {{ .Type.TypeKind }} typekind, which means its data model behaviors are that of a {{ .Kind }} kind.\n\t\t{{- end}}\n\t\ttype {{ .Type | TypeSymbol }} = *_{{ .Type | TypeSymbol }}\n\t\ttype _{{ .Type | TypeSymbol }} struct {\n\t\t\t{{- if (eq (.AdjCfg.UnionMemlayout .Type) \"embedAll\") }}\n\t\t\ttag uint\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tx{{ add $i 1 }} _{{ $member | TypeSymbol }}\n\t\t\t{{- end}}\n\t\t\t{{- else if (eq (.AdjCfg.UnionMemlayout .Type) \"interface\") }}\n\t\t\tx _{{ .Type | TypeSymbol }}__iface\n\t\t\t{{- end}}\n\t\t}\n\t\ttype _{{ .Type | TypeSymbol }}__iface interface {\n\t\t\t_{{ .Type | TypeSymbol }}__member()\n\t\t\t{{- if (eq (.Type.RepresentationStrategy | printf \"%T\") \"schema.UnionRepresentation_Stringprefix\") }}\n\t\t\tString() string\n\t\t\t{{- end}}\n\t\t}\n\n\t\t{{- range $member := .Type.Members }}\n\t\tfunc (_{{ $member | TypeSymbol }}) _{{ dot.Type | TypeSymbol }}__member() {}\n\t\t{{- end}}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionGenerator) EmitNativeAccessors(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n _{{ .Type | TypeSymbol }}) AsInterface() _{{ .Type | TypeSymbol }}__iface {\n\t\t\t{{- if (eq (.AdjCfg.UnionMemlayout .Type) \"embedAll\") }}\n\t\t\tswitch n.tag {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase {{ add $i 1 }}:\n\t\t\t\treturn &n.x{{ add $i 1 }}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"invalid union state; how did you create this object?\")\n\t\t\t}\n\t\t\t{{- else if (eq (.AdjCfg.UnionMemlayout .Type) \"interface\") }}\n\t\t\treturn n.x\n\t\t\t{{- end}}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionGenerator) EmitNativeBuilder(w io.Writer) {\n\t// Unclear as yet what should go here.\n}\n\nfunc (g unionGenerator) EmitNativeMaybe(w io.Writer) {\n\temitNativeMaybe(w, g.AdjCfg, g)\n}\n\n// --- type info --->\n\nfunc (g unionGenerator) EmitTypeConst(w io.Writer) {\n\tdoTemplate(`\n\t\t// TODO EmitTypeConst\n\t`, w, g.AdjCfg, g)\n}\n\n// --- TypedNode interface satisfaction --->\n\nfunc (g unionGenerator) EmitTypedNodeMethodType(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .Type | TypeSymbol }}) Type() schema.Type {\n\t\t\treturn nil /*TODO:typelit*/\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionGenerator) EmitTypedNodeMethodRepresentation(w io.Writer) {\n\temitTypicalTypedNodeMethodRepresentation(w, g.AdjCfg, g)\n}\n\n// --- Node interface satisfaction --->\n\nfunc (g unionGenerator) EmitNodeType(w io.Writer) {\n\t// No additional types needed.  Methods all attach to the native type.\n\n\t// We do, however, want some constants for our member names;\n\t//  they'll make iterators able to work faster.  So let's emit those.\n\t// These are a bit perplexing, because they're... type names.\n\t//  However, oddly enough, we don't have type names available *as nodes* anywhere else centrally available,\n\t//   so... we generate some values for them here with scoped identifiers and get on with it.\n\t//    Maybe this could be elided with future work.\n\tdoTemplate(`\n\t\tvar (\n\t\t\t{{- range $member := .Type.Members }}\n\t\t\tmemberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }} = _String{\"{{ $member.Name }}\"}\n\t\t\t{{- end }}\n\t\t)\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\temitNodeTypeAssertions_typical(w, g.AdjCfg, g)\n}\n\nfunc (g unionGenerator) EmitNodeMethodLookupByString(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) LookupByString(key string) (datamodel.Node, error) {\n\t\t\tswitch key {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase \"{{ $member.Name }}\":\n\t\t\t\t{{- if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"embedAll\") }}\n\t\t\t\tif n.tag != {{ add $i 1 }} {\n\t\t\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)}\n\t\t\t\t}\n\t\t\t\treturn &n.x{{ add $i 1 }}, nil\n\t\t\t\t{{- else if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"interface\") }}\n\t\t\t\tif n2, ok := n.x.({{ $member | TypeSymbol }}); ok {\n\t\t\t\t\treturn n2, nil\n\t\t\t\t} else {\n\t\t\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)}\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\treturn nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: datamodel.PathSegmentOfString(key)}\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionGenerator) EmitNodeMethodLookupByNode(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\t\t\tks, err := key.AsString()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn n.LookupByString(ks)\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionGenerator) EmitNodeMethodMapIterator(w io.Writer) {\n\t// This is kind of a hilarious \"iterator\": it has to count all the way up to... 1.\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) MapIterator() datamodel.MapIterator {\n\t\t\treturn &_{{ .Type | TypeSymbol }}__MapItr{n, false}\n\t\t}\n\n\t\ttype _{{ .Type | TypeSymbol }}__MapItr struct {\n\t\t\tn {{ .Type | TypeSymbol }}\n\t\t\tdone bool\n\t\t}\n\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__MapItr) Next() (k datamodel.Node, v datamodel.Node, _ error) {\n\t\t\tif itr.done {\n\t\t\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t\t\t}\n\t\t\t{{- if (eq (.AdjCfg.UnionMemlayout .Type) \"embedAll\") }}\n\t\t\tswitch itr.n.tag {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase {{ add $i 1 }}:\n\t\t\t\tk, v = &memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}, &itr.n.x{{ add $i 1 }}\n\t\t\t{{- end}}\n\t\t\t{{- else if (eq (.AdjCfg.UnionMemlayout .Type) \"interface\") }}\n\t\t\tswitch n2 := itr.n.x.(type) {\n\t\t\t{{- range $member := .Type.Members }}\n\t\t\tcase {{ $member | TypeSymbol }}:\n\t\t\t\tk, v = &memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}, n2\n\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t\titr.done = true\n\t\t\treturn\n\t\t}\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__MapItr) Done() bool {\n\t\t\treturn itr.done\n\t\t}\n\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionGenerator) EmitNodeMethodLength(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .Type | TypeSymbol }}) Length() int64 {\n\t\t\treturn 1\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\n\nfunc (g unionGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g unionGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn unionBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.MapAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype unionBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.MapAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeUnion\n}\n\nfunc (unionBuilderGenerator) IsRepr() bool { return false } // hint used in some generalized templates.\n\nfunc (g unionBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g unionBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g unionBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// Assemblers for unions are not unlikely those for structs or maps:\n\t//\n\t// - 'w' is the \"**w**ip\" pointer.\n\t// - 'm' is the pointer to a **m**aybe which communicates our completeness to the parent if we're a child assembler.\n\t//     Like any other structure, a union can be nullable in the context of some enclosing object, and we'll have the usual branches for handling that in our various Assign methods.\n\t// - 'state' is what it says on the tin.  Unions use maState to sequence the transitions between a new assembler, the map having been started, key insertions, value insertions, and finish.\n\t//     Most of this is just like the way struct and map use maState.\n\t//     However, we also need to guard to make sure a second entry never begins; after the first, finish is the *only* valid transition.\n\t//     In structs, this is done using the \"set\" bitfield; in maps, the state resides in the wip map itself.\n\t//     Unions are more like the latter: depending on which memory layout we're using, either the `na.w.tag` value, or, a non-nil `na.w.x`, is indicative that one key has been entered.\n\t//     (The zero value for `na.w.tag` is reserved, and all  for this reason.\n\t// - There is no additional state need to store \"focus\" (in contrast to structs);\n\t//     information during the AssembleValue phase about which member is selected is also just handled in `na.w.tag`, or, in the type info of `na.w.x`, again depending on memory layout strategy.\n\t//     (This is subverted a bit by the 'ca' field, however... which effectively mirrors `na.w.tag`, and is only active in the resetting process, but is necessary because it outlives its twin inside 'w'.)\n\t//\n\t// - 'cm' is **c**hild **m**aybe and is used for the completion message from children.\n\t// - 'ca*' fields embed **c**hild **a**ssemblers -- these are embedded so we can yield pointers to them during recursion into child value assembly without causing new allocations.\n\t//     In unions, only one of these will every be used!  However, we don't know *which one* in advance, so, we have to embed them all.\n\t//     (It's ironic to note that if the golang compiler had an understanding of unions itself (either tagged or untagged would suffice), we could compile this down into *much* more minimal amounts of resident memory reservation.  Alas!)\n\t//     The 'ca*' fields are pointers (and allocated on demand) instead of embeds for unions with memlayout=interface mode.  (Arguably, this is overloading that config; PRs for more granular configurability welcome.)\n\t// - 'ca' (with no further suffix) identifies which child assembler was previously used.\n\t//     This is for minimizing the amount of work that resetting has to do: it will only recurse into resetting that child assembler.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Assembler struct {\n\t\t\tw *_{{ .Type | TypeSymbol }}\n\t\t\tm *schema.Maybe\n\t\t\tstate maState\n\n\t\t\tcm schema.Maybe\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tca{{ add $i 1 }} {{ if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"interface\") }}*{{end}}_{{ $member | TypeSymbol }}__Assembler\n\t\t\t{{end -}}\n\t\t\tca uint\n\t\t}\n\t`, w, g.AdjCfg, g)\n\n\t// Reset methods for unions are a tad more involved than for most other assemblers:\n\t//  we only want to bother to reset whichever child assembler (if any) we actually used last.\n\t//  We *could* blithely reset *all* child assemblers every time; but, trading an extra bit of state in our assembler\n\t//   for the privilege of trimming off a potentially sizable amount of unnecessary zeroing efforts seems preferable.\n\t//  Also, although go syntax makes it not textually obvious here, note that it's possible for the child assemblers to be either pointers or embeds:\n\t//   on consequence of this is that just zeroing this struct would be both unreliable and undesirable in the pointer case\n\t//    (it would leave orphan child assemblers that might still have pointers into us, which could be guarded against but is nonetheless is considerably scary in complexity;\n\t//    and it would also mean that we can't keep ahold of the child assemblers across resets and thus amortize allocations, which... is the whole reason the reset system exists in the first place).\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__Assembler) reset() {\n\t\t\tna.state = maState_initial\n\t\t\tswitch na.ca {\n\t\t\tcase 0:\n\t\t\t\treturn\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase {{ add $i 1 }}:\n\t\t\t\tna.ca{{ add $i 1 }}.reset()\n\t\t\t{{end -}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t\tna.ca = 0\n\t\t\tna.cm = schema.Maybe_Absent\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g unionBuilderGenerator) EmitNodeAssemblerMethodBeginMap(w io.Writer) {\n\temitNodeAssemblerMethodBeginMap_strictoid(w, g.AdjCfg, g)\n}\nfunc (g unionBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\t// It might sound a bit odd to call a union \"recursive\", since it's so very trivially so (no fan-out),\n\t//  but it's functionally accurate: the generated method should include a branch for the 'midvalue' state.\n\temitNodeAssemblerMethodAssignNull_recursive(w, g.AdjCfg, g)\n}\nfunc (g unionBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\t// AssignNode goes through three phases:\n\t// 1. is it null?  Jump over to AssignNull (which may or may not reject it).\n\t// 2. is it our own type?  Handle specially -- we might be able to do efficient things.\n\t// 3. is it the right kind to morph into us?  Do so.\n\t//\n\t// We do not set m=midvalue in phase 3 -- it shouldn't matter unless you're trying to pull off concurrent access, which is wrong and unsafe regardless.\n\t//\n\t// DRY: this turns out to be textually identical to the method for structs!  (At least, for now.  It could/should probably be optimized to get to the point faster in phase 3.)\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__Assembler) AssignNode(v datamodel.Node) error {\n\t\t\tif v.IsNull() {\n\t\t\t\treturn na.AssignNull()\n\t\t\t}\n\t\t\tif v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok {\n\t\t\t\tswitch *na.m {\n\t\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\t\tcase midvalue:\n\t\t\t\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t\t\t\t}\n\t\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\t\tif na.w == nil {\n\t\t\t\t\tna.w = v2\n\t\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t*na.w = *v2\n\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif v.Kind() != datamodel.Kind_Map {\n\t\t\t\treturn datamodel.ErrWrongKind{TypeName: \"{{ .PkgName }}.{{ .Type.Name }}\", MethodName: \"AssignNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: v.Kind()}\n\t\t\t}\n\t\t\titr := v.MapIterator()\n\t\t\tfor !itr.Done() {\n\t\t\t\tk, v, err := itr.Next()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := na.AssembleKey().AssignNode(k); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn na.Finish()\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g unionBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\tg.emitMapAssemblerChildTidyHelper(w)\n\tg.emitMapAssemblerMethods(w)\n\tg.emitKeyAssembler(w)\n}\nfunc (g unionBuilderGenerator) emitMapAssemblerChildTidyHelper(w io.Writer) {\n\t// This function attempts to clean up the state machine to acknolwedge child assembly finish.\n\t//  If the child was finished and we just collected it, return true and update state to maState_initial.\n\t//  Otherwise, if it wasn't done, return false;\n\t//   and the caller is almost certain to emit an error momentarily.\n\t// The function will only be called when the current state is maState_midValue.\n\t//  (In general, the idea is that if the user is doing things correctly,\n\t//   this function will only be called when the child is in fact finished.)\n\t// This is a *lot* simpler than the tidy behaviors needed for any of the other recursive kinds:\n\t//  unions don't allow either nullable nor optional members, so there's no need to process anything except Maybe_Value state,\n\t//  and the lack of need to consider nullable nor optionals also means we never need to worry about moving memory in the case of MaybeUsePtr modes.\n\t//  (FUTURE: this may get a bit more conditional if we support members that are of unit ype and have null as a representation.  Unsure how that would work out exactly, but should be possible.)\n\t// We don't bother to nil the child assembler's 'w' pointer: it's not necessary,\n\t//  because we'll never \"share\" 'cm' (as some systems, like maps and lists, do) or change its value (short of the whole assembler resetting),\n\t//   and therefore we should be able to rely on the child assembler to be reasonable and never start acting again after finish.\n\t//  (This *does* mean some care is required in the reset logic: we have to be absolutely sure that resetting propagates to all child assemblers,\n\t//   even if they're in other regions of the heap; otherwise, they might end up still holding actionable 'w' and 'm' pointers into bad times!)\n\t//  (If you want to compare this to the logic in struct assemblers: it's similar to how only children that don't have maybes need an active 'w' nil'ing;\n\t//   but the salient reason there isn't \"because the don't have maybes\"; it's \"because they have a potentially-reused 'cm'\".  We don't have the former; but we *also* don't have the latter, for other reasons.)\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__Assembler) valueFinishTidy() bool {\n\t\t\tswitch ma.cm {\n\t\t\tcase schema.Maybe_Value:\n\t\t\t\t{{- /* nothing to do for memlayout=embedAll; the tag is already set and memory already in place. */ -}}\n\t\t\t\t{{- /* nothing to do for memlayout=interface either; same story, the values are already in place. */ -}}\n\t\t\t\tma.state = maState_initial\n\t\t\t\treturn true\n\t\t\tdefault:\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g unionBuilderGenerator) emitMapAssemblerMethods(w io.Writer) {\n\t// DRY: I did an interesting thing here: the `switch ma.state` block remains textually identical to the one for structs,\n\t//  even though the branch by valueFinishTidy could jump directly to an error state.\n\t//   That same semantic error state gets checked separately a few lines later in a different mechanism.\n\t//    The later check is needed either way (the assembler needs to *keep* erroring if some derp calls AssembleEntry *again* after a previous call already did the tidy and got rejected),\n\t//     but we could arguably save a step there.  It would probably trade more assembly size for the cycles saved, too, though.\n\t//  Ah, tradeoffs.  I think the textually simple approach here is probably in fact the best.  But it could be done differently, yes.\n\t// Note that calling AssembleEntry again when it's not for the first entry *returns* an error; it doesn't panic.\n\t//  This is subtle but important: trying to add more data than is acceptable is a data mismatch, not a system misuse, and must error accordingly politely.\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__Assembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling another key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on for the moment, but we'll still be erroring shortly.\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tif ma.ca != 0 {\n\t\t\t\treturn nil, schema.ErrNotUnionStructure{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}\", Detail: \"cannot add another entry -- a union can only contain one thing!\"}\n\t\t\t}\n\t\t\t{{- if .Type.Members }}\n\t\t\tswitch k {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase \"{{ $member.Name }}\":\n\t\t\t\tma.state = maState_midValue\n\t\t\t\tma.ca = {{ add $i 1 }}\n\t\t\t\t{{- if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"embedAll\") }}\n\t\t\t\tma.w.tag = {{ add $i 1 }}\n\t\t\t\tma.ca{{ add $i 1 }}.w = &ma.w.x{{ add $i 1 }}\n\t\t\t\tma.ca{{ add $i 1 }}.m = &ma.cm\n\t\t\t\treturn &ma.ca{{ add $i 1 }}, nil\n\t\t\t\t{{- else if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"interface\") }}\n\t\t\t\tx := &_{{ $member | TypeSymbol}}{}\n\t\t\t\tma.w.x = x\n\t\t\t\tif ma.ca{{ add $i 1 }} == nil {\n\t\t\t\t\tma.ca{{ add $i 1 }} = &_{{ $member | TypeSymbol }}__Assembler{}\n\t\t\t\t}\n\t\t\t\tma.ca{{ add $i 1 }}.w = x\n\t\t\t\tma.ca{{ add $i 1 }}.m = &ma.cm\n\t\t\t\treturn ma.ca{{ add $i 1 }}, nil\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\t}\n\t\t\treturn nil, schema.ErrInvalidKey{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}\", Key:&_String{k}}\n\t\t}\n\t`, w, g.AdjCfg, g)\n\n\t// AssembleKey has a similar DRY note as the AssembleEntry above had.\n\t// One misfortune in this method: we may know that we're doomed to errors because the caller is trying to start a second entry,\n\t//  but we can't report it from this method: we have to sit on our tongue, slide to midKey state (even though we're doomed!),\n\t//   and let the keyAssembler return the error later.\n\t//    This sucks, but panicking wouldn't be correct (see remarks about error vs panic on the AssembleEntry method),\n\t//     and we don't want to make this call unchainable for everyone everywhere, either, so it can't be rewritten to have an immediate error return.\n\t//    The transition to midKey state is particularly irritating because it means this assembler will be perma-wedged; but I see no alternative.\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__Assembler) AssembleKey() datamodel.NodeAssembler {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling another key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on for the moment, but we'll still be erroring shortly... or rather, the keyassembler will be.\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tma.state = maState_midKey\n\t\t\treturn (*_{{ .Type | TypeSymbol }}__KeyAssembler)(ma)\n\t\t}\n\t`, w, g.AdjCfg, g)\n\n\t// As with structs, the responsibilties of this are similar to AssembleEntry, but with some of the burden split into the key assembler (which should have acted earlier),\n\t//  and some of the logical continuity bounces through state in the form of 'ma.ca'.\n\t//  The potential to DRY up some of this should be plentiful, but it's a bit heady.\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__Assembler) AssembleValue() datamodel.NodeAssembler {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when no key is primed\")\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling a key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\t// carry on\n\t\t\tcase maState_midValue:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling another value\")\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tma.state = maState_midValue\n\t\t\tswitch ma.ca {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase {{ add $i 1 }}:\n\t\t\t\t{{- if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"embedAll\") }}\n\t\t\t\tma.ca{{ add $i 1 }}.w = &ma.w.x{{ add $i 1 }}\n\t\t\t\tma.ca{{ add $i 1 }}.m = &ma.cm\n\t\t\t\treturn &ma.ca{{ add $i 1 }}\n\t\t\t\t{{- else if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"interface\") }}\n\t\t\t\tx := &_{{ $member | TypeSymbol}}{}\n\t\t\t\tma.w.x = x\n\t\t\t\tif ma.ca{{ add $i 1 }} == nil {\n\t\t\t\t\tma.ca{{ add $i 1 }} = &_{{ $member | TypeSymbol }}__Assembler{}\n\t\t\t\t}\n\t\t\t\tma.ca{{ add $i 1 }}.w = x\n\t\t\t\tma.ca{{ add $i 1 }}.m = &ma.cm\n\t\t\t\treturn ma.ca{{ add $i 1 }}\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n\n\t// Finish checks are nice and easy.  Is the maState in the right place now and was a 'ca' ever marked?\n\t//  If yes and yes, then together with the rules elsewhere, we must've processed and accepted exactly one entry; perfect.\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__Assembler) Finish() error {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tif ma.ca == 0 {\n\t\t\t\treturn schema.ErrNotUnionStructure{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}\", Detail: \"a union must have exactly one entry (not none)!\"}\n\t\t\t}\n\t\t\tma.state = maState_finished\n\t\t\t*ma.m = schema.Maybe_Value\n\t\t\treturn nil\n\t\t}\n\t`, w, g.AdjCfg, g)\n\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__Assembler) KeyPrototype() datamodel.NodePrototype {\n\t\t\treturn _String__Prototype{}\n\t\t}\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__Assembler) ValuePrototype(k string) datamodel.NodePrototype {\n\t\t\tswitch k {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase \"{{ $member.Name }}\":\n\t\t\t\treturn _{{ $member | TypeSymbol }}__Prototype{}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g unionBuilderGenerator) emitKeyAssembler(w io.Writer) {\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__KeyAssembler _{{ .Type | TypeSymbol }}__Assembler\n\t`, w, g.AdjCfg, g)\n\tstubs := mixins.StringAssemblerTraits{\n\t\tPkgName:       g.PkgName,\n\t\tTypeName:      g.TypeName + \".KeyAssembler\",\n\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Key\",\n\t}\n\t// This key assembler can disregard any idea of complex keys because we're fronting for a union!\n\t//  Union member names must be strings (and quite simple ones at that).\n\tstubs.EmitNodeAssemblerMethodBeginMap(w)\n\tstubs.EmitNodeAssemblerMethodBeginList(w)\n\tstubs.EmitNodeAssemblerMethodAssignNull(w)\n\tstubs.EmitNodeAssemblerMethodAssignBool(w)\n\tstubs.EmitNodeAssemblerMethodAssignInt(w)\n\tstubs.EmitNodeAssemblerMethodAssignFloat(w)\n\tdoTemplate(`\n\t\tfunc (ka *_{{ .Type | TypeSymbol }}__KeyAssembler) AssignString(k string) error {\n\t\t\tif ka.state != maState_midKey {\n\t\t\t\tpanic(\"misuse: KeyAssembler held beyond its valid lifetime\")\n\t\t\t}\n\t\t\tif ka.ca != 0 {\n\t\t\t\treturn schema.ErrNotUnionStructure{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}\", Detail: \"cannot add another entry -- a union can only contain one thing!\"}\n\t\t\t}\n\t\t\tswitch k {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase \"{{ $member.Name }}\":\n\t\t\t\tka.ca = {{ add $i 1 }}\n\t\t\t\t{{- if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"embedAll\") }}\n\t\t\t\tka.w.tag = {{ add $i 1 }}\n\t\t\t\t{{- end}}\n\t\t\t\tka.state = maState_expectValue\n\t\t\t\treturn nil\n\t\t\t{{- end}}\n\t\t\t}\n\t\t\treturn schema.ErrInvalidKey{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}\", Key:&_String{k}} // TODO: error quality: ErrInvalidUnionDiscriminant ?\n\t\t}\n\t`, w, g.AdjCfg, g)\n\tstubs.EmitNodeAssemblerMethodAssignBytes(w)\n\tstubs.EmitNodeAssemblerMethodAssignLink(w)\n\tdoTemplate(`\n\t\tfunc (ka *_{{ .Type | TypeSymbol }}__KeyAssembler) AssignNode(v datamodel.Node) error {\n\t\t\tif v2, err := v.AsString(); err != nil {\n\t\t\t\treturn err\n\t\t\t} else {\n\t\t\t\treturn ka.AssignString(v2)\n\t\t\t}\n\t\t}\n\t\tfunc (_{{ .Type | TypeSymbol }}__KeyAssembler) Prototype() datamodel.NodePrototype {\n\t\t\treturn _String__Prototype{}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n"
  },
  {
    "path": "schema/gen/go/genUnionReprKeyed.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\nvar _ TypeGenerator = &unionReprKeyedGenerator{}\n\n// General observation: many things about the keyed representation of unions is *very* similar to the type-level code,\n//  because the type level code effective does espouse keyed-style behavior (just with type names as the keys).\n//  Be advised that this similarity does not hold at *all* true of any of the other representation modes of unions!\n\nfunc NewUnionReprKeyedGenerator(pkgName string, typ *schema.TypeUnion, adjCfg *AdjunctCfg) TypeGenerator {\n\treturn unionReprKeyedGenerator{\n\t\tunionGenerator{\n\t\t\tadjCfg,\n\t\t\tmixins.MapTraits{\n\t\t\t\tPkgName:    pkgName,\n\t\t\t\tTypeName:   string(typ.Name()),\n\t\t\t\tTypeSymbol: adjCfg.TypeSymbol(typ),\n\t\t\t},\n\t\t\tpkgName,\n\t\t\ttyp,\n\t\t},\n\t}\n}\n\ntype unionReprKeyedGenerator struct {\n\tunionGenerator\n}\n\nfunc (g unionReprKeyedGenerator) GetRepresentationNodeGen() NodeGenerator {\n\treturn unionReprKeyedReprGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.MapTraits{\n\t\t\tPkgName:    g.PkgName,\n\t\t\tTypeName:   string(g.Type.Name()) + \".Repr\",\n\t\t\tTypeSymbol: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Repr\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype unionReprKeyedReprGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.MapTraits\n\tPkgName string\n\tType    *schema.TypeUnion\n}\n\nfunc (unionReprKeyedReprGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g unionReprKeyedReprGenerator) EmitNodeType(w io.Writer) {\n\t// The type is structurally the same, but will have a different set of methods.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Repr _{{ .Type | TypeSymbol }}\n\t`, w, g.AdjCfg, g)\n\n\t// We do also want some constants for our discriminant values;\n\t//  they'll make iterators able to work faster.\n\tdoTemplate(`\n\t\tvar (\n\t\t\t{{- range $member := .Type.Members }}\n\t\t\tmemberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial = _String{\"{{ $member | dot.Type.RepresentationStrategy.GetDiscriminant }}\"}\n\t\t\t{{- end }}\n\t\t)\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionReprKeyedReprGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionReprKeyedReprGenerator) EmitNodeMethodLookupByString(w io.Writer) {\n\t// Similar to the type-level method, except uses discriminant values as keys instead of the member type names.\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) LookupByString(key string) (datamodel.Node, error) {\n\t\t\tswitch key {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase \"{{ $member | dot.Type.RepresentationStrategy.GetDiscriminant }}\":\n\t\t\t\t{{- if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"embedAll\") }}\n\t\t\t\tif n.tag != {{ add $i 1 }} {\n\t\t\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)}\n\t\t\t\t}\n\t\t\t\treturn n.x{{ add $i 1 }}.Representation(), nil\n\t\t\t\t{{- else if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"interface\") }}\n\t\t\t\tif n2, ok := n.x.({{ $member | TypeSymbol }}); ok {\n\t\t\t\t\treturn n2.Representation(), nil\n\t\t\t\t} else {\n\t\t\t\t\treturn nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)}\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\treturn nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: datamodel.PathSegmentOfString(key)}\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionReprKeyedReprGenerator) EmitNodeMethodLookupByNode(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\t\t\tks, err := key.AsString()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn n.LookupByString(ks)\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionReprKeyedReprGenerator) EmitNodeMethodMapIterator(w io.Writer) {\n\t// Similar to the type-level method, except yields discriminant values as keys instead of the member type names.\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) MapIterator() datamodel.MapIterator {\n\t\t\treturn &_{{ .Type | TypeSymbol }}__ReprMapItr{n, false}\n\t\t}\n\n\t\ttype _{{ .Type | TypeSymbol }}__ReprMapItr struct {\n\t\t\tn *_{{ .Type | TypeSymbol }}__Repr\n\t\t\tdone bool\n\t\t}\n\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__ReprMapItr) Next() (k datamodel.Node, v datamodel.Node, _ error) {\n\t\t\tif itr.done {\n\t\t\t\treturn nil, nil, datamodel.ErrIteratorOverread{}\n\t\t\t}\n\t\t\t{{- if (eq (.AdjCfg.UnionMemlayout .Type) \"embedAll\") }}\n\t\t\tswitch itr.n.tag {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase {{ add $i 1 }}:\n\t\t\t\tk, v = &memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial, itr.n.x{{ add $i 1 }}.Representation()\n\t\t\t{{- end}}\n\t\t\t{{- else if (eq (.AdjCfg.UnionMemlayout .Type) \"interface\") }}\n\t\t\tswitch n2 := itr.n.x.(type) {\n\t\t\t{{- range $member := .Type.Members }}\n\t\t\tcase {{ $member | TypeSymbol }}:\n\t\t\t\tk, v = &memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial, n2.Representation()\n\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t\titr.done = true\n\t\t\treturn\n\t\t}\n\t\tfunc (itr *_{{ .Type | TypeSymbol }}__ReprMapItr) Done() bool {\n\t\t\treturn itr.done\n\t\t}\n\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionReprKeyedReprGenerator) EmitNodeMethodLength(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (_{{ .Type | TypeSymbol }}__Repr) Length() int64 {\n\t\t\treturn 1\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionReprKeyedReprGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\n\nfunc (g unionReprKeyedReprGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g unionReprKeyedReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn unionReprKeyedReprBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.MapAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Repr\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype unionReprKeyedReprBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.MapAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeUnion\n}\n\nfunc (unionReprKeyedReprBuilderGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g unionReprKeyedReprBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g unionReprKeyedReprBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g unionReprKeyedReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// Nearly identical to the type-level system, except it embeds the Repr variant of child assemblers\n\t//  (which is a very minor difference textually, but means this structure can end up with a pretty wildly different resident memory size than the type-level one).\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprAssembler struct {\n\t\t\tw *_{{ .Type | TypeSymbol }}\n\t\t\tm *schema.Maybe\n\t\t\tstate maState\n\n\t\t\tcm schema.Maybe\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tca{{ add $i 1 }} {{ if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"interface\") }}*{{end}}_{{ $member | TypeSymbol }}__ReprAssembler\n\t\t\t{{end -}}\n\t\t\tca uint\n\t\t}\n\t`, w, g.AdjCfg, g)\n\n\t// Reset methods: also nearly identical to the type-level ones.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) reset() {\n\t\t\tna.state = maState_initial\n\t\t\tswitch na.ca {\n\t\t\tcase 0:\n\t\t\t\treturn\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase {{ add $i 1 }}:\n\t\t\t\tna.ca{{ add $i 1 }}.reset()\n\t\t\t{{end -}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t\tna.ca = 0\n\t\t\tna.cm = schema.Maybe_Absent\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g unionReprKeyedReprBuilderGenerator) EmitNodeAssemblerMethodBeginMap(w io.Writer) {\n\temitNodeAssemblerMethodBeginMap_strictoid(w, g.AdjCfg, g)\n}\nfunc (g unionReprKeyedReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\t// It might sound a bit odd to call a union \"recursive\", since it's so very trivially so (no fan-out),\n\t//  but it's functionally accurate: the generated method should include a branch for the 'midvalue' state.\n\temitNodeAssemblerMethodAssignNull_recursive(w, g.AdjCfg, g)\n}\nfunc (g unionReprKeyedReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\t// DRY: this is once again not-coincidentally very nearly equal to the type-level method.  Would be good to dedup them... after we do the get-to-the-point-in-phase-3 improvement.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignNode(v datamodel.Node) error {\n\t\t\tif v.IsNull() {\n\t\t\t\treturn na.AssignNull()\n\t\t\t}\n\t\t\tif v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok {\n\t\t\t\tswitch *na.m {\n\t\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\t\tcase midvalue:\n\t\t\t\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t\t\t\t}\n\t\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\t\tif na.w == nil {\n\t\t\t\t\tna.w = v2\n\t\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t*na.w = *v2\n\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif v.Kind() != datamodel.Kind_Map {\n\t\t\t\treturn datamodel.ErrWrongKind{TypeName: \"{{ .PkgName }}.{{ .Type.Name }}.Repr\", MethodName: \"AssignNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: v.Kind()}\n\t\t\t}\n\t\t\titr := v.MapIterator()\n\t\t\tfor !itr.Done() {\n\t\t\t\tk, v, err := itr.Next()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := na.AssembleKey().AssignNode(k); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn na.Finish()\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g unionReprKeyedReprBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\tg.emitMapAssemblerChildTidyHelper(w)\n\tg.emitMapAssemblerMethods(w)\n\tg.emitKeyAssembler(w)\n}\nfunc (g unionReprKeyedReprBuilderGenerator) emitMapAssemblerChildTidyHelper(w io.Writer) {\n\t// Nearly identical to the type-level equivalent.\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) valueFinishTidy() bool {\n\t\t\tswitch ma.cm {\n\t\t\tcase schema.Maybe_Value:\n\t\t\t\t{{- /* nothing to do for memlayout=embedAll; the tag is already set and memory already in place. */ -}}\n\t\t\t\t{{- /* nothing to do for memlayout=interface either; same story, the values are already in place. */ -}}\n\t\t\t\tma.state = maState_initial\n\t\t\t\treturn true\n\t\t\tdefault:\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g unionReprKeyedReprBuilderGenerator) emitMapAssemblerMethods(w io.Writer) {\n\t// All of these: shamelessly similar to the type-level equivalent, modulo a few appearances of \"Repr\".\n\t//  Alright, and also the \"discriminant values as keys instead of the member type names\" thing.\n\t// DRY: the number of times these `ma.state` switches are appearing is truly intense!  This is starting to look like one of them most important things to shrink the GSLOC/ASM size of!\n\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling another key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on for the moment, but we'll still be erroring shortly.\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tif ma.ca != 0 {\n\t\t\t\treturn nil, schema.ErrNotUnionStructure{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}.Repr\", Detail: \"cannot add another entry -- a union can only contain one thing!\"}\n\t\t\t}\n\t\t\t{{- if .Type.Members }}\n\t\t\tswitch k {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase \"{{ $member | dot.Type.RepresentationStrategy.GetDiscriminant }}\":\n\t\t\t\tma.state = maState_midValue\n\t\t\t\tma.ca = {{ add $i 1 }}\n\t\t\t\t{{- if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"embedAll\") }}\n\t\t\t\tma.w.tag = {{ add $i 1 }}\n\t\t\t\tma.ca{{ add $i 1 }}.w = &ma.w.x{{ add $i 1 }}\n\t\t\t\tma.ca{{ add $i 1 }}.m = &ma.cm\n\t\t\t\treturn &ma.ca{{ add $i 1 }}, nil\n\t\t\t\t{{- else if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"interface\") }}\n\t\t\t\tx := &_{{ $member | TypeSymbol }}{}\n\t\t\t\tma.w.x = x\n\t\t\t\tif ma.ca{{ add $i 1 }} == nil {\n\t\t\t\t\tma.ca{{ add $i 1 }} = &_{{ $member | TypeSymbol }}__ReprAssembler{}\n\t\t\t\t}\n\t\t\t\tma.ca{{ add $i 1 }}.w = x\n\t\t\t\tma.ca{{ add $i 1 }}.m = &ma.cm\n\t\t\t\treturn ma.ca{{ add $i 1 }}, nil\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\treturn nil, schema.ErrInvalidKey{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}.Repr\", Key:&_String{k}}\n\t\t}\n\t`, w, g.AdjCfg, g)\n\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) AssembleKey() datamodel.NodeAssembler {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling another key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on for the moment, but we'll still be erroring shortly... or rather, the keyassembler will be.\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tma.state = maState_midKey\n\t\t\treturn (*_{{ .Type | TypeSymbol }}__ReprKeyAssembler)(ma)\n\t\t}\n\t`, w, g.AdjCfg, g)\n\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) AssembleValue() datamodel.NodeAssembler {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when no key is primed\")\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling a key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\t// carry on\n\t\t\tcase maState_midValue:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling another value\")\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tma.state = maState_midValue\n\t\t\tswitch ma.ca {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase {{ add $i 1 }}:\n\t\t\t\t{{- if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"embedAll\") }}\n\t\t\t\tma.ca{{ add $i 1 }}.w = &ma.w.x{{ add $i 1 }}\n\t\t\t\tma.ca{{ add $i 1 }}.m = &ma.cm\n\t\t\t\treturn &ma.ca{{ add $i 1 }}\n\t\t\t\t{{- else if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"interface\") }}\n\t\t\t\tx := &_{{ $member | TypeSymbol }}{}\n\t\t\t\tma.w.x = x\n\t\t\t\tif ma.ca{{ add $i 1 }} == nil {\n\t\t\t\t\tma.ca{{ add $i 1 }} = &_{{ $member | TypeSymbol }}__ReprAssembler{}\n\t\t\t\t}\n\t\t\t\tma.ca{{ add $i 1 }}.w = x\n\t\t\t\tma.ca{{ add $i 1 }}.m = &ma.cm\n\t\t\t\treturn ma.ca{{ add $i 1 }}\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) Finish() error {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tif ma.ca == 0 {\n\t\t\t\treturn schema.ErrNotUnionStructure{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}.Repr\", Detail: \"a union must have exactly one entry (not none)!\"}\n\t\t\t}\n\t\t\tma.state = maState_finished\n\t\t\t*ma.m = schema.Maybe_Value\n\t\t\treturn nil\n\t\t}\n\t`, w, g.AdjCfg, g)\n\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) KeyPrototype() datamodel.NodePrototype {\n\t\t\treturn _String__Prototype{}\n\t\t}\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__ReprAssembler) ValuePrototype(k string) datamodel.NodePrototype {\n\t\t\tswitch k {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase \"{{ $member.Name }}\":\n\t\t\t\treturn _{{ $member | TypeSymbol }}__ReprPrototype{}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g unionReprKeyedReprBuilderGenerator) emitKeyAssembler(w io.Writer) {\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprKeyAssembler _{{ .Type | TypeSymbol }}__ReprAssembler\n\t`, w, g.AdjCfg, g)\n\tstubs := mixins.StringAssemblerTraits{\n\t\tPkgName:       g.PkgName,\n\t\tTypeName:      g.TypeName + \".KeyAssembler\", // \".Repr\" is already in `g.TypeName`, so don't stutter the \"Repr\" part.\n\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__ReprKey\",\n\t}\n\t// This key assembler can disregard any idea of complex keys because we know that our discriminants are just strings!\n\tstubs.EmitNodeAssemblerMethodBeginMap(w)\n\tstubs.EmitNodeAssemblerMethodBeginList(w)\n\tstubs.EmitNodeAssemblerMethodAssignNull(w)\n\tstubs.EmitNodeAssemblerMethodAssignBool(w)\n\tstubs.EmitNodeAssemblerMethodAssignInt(w)\n\tstubs.EmitNodeAssemblerMethodAssignFloat(w)\n\tdoTemplate(`\n\t\tfunc (ka *_{{ .Type | TypeSymbol }}__ReprKeyAssembler) AssignString(k string) error {\n\t\t\tif ka.state != maState_midKey {\n\t\t\t\tpanic(\"misuse: KeyAssembler held beyond its valid lifetime\")\n\t\t\t}\n\t\t\tif ka.ca != 0 {\n\t\t\t\treturn schema.ErrNotUnionStructure{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}.Repr\", Detail: \"cannot add another entry -- a union can only contain one thing!\"}\n\t\t\t}\n\t\t\tswitch k {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase \"{{ $member | dot.Type.RepresentationStrategy.GetDiscriminant }}\":\n\t\t\t\tka.ca = {{ add $i 1 }}\n\t\t\t\t{{- if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"embedAll\") }}\n\t\t\t\tka.w.tag = {{ add $i 1 }}\n\t\t\t\t{{- end}}\n\t\t\t\tka.state = maState_expectValue\n\t\t\t\treturn nil\n\t\t\t{{- end}}\n\t\t\t}\n\t\t\treturn schema.ErrInvalidKey{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}.Repr\", Key:&_String{k}} // TODO: error quality: ErrInvalidUnionDiscriminant ?\n\t\t}\n\t`, w, g.AdjCfg, g)\n\tstubs.EmitNodeAssemblerMethodAssignBytes(w)\n\tstubs.EmitNodeAssemblerMethodAssignLink(w)\n\tdoTemplate(`\n\t\tfunc (ka *_{{ .Type | TypeSymbol }}__ReprKeyAssembler) AssignNode(v datamodel.Node) error {\n\t\t\tif v2, err := v.AsString(); err != nil {\n\t\t\t\treturn err\n\t\t\t} else {\n\t\t\t\treturn ka.AssignString(v2)\n\t\t\t}\n\t\t}\n\t\tfunc (_{{ .Type | TypeSymbol }}__ReprKeyAssembler) Prototype() datamodel.NodePrototype {\n\t\t\treturn _String__Prototype{}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n"
  },
  {
    "path": "schema/gen/go/genUnionReprKinded.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\nvar _ TypeGenerator = &unionKindedGenerator{}\n\n// Kinded union representations are quite wild: their behavior varies almost completely per inhabitant,\n//  and their implementation is generally delegating directly to something else,\n//   rather than having an intermediate node (like most unions do, and like the type-level view of this same value will).\n//\n// This also means any error values can be a little weird:\n//  sometimes they'll have the union's type name, but sometimes they'll have the inhabitant's type name instead;\n//  this depends on whether the error is an ErrWrongKind that was found while checking the method for appropriateness on the union's inhabitant\n//  versus if the error came from the union inhabitant itself after delegation occurred.\n\nfunc NewUnionReprKindedGenerator(pkgName string, typ *schema.TypeUnion, adjCfg *AdjunctCfg) TypeGenerator {\n\treturn unionKindedGenerator{\n\t\tunionGenerator{\n\t\t\tadjCfg,\n\t\t\tmixins.MapTraits{\n\t\t\t\tPkgName:    pkgName,\n\t\t\t\tTypeName:   string(typ.Name()),\n\t\t\t\tTypeSymbol: adjCfg.TypeSymbol(typ),\n\t\t\t},\n\t\t\tpkgName,\n\t\t\ttyp,\n\t\t},\n\t}\n}\n\ntype unionKindedGenerator struct {\n\tunionGenerator\n}\n\nfunc (g unionKindedGenerator) GetRepresentationNodeGen() NodeGenerator {\n\treturn unionKindedReprGenerator{\n\t\tg.AdjCfg,\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype unionKindedReprGenerator struct {\n\t// Note that there's no MapTraits (or any other FooTraits) mixin in this one!\n\t//  This is no accident: *None* of them apply!\n\n\tAdjCfg  *AdjunctCfg\n\tPkgName string\n\tType    *schema.TypeUnion\n}\n\nfunc (unionKindedReprGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g unionKindedReprGenerator) EmitNodeType(w io.Writer) {\n\t// The type is structurally the same, but will have a different set of methods.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Repr _{{ .Type | TypeSymbol }}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodKind(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) Kind() datamodel.Kind {\n\t\t\t{{- if (eq (.AdjCfg.UnionMemlayout .Type) \"embedAll\") }}\n\t\t\tswitch n.tag {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase {{ add $i 1 }}:\n\t\t\t\treturn {{ $member.RepresentationBehavior | KindSymbol }}\n\t\t\t{{- end}}\n\t\t\t{{- else if (eq (.AdjCfg.UnionMemlayout .Type) \"interface\") }}\n\t\t\tswitch n.x.(type) {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase {{ $member | TypeSymbol }}:\n\t\t\t\treturn {{ $member.RepresentationBehavior | KindSymbol }}\n\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc kindedUnionNodeMethodTemplateMunge(\n\tmethodName string, // for error messages\n\tmethodSig string, // output literally\n\tsomeSwitchClause string, // template condition for if *any* switch clause should be present\n\tcondClause string, // template condition for the member this should match on when in the range\n\tretClause string, // clause returning the thing (how to delegate methodsig, generally)\n\tappropriateKind string, // for error messages\n\tnopeSentinel string, // for error return paths; generally the zero value for the first return type.\n\tnopeSentinelOnly bool, // true if this method has no error return, just the sentinel.\n) string {\n\t// We really could just... call the methods directly (and elide the switch entirely all the time), in the case of the \"interface\" implementation strategy.\n\t//  We don't, though, because that would deprive us of getting the union type's name in the wrong-kind errors...\n\t//   and in addition to that being sadface in general, it would be downright unacceptable if that behavior varied based on implementation strategy.\n\t//\n\t// This error text doesn't tell us what the member kind is.  This might read weirdly.\n\t//  It's possible we could try to cram a description of the inhabitant into the \"TypeName\" since it's stringy; but unclear if that's a good idea either.\n\n\t// These template concatenations have evolved into a mess very quickly.  This entire thing should be replaced.\n\t//  String concatenations of template clauses is an atrociously unhygenic way to compose things;\n\t//   it looked like we could limp by with it for a while, but it's gotten messier faster than expected.\n\n\terrorClause := `return ` + nopeSentinel\n\tif !nopeSentinelOnly {\n\t\terrorClause += `, datamodel.ErrWrongKind{TypeName: \"{{ .PkgName }}.{{ .Type.Name }}.Repr\", MethodName: \"` + methodName + `\", AppropriateKind: ` + appropriateKind + `, ActualKind: n.Kind()}`\n\t}\n\treturn `\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) ` + methodSig + ` {\n\t\t\t` + someSwitchClause + `\n\t\t\t{{- if (eq (.AdjCfg.UnionMemlayout .Type) \"embedAll\") }}\n\t\t\tswitch n.tag {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\t` + condClause + `\n\t\t\tcase {{ add $i 1 }}:\n\t\t\t\treturn n.x{{ add $i 1 }}.Representation()` + retClause + `\n\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\t{{- else if (eq (.AdjCfg.UnionMemlayout .Type) \"interface\") }}\n\t\t\tswitch n2 := n.x.(type) {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\t` + condClause + `\n\t\t\tcase {{ $member | TypeSymbol }}:\n\t\t\t\treturn n2.Representation()` + retClause + `\n\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t{{- end}}\n\t\t\t\t` + errorClause + `\n\t\t\t` + someSwitchClause + `\n\t\t\t}\n\t\t\t{{- end}}\n\t\t}\n\t`\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodLookupByString(w io.Writer) {\n\tdoTemplate(kindedUnionNodeMethodTemplateMunge(\n\t\t`LookupByString`,\n\t\t`LookupByString(key string) (datamodel.Node, error)`,\n\t\t`{{- if .Type.RepresentationStrategy.GetMember (Kind \"map\") }}`,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"map\" }}`,\n\t\t`.LookupByString(key)`,\n\t\t`datamodel.KindSet_JustMap`,\n\t\t`nil`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodLookupByIndex(w io.Writer) {\n\tdoTemplate(kindedUnionNodeMethodTemplateMunge(\n\t\t`LookupByIndex`,\n\t\t`LookupByIndex(idx int64) (datamodel.Node, error)`,\n\t\t`{{- if .Type.RepresentationStrategy.GetMember (Kind \"list\") }}`,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"list\" }}`,\n\t\t`.LookupByIndex(idx)`,\n\t\t`datamodel.KindSet_JustList`,\n\t\t`nil`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodLookupByNode(w io.Writer) {\n\tdoTemplate(kindedUnionNodeMethodTemplateMunge(\n\t\t`LookupByNode`,\n\t\t`LookupByNode(key datamodel.Node) (datamodel.Node, error)`,\n\t\t`{{- if or (.Type.RepresentationStrategy.GetMember (Kind \"map\")) (.Type.RepresentationStrategy.GetMember (Kind \"list\")) }}`,\n\t\t`{{- if or (eq $member.RepresentationBehavior.String \"map\") (eq $member.RepresentationBehavior.String \"list\") }}`,\n\t\t`.LookupByNode(key)`,\n\t\t`datamodel.KindSet_Recursive`,\n\t\t`nil`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodLookupBySegment(w io.Writer) {\n\tdoTemplate(kindedUnionNodeMethodTemplateMunge(\n\t\t`LookupBySegment`,\n\t\t`LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error)`,\n\t\t`{{- if or (.Type.RepresentationStrategy.GetMember (Kind \"map\")) (.Type.RepresentationStrategy.GetMember (Kind \"list\")) }}`,\n\t\t`{{- if or (eq $member.RepresentationBehavior.String \"map\") (eq $member.RepresentationBehavior.String \"list\") }}`,\n\t\t`.LookupBySegment(seg)`,\n\t\t`datamodel.KindSet_Recursive`,\n\t\t`nil`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodMapIterator(w io.Writer) {\n\tdoTemplate(kindedUnionNodeMethodTemplateMunge(\n\t\t`MapIterator`,\n\t\t`MapIterator() datamodel.MapIterator`,\n\t\t`{{- if .Type.RepresentationStrategy.GetMember (Kind \"map\") }}`,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"map\" }}`,\n\t\t`.MapIterator()`,\n\t\t`datamodel.KindSet_JustMap`,\n\t\t`nil`,\n\t\ttrue,\n\t), w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodListIterator(w io.Writer) {\n\tdoTemplate(kindedUnionNodeMethodTemplateMunge(\n\t\t`ListIterator`,\n\t\t`ListIterator() datamodel.ListIterator`,\n\t\t`{{- if .Type.RepresentationStrategy.GetMember (Kind \"list\") }}`,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"list\" }}`,\n\t\t`.ListIterator()`,\n\t\t`datamodel.KindSet_JustList`,\n\t\t`nil`,\n\t\ttrue,\n\t), w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodLength(w io.Writer) {\n\tdoTemplate(kindedUnionNodeMethodTemplateMunge(\n\t\t`Length`,\n\t\t`Length() int64`,\n\t\t`{{- if or (.Type.RepresentationStrategy.GetMember (Kind \"map\")) (.Type.RepresentationStrategy.GetMember (Kind \"list\")) }}`,\n\t\t`{{- if or (eq $member.RepresentationBehavior.String \"map\") (eq $member.RepresentationBehavior.String \"list\") }}`,\n\t\t`.Length()`,\n\t\t`datamodel.KindSet_Recursive`,\n\t\t`-1`,\n\t\ttrue,\n\t), w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodIsAbsent(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) IsAbsent() bool {\n\t\t\treturn false\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodIsNull(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) IsNull() bool {\n\t\t\treturn false\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodAsBool(w io.Writer) {\n\tdoTemplate(kindedUnionNodeMethodTemplateMunge(\n\t\t`AsBool`,\n\t\t`AsBool() (bool, error)`,\n\t\t`{{- if .Type.RepresentationStrategy.GetMember (Kind \"bool\") }}`,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"bool\" }}`,\n\t\t`.AsBool()`,\n\t\t`datamodel.KindSet_JustBool`,\n\t\t`false`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodAsInt(w io.Writer) {\n\tdoTemplate(kindedUnionNodeMethodTemplateMunge(\n\t\t`AsInt`,\n\t\t`AsInt() (int64, error)`,\n\t\t`{{- if .Type.RepresentationStrategy.GetMember (Kind \"int\") }}`,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"int\" }}`,\n\t\t`.AsInt()`,\n\t\t`datamodel.KindSet_JustInt`,\n\t\t`0`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodAsFloat(w io.Writer) {\n\tdoTemplate(kindedUnionNodeMethodTemplateMunge(\n\t\t`AsFloat`,\n\t\t`AsFloat() (float64, error)`,\n\t\t`{{- if .Type.RepresentationStrategy.GetMember (Kind \"float\") }}`,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"float\" }}`,\n\t\t`.AsFloat()`,\n\t\t`datamodel.KindSet_JustFloat`,\n\t\t`0`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodAsString(w io.Writer) {\n\tdoTemplate(kindedUnionNodeMethodTemplateMunge(\n\t\t`AsString`,\n\t\t`AsString() (string, error)`,\n\t\t`{{- if .Type.RepresentationStrategy.GetMember (Kind \"string\") }}`,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"string\" }}`,\n\t\t`.AsString()`,\n\t\t`datamodel.KindSet_JustString`,\n\t\t`\"\"`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodAsBytes(w io.Writer) {\n\tdoTemplate(kindedUnionNodeMethodTemplateMunge(\n\t\t`AsBytes`,\n\t\t`AsBytes() ([]byte, error)`,\n\t\t`{{- if .Type.RepresentationStrategy.GetMember (Kind \"bytes\") }}`,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"bytes\" }}`,\n\t\t`.AsBytes()`,\n\t\t`datamodel.KindSet_JustBytes`,\n\t\t`nil`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodAsLink(w io.Writer) {\n\tdoTemplate(kindedUnionNodeMethodTemplateMunge(\n\t\t`AsLink`,\n\t\t`AsLink() (datamodel.Link, error)`,\n\t\t`{{- if .Type.RepresentationStrategy.GetMember (Kind \"link\") }}`,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"link\" }}`,\n\t\t`.AsLink()`,\n\t\t`datamodel.KindSet_JustLink`,\n\t\t`nil`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\n\nfunc (g unionKindedReprGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g unionKindedReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn unionKindedReprBuilderGenerator(g)\n}\n\ntype unionKindedReprBuilderGenerator struct {\n\tAdjCfg  *AdjunctCfg\n\tPkgName string\n\tType    *schema.TypeUnion\n}\n\nfunc (unionKindedReprBuilderGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g unionKindedReprBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g unionKindedReprBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n}\nfunc (g unionKindedReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\t// Much of this is familiar: the 'w', the 'm' are all as usual.\n\t// Some things may look a little odd here compared to all other assemblers:\n\t//  we're kinda halfway between what's conventionally seen for a scalar and what's conventionally seen for a recursive.\n\t// There's no 'maState' or 'laState'-typed fields (which feels like a scalar) because even if we end up acting like a map or list, that state is in the relevant child assembler.\n\t// We don't even have a 'cm' field, because we can get away with something really funky: we can just copy our own 'm' _pointer_ into children; our doneness and their doneness is the same.\n\t// We never have to worry about maybeism of our children; the nullable and optional modifiers aren't possible on union members.\n\t//  (We *do* still have to consider null values though, as null is still a kind, and thus can be routed to one of our members!)\n\t// 'ca' is as it is in the type-level assembler: technically, not super necessary, except that it allows minimizing the amount of work that resetting needs to do.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprAssembler struct {\n\t\t\tw *_{{ .Type | TypeSymbol }}\n\t\t\tm *schema.Maybe\n\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tca{{ add $i 1 }} {{ if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"interface\") }}*{{end}}_{{ $member | TypeSymbol }}__ReprAssembler\n\t\t\t{{- end}}\n\t\t\tca uint\n\t\t}\n\t`, w, g.AdjCfg, g)\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) reset() {\n\t\t\tswitch na.ca {\n\t\t\tcase 0:\n\t\t\t\treturn\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase {{ add $i 1 }}:\n\t\t\t\tna.ca{{ add $i 1 }}.reset()\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t\tna.ca = 0\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc kindedUnionNodeAssemblerMethodTemplateMunge(\n\tmethodName string, // for error messages\n\tmethodSig string, // output literally\n\tcondClause string, // template condition for the member this should match on\n\tretClause string, // clause returning the thing (how to delegate methodsig, generally)\n\ttwoReturns bool, // true if a nil should be returned as well as the error\n) string {\n\t// The value pointed to by `na.m` isn't modified here, because we're sharing it with the child, who should do so.\n\t//  This also means that value gets checked twice -- once by us, because we need to halt if we've already been used --\n\t//   and also a second time by the child when we delegate to it, which, unbeknownst to it, is irrelevant.\n\t//   I don't see a good way to remedy this shy of making more granular (unexported!) methods.  (Might be worth it.)\n\t//   This probably also isn't the same for all of the assembler methods: the methods we delegate to aren't doing as many check branches when they're for scalars,\n\t//    because they expected to be used in contexts where many values of the 'm' enum aren't reachable -- an expectation we've suddenly subverted with this path!\n\t//\n\t// FUTURE: The error returns here are deeply questionable, and not as helpful as they could be.\n\t//  ErrNotUnionStructure is about the most applicable thing so far, but it's very freetext.\n\t//  ErrWrongKind wouldn't fit at all: assumes that we can say what kind of node we have, but this is the one case in the whole system where *we can't*; also, assumes there's one actual correct kind, and that too is false here!\n\tmaybeNilComma := \"\"\n\tif twoReturns {\n\t\tmaybeNilComma += \"nil,\"\n\t}\n\treturn `\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) ` + methodSig + ` {\n\t\t\tswitch *na.m {\n\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\tcase midvalue:\n\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already working on a larger structure!\")\n\t\t\t}\n\t\t\t{{- $returned := false -}}\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\t` + condClause + `\n\t\t\t\t{{- if dot.Type | MaybeUsesPtr }}\n\t\t\t\t\tif na.w == nil {\n\t\t\t\t\t\tna.w = &_{{ dot.Type | TypeSymbol }}{}\n\t\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\tna.ca = {{ add $i 1 }}\n\t\t\t\t{{- if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"embedAll\") }}\n\t\t\t\t\tna.w.tag = {{ add $i 1 }}\n\t\t\t\t\tna.ca{{ add $i 1 }}.w = &na.w.x{{ add $i 1 }}\n\t\t\t\t\tna.ca{{ add $i 1 }}.m = na.m\n\t\t\t\t\treturn na.ca{{ add $i 1 }}` + retClause + `\n\t\t\t\t{{- else if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"interface\") }}\n\t\t\t\t\tx := &_{{ $member | TypeSymbol }}{}\n\t\t\t\t\tna.w.x = x\n\t\t\t\t\tif na.ca{{ add $i 1 }} == nil {\n\t\t\t\t\t\tna.ca{{ add $i 1 }} = &_{{ $member | TypeSymbol }}__ReprAssembler{}\n\t\t\t\t\t}\n\t\t\t\t\tna.ca{{ add $i 1 }}.w = x\n\t\t\t\t\tna.ca{{ add $i 1 }}.m = na.m\n\t\t\t\t\treturn na.ca{{ add $i 1 }}` + retClause + `\n\t\t\t\t{{- end}}\n\t\t\t\t{{- $returned = true -}}\n\t\t\t{{- end }}\n\t\t\t{{- end }}\n\t\t\t{{- if not $returned }}\n\t\t\treturn ` + maybeNilComma + ` schema.ErrNotUnionStructure{TypeName: \"{{ .PkgName }}.{{ .Type.Name }}.Repr\", Detail: \"` + methodName + ` called but is not valid for any of the kinds that are valid members of this union\"}\n\t\t\t{{- end }}\n\t\t}\n\t`\n}\n\nfunc (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodBeginMap(w io.Writer) {\n\tdoTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(\n\t\t`BeginMap`,\n\t\t`BeginMap(sizeHint int64) (datamodel.MapAssembler, error)`,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"map\" }}`,\n\t\t`.BeginMap(sizeHint)`,\n\t\ttrue,\n\t), w, g.AdjCfg, g)\n}\nfunc (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodBeginList(w io.Writer) {\n\tdoTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(\n\t\t`BeginList`,\n\t\t`BeginList(sizeHint int64) (datamodel.ListAssembler, error)`,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"list\" }}`,\n\t\t`.BeginList(sizeHint)`,\n\t\ttrue,\n\t), w, g.AdjCfg, g)\n}\nfunc (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\t// TODO: I think this may need some special handling to account for if our union is itself used in a nullable circumstance; that should overrule this behavior.\n\tdoTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(\n\t\t`AssignNull`,\n\t\t`AssignNull() error `,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"null\" }}`,\n\t\t`.AssignNull()`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\nfunc (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignBool(w io.Writer) {\n\tdoTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(\n\t\t`AssignBool`,\n\t\t`AssignBool(v bool) error `,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"bool\" }}`,\n\t\t`.AssignBool(v)`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\nfunc (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignInt(w io.Writer) {\n\tdoTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(\n\t\t`AssignInt`,\n\t\t`AssignInt(v int64) error `,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"int\" }}`,\n\t\t`.AssignInt(v)`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\nfunc (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignFloat(w io.Writer) {\n\tdoTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(\n\t\t`AssignFloat`,\n\t\t`AssignFloat(v float64) error `,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"float\" }}`,\n\t\t`.AssignFloat(v)`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\nfunc (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignString(w io.Writer) {\n\tdoTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(\n\t\t`AssignString`,\n\t\t`AssignString(v string) error `,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"string\" }}`,\n\t\t`.AssignString(v)`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\nfunc (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignBytes(w io.Writer) {\n\tdoTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(\n\t\t`AssignBytes`,\n\t\t`AssignBytes(v []byte) error `,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"bytes\" }}`,\n\t\t`.AssignBytes(v)`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\nfunc (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignLink(w io.Writer) {\n\tdoTemplate(kindedUnionNodeAssemblerMethodTemplateMunge(\n\t\t`AssignLink`,\n\t\t`AssignLink(v datamodel.Link) error `,\n\t\t`{{- if eq $member.RepresentationBehavior.String \"link\" }}`,\n\t\t`.AssignLink(v)`,\n\t\tfalse,\n\t), w, g.AdjCfg, g)\n}\nfunc (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\t// This is a very mundane AssignNode: it just calls out to the other methods on this type.\n\t//  However, even that is a little more exciting than usual: because we can't *necessarily* reject any kind of arg,\n\t//   we have the whole barrage of switch cases here.  We then leave any particular rejections to those methods.\n\t//  Several cases could be statically replaced with errors and it would be an improvement.\n\t//\n\t// Errors are problematic again, same as is noted in kindedUnionNodeAssemblerMethodTemplateMunge.\n\t//  We also end up returning errors with other method names due to how we delegate; unfortunate.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignNode(v datamodel.Node) error {\n\t\t\tif v.IsNull() {\n\t\t\t\treturn na.AssignNull()\n\t\t\t}\n\t\t\tif v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok {\n\t\t\t\tswitch *na.m {\n\t\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\t\tcase midvalue:\n\t\t\t\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t\t\t\t}\n\t\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\t\tif na.w == nil {\n\t\t\t\t\tna.w = v2\n\t\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t*na.w = *v2\n\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tswitch v.Kind() {\n\t\t\tcase datamodel.Kind_Bool:\n\t\t\t\tv2, _ := v.AsBool()\n\t\t\t\treturn na.AssignBool(v2)\n\t\t\tcase datamodel.Kind_Int:\n\t\t\t\tv2, _ := v.AsInt()\n\t\t\t\treturn na.AssignInt(v2)\n\t\t\tcase datamodel.Kind_Float:\n\t\t\t\tv2, _ := v.AsFloat()\n\t\t\t\treturn na.AssignFloat(v2)\n\t\t\tcase datamodel.Kind_String:\n\t\t\t\tv2, _ := v.AsString()\n\t\t\t\treturn na.AssignString(v2)\n\t\t\tcase datamodel.Kind_Bytes:\n\t\t\t\tv2, _ := v.AsBytes()\n\t\t\t\treturn na.AssignBytes(v2)\n\t\t\tcase datamodel.Kind_Map:\n\t\t\t\tna, err := na.BeginMap(v.Length())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\titr := v.MapIterator()\n\t\t\t\tfor !itr.Done() {\n\t\t\t\t\tk, v, err := itr.Next()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif err := na.AssembleKey().AssignNode(k); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn na.Finish()\n\t\t\tcase datamodel.Kind_List:\n\t\t\t\tna, err := na.BeginList(v.Length())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\titr := v.ListIterator()\n\t\t\t\tfor !itr.Done() {\n\t\t\t\t\t_, v, err := itr.Next()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn na.Finish()\n\t\t\tcase datamodel.Kind_Link:\n\t\t\t\tv2, _ := v.AsLink()\n\t\t\t\treturn na.AssignLink(v2)\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g unionKindedReprBuilderGenerator) EmitNodeAssemblerMethodPrototype(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) Prototype() datamodel.NodePrototype {\n\t\t\treturn _{{ .Type | TypeSymbol }}__ReprPrototype{}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g unionKindedReprBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\t// somewhat shockingly: nothing.\n}\n"
  },
  {
    "path": "schema/gen/go/genUnionReprStringprefix.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\"github.com/ipld/go-ipld-prime/schema/gen/go/mixins\"\n)\n\nvar _ TypeGenerator = &unionReprStringprefixGenerator{}\n\nfunc NewUnionReprStringprefixGenerator(pkgName string, typ *schema.TypeUnion, adjCfg *AdjunctCfg) TypeGenerator {\n\treturn unionReprStringprefixGenerator{\n\t\tunionGenerator{\n\t\t\tAdjCfg: adjCfg,\n\t\t\tMapTraits: mixins.MapTraits{\n\t\t\t\tPkgName:    pkgName,\n\t\t\t\tTypeName:   string(typ.Name()),\n\t\t\t\tTypeSymbol: adjCfg.TypeSymbol(typ),\n\t\t\t},\n\t\t\tPkgName: pkgName,\n\t\t\tType:    typ,\n\t\t},\n\t}\n}\n\ntype unionReprStringprefixGenerator struct {\n\tunionGenerator\n}\n\nfunc (g unionReprStringprefixGenerator) GetRepresentationNodeGen() NodeGenerator {\n\treturn unionReprStringprefixReprGenerator{\n\t\tAdjCfg: g.AdjCfg,\n\t\tStringTraits: mixins.StringTraits{\n\t\t\tPkgName:    g.PkgName,\n\t\t\tTypeName:   string(g.Type.Name()) + \".Repr\",\n\t\t\tTypeSymbol: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Repr\",\n\t\t},\n\t\tPkgName: g.PkgName,\n\t\tType:    g.Type,\n\t}\n}\n\ntype unionReprStringprefixReprGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.StringTraits\n\tPkgName string\n\tType    *schema.TypeUnion\n}\n\nfunc (unionReprStringprefixReprGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g unionReprStringprefixReprGenerator) EmitNodeType(w io.Writer) {\n\t// The type is structurally the same, but will have a different set of methods.\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Repr _{{ .Type | TypeSymbol }}\n\t`, w, g.AdjCfg, g)\n\n\t// We do also want some constants for our discriminant values;\n\t//  they'll make iterators able to work faster.\n\tdoTemplate(`\n\t\tvar (\n\t\t\t{{- range $member := .Type.Members }}\n\t\t\tmemberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial = _String{\"{{ $member | dot.Type.RepresentationStrategy.GetDiscriminant }}\"}\n\t\t\t{{- end }}\n\t\t)\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionReprStringprefixReprGenerator) EmitNodeTypeAssertions(w io.Writer) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionReprStringprefixReprGenerator) EmitNodeMethodAsString(w io.Writer) {\n\t// See comment block in structReprStringjoinReprGenerator.EmitNodeMethodAsString for a lot of philosophizing about this.\n\tdoTemplate(`\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) AsString() (string, error) {\n\t\t\treturn n.String(), nil\n\t\t}\n\t\tfunc (n *_{{ .Type | TypeSymbol }}__Repr) String() string {\n\t\t\t{{- if (eq (.AdjCfg.UnionMemlayout .Type) \"embedAll\") }}\n\t\t\tswitch n.tag {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase {{ add $i 1 }}:\n\t\t\t\treturn memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial.String() + \"{{ dot.Type.RepresentationStrategy.GetDelim }}\" + n.x{{ add $i 1 }}.String()\n\t\t\t{{- end}}\n\t\t\t{{- else if (eq (.AdjCfg.UnionMemlayout .Type) \"interface\") }}\n\t\t\tswitch n2 := n.x.(type) {\n\t\t\t{{- range $member := .Type.Members }}\n\t\t\tcase {{ $member | TypeSymbol }}:\n\t\t\t\treturn memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial.String() + \"{{ dot.Type.RepresentationStrategy.GetDelim }}\" + n2.String()\n\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t}\n\t\tfunc (n {{ .Type | TypeSymbol }}) String() string {\n\t\t\treturn (*_{{ .Type | TypeSymbol }}__Repr)(n).String()\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionReprStringprefixReprGenerator) EmitNodeMethodPrototype(w io.Writer) {\n\temitNodeMethodPrototype_typical(w, g.AdjCfg, g)\n}\n\nfunc (g unionReprStringprefixReprGenerator) EmitNodePrototypeType(w io.Writer) {\n\temitNodePrototypeType_typical(w, g.AdjCfg, g)\n}\n\n// --- NodeBuilder and NodeAssembler --->\n\nfunc (g unionReprStringprefixReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {\n\treturn unionReprStringprefixReprBuilderGenerator{\n\t\tg.AdjCfg,\n\t\tmixins.StringAssemblerTraits{\n\t\t\tPkgName:       g.PkgName,\n\t\t\tTypeName:      g.TypeName,\n\t\t\tAppliedPrefix: \"_\" + g.AdjCfg.TypeSymbol(g.Type) + \"__Repr\",\n\t\t},\n\t\tg.PkgName,\n\t\tg.Type,\n\t}\n}\n\ntype unionReprStringprefixReprBuilderGenerator struct {\n\tAdjCfg *AdjunctCfg\n\tmixins.StringAssemblerTraits\n\tPkgName string\n\tType    *schema.TypeUnion\n}\n\nfunc (unionReprStringprefixReprBuilderGenerator) IsRepr() bool { return true } // hint used in some generalized templates.\n\nfunc (g unionReprStringprefixReprBuilderGenerator) EmitNodeBuilderType(w io.Writer) {\n\temitEmitNodeBuilderType_typical(w, g.AdjCfg, g)\n}\nfunc (g unionReprStringprefixReprBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {\n\temitNodeBuilderMethods_typical(w, g.AdjCfg, g)\n\n\t// Generate a single-step construction function -- this is easy to do for a scalar,\n\t//  and all representations of scalar kind can be expected to have a method like this.\n\t// The function is attached to the NodePrototype for convenient namespacing;\n\t//  it needs no new memory, so it would be inappropriate to attach to the builder or assembler.\n\t// The function is directly used internally by anything else that might involve recursive destructuring on the same scalar kind\n\t//  (for example, structs using stringjoin strategies that have one of this type as a field, etc).\n\t// Since we're a representation of scalar kind, and can recurse,\n\t//  we ourselves presume this plain construction method must also exist for all our members.\n\t// REVIEW: We could make an immut-safe version of this and export it on the NodePrototype too, as `FromString(string)`.\n\tdoTemplate(`\n\t\tfunc (_{{ .Type | TypeSymbol }}__ReprPrototype) fromString(w *_{{ .Type | TypeSymbol }}, v string) error {\n\t\t\tss := mixins.SplitN(v, \"{{ .Type.RepresentationStrategy.GetDelim }}\", 2)\n\t\t\tif len(ss) != 2 {\n\t\t\t\treturn schema.ErrUnmatchable{TypeName:\"{{ .PkgName }}.{{ .Type.Name }}.Repr\"}.Reasonf(\"expecting a stringprefix union but found no delimiter in the value\")\n\t\t\t}\n\t\t\tswitch ss[0] {\n\t\t\t{{- range $i, $member := .Type.Members }}\n\t\t\tcase \"{{ $member | dot.Type.RepresentationStrategy.GetDiscriminant }}\":\n\t\t\t\t{{- if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"embedAll\") }}\n\t\t\t\tw.tag = {{ add $i 1 }}\n\t\t\t\tif err := (_{{ $member | TypeSymbol }}__ReprPrototype{}).fromString(&w.x{{ add $i 1 }}, ss[1]); err != nil {\n\t\t\t\t\treturn schema.ErrUnmatchable{TypeName:\"{{ dot.PkgName }}.{{ dot.Type.Name }}.Repr\", Reason: err}\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t\t{{- else if (eq (dot.AdjCfg.UnionMemlayout dot.Type) \"interface\") }}\n\t\t\t\tvar n2 _{{ $member | TypeSymbol }}\n\t\t\t\tif err := (_{{ $member | TypeSymbol }}__ReprPrototype{}).fromString(&n2, ss[1]); err != nil {\n\t\t\t\t\treturn schema.ErrUnmatchable{TypeName:\"{{ dot.PkgName }}.{{ dot.Type.Name }}.Repr\", Reason: err}\n\t\t\t\t}\n\t\t\t\tw.x = &n2\n\t\t\t\treturn nil\n\t\t\t\t{{- end}}\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\treturn schema.ErrNoSuchField{Type: nil /*TODO*/, Field: datamodel.PathSegmentOfString(ss[0])}\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__ReprAssembler struct {\n\t\t\tw *_{{ .Type | TypeSymbol }}\n\t\t\tm *schema.Maybe\n\t\t}\n\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) reset() {}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\temitNodeAssemblerMethodAssignNull_scalar(w, g.AdjCfg, g)\n}\nfunc (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerMethodAssignString(w io.Writer) {\n\t// This method contains a branch to support MaybeUsesPtr because new memory may need to be allocated.\n\t//  This allocation only happens if the 'w' ptr is nil, which means we're being used on a Maybe;\n\t//  otherwise, the 'w' ptr should already be set, and we fill that memory location without allocating, as usual.\n\t// TODO:DRY: this is identical to other string-repr-on-non-string-type.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignString(v string) error {\n\t\t\tswitch *na.m {\n\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\t}\n\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\tif na.w == nil {\n\t\t\t\tna.w = &_{{ .Type | TypeSymbol }}{}\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\tif err := (_{{ .Type | TypeSymbol }}__ReprPrototype{}).fromString(na.w, v); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t*na.m = schema.Maybe_Value\n\t\t\treturn nil\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\n\nfunc (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {\n\t// AssignNode goes through three phases:\n\t// 1. is it null?  Jump over to AssignNull (which may or may not reject it).\n\t// 2. is it our own type?  Handle specially -- we might be able to do efficient things.\n\t// 3. is it the right kind to morph into us?  Do so.\n\t// TODO:DRY: this is identical to other string-repr-on-non-string-type.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignNode(v datamodel.Node) error {\n\t\t\tif v.IsNull() {\n\t\t\t\treturn na.AssignNull()\n\t\t\t}\n\t\t\tif v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok {\n\t\t\t\tswitch *na.m {\n\t\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\t\t}\n\t\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\t\tif na.w == nil {\n\t\t\t\t\tna.w = v2\n\t\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t*na.w = *v2\n\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif v2, err := v.AsString(); err != nil {\n\t\t\t\treturn err\n\t\t\t} else {\n\t\t\t\treturn na.AssignString(v2)\n\t\t\t}\n\t\t}\n\t`, w, g.AdjCfg, g)\n}\nfunc (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {\n\t// None for this.\n}\n"
  },
  {
    "path": "schema/gen/go/generate.go",
    "content": "package gengo\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"go/format\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// Generate takes a typesystem and the adjunct config for codegen,\n// and emits generated code in the given path with the given package name.\n//\n// All of the files produced will match the pattern \"ipldsch.*.gen.go\".\nfunc Generate(pth string, pkgName string, ts schema.TypeSystem, adjCfg *AdjunctCfg) {\n\t// Emit fixed bits.\n\twithFile(filepath.Join(pth, \"ipldsch_minima.go\"), func(f io.Writer) {\n\t\tEmitInternalEnums(pkgName, f)\n\t})\n\n\texterns, err := getExternTypes(pth)\n\tif err != nil {\n\t\t// Consider warning that duplication may be present due to inability to parse destination.\n\t\texterns = make(map[string]struct{})\n\t}\n\n\t// Local helper function for applying generation logic to each type.\n\t//  We will end up doing this more than once because in this layout, more than one file contains part of the story for each type.\n\tapplyToEachType := func(fn func(tg TypeGenerator, w io.Writer), f io.Writer) {\n\t\t// Sort the type names so we have a determinisic order; this affects output consistency.\n\t\t//  Any stable order would do, but we don't presently have one, so a sort is necessary.\n\t\ttypes := ts.GetTypes()\n\t\tkeys := make(sortableTypeNames, 0, len(types))\n\t\tfor tn := range types {\n\t\t\tif _, exists := externs[tn]; !exists {\n\t\t\t\tkeys = append(keys, tn)\n\t\t\t}\n\t\t}\n\t\tsort.Sort(keys)\n\t\tfor _, tn := range keys {\n\t\t\tswitch t2 := types[tn].(type) {\n\t\t\tcase *schema.TypeBool:\n\t\t\t\tfn(NewBoolReprBoolGenerator(pkgName, t2, adjCfg), f)\n\t\t\tcase *schema.TypeInt:\n\t\t\t\tfn(NewIntReprIntGenerator(pkgName, t2, adjCfg), f)\n\t\t\tcase *schema.TypeFloat:\n\t\t\t\tfn(NewFloatReprFloatGenerator(pkgName, t2, adjCfg), f)\n\t\t\tcase *schema.TypeString:\n\t\t\t\tfn(NewStringReprStringGenerator(pkgName, t2, adjCfg), f)\n\t\t\tcase *schema.TypeBytes:\n\t\t\t\tfn(NewBytesReprBytesGenerator(pkgName, t2, adjCfg), f)\n\t\t\tcase *schema.TypeLink:\n\t\t\t\tfn(NewLinkReprLinkGenerator(pkgName, t2, adjCfg), f)\n\t\t\tcase *schema.TypeStruct:\n\t\t\t\tswitch t2.RepresentationStrategy().(type) {\n\t\t\t\tcase schema.StructRepresentation_Map:\n\t\t\t\t\tfn(NewStructReprMapGenerator(pkgName, t2, adjCfg), f)\n\t\t\t\tcase schema.StructRepresentation_Tuple:\n\t\t\t\t\tfn(NewStructReprTupleGenerator(pkgName, t2, adjCfg), f)\n\t\t\t\tcase schema.StructRepresentation_Stringjoin:\n\t\t\t\t\tfn(NewStructReprStringjoinGenerator(pkgName, t2, adjCfg), f)\n\t\t\t\tdefault:\n\t\t\t\t\tpanic(\"unrecognized struct representation strategy\")\n\t\t\t\t}\n\t\t\tcase *schema.TypeMap:\n\t\t\t\tfn(NewMapReprMapGenerator(pkgName, t2, adjCfg), f)\n\t\t\tcase *schema.TypeList:\n\t\t\t\tfn(NewListReprListGenerator(pkgName, t2, adjCfg), f)\n\t\t\tcase *schema.TypeUnion:\n\t\t\t\tswitch t2.RepresentationStrategy().(type) {\n\t\t\t\tcase schema.UnionRepresentation_Keyed:\n\t\t\t\t\tfn(NewUnionReprKeyedGenerator(pkgName, t2, adjCfg), f)\n\t\t\t\tcase schema.UnionRepresentation_Kinded:\n\t\t\t\t\tfn(NewUnionReprKindedGenerator(pkgName, t2, adjCfg), f)\n\t\t\t\tcase schema.UnionRepresentation_Stringprefix:\n\t\t\t\t\tfn(NewUnionReprStringprefixGenerator(pkgName, t2, adjCfg), f)\n\t\t\t\tdefault:\n\t\t\t\t\tpanic(\"unrecognized union representation strategy\")\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tpanic(fmt.Sprintf(\"add more type switches here :), failed at type %s\", tn))\n\t\t\t}\n\t\t}\n\t}\n\n\t// Emit a file with the type table, and the golang type defns for each type.\n\twithFile(filepath.Join(pth, \"ipldsch_types.go\"), func(f io.Writer) {\n\t\t// Emit headers, import statements, etc.\n\t\tfmt.Fprintf(f, \"package %s\\n\\n\", pkgName)\n\t\tfmt.Fprintf(f, doNotEditComment+\"\\n\\n\")\n\t\tfmt.Fprintf(f, \"import (\\n\")\n\t\tfmt.Fprintf(f, \"\\t\\\"github.com/ipld/go-ipld-prime/datamodel\\\"\\n\") // referenced for links\n\t\tfmt.Fprintf(f, \")\\n\")\n\t\tfmt.Fprintf(f, \"var _ datamodel.Node = nil // suppress errors when this dependency is not referenced\\n\")\n\n\t\t// Emit the type table.\n\t\tEmitTypeTable(pkgName, ts, adjCfg, f)\n\n\t\t// Emit the type defns matching the schema types.\n\t\tfmt.Fprintf(f, \"\\n// --- type definitions follow ---\\n\\n\")\n\t\tapplyToEachType(func(tg TypeGenerator, w io.Writer) {\n\t\t\ttg.EmitNativeType(w)\n\t\t\tfmt.Fprintf(f, \"\\n\")\n\t\t}, f)\n\n\t})\n\n\t// Emit a file with all the Node/NodeBuilder/NodeAssembler boilerplate.\n\t//  Also includes typedefs for representation-level data.\n\t//  Also includes the MaybeT boilerplate.\n\twithFile(filepath.Join(pth, \"ipldsch_satisfaction.go\"), func(f io.Writer) {\n\t\t// Emit headers, import statements, etc.\n\t\tfmt.Fprintf(f, \"package %s\\n\\n\", pkgName)\n\t\tfmt.Fprintf(f, doNotEditComment+\"\\n\\n\")\n\t\tfmt.Fprintf(f, \"import (\\n\")\n\t\tfmt.Fprintf(f, \"\\t\\\"github.com/ipld/go-ipld-prime/datamodel\\\"\\n\")   // referenced everywhere.\n\t\tfmt.Fprintf(f, \"\\t\\\"github.com/ipld/go-ipld-prime/node/mixins\\\"\\n\") // referenced by node implementation guts.\n\t\tfmt.Fprintf(f, \"\\t\\\"github.com/ipld/go-ipld-prime/schema\\\"\\n\")      // referenced by maybes (and surprisingly little else).\n\t\tfmt.Fprintf(f, \")\\n\\n\")\n\n\t\t// For each type, we'll emit... everything except the native type, really.\n\t\tapplyToEachType(func(tg TypeGenerator, w io.Writer) {\n\t\t\ttg.EmitNativeAccessors(w)\n\t\t\ttg.EmitNativeBuilder(w)\n\t\t\ttg.EmitNativeMaybe(w)\n\t\t\tEmitNode(tg, w)\n\t\t\ttg.EmitTypedNodeMethodType(w)\n\t\t\ttg.EmitTypedNodeMethodRepresentation(w)\n\n\t\t\tnrg := tg.GetRepresentationNodeGen()\n\t\t\tEmitNode(nrg, w)\n\n\t\t\tfmt.Fprintf(f, \"\\n\")\n\t\t}, f)\n\t})\n}\n\nfunc withFile(filename string, fn func(io.Writer)) {\n\t// Don't write directly to the file, as that many write syscalls can be\n\t// expensive. Moreover, they can have a knock-on effect on daemons\n\t// watching for file changes. gopls can easily eat CPU for many seconds\n\t// just handling tens of thousands of file writes, for example.\n\t//\n\t// To alleviate both of those problems, write to a buffer first, and\n\t// then write the resulting bytes to disk in a single go.\n\t// A buffer is slightly better than bufio.Writer, as it gets us a bit\n\t// more atomicity via the single write.\n\tbuf := new(bytes.Buffer)\n\tfn(buf)\n\n\tsrc := buf.Bytes()\n\t// Format the source before writing, just like gofmt would.\n\t// This also prevents us from writing invalid syntax to disk.\n\tsrc, err := format.Source(src)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tif err := os.WriteFile(filename, src, 0666); err != nil {\n\t\tpanic(err)\n\t}\n}\n\ntype sortableTypeNames []schema.TypeName\n\nfunc (a sortableTypeNames) Len() int           { return len(a) }\nfunc (a sortableTypeNames) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }\nfunc (a sortableTypeNames) Less(i, j int) bool { return a[i] < a[j] }\n"
  },
  {
    "path": "schema/gen/go/generators.go",
    "content": "package gengo\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// TypeGenerator gathers all the info for generating all code related to one\n// type in the schema.\ntype TypeGenerator interface {\n\t// -- the natively-typed apis -->\n\n\tEmitNativeType(io.Writer)\n\tEmitNativeAccessors(io.Writer) // depends on the kind -- field accessors for struct, typed iterators for map, etc.\n\tEmitNativeBuilder(io.Writer)   // typically emits some kind of struct that has a Build method.\n\tEmitNativeMaybe(io.Writer)     // a pointer-free 'maybe' mechanism is generated for all types.\n\n\t// -- the schema.TypedNode.Type method and vars -->\n\n\tEmitTypeConst(io.Writer)           // these emit dummies for now\n\tEmitTypedNodeMethodType(io.Writer) // these emit dummies for now\n\n\t// -- all node methods -->\n\t//   (and note that the nodeBuilder for this one should be the \"semantic\" one,\n\t//     e.g. it *always* acts like a map for structs, even if the repr is different.)\n\n\tNodeGenerator\n\n\t// -- and the representation and its node and nodebuilder -->\n\t//    (these vary!)\n\n\tEmitTypedNodeMethodRepresentation(io.Writer)\n\tGetRepresentationNodeGen() NodeGenerator // includes transitively the matched NodeBuilderGenerator\n}\n\ntype NodeGenerator interface {\n\tEmitNodeType(io.Writer)           // usually already covered by EmitNativeType for the primary node, but has a nonzero body for the repr node\n\tEmitNodeTypeAssertions(io.Writer) // optional to include this content\n\tEmitNodeMethodKind(io.Writer)\n\tEmitNodeMethodLookupByString(io.Writer)\n\tEmitNodeMethodLookupByNode(io.Writer)\n\tEmitNodeMethodLookupByIndex(io.Writer)\n\tEmitNodeMethodLookupBySegment(io.Writer)\n\tEmitNodeMethodMapIterator(io.Writer)  // also iterator itself\n\tEmitNodeMethodListIterator(io.Writer) // also iterator itself\n\tEmitNodeMethodLength(io.Writer)\n\tEmitNodeMethodIsAbsent(io.Writer)\n\tEmitNodeMethodIsNull(io.Writer)\n\tEmitNodeMethodAsBool(io.Writer)\n\tEmitNodeMethodAsInt(io.Writer)\n\tEmitNodeMethodAsFloat(io.Writer)\n\tEmitNodeMethodAsString(io.Writer)\n\tEmitNodeMethodAsBytes(io.Writer)\n\tEmitNodeMethodAsLink(io.Writer)\n\tEmitNodeMethodPrototype(io.Writer)\n\tEmitNodePrototypeType(io.Writer)\n\tGetNodeBuilderGenerator() NodeBuilderGenerator // assembler features also included inside\n}\n\ntype NodeBuilderGenerator interface {\n\tEmitNodeBuilderType(io.Writer)\n\tEmitNodeBuilderMethods(io.Writer) // not many, so just slung them together.\n\tEmitNodeAssemblerType(io.Writer)  // you can call this and not EmitNodeBuilderType in some situations.\n\tEmitNodeAssemblerMethodBeginMap(io.Writer)\n\tEmitNodeAssemblerMethodBeginList(io.Writer)\n\tEmitNodeAssemblerMethodAssignNull(io.Writer)\n\tEmitNodeAssemblerMethodAssignBool(io.Writer)\n\tEmitNodeAssemblerMethodAssignInt(io.Writer)\n\tEmitNodeAssemblerMethodAssignFloat(io.Writer)\n\tEmitNodeAssemblerMethodAssignString(io.Writer)\n\tEmitNodeAssemblerMethodAssignBytes(io.Writer)\n\tEmitNodeAssemblerMethodAssignLink(io.Writer)\n\tEmitNodeAssemblerMethodAssignNode(io.Writer)\n\tEmitNodeAssemblerMethodPrototype(io.Writer)\n\tEmitNodeAssemblerOtherBits(io.Writer) // key and value child assemblers are done here.\n}\n\n// EmitFileHeader emits a baseline package header that will\n// allow a file with a generated type to compile.\n// (Fortunately, there are no variations in this.)\nfunc EmitFileHeader(packageName string, w io.Writer) {\n\tfmt.Fprintf(w, \"package %s\\n\\n\", packageName)\n\tfmt.Fprintf(w, doNotEditComment+\"\\n\\n\")\n\tfmt.Fprintf(w, \"import (\\n\")\n\tfmt.Fprintf(w, \"\\t\\\"github.com/ipld/go-ipld-prime/datamodel\\\"\\n\")\n\tfmt.Fprintf(w, \"\\t\\\"github.com/ipld/go-ipld-prime/node/mixins\\\"\\n\")\n\tfmt.Fprintf(w, \"\\t\\\"github.com/ipld/go-ipld-prime/schema\\\"\\n\")\n\tfmt.Fprintf(w, \")\\n\\n\")\n}\n\n// EmitEntireType is a helper function calls all methods of TypeGenerator\n// and streams all results into a single writer.\n// (This implies two calls to EmitNode -- one for the type-level and one for the representation-level.)\nfunc EmitEntireType(tg TypeGenerator, w io.Writer) {\n\ttg.EmitNativeType(w)\n\ttg.EmitNativeAccessors(w)\n\ttg.EmitNativeBuilder(w)\n\ttg.EmitNativeMaybe(w)\n\tEmitNode(tg, w)\n\ttg.EmitTypedNodeMethodType(w)\n\ttg.EmitTypedNodeMethodRepresentation(w)\n\n\trng := tg.GetRepresentationNodeGen()\n\tif rng == nil { // FIXME: hack to save me from stubbing tons right now, remove when done\n\t\treturn\n\t}\n\tEmitNode(rng, w)\n}\n\n// EmitNode is a helper function that calls all methods of NodeGenerator\n// and streams all results into a single writer.\nfunc EmitNode(ng NodeGenerator, w io.Writer) {\n\tng.EmitNodeType(w)\n\tng.EmitNodeTypeAssertions(w)\n\tng.EmitNodeMethodKind(w)\n\tng.EmitNodeMethodLookupByString(w)\n\tng.EmitNodeMethodLookupByNode(w)\n\tng.EmitNodeMethodLookupByIndex(w)\n\tng.EmitNodeMethodLookupBySegment(w)\n\tng.EmitNodeMethodMapIterator(w)\n\tng.EmitNodeMethodListIterator(w)\n\tng.EmitNodeMethodLength(w)\n\tng.EmitNodeMethodIsAbsent(w)\n\tng.EmitNodeMethodIsNull(w)\n\tng.EmitNodeMethodAsBool(w)\n\tng.EmitNodeMethodAsInt(w)\n\tng.EmitNodeMethodAsFloat(w)\n\tng.EmitNodeMethodAsString(w)\n\tng.EmitNodeMethodAsBytes(w)\n\tng.EmitNodeMethodAsLink(w)\n\tng.EmitNodeMethodPrototype(w)\n\n\tng.EmitNodePrototypeType(w)\n\n\tnbg := ng.GetNodeBuilderGenerator()\n\tif nbg == nil { // FIXME: hack to save me from stubbing tons right now, remove when done\n\t\treturn\n\t}\n\tnbg.EmitNodeBuilderType(w)\n\tnbg.EmitNodeBuilderMethods(w)\n\tnbg.EmitNodeAssemblerType(w)\n\tnbg.EmitNodeAssemblerMethodBeginMap(w)\n\tnbg.EmitNodeAssemblerMethodBeginList(w)\n\tnbg.EmitNodeAssemblerMethodAssignNull(w)\n\tnbg.EmitNodeAssemblerMethodAssignBool(w)\n\tnbg.EmitNodeAssemblerMethodAssignInt(w)\n\tnbg.EmitNodeAssemblerMethodAssignFloat(w)\n\tnbg.EmitNodeAssemblerMethodAssignString(w)\n\tnbg.EmitNodeAssemblerMethodAssignBytes(w)\n\tnbg.EmitNodeAssemblerMethodAssignLink(w)\n\tnbg.EmitNodeAssemblerMethodAssignNode(w)\n\tnbg.EmitNodeAssemblerMethodPrototype(w)\n\tnbg.EmitNodeAssemblerOtherBits(w)\n}\n\nfunc EmitTypeTable(pkgName string, ts schema.TypeSystem, adjCfg *AdjunctCfg, w io.Writer) {\n\t// REVIEW: if \"T__Repr\" is how we want to expose this.  We could also put 'Repr' accessors on the type/prototype objects.\n\t// FUTURE: types and prototypes are proposed to be the same.  Some of this text pretends they already are, but work is needed on this.\n\tdoTemplate(`\n\t\t// Type is a struct embedding a NodePrototype/Type for every Node implementation in this package.\n\t\t// One of its major uses is to start the construction of a value.\n\t\t// You can use it like this:\n\t\t//\n\t\t// \t\t`+pkgName+`.Type.YourTypeName.NewBuilder().BeginMap() //...\n\t\t//\n\t\t// and:\n\t\t//\n\t\t// \t\t`+pkgName+`.Type.OtherTypeName.NewBuilder().AssignString(\"x\") // ...\n\t\t//\n\t\tvar Type typeSlab\n\n\t\ttype typeSlab struct {\n\t\t\t{{- range . }}\n\t\t\t{{ .Name }}       _{{ . | TypeSymbol }}__Prototype\n\t\t\t{{ .Name }}__Repr _{{ . | TypeSymbol }}__ReprPrototype\n\t\t\t{{- end}}\n\t\t}\n\t`, w, adjCfg, ts.GetTypes())\n}\n"
  },
  {
    "path": "schema/gen/go/genpartsCommon.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n)\n\n/*\n\tThis file is full of \"typical\" templates.\n\tThey may not be used by *every* type and representation,\n\tbut if they're extracted here, they're at least used by *many*.\n*/\n\n// The codegen do-not-edit warning comment.\n// Follows the pattern in https://golang.org/s/generatedcode / https://github.com/golang/go/issues/13560#issuecomment-288457920 .\n// Should appear somewhere near the top of every file (though precise order doesn't matter).\nconst doNotEditComment = `// Code generated by go-ipld-prime gengo.  DO NOT EDIT.`\n\n// emitNativeMaybe turns out to be completely agnostic to pretty much everything;\n// it doesn't vary by kind at all, and has never yet ended up needing specialization.\nfunc emitNativeMaybe(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Maybe struct {\n\t\t\tm schema.Maybe\n\t\t\tv {{if not (MaybeUsesPtr .Type) }}_{{end}}{{ .Type | TypeSymbol }}\n\t\t}\n\t\ttype Maybe{{ .Type | TypeSymbol }} = *_{{ .Type | TypeSymbol }}__Maybe\n\n\t\tfunc (m Maybe{{ .Type | TypeSymbol }}) IsNull() bool {\n\t\t\treturn m.m == schema.Maybe_Null\n\t\t}\n\t\tfunc (m Maybe{{ .Type | TypeSymbol }}) IsAbsent() bool {\n\t\t\treturn m.m == schema.Maybe_Absent\n\t\t}\n\t\tfunc (m Maybe{{ .Type | TypeSymbol }}) Exists() bool {\n\t\t\treturn m.m == schema.Maybe_Value\n\t\t}\n\t\tfunc (m Maybe{{ .Type | TypeSymbol }}) AsNode() datamodel.Node {\n\t\t\tswitch m.m {\n\t\t\t\tcase schema.Maybe_Absent:\n\t\t\t\t\treturn datamodel.Absent\n\t\t\t\tcase schema.Maybe_Null:\n\t\t\t\t\treturn datamodel.Null\n\t\t\t\tcase schema.Maybe_Value:\n\t\t\t\t\treturn {{if not (MaybeUsesPtr .Type) }}&{{end}}m.v\n\t\t\t\tdefault:\n\t\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t}\n\t\tfunc (m Maybe{{ .Type | TypeSymbol }}) Must() {{ .Type | TypeSymbol }} {\n\t\t\tif !m.Exists() {\n\t\t\t\tpanic(\"unbox of a maybe rejected\")\n\t\t\t}\n\t\t\treturn {{if not (MaybeUsesPtr .Type) }}&{{end}}m.v\n\t\t}\n\t`, w, adjCfg, data)\n}\n\nfunc emitNativeType_scalar(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// Using a struct with a single member is the same size in memory as a typedef,\n\t//  while also having the advantage of meaning we can block direct casting,\n\t//   which is desirable because the compiler then ensures our validate methods can't be evaded.\n\tdoTemplate(`\n\t\t{{- if Comments -}}\n\t\t// {{ .Type | TypeSymbol }} matches the IPLD Schema type \"{{ .Type.Name }}\".  It has {{ .Kind }} kind.\n\t\t{{- end}}\n\t\ttype {{ .Type | TypeSymbol }} = *_{{ .Type | TypeSymbol }}\n\t\ttype _{{ .Type | TypeSymbol }} struct{ x {{ .Kind | KindPrim }} }\n\t`, w, adjCfg, data)\n}\n\nfunc emitNativeAccessors_scalar(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// The node interface's `AsFoo` method is almost sufficient... but\n\t//  this method unboxes without needing to return an error that's statically impossible,\n\t//   which makes it easier to use in chaining.\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) {{ .Kind.String | title }}() {{ .Kind | KindPrim }} {\n\t\t\treturn n.x\n\t\t}\n\t`, w, adjCfg, data)\n}\n\nfunc emitNativeBuilder_scalar(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// Generate a single-step construction function -- this is easy to do for a scalar,\n\t//  and all representations of scalar kind can be expected to have a method like this.\n\t// The function is attached to the NodePrototype for convenient namespacing;\n\t//  it needs no new memory, so it would be inappropriate to attach to the builder or assembler.\n\t// FUTURE: should engage validation flow.\n\tdoTemplate(`\n\t\tfunc (_{{ .Type | TypeSymbol }}__Prototype) From{{ .Kind.String | title }}(v {{ .Kind | KindPrim }}) ({{ .Type | TypeSymbol }}, error) {\n\t\t\tn := _{{ .Type | TypeSymbol }}{v}\n\t\t\treturn &n, nil\n\t\t}\n\t`, w, adjCfg, data)\n}\n\nfunc emitNodeTypeAssertions_typical(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\tdoTemplate(`\n\t\tvar _ datamodel.Node = ({{ .Type | TypeSymbol }})(&_{{ .Type | TypeSymbol }}{})\n\t\tvar _ schema.TypedNode = ({{ .Type | TypeSymbol }})(&_{{ .Type | TypeSymbol }}{})\n\t`, w, adjCfg, data)\n}\n\nfunc emitNodeMethodAsKind_scalar(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) As{{ .Kind.String | title }}() ({{ .Kind | KindPrim }}, error) {\n\t\t\treturn n.x, nil\n\t\t}\n\t`, w, adjCfg, data)\n}\n\nfunc emitNodeMethodPrototype_typical(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\tdoTemplate(`\n\t\tfunc ({{ if .IsRepr }}_{{end}}{{ .Type | TypeSymbol }}{{ if .IsRepr }}__Repr{{end}}) Prototype() datamodel.NodePrototype {\n\t\t\treturn _{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Prototype{}\n\t\t}\n\t`, w, adjCfg, data)\n}\n\n// nodePrototype doesn't really vary textually at all between types and kinds\n// because it's just builders and standard resets.\nfunc emitNodePrototypeType_typical(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Prototype struct{}\n\n\t\tfunc (_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Prototype) NewBuilder() datamodel.NodeBuilder {\n\t\t\tvar nb _{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Builder\n\t\t\tnb.Reset()\n\t\t\treturn &nb\n\t\t}\n\t`, w, adjCfg, data)\n}\n\n// emitTypicalTypedNodeMethodRepresentation does... what it says on the tin.\n//\n// For most types, the way to get the representation node pointer doesn't\n// textually depend on either the node implementation details nor what the representation strategy is,\n// or really much at all for that matter.\n// It only depends on that they have the same structure, so this cast works.\n//\n// Most (all?) types can use this.  However, it's here rather in the mixins, for two reasons:\n// one, it still seems possible to imagine we'll have a type someday for which this pattern won't hold;\n// and two, mixins are also used in the repr generators, and it wouldn't be all sane for this method to end up also on reprs.\nfunc emitTypicalTypedNodeMethodRepresentation(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\tdoTemplate(`\n\t\tfunc (n {{ .Type | TypeSymbol }}) Representation() datamodel.Node {\n\t\t\treturn (*_{{ .Type | TypeSymbol }}__Repr)(n)\n\t\t}\n\t`, w, adjCfg, data)\n}\n\n// Turns out basically all builders are just an embed of the corresponding assembler.\nfunc emitEmitNodeBuilderType_typical(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Builder struct {\n\t\t\t_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler\n\t\t}\n\t`, w, adjCfg, data)\n}\n\n// Builder build and reset methods are common even when some parts of the assembler vary.\n// We count on the zero value of any addntl non-common fields of the assembler being correct.\nfunc emitNodeBuilderMethods_typical(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\tdoTemplate(`\n\t\tfunc (nb *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Builder) Build() datamodel.Node {\n\t\t\tif *nb.m != schema.Maybe_Value {\n\t\t\t\tpanic(\"invalid state: cannot call Build on an assembler that's not finished\")\n\t\t\t}\n\t\t\treturn nb.w\n\t\t}\n\t\tfunc (nb *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Builder) Reset() {\n\t\t\tvar w _{{ .Type | TypeSymbol }}\n\t\t\tvar m schema.Maybe\n\t\t\t*nb = _{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Builder{_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler{w: &w, m: &m}}\n\t\t}\n\t`, w, adjCfg, data)\n}\n\n// emitNodeAssemblerType_scalar emits a NodeAssembler that's typical for a scalar.\n// Types that are recursive tend to have more state and custom stuff, so won't use this\n// (although the 'm' and 'w' variable names may still be presumed universally).\nfunc emitNodeAssemblerType_scalar(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\tdoTemplate(`\n\t\ttype _{{ .Type | TypeSymbol }}__Assembler struct {\n\t\t\tw *_{{ .Type | TypeSymbol }}\n\t\t\tm *schema.Maybe\n\t\t}\n\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__Assembler) reset() {}\n\t`, w, adjCfg, data)\n}\n\nfunc emitNodeAssemblerMethodAssignNull_scalar(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) AssignNull() error {\n\t\t\tswitch *na.m {\n\t\t\tcase allowNull:\n\t\t\t\t*na.m = schema.Maybe_Null\n\t\t\t\treturn nil\n\t\t\tcase schema.Maybe_Absent:\n\t\t\t\treturn mixins.{{ .Kind.String | title }}Assembler{TypeName: \"{{ .PkgName }}.{{ .TypeName }}{{ if .IsRepr }}.Repr{{end}}\"}.AssignNull()\n\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\t}\n\t\t\tpanic(\"unreachable\")\n\t\t}\n\t`, w, adjCfg, data)\n}\n\n// almost the same as the variant for scalars, but also has to check for midvalue state.\nfunc emitNodeAssemblerMethodAssignNull_recursive(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) AssignNull() error {\n\t\t\tswitch *na.m {\n\t\t\tcase allowNull:\n\t\t\t\t*na.m = schema.Maybe_Null\n\t\t\t\treturn nil\n\t\t\tcase schema.Maybe_Absent:\n\t\t\t\treturn mixins.{{ .Kind.String | title }}Assembler{TypeName: \"{{ .PkgName }}.{{ .TypeName }}{{ if .IsRepr }}.Repr{{end}}\"}.AssignNull()\n\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\tcase midvalue:\n\t\t\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t\t\t}\n\t\t\tpanic(\"unreachable\")\n\t\t}\n\t`, w, adjCfg, data)\n}\n\n// works for the AssignFoo methods for scalar kinds that are just boxing a thing.\n// There's no equivalent of this at all for recursives -- they're too diverse.\nfunc emitNodeAssemblerMethodAssignKind_scalar(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// This method contains a branch to support MaybeUsesPtr because new memory may need to be allocated.\n\t//  This allocation only happens if the 'w' ptr is nil, which means we're being used on a Maybe;\n\t//  otherwise, the 'w' ptr should already be set, and we fill that memory location without allocating, as usual.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__Assembler) Assign{{ .Kind.String | title }}(v {{ .Kind | KindPrim }}) error {\n\t\t\tswitch *na.m {\n\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\t}\n\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\tif na.w == nil {\n\t\t\t\tna.w = &_{{ .Type | TypeSymbol }}{}\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\tna.w.x = v\n\t\t\t*na.m = schema.Maybe_Value\n\t\t\treturn nil\n\t\t}\n\t`, w, adjCfg, data)\n}\n\n// leans heavily on the fact all the AsFoo and AssignFoo methods follow a very consistent textual pattern.\n// FUTURE: may be able to get this to work for recursives, too -- but maps and lists each have very unique bottom thirds of this function.\nfunc emitNodeAssemblerMethodAssignNode_scalar(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// AssignNode goes through three phases:\n\t// 1. is it null?  Jump over to AssignNull (which may or may not reject it).\n\t// 2. is it our own type?  Handle specially -- we might be able to do efficient things.\n\t// 3. is it the right kind to morph into us?  Do so.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__Assembler) AssignNode(v datamodel.Node) error {\n\t\t\tif v.IsNull() {\n\t\t\t\treturn na.AssignNull()\n\t\t\t}\n\t\t\tif v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok {\n\t\t\t\tswitch *na.m {\n\t\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\t\t}\n\t\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\t\tif na.w == nil {\n\t\t\t\t\tna.w = v2\n\t\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t*na.w = *v2\n\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif v2, err := v.As{{ .Kind.String | title }}(); err != nil {\n\t\t\t\treturn err\n\t\t\t} else {\n\t\t\t\treturn na.Assign{{ .Kind.String | title }}(v2)\n\t\t\t}\n\t\t}\n\t`, w, adjCfg, data)\n}\n"
  },
  {
    "path": "schema/gen/go/genpartsList.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n)\n\n// FIXME docs: these methods all say \"-oid\" but I think that was overoptimistic and not actually that applicable, really.\n//  AssignNode?  Okay, that one's fine.\n//  The rest?  They're all *very* emphatic about knowing either:\n//   - that na.w.x is a slice; or,\n//   - that there's only one 'va' (one type; and that it's reused).\n//   The reuse level for those two traits is pretty minimal.\n\nfunc emitNodeAssemblerMethodBeginList_listoid(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// This method contains a branch to support MaybeUsesPtr because new memory may need to be allocated.\n\t//  This allocation only happens if the 'w' ptr is nil, which means we're being used on a Maybe;\n\t//  otherwise, the 'w' ptr should already be set, and we fill that memory location without allocating, as usual.\n\t//\n\t// There's surprisingly little variation for IsRepr on this one:\n\t//   - the child types we *store* are the same either way, so that doesn't vary;\n\t//   - the only thing that we return that's different is... ourself.\n\t//\n\t// DRY: even further, to an extracted function in the final output?  Maybe.\n\t//  This could be plausible, iff... the top half of the struct (na.m, na.w) was independently addressable.  (na.va has a varying concrete type and blocks extractions.)\n\t//  Would also want to examine if that makes desirable trades in gsloc/asmsize/speed/debuggability.\n\t//  Only seems to apply to case of list-repr-list, so unclear if worth the effort.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\t\t\tswitch *na.m {\n\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\tcase midvalue:\n\t\t\t\tpanic(\"invalid state: it makes no sense to 'begin' twice on the same assembler!\")\n\t\t\t}\n\t\t\t*na.m = midvalue\n\t\t\tif sizeHint < 0 {\n\t\t\t\tsizeHint = 0\n\t\t\t}\n\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\tif na.w == nil {\n\t\t\t\tna.w = &_{{ .Type | TypeSymbol }}{}\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\tif sizeHint > 0 {\n\t\t\t\tna.w.x = make([]_{{ .Type.ValueType | TypeSymbol }}{{if .Type.ValueIsNullable }}__Maybe{{end}}, 0, sizeHint)\n\t\t\t}\n\t\t\treturn na, nil\n\t\t}\n\t`, w, adjCfg, data)\n}\n\nfunc emitNodeAssemblerMethodAssignNode_listoid(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// AssignNode goes through three phases:\n\t// 1. is it null?  Jump over to AssignNull (which may or may not reject it).\n\t// 2. is it our own type?  Handle specially -- we might be able to do efficient things.\n\t// 3. is it the right kind to morph into us?  Do so.\n\t//\n\t// We do not set m=midvalue in phase 3 -- it shouldn't matter unless you're trying to pull off concurrent access, which is wrong and unsafe regardless.\n\t//\n\t// This works easily for both type-level and representational nodes because\n\t//  any divergences that have to do with the child value are nicely hidden behind `AssembleValue`.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) AssignNode(v datamodel.Node) error {\n\t\t\tif v.IsNull() {\n\t\t\t\treturn na.AssignNull()\n\t\t\t}\n\t\t\tif v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok {\n\t\t\t\tswitch *na.m {\n\t\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\t\tcase midvalue:\n\t\t\t\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t\t\t\t}\n\t\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\t\tif na.w == nil {\n\t\t\t\t\tna.w = v2\n\t\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t*na.w = *v2\n\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif v.Kind() != datamodel.Kind_List {\n\t\t\t\treturn datamodel.ErrWrongKind{TypeName: \"{{ .PkgName }}.{{ .Type.Name }}{{ if .IsRepr }}.Repr{{end}}\", MethodName: \"AssignNode\", AppropriateKind: datamodel.KindSet_JustList, ActualKind: v.Kind()}\n\t\t\t}\n\t\t\titr := v.ListIterator()\n\t\t\tfor !itr.Done() {\n\t\t\t\t_, v, err := itr.Next()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn na.Finish()\n\t\t}\n\t`, w, adjCfg, data)\n}\n\nfunc emitNodeAssemblerHelper_listoid_tidyHelper(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// This function attempts to clean up the state machine to acknolwedge child value assembly finish.\n\t//  If the child was finished and we just collected it, return true and update state to laState_initial.\n\t//  Otherwise, if it wasn't done, return false;\n\t//   and the caller is almost certain to emit an error momentarily.\n\t// The function will only be called when the current state is laState_midValue.\n\t//  (In general, the idea is that if the user is doing things correctly,\n\t//   this function will only be called when the child is in fact finished.)\n\t// If 'cm' is used, we reset it to its initial condition of Maybe_Absent here.\n\t//  At the same time, we nil the 'w' pointer for the child assembler; otherwise its own state machine would probably let it modify 'w' again!\n\t//\n\t// DRY(nope): Can this be extracted to be a shared function between repr and type level nodes?\n\t//  It is textually identical, so... yeah, that'd be nice.  But...\n\t//  Nope.  It touches `la.va` directly.\n\t//   Attempting to extract that or hide it behind an interface would create virtual function calls in a very tight spot, and we don't want the execution time cost.\n\tdoTemplate(`\n\t\tfunc (la *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) valueFinishTidy() bool {\n\t\t\t{{- if .Type.ValueIsNullable }}\n\t\t\trow := &la.w.x[len(la.w.x)-1]\n\t\t\tswitch row.m {\n\t\t\tcase schema.Maybe_Value:\n\t\t\t\t{{- if (MaybeUsesPtr .Type.ValueType) }}\n\t\t\t\trow.v = la.va.w\n\t\t\t\t{{- end}}\n\t\t\t\tla.va.w = nil\n\t\t\t\tfallthrough\n\t\t\tcase schema.Maybe_Null:\n\t\t\t\tla.state = laState_initial\n\t\t\t\tla.va.reset()\n\t\t\t\treturn true\n\t\t\t{{- else}}\n\t\t\tswitch la.cm {\n\t\t\tcase schema.Maybe_Value:\n\t\t\t\tla.va.w = nil\n\t\t\t\tla.cm = schema.Maybe_Absent\n\t\t\t\tla.state = laState_initial\n\t\t\t\tla.va.reset()\n\t\t\t\treturn true\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t`, w, adjCfg, data)\n}\n\nfunc emitNodeAssemblerHelper_listoid_listAssemblerMethods(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// DRY: Might want to split this up a bit further so it can be used by more kinds.\n\t//  Some parts of this could be reused by struct-repr-tuple, potentially, but would require being able to insert some more checks relating to length.\n\t//   This would also require excluding *all* 'va' references; those are radicaly different for structs, in that there's not even one (singular) of them.\n\t//\n\t// DRY(nope): Can this be extracted to a shared function in the output?\n\t//  Same story as the tidy helper -- it touches `la.va` concretely in several places, and that blocks extraction.\n\tdoTemplate(`\n\t\tfunc (la *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) AssembleValue() datamodel.NodeAssembler {\n\t\t\tswitch la.state {\n\t\t\tcase laState_initial:\n\t\t\t\t// carry on\n\t\t\tcase laState_midValue:\n\t\t\t\tif !la.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when still in the middle of assembling the previous value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase laState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tla.w.x = append(la.w.x, _{{ .Type.ValueType | TypeSymbol }}{{if .Type.ValueIsNullable }}__Maybe{{end}}{})\n\t\t\tla.state = laState_midValue\n\t\t\trow := &la.w.x[len(la.w.x)-1]\n\t\t\t{{- if .Type.ValueIsNullable }}\n\t\t\t{{- if not (MaybeUsesPtr .Type.ValueType) }}\n\t\t\tla.va.w = &row.v\n\t\t\t{{- end}}\n\t\t\tla.va.m = &row.m\n\t\t\trow.m = allowNull\n\t\t\t{{- else}}\n\t\t\tla.va.w = row\n\t\t\tla.va.m = &la.cm\n\t\t\t{{- end}}\n\t\t\treturn &la.va\n\t\t}\n\t`, w, adjCfg, data)\n\tdoTemplate(`\n\t\tfunc (la *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) Finish() error {\n\t\t\tswitch la.state {\n\t\t\tcase laState_initial:\n\t\t\t\t// carry on\n\t\t\tcase laState_midValue:\n\t\t\t\tif !la.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase laState_finished:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tla.state = laState_finished\n\t\t\t*la.m = schema.Maybe_Value\n\t\t\treturn nil\n\t\t}\n\t`, w, adjCfg, data)\n\tdoTemplate(`\n\t\tfunc (la *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) ValuePrototype(_ int64) datamodel.NodePrototype {\n\t\t\treturn _{{ .Type.ValueType | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Prototype{}\n\t\t}\n\t`, w, adjCfg, data)\n}\n"
  },
  {
    "path": "schema/gen/go/genpartsMap.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n)\n\n// FIXME docs: these methods all say \"-oid\" but I think that was overoptimistic and not actually that applicable, really.\n//  AssignNode?  Okay, that one's fine.\n//  The rest?  They're all *very* emphatic about knowing either:\n//   - that na.w.t and na.w.m are fields; or,\n//   - that there's only one 'ka' and 'va' (one type each; and that it's reused).\n//   The reuse level for those two traits is pretty minimal.\n\nfunc emitNodeAssemblerMethodBeginMap_mapoid(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// This method contains a branch to support MaybeUsesPtr because new memory may need to be allocated.\n\t//  This allocation only happens if the 'w' ptr is nil, which means we're being used on a Maybe;\n\t//  otherwise, the 'w' ptr should already be set, and we fill that memory location without allocating, as usual.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\t\t\tswitch *na.m {\n\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\tcase midvalue:\n\t\t\t\tpanic(\"invalid state: it makes no sense to 'begin' twice on the same assembler!\")\n\t\t\t}\n\t\t\t*na.m = midvalue\n\t\t\tif sizeHint < 0 {\n\t\t\t\tsizeHint = 0\n\t\t\t}\n\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\tif na.w == nil {\n\t\t\t\tna.w = &_{{ .Type | TypeSymbol }}{}\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\tna.w.m = make(map[_{{ .Type.KeyType | TypeSymbol }}]{{if .Type.ValueIsNullable }}Maybe{{else}}*_{{end}}{{ .Type.ValueType | TypeSymbol }}, sizeHint)\n\t\t\tna.w.t = make([]_{{ .Type | TypeSymbol }}__entry, 0, sizeHint)\n\t\t\treturn na, nil\n\t\t}\n\t`, w, adjCfg, data)\n}\n\nfunc emitNodeAssemblerMethodAssignNode_mapoid(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// AssignNode goes through three phases:\n\t// 1. is it null?  Jump over to AssignNull (which may or may not reject it).\n\t// 2. is it our own type?  Handle specially -- we might be able to do efficient things.\n\t// 3. is it the right kind to morph into us?  Do so.\n\t//\n\t// We do not set m=midvalue in phase 3 -- it shouldn't matter unless you're trying to pull off concurrent access, which is wrong and unsafe regardless.\n\t//\n\t// This works easily for both type-level and representational nodes because\n\t//  any divergences that have to do with the child value are nicely hidden behind  `AssembleKey` and `AssembleValue`.\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) AssignNode(v datamodel.Node) error {\n\t\t\tif v.IsNull() {\n\t\t\t\treturn na.AssignNull()\n\t\t\t}\n\t\t\tif v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok {\n\t\t\t\tswitch *na.m {\n\t\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\t\tcase midvalue:\n\t\t\t\t\tpanic(\"invalid state: cannot assign null into an assembler that's already begun working on recursive structures!\")\n\t\t\t\t}\n\t\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\t\tif na.w == nil {\n\t\t\t\t\tna.w = v2\n\t\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t{{- end}}\n\t\t\t\t*na.w = *v2\n\t\t\t\t*na.m = schema.Maybe_Value\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif v.Kind() != datamodel.Kind_Map {\n\t\t\t\treturn datamodel.ErrWrongKind{TypeName: \"{{ .PkgName }}.{{ .Type.Name }}{{ if .IsRepr }}.Repr{{end}}\", MethodName: \"AssignNode\", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: v.Kind()}\n\t\t\t}\n\t\t\titr := v.MapIterator()\n\t\t\tfor !itr.Done() {\n\t\t\t\tk, v, err := itr.Next()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := na.AssembleKey().AssignNode(k); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := na.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn na.Finish()\n\t\t}\n\t`, w, adjCfg, data)\n}\n\nfunc emitNodeAssemblerHelper_mapoid_keyTidyHelper(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// This function attempts to clean up the state machine to acknolwedge key assembly finish.\n\t//  If the child was finished and we just collected it, return true and update state to maState_expectValue.\n\t//   Collecting the child includes updating the 'ma.w.m' to point into the relevant row of 'ma.w.t', since that couldn't be done earlier,\n\t//    AND initializing the 'ma.va' (since we're already holding relevant offsets into 'ma.w.t').\n\t//  Otherwise, if it wasn't done, return false;\n\t//   and the caller is almost certain to emit an error momentarily.\n\t// The function will only be called when the current state is maState_midKey.\n\t//  (In general, the idea is that if the user is doing things correctly,\n\t//   this function will only be called when the child is in fact finished.)\n\t// Completion info always comes via 'cm', and we reset it to its initial condition of Maybe_Absent here.\n\t//  At the same time, we nil the 'w' pointer for the child assembler; otherwise its own state machine would probably let it modify 'w' again!\n\t//\n\t// DRY(nope): Can this be extracted to be a shared function between repr and type level nodes?\n\t//  It is textually identical, so... yeah, that'd be nice.  But...\n\t//  Nope.  It touches `ma.ka` and `ma.va` directly.\n\t//   Attempting to extract or hide those behind an interface would create virtual function calls in a very tight spot, and we don't want the execution time cost.\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) keyFinishTidy() bool {\n\t\t\tswitch ma.cm {\n\t\t\tcase schema.Maybe_Value:\n\t\t\t\tma.ka.w = nil\n\t\t\t\ttz := &ma.w.t[len(ma.w.t)-1]\n\t\t\t\tma.cm = schema.Maybe_Absent\n\t\t\t\tma.state = maState_expectValue\n\t\t\t\tma.w.m[tz.k] = &tz.v\n\t\t\t\t{{- if .Type.ValueIsNullable }}\n\t\t\t\t{{- if not (MaybeUsesPtr .Type.ValueType) }}\n\t\t\t\tma.va.w = &tz.v.v\n\t\t\t\t{{- end}}\n\t\t\t\tma.va.m = &tz.v.m\n\t\t\t\ttz.v.m = allowNull\n\t\t\t\t{{- else}}\n\t\t\t\tma.va.w = &tz.v\n\t\t\t\tma.va.m = &ma.cm\n\t\t\t\t{{- end}}\n\t\t\t\tma.ka.reset()\n\t\t\t\treturn true\n\t\t\tdefault:\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t`, w, adjCfg, data)\n}\n\nfunc emitNodeAssemblerHelper_mapoid_valueTidyHelper(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// This function attempts to clean up the state machine to acknolwedge child value assembly finish.\n\t//  If the child was finished and we just collected it, return true and update state to maState_initial.\n\t//  Otherwise, if it wasn't done, return false;\n\t//   and the caller is almost certain to emit an error momentarily.\n\t// The function will only be called when the current state is maState_midValue.\n\t//  (In general, the idea is that if the user is doing things correctly,\n\t//   this function will only be called when the child is in fact finished.)\n\t// If 'cm' is used, we reset it to its initial condition of Maybe_Absent here.\n\t//  At the same time, we nil the 'w' pointer for the child assembler; otherwise its own state machine would probably let it modify 'w' again!\n\t//\n\t// DRY(nope): Can this be extracted to be a shared function between repr and type level nodes?\n\t//  Exact same story as the key tidy helper -- touches child assemblers concretely, and that blocks extraction.\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) valueFinishTidy() bool {\n\t\t\t{{- if .Type.ValueIsNullable }}\n\t\t\ttz := &ma.w.t[len(ma.w.t)-1]\n\t\t\tswitch tz.v.m {\n\t\t\tcase schema.Maybe_Null:\n\t\t\t\tma.state = maState_initial\n\t\t\t\tma.va.reset()\n\t\t\t\treturn true\n\t\t\tcase schema.Maybe_Value:\n\t\t\t\t{{- if (MaybeUsesPtr .Type.ValueType) }}\n\t\t\t\ttz.v.v = ma.va.w\n\t\t\t\t{{- end}}\n\t\t\t\tma.va.w = nil\n\t\t\t\tma.state = maState_initial\n\t\t\t\tma.va.reset()\n\t\t\t\treturn true\n\t\t\t{{- else}}\n\t\t\tswitch ma.cm {\n\t\t\tcase schema.Maybe_Value:\n\t\t\t\tma.va.w = nil\n\t\t\t\tma.cm = schema.Maybe_Absent\n\t\t\t\tma.state = maState_initial\n\t\t\t\tma.va.reset()\n\t\t\t\treturn true\n\t\t\t{{- end}}\n\t\t\tdefault:\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t`, w, adjCfg, data)\n}\n\nfunc emitNodeAssemblerHelper_mapoid_mapAssemblerMethods(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// FUTURE: some of the setup of the child assemblers could probably be DRY'd up.\n\t//\n\t// REVIEW: there's a copy-by-value of k2 that's avoidable.  But it simplifies the error path.  Worth working on?\n\t//\n\t// REVIEW: processing the key via the reprPrototype of the key even when we're at the type level if it's type kind isn't string is currently supported, but should it be?  or is that more confusing than valuable?\n\t//  Very possible that it shouldn't be supported: the full-on keyAssembler route won't accept this, so consistency with that might be best.\n\t//  On the other hand, lookups by string *do* support this kind of processing (and it must, or PathSegment utility becomes unacceptably damaged), so either way, something feels surprising.\n\t//\n\t// DRY(nope): Can this be extracted to a shared function in the output?\n\t//  Same story as the tidy helpers -- it touches `va` and `ka` concretely in several places, and that blocks extraction.\n\t//\n\t// DRY: a lot of the state transition fences again are common for all mapoids, and could probably even be a function over '*state'...\n\t//   except for the fact they need to call the valueFinishTidy function, which is another one of those points that blocks extraction because we strongly don't want virtual functions calls there.\n\t//   Maybe the templates can be textually dedup'd more, though, at least.\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling another key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleEntry cannot be called on an assembler that's already finished\")\n\t\t\t}\n\n\t\t\tvar k2 _{{ .Type.KeyType | TypeSymbol }}\n\t\t\t{{- if or (not (eq .Type.KeyType.TypeKind.String \"String\")) .IsRepr }}\n\t\t\tif err := (_{{ .Type.KeyType | TypeSymbol }}__ReprPrototype{}).fromString(&k2, k); err != nil {\n\t\t\t\treturn nil, err // TODO wrap in some kind of ErrInvalidKey\n\t\t\t}\n\t\t\t{{- else}}\n\t\t\tif err := (_{{ .Type.KeyType | TypeSymbol }}__Prototype{}).fromString(&k2, k); err != nil {\n\t\t\t\treturn nil, err // TODO wrap in some kind of ErrInvalidKey\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\tif _, exists := ma.w.m[k2]; exists {\n\t\t\t\treturn nil, datamodel.ErrRepeatedMapKey{Key: &k2}\n\t\t\t}\n\t\t\tma.w.t = append(ma.w.t, _{{ .Type | TypeSymbol }}__entry{k: k2})\n\t\t\ttz := &ma.w.t[len(ma.w.t)-1]\n\t\t\tma.state = maState_midValue\n\n\t\t\tma.w.m[k2] = &tz.v\n\t\t\t{{- if .Type.ValueIsNullable }}\n\t\t\t{{- if not (MaybeUsesPtr .Type.ValueType) }}\n\t\t\tma.va.w = &tz.v.v\n\t\t\t{{- end}}\n\t\t\tma.va.m = &tz.v.m\n\t\t\ttz.v.m = allowNull\n\t\t\t{{- else}}\n\t\t\tma.va.w = &tz.v\n\t\t\tma.va.m = &ma.cm\n\t\t\t{{- end}}\n\t\t\treturn &ma.va, nil\n\t\t}\n\t`, w, adjCfg, data)\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) AssembleKey() datamodel.NodeAssembler {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling another key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleKey cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tma.w.t = append(ma.w.t, _{{ .Type | TypeSymbol }}__entry{})\n\t\t\tma.state = maState_midKey\n\t\t\tma.ka.m = &ma.cm\n\t\t\tma.ka.w = &ma.w.t[len(ma.w.t)-1].k\n\t\t\treturn &ma.ka\n\t\t}\n\t`, w, adjCfg, data)\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) AssembleValue() datamodel.NodeAssembler {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when no key is primed\")\n\t\t\tcase maState_midKey:\n\t\t\t\tif !ma.keyFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling a key\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase maState_expectValue:\n\t\t\t\t// carry on\n\t\t\tcase maState_midValue:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called when in the middle of assembling another value\")\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: AssembleValue cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tma.state = maState_midValue\n\t\t\treturn &ma.va\n\t\t}\n\t`, w, adjCfg, data)\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) Finish() error {\n\t\t\tswitch ma.state {\n\t\t\tcase maState_initial:\n\t\t\t\t// carry on\n\t\t\tcase maState_midKey:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a key\")\n\t\t\tcase maState_expectValue:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called when expecting start of value assembly\")\n\t\t\tcase maState_midValue:\n\t\t\t\tif !ma.valueFinishTidy() {\n\t\t\t\t\tpanic(\"invalid state: Finish cannot be called when in the middle of assembling a value\")\n\t\t\t\t} // if tidy success: carry on\n\t\t\tcase maState_finished:\n\t\t\t\tpanic(\"invalid state: Finish cannot be called on an assembler that's already finished\")\n\t\t\t}\n\t\t\tma.state = maState_finished\n\t\t\t*ma.m = schema.Maybe_Value\n\t\t\treturn nil\n\t\t}\n\t`, w, adjCfg, data)\n\tdoTemplate(`\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) KeyPrototype() datamodel.NodePrototype {\n\t\t\treturn _{{ .Type.KeyType | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Prototype{}\n\t\t}\n\t\tfunc (ma *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) ValuePrototype(_ string) datamodel.NodePrototype {\n\t\t\treturn _{{ .Type.ValueType | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Prototype{}\n\t\t}\n\t`, w, adjCfg, data)\n}\n"
  },
  {
    "path": "schema/gen/go/genpartsMinima.go",
    "content": "package gengo\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/testutil\"\n)\n\n// EmitInternalEnums creates a file with enum types used internally.\n// For example, the state machine values used in map and list builders.\n// These always need to exist exactly once in each package created by codegen.\n//\n// The file header and import statements are included in the output of this function.\n// (The imports in this file are different than most others in codegen output;\n// we gather up any references to other packages in this file in order to simplify the rest of codegen's awareness of imports.)\nfunc EmitInternalEnums(packageName string, w io.Writer) {\n\tfmt.Fprint(w, testutil.Dedent(`\n\t\tpackage `+packageName+`\n\n\t\t`+doNotEditComment+`\n\n\t\timport (\n\t\t\t\"fmt\"\n\n\t\t\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\t\t\"github.com/ipld/go-ipld-prime/schema\"\n\t\t)\n\n\t`))\n\n\t// The 'Maybe' enum does double-duty in this package as a state machine for assembler completion.\n\t//\n\t// The 'Maybe_Absent' value gains the additional semantic of \"clear to assign (but not null)\"\n\t//  (which works because if you're *in* a value assembler, \"absent\" as a final result is already off the table).\n\t// Additionally, we get a few extra states that we cram into the same area of bits:\n\t//   - `midvalue` is used by assemblers of recursives to block AssignNull after BeginX.\n\t//   - `allowNull` is used by parent assemblers when initializing a child assembler to tell the child a transition to Maybe_Null is allowed in this context.\n\tfmt.Fprint(w, testutil.Dedent(`\n\t\tconst (\n\t\t\tmidvalue = schema.Maybe(4)\n\t\t\tallowNull = schema.Maybe(5)\n\t\t)\n\n\t`))\n\n\tfmt.Fprint(w, testutil.Dedent(`\n\t\ttype maState uint8\n\n\t\tconst (\n\t\t\tmaState_initial     maState = iota\n\t\t\tmaState_midKey\n\t\t\tmaState_expectValue\n\t\t\tmaState_midValue\n\t\t\tmaState_finished\n\t\t)\n\n\t\ttype laState uint8\n\n\t\tconst (\n\t\t\tlaState_initial  laState = iota\n\t\t\tlaState_midValue\n\t\t\tlaState_finished\n\t\t)\n\t`))\n\n\t// We occasionally need this erroring thunk to be able to snake an error out from some assembly processes.\n\t// It implements all of datamodel.NodeAssembler, but all of its methods return errors when used.\n\tfmt.Fprint(w, testutil.Dedent(`\n\t\ttype _ErrorThunkAssembler struct {\n\t\t\te error\n\t\t}\n\n\t\tfunc (ea _ErrorThunkAssembler) BeginMap(_ int64) (datamodel.MapAssembler, error) { return nil, ea.e }\n\t\tfunc (ea _ErrorThunkAssembler) BeginList(_ int64) (datamodel.ListAssembler, error) { return nil, ea.e }\n\t\tfunc (ea _ErrorThunkAssembler) AssignNull() error { return ea.e }\n\t\tfunc (ea _ErrorThunkAssembler) AssignBool(bool) error { return ea.e }\n\t\tfunc (ea _ErrorThunkAssembler) AssignInt(int64) error { return ea.e }\n\t\tfunc (ea _ErrorThunkAssembler) AssignFloat(float64) error { return ea.e }\n\t\tfunc (ea _ErrorThunkAssembler) AssignString(string) error { return ea.e }\n\t\tfunc (ea _ErrorThunkAssembler) AssignBytes([]byte) error { return ea.e }\n\t\tfunc (ea _ErrorThunkAssembler) AssignLink(datamodel.Link) error { return ea.e }\n\t\tfunc (ea _ErrorThunkAssembler) AssignNode(datamodel.Node) error { return ea.e }\n\t\tfunc (ea _ErrorThunkAssembler) Prototype() datamodel.NodePrototype {\n\t\t\tpanic(fmt.Errorf(\"cannot get prototype from error-carrying assembler: already derailed with error: %w\", ea.e))\n\t\t}\n\t`))\n}\n"
  },
  {
    "path": "schema/gen/go/genpartsStrictoid.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n)\n\n// What's \"strictoid\" mean?  Anything that's recursive but not infinite -- so structs, unions.\n\n// This form of BeginMap method is reusable for anything that has fixed size and thus ignores sizehint.\n// That means: structs, unions, and their relevant representations.\nfunc emitNodeAssemblerMethodBeginMap_strictoid(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\t// We currently disregard sizeHint.  It's not relevant to us.\n\t//  We could check it strictly and emit errors; presently, we don't.\n\t// This method contains a branch to support MaybeUsesPtr because new memory may need to be allocated.\n\t//  This allocation only happens if the 'w' ptr is nil, which means we're being used on a Maybe;\n\t//  otherwise, the 'w' ptr should already be set, and we fill that memory location without allocating, as usual.\n\t//  (Note that the Maybe we're talking about here is for us, not our children: so it applies on unions too.)\n\tdoTemplate(`\n\t\tfunc (na *_{{ .Type | TypeSymbol }}__{{ if .IsRepr }}Repr{{end}}Assembler) BeginMap(int64) (datamodel.MapAssembler, error) {\n\t\t\tswitch *na.m {\n\t\t\tcase schema.Maybe_Value, schema.Maybe_Null:\n\t\t\t\tpanic(\"invalid state: cannot assign into assembler that's already finished\")\n\t\t\tcase midvalue:\n\t\t\t\tpanic(\"invalid state: it makes no sense to 'begin' twice on the same assembler!\")\n\t\t\t}\n\t\t\t*na.m = midvalue\n\t\t\t{{- if .Type | MaybeUsesPtr }}\n\t\t\tif na.w == nil {\n\t\t\t\tna.w = &_{{ .Type | TypeSymbol }}{}\n\t\t\t}\n\t\t\t{{- end}}\n\t\t\treturn na, nil\n\t\t}\n\t`, w, adjCfg, data)\n}\n"
  },
  {
    "path": "schema/gen/go/mixins/boolGenMixin.go",
    "content": "package mixins\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\ntype BoolTraits struct {\n\tPkgName    string\n\tTypeName   string // see doc in kindTraitsGenerator\n\tTypeSymbol string // see doc in kindTraitsGenerator\n}\n\nfunc (BoolTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Bool\n}\nfunc (g BoolTraits) EmitNodeMethodKind(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) Kind() datamodel.Kind {\n\t\t\treturn datamodel.Kind_Bool\n\t\t}\n\t`, w, g)\n}\nfunc (g BoolTraits) EmitNodeMethodLookupByString(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bool}.emitNodeMethodLookupByString(w)\n}\nfunc (g BoolTraits) EmitNodeMethodLookupByNode(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bool}.emitNodeMethodLookupByNode(w)\n}\nfunc (g BoolTraits) EmitNodeMethodLookupByIndex(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bool}.emitNodeMethodLookupByIndex(w)\n}\nfunc (g BoolTraits) EmitNodeMethodLookupBySegment(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bool}.emitNodeMethodLookupBySegment(w)\n}\nfunc (g BoolTraits) EmitNodeMethodMapIterator(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bool}.emitNodeMethodMapIterator(w)\n}\nfunc (g BoolTraits) EmitNodeMethodListIterator(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bool}.emitNodeMethodListIterator(w)\n}\nfunc (g BoolTraits) EmitNodeMethodLength(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bool}.emitNodeMethodLength(w)\n}\nfunc (g BoolTraits) EmitNodeMethodIsAbsent(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bool}.emitNodeMethodIsAbsent(w)\n}\nfunc (g BoolTraits) EmitNodeMethodIsNull(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bool}.emitNodeMethodIsNull(w)\n}\nfunc (g BoolTraits) EmitNodeMethodAsInt(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bool}.emitNodeMethodAsInt(w)\n}\nfunc (g BoolTraits) EmitNodeMethodAsFloat(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bool}.emitNodeMethodAsFloat(w)\n}\nfunc (g BoolTraits) EmitNodeMethodAsString(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bool}.emitNodeMethodAsString(w)\n}\nfunc (g BoolTraits) EmitNodeMethodAsBytes(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bool}.emitNodeMethodAsBytes(w)\n}\nfunc (g BoolTraits) EmitNodeMethodAsLink(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bool}.emitNodeMethodAsLink(w)\n}\n\ntype BoolAssemblerTraits struct {\n\tPkgName       string\n\tTypeName      string // see doc in kindAssemblerTraitsGenerator\n\tAppliedPrefix string // see doc in kindAssemblerTraitsGenerator\n}\n\nfunc (BoolAssemblerTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Bool\n}\nfunc (g BoolAssemblerTraits) EmitNodeAssemblerMethodBeginMap(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bool}.emitNodeAssemblerMethodBeginMap(w)\n}\nfunc (g BoolAssemblerTraits) EmitNodeAssemblerMethodBeginList(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bool}.emitNodeAssemblerMethodBeginList(w)\n}\nfunc (g BoolAssemblerTraits) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bool}.emitNodeAssemblerMethodAssignNull(w)\n}\nfunc (g BoolAssemblerTraits) EmitNodeAssemblerMethodAssignInt(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bool}.emitNodeAssemblerMethodAssignInt(w)\n}\nfunc (g BoolAssemblerTraits) EmitNodeAssemblerMethodAssignFloat(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bool}.emitNodeAssemblerMethodAssignFloat(w)\n}\nfunc (g BoolAssemblerTraits) EmitNodeAssemblerMethodAssignString(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bool}.emitNodeAssemblerMethodAssignString(w)\n}\nfunc (g BoolAssemblerTraits) EmitNodeAssemblerMethodAssignBytes(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bool}.emitNodeAssemblerMethodAssignBytes(w)\n}\nfunc (g BoolAssemblerTraits) EmitNodeAssemblerMethodAssignLink(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bool}.emitNodeAssemblerMethodAssignLink(w)\n}\nfunc (g BoolAssemblerTraits) EmitNodeAssemblerMethodPrototype(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bool}.emitNodeAssemblerMethodPrototype(w)\n}\n"
  },
  {
    "path": "schema/gen/go/mixins/bytesGenMixin.go",
    "content": "package mixins\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\ntype BytesTraits struct {\n\tPkgName    string\n\tTypeName   string // see doc in kindTraitsGenerator\n\tTypeSymbol string // see doc in kindTraitsGenerator\n}\n\nfunc (BytesTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Bytes\n}\nfunc (g BytesTraits) EmitNodeMethodKind(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) Kind() datamodel.Kind {\n\t\t\treturn datamodel.Kind_Bytes\n\t\t}\n\t`, w, g)\n}\nfunc (g BytesTraits) EmitNodeMethodLookupByString(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bytes}.emitNodeMethodLookupByString(w)\n}\nfunc (g BytesTraits) EmitNodeMethodLookupByNode(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bytes}.emitNodeMethodLookupByNode(w)\n}\nfunc (g BytesTraits) EmitNodeMethodLookupByIndex(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bytes}.emitNodeMethodLookupByIndex(w)\n}\nfunc (g BytesTraits) EmitNodeMethodLookupBySegment(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bytes}.emitNodeMethodLookupBySegment(w)\n}\nfunc (g BytesTraits) EmitNodeMethodMapIterator(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bytes}.emitNodeMethodMapIterator(w)\n}\nfunc (g BytesTraits) EmitNodeMethodListIterator(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bytes}.emitNodeMethodListIterator(w)\n}\nfunc (g BytesTraits) EmitNodeMethodLength(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bytes}.emitNodeMethodLength(w)\n}\nfunc (g BytesTraits) EmitNodeMethodIsAbsent(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bytes}.emitNodeMethodIsAbsent(w)\n}\nfunc (g BytesTraits) EmitNodeMethodIsNull(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bytes}.emitNodeMethodIsNull(w)\n}\nfunc (g BytesTraits) EmitNodeMethodAsBool(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bytes}.emitNodeMethodAsBool(w)\n}\nfunc (g BytesTraits) EmitNodeMethodAsInt(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bytes}.emitNodeMethodAsInt(w)\n}\nfunc (g BytesTraits) EmitNodeMethodAsFloat(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bytes}.emitNodeMethodAsFloat(w)\n}\nfunc (g BytesTraits) EmitNodeMethodAsString(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bytes}.emitNodeMethodAsString(w)\n}\nfunc (g BytesTraits) EmitNodeMethodAsLink(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Bytes}.emitNodeMethodAsLink(w)\n}\n\ntype BytesAssemblerTraits struct {\n\tPkgName       string\n\tTypeName      string // see doc in kindAssemblerTraitsGenerator\n\tAppliedPrefix string // see doc in kindAssemblerTraitsGenerator\n}\n\nfunc (BytesAssemblerTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Bytes\n}\nfunc (g BytesAssemblerTraits) EmitNodeAssemblerMethodBeginMap(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bytes}.emitNodeAssemblerMethodBeginMap(w)\n}\nfunc (g BytesAssemblerTraits) EmitNodeAssemblerMethodBeginList(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bytes}.emitNodeAssemblerMethodBeginList(w)\n}\nfunc (g BytesAssemblerTraits) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bytes}.emitNodeAssemblerMethodAssignNull(w)\n}\nfunc (g BytesAssemblerTraits) EmitNodeAssemblerMethodAssignBool(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bytes}.emitNodeAssemblerMethodAssignBool(w)\n}\nfunc (g BytesAssemblerTraits) EmitNodeAssemblerMethodAssignInt(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bytes}.emitNodeAssemblerMethodAssignInt(w)\n}\nfunc (g BytesAssemblerTraits) EmitNodeAssemblerMethodAssignFloat(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bytes}.emitNodeAssemblerMethodAssignFloat(w)\n}\nfunc (g BytesAssemblerTraits) EmitNodeAssemblerMethodAssignString(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bytes}.emitNodeAssemblerMethodAssignString(w)\n}\nfunc (g BytesAssemblerTraits) EmitNodeAssemblerMethodAssignLink(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bytes}.emitNodeAssemblerMethodAssignLink(w)\n}\nfunc (g BytesAssemblerTraits) EmitNodeAssemblerMethodPrototype(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Bytes}.emitNodeAssemblerMethodPrototype(w)\n}\n"
  },
  {
    "path": "schema/gen/go/mixins/floatGenMixin.go",
    "content": "package mixins\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\ntype FloatTraits struct {\n\tPkgName    string\n\tTypeName   string // see doc in kindTraitsGenerator\n\tTypeSymbol string // see doc in kindTraitsGenerator\n}\n\nfunc (FloatTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Float\n}\nfunc (g FloatTraits) EmitNodeMethodKind(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) Kind() datamodel.Kind {\n\t\t\treturn datamodel.Kind_Float\n\t\t}\n\t`, w, g)\n}\nfunc (g FloatTraits) EmitNodeMethodLookupByString(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Float}.emitNodeMethodLookupByString(w)\n}\nfunc (g FloatTraits) EmitNodeMethodLookupByNode(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Float}.emitNodeMethodLookupByNode(w)\n}\nfunc (g FloatTraits) EmitNodeMethodLookupByIndex(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Float}.emitNodeMethodLookupByIndex(w)\n}\nfunc (g FloatTraits) EmitNodeMethodLookupBySegment(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Float}.emitNodeMethodLookupBySegment(w)\n}\nfunc (g FloatTraits) EmitNodeMethodMapIterator(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Float}.emitNodeMethodMapIterator(w)\n}\nfunc (g FloatTraits) EmitNodeMethodListIterator(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Float}.emitNodeMethodListIterator(w)\n}\nfunc (g FloatTraits) EmitNodeMethodLength(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Float}.emitNodeMethodLength(w)\n}\nfunc (g FloatTraits) EmitNodeMethodIsAbsent(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Float}.emitNodeMethodIsAbsent(w)\n}\nfunc (g FloatTraits) EmitNodeMethodIsNull(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Float}.emitNodeMethodIsNull(w)\n}\nfunc (g FloatTraits) EmitNodeMethodAsBool(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Float}.emitNodeMethodAsBool(w)\n}\nfunc (g FloatTraits) EmitNodeMethodAsInt(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Float}.emitNodeMethodAsInt(w)\n}\nfunc (g FloatTraits) EmitNodeMethodAsString(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Float}.emitNodeMethodAsString(w)\n}\nfunc (g FloatTraits) EmitNodeMethodAsBytes(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Float}.emitNodeMethodAsBytes(w)\n}\nfunc (g FloatTraits) EmitNodeMethodAsLink(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Float}.emitNodeMethodAsLink(w)\n}\n\ntype FloatAssemblerTraits struct {\n\tPkgName       string\n\tTypeName      string // see doc in kindAssemblerTraitsGenerator\n\tAppliedPrefix string // see doc in kindAssemblerTraitsGenerator\n}\n\nfunc (FloatAssemblerTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Float\n}\nfunc (g FloatAssemblerTraits) EmitNodeAssemblerMethodBeginMap(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Float}.emitNodeAssemblerMethodBeginMap(w)\n}\nfunc (g FloatAssemblerTraits) EmitNodeAssemblerMethodBeginList(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Float}.emitNodeAssemblerMethodBeginList(w)\n}\nfunc (g FloatAssemblerTraits) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Float}.emitNodeAssemblerMethodAssignNull(w)\n}\nfunc (g FloatAssemblerTraits) EmitNodeAssemblerMethodAssignBool(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Float}.emitNodeAssemblerMethodAssignBool(w)\n}\nfunc (g FloatAssemblerTraits) EmitNodeAssemblerMethodAssignInt(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Float}.emitNodeAssemblerMethodAssignInt(w)\n}\nfunc (g FloatAssemblerTraits) EmitNodeAssemblerMethodAssignString(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Float}.emitNodeAssemblerMethodAssignString(w)\n}\nfunc (g FloatAssemblerTraits) EmitNodeAssemblerMethodAssignBytes(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Float}.emitNodeAssemblerMethodAssignBytes(w)\n}\nfunc (g FloatAssemblerTraits) EmitNodeAssemblerMethodAssignLink(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Float}.emitNodeAssemblerMethodAssignLink(w)\n}\nfunc (g FloatAssemblerTraits) EmitNodeAssemblerMethodPrototype(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Float}.emitNodeAssemblerMethodPrototype(w)\n}\n"
  },
  {
    "path": "schema/gen/go/mixins/intGenMixin.go",
    "content": "package mixins\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\ntype IntTraits struct {\n\tPkgName    string\n\tTypeName   string // see doc in kindTraitsGenerator\n\tTypeSymbol string // see doc in kindTraitsGenerator\n}\n\nfunc (IntTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Int\n}\nfunc (g IntTraits) EmitNodeMethodKind(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) Kind() datamodel.Kind {\n\t\t\treturn datamodel.Kind_Int\n\t\t}\n\t`, w, g)\n}\nfunc (g IntTraits) EmitNodeMethodLookupByString(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Int}.emitNodeMethodLookupByString(w)\n}\nfunc (g IntTraits) EmitNodeMethodLookupByNode(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Int}.emitNodeMethodLookupByNode(w)\n}\nfunc (g IntTraits) EmitNodeMethodLookupByIndex(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Int}.emitNodeMethodLookupByIndex(w)\n}\nfunc (g IntTraits) EmitNodeMethodLookupBySegment(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Int}.emitNodeMethodLookupBySegment(w)\n}\nfunc (g IntTraits) EmitNodeMethodMapIterator(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Int}.emitNodeMethodMapIterator(w)\n}\nfunc (g IntTraits) EmitNodeMethodListIterator(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Int}.emitNodeMethodListIterator(w)\n}\nfunc (g IntTraits) EmitNodeMethodLength(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Int}.emitNodeMethodLength(w)\n}\nfunc (g IntTraits) EmitNodeMethodIsAbsent(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Int}.emitNodeMethodIsAbsent(w)\n}\nfunc (g IntTraits) EmitNodeMethodIsNull(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Int}.emitNodeMethodIsNull(w)\n}\nfunc (g IntTraits) EmitNodeMethodAsBool(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Int}.emitNodeMethodAsBool(w)\n}\nfunc (g IntTraits) EmitNodeMethodAsFloat(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Int}.emitNodeMethodAsFloat(w)\n}\nfunc (g IntTraits) EmitNodeMethodAsString(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Int}.emitNodeMethodAsString(w)\n}\nfunc (g IntTraits) EmitNodeMethodAsBytes(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Int}.emitNodeMethodAsBytes(w)\n}\nfunc (g IntTraits) EmitNodeMethodAsLink(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Int}.emitNodeMethodAsLink(w)\n}\n\ntype IntAssemblerTraits struct {\n\tPkgName       string\n\tTypeName      string // see doc in kindAssemblerTraitsGenerator\n\tAppliedPrefix string // see doc in kindAssemblerTraitsGenerator\n}\n\nfunc (IntAssemblerTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Int\n}\nfunc (g IntAssemblerTraits) EmitNodeAssemblerMethodBeginMap(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Int}.emitNodeAssemblerMethodBeginMap(w)\n}\nfunc (g IntAssemblerTraits) EmitNodeAssemblerMethodBeginList(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Int}.emitNodeAssemblerMethodBeginList(w)\n}\nfunc (g IntAssemblerTraits) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Int}.emitNodeAssemblerMethodAssignNull(w)\n}\nfunc (g IntAssemblerTraits) EmitNodeAssemblerMethodAssignBool(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Int}.emitNodeAssemblerMethodAssignBool(w)\n}\nfunc (g IntAssemblerTraits) EmitNodeAssemblerMethodAssignFloat(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Int}.emitNodeAssemblerMethodAssignFloat(w)\n}\nfunc (g IntAssemblerTraits) EmitNodeAssemblerMethodAssignString(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Int}.emitNodeAssemblerMethodAssignString(w)\n}\nfunc (g IntAssemblerTraits) EmitNodeAssemblerMethodAssignBytes(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Int}.emitNodeAssemblerMethodAssignBytes(w)\n}\nfunc (g IntAssemblerTraits) EmitNodeAssemblerMethodAssignLink(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Int}.emitNodeAssemblerMethodAssignLink(w)\n}\nfunc (g IntAssemblerTraits) EmitNodeAssemblerMethodPrototype(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Int}.emitNodeAssemblerMethodPrototype(w)\n}\n"
  },
  {
    "path": "schema/gen/go/mixins/kindTraits.go",
    "content": "package mixins\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// kindTraitsGenerator is the center of all the other mixins,\n// and handles all the method generation which is a pure function of the kind.\n//\n// OVERRIDE THE METHODS THAT DO APPLY TO YOUR KIND;\n// the default method bodies produced by this mixin are those that return errors,\n// and that is not what you want for the methods that *are* interesting for your kind.\n// The kindTraitsGenerator methods will panic if called for a kind that should've overridden them.\n//\n// If you're implementing something that can hold \"any\" kind,\n// probably none of these methods apply to you at all.\n//\n// The other types in this package use kindTraitsGenerator with a fixed Kind,\n// and only forward the methods to it that don't apply for their kind;\n// this means when they're used as an anonymous embed, they grant\n// all the appropriate dummy methods to their container,\n// while leaving the ones that are still needed entirely absent,\n// so the compiler helpfully tells you to finish rather than waiting until\n// runtime to panic if a should-have-been-overriden method slips through.\ntype kindTraitsGenerator struct {\n\tPkgName    string\n\tTypeName   string // as will be printed in messages (e.g. can be goosed up a bit, like \"Thing.Repr\" instead of \"_Thing__Repr\").\n\tTypeSymbol string // the identifier in code (sometimes is munged internals like \"_Thing__Repr\" corresponding to no publicly admitted schema.Type.Name).\n\tKind       datamodel.Kind\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodLookupByString(w io.Writer) {\n\tif datamodel.KindSet_JustMap.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) LookupByString(string) (datamodel.Node, error) {\n\t\t\treturn mixins.{{ .Kind.String | title }}{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.LookupByString(\"\")\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodLookupByNode(w io.Writer) {\n\tif datamodel.KindSet_JustMap.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) LookupByNode(datamodel.Node) (datamodel.Node, error) {\n\t\t\treturn mixins.{{ .Kind.String | title }}{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.LookupByNode(nil)\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodLookupByIndex(w io.Writer) {\n\tif datamodel.KindSet_JustList.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) LookupByIndex(idx int64) (datamodel.Node, error) {\n\t\t\treturn mixins.{{ .Kind.String | title }}{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.LookupByIndex(0)\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodLookupBySegment(w io.Writer) {\n\tif datamodel.KindSet_Recursive.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\t\t\treturn mixins.{{ .Kind.String | title }}{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.LookupBySegment(seg)\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodMapIterator(w io.Writer) {\n\tif datamodel.KindSet_JustMap.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) MapIterator() datamodel.MapIterator {\n\t\t\treturn nil\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodListIterator(w io.Writer) {\n\tif datamodel.KindSet_JustList.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) ListIterator() datamodel.ListIterator {\n\t\t\treturn nil\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodLength(w io.Writer) {\n\tif datamodel.KindSet_Recursive.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) Length() int64 {\n\t\t\treturn -1\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodIsAbsent(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) IsAbsent() bool {\n\t\t\treturn false\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodIsNull(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) IsNull() bool {\n\t\t\treturn false\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodAsBool(w io.Writer) {\n\tif datamodel.KindSet_JustBool.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) AsBool() (bool, error) {\n\t\t\treturn mixins.{{ .Kind.String | title }}{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.AsBool()\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodAsInt(w io.Writer) {\n\tif datamodel.KindSet_JustInt.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) AsInt() (int64, error) {\n\t\t\treturn mixins.{{ .Kind.String | title }}{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.AsInt()\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodAsFloat(w io.Writer) {\n\tif datamodel.KindSet_JustFloat.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) AsFloat() (float64, error) {\n\t\t\treturn mixins.{{ .Kind.String | title }}{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.AsFloat()\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodAsString(w io.Writer) {\n\tif datamodel.KindSet_JustString.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) AsString() (string, error) {\n\t\t\treturn mixins.{{ .Kind.String | title }}{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.AsString()\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodAsBytes(w io.Writer) {\n\tif datamodel.KindSet_JustBytes.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) AsBytes() ([]byte, error) {\n\t\t\treturn mixins.{{ .Kind.String | title }}{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.AsBytes()\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindTraitsGenerator) emitNodeMethodAsLink(w io.Writer) {\n\tif datamodel.KindSet_JustLink.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) AsLink() (datamodel.Link, error) {\n\t\t\treturn mixins.{{ .Kind.String | title }}{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.AsLink()\n\t\t}\n\t`, w, g)\n}\n\n// kindAssemblerTraitsGenerator is an awfully lot like kindTraitsGenerator,\n// except applying to methods for builders and assemblers.\ntype kindAssemblerTraitsGenerator struct {\n\tPkgName       string\n\tTypeName      string // as will be printed in messages (e.g. can be goosed up a bit, like \"Thing.Repr\" instead of \"_Thing__Repr\").\n\tAppliedPrefix string // the prefix of what to attach methods to... this one is a little wild: should probably be either \"_{{ .Type | TypeSymbol }}__\" or \"_{{ .Type | TypeSymbol }}__Repr\", and we'll just add the words \"Builder\" and \"Assembler\".\n\tKind          datamodel.Kind\n}\n\n// bailed on extracting a common emitNodeBuilderType: too many variations in content and pointer placement to be worth it.\n// bailed on extracting a common emitNodeBuilderMethods: same.\n// bailed on extracting a common emitNodeAssemblerType: same.\n//\n// If you try to do these, you'll probably need:\n//  - an explicit understanding of if generating representations or not\n//  - to still be ready for boatloads of exceptions if the representation isn't directly castable to and from the type-level node.\n\nfunc (g kindAssemblerTraitsGenerator) emitNodeAssemblerMethodBeginMap(w io.Writer) {\n\tif datamodel.KindSet_JustMap.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .AppliedPrefix }}Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {\n\t\t\treturn mixins.{{ .Kind.String | title }}Assembler{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.BeginMap(0)\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindAssemblerTraitsGenerator) emitNodeAssemblerMethodBeginList(w io.Writer) {\n\tif datamodel.KindSet_JustList.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .AppliedPrefix }}Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {\n\t\t\treturn mixins.{{ .Kind.String | title }}Assembler{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.BeginList(0)\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindAssemblerTraitsGenerator) emitNodeAssemblerMethodAssignNull(w io.Writer) {\n\tif datamodel.KindSet_JustNull.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc (na *{{ .AppliedPrefix }}Assembler) AssignNull() error {\n\t\t\treturn mixins.{{ .Kind.String | title }}Assembler{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.AssignNull()\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindAssemblerTraitsGenerator) emitNodeAssemblerMethodAssignBool(w io.Writer) {\n\tif datamodel.KindSet_JustBool.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .AppliedPrefix }}Assembler) AssignBool(bool) error {\n\t\t\treturn mixins.{{ .Kind.String | title }}Assembler{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.AssignBool(false)\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindAssemblerTraitsGenerator) emitNodeAssemblerMethodAssignInt(w io.Writer) {\n\tif datamodel.KindSet_JustInt.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .AppliedPrefix }}Assembler) AssignInt(int64) error {\n\t\t\treturn mixins.{{ .Kind.String | title }}Assembler{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.AssignInt(0)\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindAssemblerTraitsGenerator) emitNodeAssemblerMethodAssignFloat(w io.Writer) {\n\tif datamodel.KindSet_JustFloat.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .AppliedPrefix }}Assembler) AssignFloat(float64) error {\n\t\t\treturn mixins.{{ .Kind.String | title }}Assembler{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.AssignFloat(0)\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindAssemblerTraitsGenerator) emitNodeAssemblerMethodAssignString(w io.Writer) {\n\tif datamodel.KindSet_JustString.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .AppliedPrefix }}Assembler) AssignString(string) error {\n\t\t\treturn mixins.{{ .Kind.String | title }}Assembler{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.AssignString(\"\")\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindAssemblerTraitsGenerator) emitNodeAssemblerMethodAssignBytes(w io.Writer) {\n\tif datamodel.KindSet_JustBytes.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .AppliedPrefix }}Assembler) AssignBytes([]byte) error {\n\t\t\treturn mixins.{{ .Kind.String | title }}Assembler{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.AssignBytes(nil)\n\t\t}\n\t`, w, g)\n}\n\nfunc (g kindAssemblerTraitsGenerator) emitNodeAssemblerMethodAssignLink(w io.Writer) {\n\tif datamodel.KindSet_JustLink.Contains(g.Kind) {\n\t\tpanic(\"gen internals error: you should've overridden this\")\n\t}\n\tdoTemplate(`\n\t\tfunc ({{ .AppliedPrefix }}Assembler) AssignLink(datamodel.Link) error {\n\t\t\treturn mixins.{{ .Kind.String | title }}Assembler{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\"}.AssignLink(nil)\n\t\t}\n\t`, w, g)\n}\n\n// bailed on extracting a common emitNodeAssemblerMethodAssignNode: way too many variations.\n\nfunc (g kindAssemblerTraitsGenerator) emitNodeAssemblerMethodPrototype(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .AppliedPrefix }}Assembler) Prototype() datamodel.NodePrototype {\n\t\t\treturn {{ .AppliedPrefix }}Prototype{}\n\t\t}\n\t`, w, g)\n}\n\n// bailed on extracting a common emitNodeAssemblerOtherBits: it's just self-evident there's nothing common there.\n"
  },
  {
    "path": "schema/gen/go/mixins/linkGenMixin.go",
    "content": "package mixins\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\ntype LinkTraits struct {\n\tPkgName    string\n\tTypeName   string // see doc in kindTraitsGenerator\n\tTypeSymbol string // see doc in kindTraitsGenerator\n}\n\nfunc (LinkTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Link\n}\nfunc (g LinkTraits) EmitNodeMethodKind(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) Kind() datamodel.Kind {\n\t\t\treturn datamodel.Kind_Link\n\t\t}\n\t`, w, g)\n}\nfunc (g LinkTraits) EmitNodeMethodLookupByString(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Link}.emitNodeMethodLookupByString(w)\n}\nfunc (g LinkTraits) EmitNodeMethodLookupByNode(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Link}.emitNodeMethodLookupByNode(w)\n}\nfunc (g LinkTraits) EmitNodeMethodLookupByIndex(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Link}.emitNodeMethodLookupByIndex(w)\n}\nfunc (g LinkTraits) EmitNodeMethodLookupBySegment(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Link}.emitNodeMethodLookupBySegment(w)\n}\nfunc (g LinkTraits) EmitNodeMethodMapIterator(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Link}.emitNodeMethodMapIterator(w)\n}\nfunc (g LinkTraits) EmitNodeMethodListIterator(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Link}.emitNodeMethodListIterator(w)\n}\nfunc (g LinkTraits) EmitNodeMethodLength(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Link}.emitNodeMethodLength(w)\n}\nfunc (g LinkTraits) EmitNodeMethodIsAbsent(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Link}.emitNodeMethodIsAbsent(w)\n}\nfunc (g LinkTraits) EmitNodeMethodIsNull(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Link}.emitNodeMethodIsNull(w)\n}\nfunc (g LinkTraits) EmitNodeMethodAsBool(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Link}.emitNodeMethodAsBool(w)\n}\nfunc (g LinkTraits) EmitNodeMethodAsInt(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Link}.emitNodeMethodAsInt(w)\n}\nfunc (g LinkTraits) EmitNodeMethodAsFloat(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Link}.emitNodeMethodAsFloat(w)\n}\nfunc (g LinkTraits) EmitNodeMethodAsString(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Link}.emitNodeMethodAsString(w)\n}\nfunc (g LinkTraits) EmitNodeMethodAsBytes(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Link}.emitNodeMethodAsBytes(w)\n}\n\ntype LinkAssemblerTraits struct {\n\tPkgName       string\n\tTypeName      string // see doc in kindAssemblerTraitsGenerator\n\tAppliedPrefix string // see doc in kindAssemblerTraitsGenerator\n}\n\nfunc (LinkAssemblerTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Link\n}\nfunc (g LinkAssemblerTraits) EmitNodeAssemblerMethodBeginMap(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Link}.emitNodeAssemblerMethodBeginMap(w)\n}\nfunc (g LinkAssemblerTraits) EmitNodeAssemblerMethodBeginList(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Link}.emitNodeAssemblerMethodBeginList(w)\n}\nfunc (g LinkAssemblerTraits) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Link}.emitNodeAssemblerMethodAssignNull(w)\n}\nfunc (g LinkAssemblerTraits) EmitNodeAssemblerMethodAssignBool(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Link}.emitNodeAssemblerMethodAssignBool(w)\n}\nfunc (g LinkAssemblerTraits) EmitNodeAssemblerMethodAssignInt(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Link}.emitNodeAssemblerMethodAssignInt(w)\n}\nfunc (g LinkAssemblerTraits) EmitNodeAssemblerMethodAssignFloat(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Link}.emitNodeAssemblerMethodAssignFloat(w)\n}\nfunc (g LinkAssemblerTraits) EmitNodeAssemblerMethodAssignString(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Link}.emitNodeAssemblerMethodAssignString(w)\n}\nfunc (g LinkAssemblerTraits) EmitNodeAssemblerMethodAssignBytes(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Link}.emitNodeAssemblerMethodAssignBytes(w)\n}\nfunc (g LinkAssemblerTraits) EmitNodeAssemblerMethodPrototype(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Link}.emitNodeAssemblerMethodPrototype(w)\n}\n"
  },
  {
    "path": "schema/gen/go/mixins/listGenMixin.go",
    "content": "package mixins\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\ntype ListTraits struct {\n\tPkgName    string\n\tTypeName   string // see doc in kindTraitsGenerator\n\tTypeSymbol string // see doc in kindTraitsGenerator\n}\n\nfunc (ListTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_List\n}\nfunc (g ListTraits) EmitNodeMethodKind(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) Kind() datamodel.Kind {\n\t\t\treturn datamodel.Kind_List\n\t\t}\n\t`, w, g)\n}\nfunc (g ListTraits) EmitNodeMethodLookupByString(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_List}.emitNodeMethodLookupByString(w)\n}\nfunc (g ListTraits) EmitNodeMethodLookupBySegment(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n {{ .TypeSymbol }}) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\t\t\ti, err := seg.Index()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, datamodel.ErrInvalidSegmentForList{TypeName: \"{{ .PkgName }}.{{ .TypeName }}\", TroubleSegment: seg, Reason: err}\n\t\t\t}\n\t\t\treturn n.LookupByIndex(i)\n\t\t}\n\t`, w, g)\n}\nfunc (g ListTraits) EmitNodeMethodMapIterator(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_List}.emitNodeMethodMapIterator(w)\n}\nfunc (g ListTraits) EmitNodeMethodIsAbsent(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_List}.emitNodeMethodIsAbsent(w)\n}\nfunc (g ListTraits) EmitNodeMethodIsNull(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_List}.emitNodeMethodIsNull(w)\n}\nfunc (g ListTraits) EmitNodeMethodAsBool(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_List}.emitNodeMethodAsBool(w)\n}\nfunc (g ListTraits) EmitNodeMethodAsInt(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_List}.emitNodeMethodAsInt(w)\n}\nfunc (g ListTraits) EmitNodeMethodAsFloat(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_List}.emitNodeMethodAsFloat(w)\n}\nfunc (g ListTraits) EmitNodeMethodAsString(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_List}.emitNodeMethodAsString(w)\n}\nfunc (g ListTraits) EmitNodeMethodAsBytes(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_List}.emitNodeMethodAsBytes(w)\n}\nfunc (g ListTraits) EmitNodeMethodAsLink(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_List}.emitNodeMethodAsLink(w)\n}\n\ntype ListAssemblerTraits struct {\n\tPkgName       string\n\tTypeName      string // see doc in kindAssemblerTraitsGenerator\n\tAppliedPrefix string // see doc in kindAssemblerTraitsGenerator\n}\n\nfunc (ListAssemblerTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_List\n}\nfunc (g ListAssemblerTraits) EmitNodeAssemblerMethodBeginMap(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_List}.emitNodeAssemblerMethodBeginMap(w)\n}\nfunc (g ListAssemblerTraits) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_List}.emitNodeAssemblerMethodAssignNull(w)\n}\nfunc (g ListAssemblerTraits) EmitNodeAssemblerMethodAssignBool(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_List}.emitNodeAssemblerMethodAssignBool(w)\n}\nfunc (g ListAssemblerTraits) EmitNodeAssemblerMethodAssignInt(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_List}.emitNodeAssemblerMethodAssignInt(w)\n}\nfunc (g ListAssemblerTraits) EmitNodeAssemblerMethodAssignFloat(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_List}.emitNodeAssemblerMethodAssignFloat(w)\n}\nfunc (g ListAssemblerTraits) EmitNodeAssemblerMethodAssignString(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_List}.emitNodeAssemblerMethodAssignString(w)\n}\nfunc (g ListAssemblerTraits) EmitNodeAssemblerMethodAssignBytes(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_List}.emitNodeAssemblerMethodAssignBytes(w)\n}\nfunc (g ListAssemblerTraits) EmitNodeAssemblerMethodAssignLink(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_List}.emitNodeAssemblerMethodAssignLink(w)\n}\nfunc (g ListAssemblerTraits) EmitNodeAssemblerMethodPrototype(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_List}.emitNodeAssemblerMethodPrototype(w)\n}\n"
  },
  {
    "path": "schema/gen/go/mixins/mapGenMixin.go",
    "content": "package mixins\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\ntype MapTraits struct {\n\tPkgName    string\n\tTypeName   string // see doc in kindTraitsGenerator\n\tTypeSymbol string // see doc in kindTraitsGenerator\n}\n\nfunc (MapTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Map\n}\nfunc (g MapTraits) EmitNodeMethodKind(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) Kind() datamodel.Kind {\n\t\t\treturn datamodel.Kind_Map\n\t\t}\n\t`, w, g)\n}\nfunc (g MapTraits) EmitNodeMethodLookupByIndex(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Map}.emitNodeMethodLookupByIndex(w)\n}\nfunc (g MapTraits) EmitNodeMethodLookupBySegment(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc (n {{ .TypeSymbol }}) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\t\t\treturn n.LookupByString(seg.String())\n\t\t}\n\t`, w, g)\n}\nfunc (g MapTraits) EmitNodeMethodListIterator(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Map}.emitNodeMethodListIterator(w)\n}\nfunc (g MapTraits) EmitNodeMethodIsAbsent(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Map}.emitNodeMethodIsAbsent(w)\n}\nfunc (g MapTraits) EmitNodeMethodIsNull(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Map}.emitNodeMethodIsNull(w)\n}\nfunc (g MapTraits) EmitNodeMethodAsBool(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Map}.emitNodeMethodAsBool(w)\n}\nfunc (g MapTraits) EmitNodeMethodAsInt(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Map}.emitNodeMethodAsInt(w)\n}\nfunc (g MapTraits) EmitNodeMethodAsFloat(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Map}.emitNodeMethodAsFloat(w)\n}\nfunc (g MapTraits) EmitNodeMethodAsString(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Map}.emitNodeMethodAsString(w)\n}\nfunc (g MapTraits) EmitNodeMethodAsBytes(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Map}.emitNodeMethodAsBytes(w)\n}\nfunc (g MapTraits) EmitNodeMethodAsLink(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_Map}.emitNodeMethodAsLink(w)\n}\n\ntype MapAssemblerTraits struct {\n\tPkgName       string\n\tTypeName      string // see doc in kindAssemblerTraitsGenerator\n\tAppliedPrefix string // see doc in kindAssemblerTraitsGenerator\n}\n\nfunc (MapAssemblerTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Map\n}\nfunc (g MapAssemblerTraits) EmitNodeAssemblerMethodBeginList(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Map}.emitNodeAssemblerMethodBeginList(w)\n}\nfunc (g MapAssemblerTraits) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Map}.emitNodeAssemblerMethodAssignNull(w)\n}\nfunc (g MapAssemblerTraits) EmitNodeAssemblerMethodAssignBool(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Map}.emitNodeAssemblerMethodAssignBool(w)\n}\nfunc (g MapAssemblerTraits) EmitNodeAssemblerMethodAssignInt(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Map}.emitNodeAssemblerMethodAssignInt(w)\n}\nfunc (g MapAssemblerTraits) EmitNodeAssemblerMethodAssignFloat(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Map}.emitNodeAssemblerMethodAssignFloat(w)\n}\nfunc (g MapAssemblerTraits) EmitNodeAssemblerMethodAssignString(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Map}.emitNodeAssemblerMethodAssignString(w)\n}\nfunc (g MapAssemblerTraits) EmitNodeAssemblerMethodAssignBytes(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Map}.emitNodeAssemblerMethodAssignBytes(w)\n}\nfunc (g MapAssemblerTraits) EmitNodeAssemblerMethodAssignLink(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Map}.emitNodeAssemblerMethodAssignLink(w)\n}\nfunc (g MapAssemblerTraits) EmitNodeAssemblerMethodPrototype(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_Map}.emitNodeAssemblerMethodPrototype(w)\n}\n"
  },
  {
    "path": "schema/gen/go/mixins/stringGenMixin.go",
    "content": "package mixins\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\ntype StringTraits struct {\n\tPkgName    string\n\tTypeName   string // see doc in kindTraitsGenerator\n\tTypeSymbol string // see doc in kindTraitsGenerator\n}\n\nfunc (StringTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_String\n}\nfunc (g StringTraits) EmitNodeMethodKind(w io.Writer) {\n\tdoTemplate(`\n\t\tfunc ({{ .TypeSymbol }}) Kind() datamodel.Kind {\n\t\t\treturn datamodel.Kind_String\n\t\t}\n\t`, w, g)\n}\nfunc (g StringTraits) EmitNodeMethodLookupByString(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_String}.emitNodeMethodLookupByString(w)\n}\nfunc (g StringTraits) EmitNodeMethodLookupByNode(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_String}.emitNodeMethodLookupByNode(w)\n}\nfunc (g StringTraits) EmitNodeMethodLookupByIndex(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_String}.emitNodeMethodLookupByIndex(w)\n}\nfunc (g StringTraits) EmitNodeMethodLookupBySegment(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_String}.emitNodeMethodLookupBySegment(w)\n}\nfunc (g StringTraits) EmitNodeMethodMapIterator(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_String}.emitNodeMethodMapIterator(w)\n}\nfunc (g StringTraits) EmitNodeMethodListIterator(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_String}.emitNodeMethodListIterator(w)\n}\nfunc (g StringTraits) EmitNodeMethodLength(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_String}.emitNodeMethodLength(w)\n}\nfunc (g StringTraits) EmitNodeMethodIsAbsent(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_String}.emitNodeMethodIsAbsent(w)\n}\nfunc (g StringTraits) EmitNodeMethodIsNull(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_String}.emitNodeMethodIsNull(w)\n}\nfunc (g StringTraits) EmitNodeMethodAsBool(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_String}.emitNodeMethodAsBool(w)\n}\nfunc (g StringTraits) EmitNodeMethodAsInt(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_String}.emitNodeMethodAsInt(w)\n}\nfunc (g StringTraits) EmitNodeMethodAsFloat(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_String}.emitNodeMethodAsFloat(w)\n}\nfunc (g StringTraits) EmitNodeMethodAsBytes(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_String}.emitNodeMethodAsBytes(w)\n}\nfunc (g StringTraits) EmitNodeMethodAsLink(w io.Writer) {\n\tkindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, datamodel.Kind_String}.emitNodeMethodAsLink(w)\n}\n\ntype StringAssemblerTraits struct {\n\tPkgName       string\n\tTypeName      string // see doc in kindAssemblerTraitsGenerator\n\tAppliedPrefix string // see doc in kindAssemblerTraitsGenerator\n}\n\nfunc (StringAssemblerTraits) Kind() datamodel.Kind {\n\treturn datamodel.Kind_String\n}\nfunc (g StringAssemblerTraits) EmitNodeAssemblerMethodBeginMap(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_String}.emitNodeAssemblerMethodBeginMap(w)\n}\nfunc (g StringAssemblerTraits) EmitNodeAssemblerMethodBeginList(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_String}.emitNodeAssemblerMethodBeginList(w)\n}\nfunc (g StringAssemblerTraits) EmitNodeAssemblerMethodAssignNull(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_String}.emitNodeAssemblerMethodAssignNull(w)\n}\nfunc (g StringAssemblerTraits) EmitNodeAssemblerMethodAssignBool(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_String}.emitNodeAssemblerMethodAssignBool(w)\n}\nfunc (g StringAssemblerTraits) EmitNodeAssemblerMethodAssignInt(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_String}.emitNodeAssemblerMethodAssignInt(w)\n}\nfunc (g StringAssemblerTraits) EmitNodeAssemblerMethodAssignFloat(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_String}.emitNodeAssemblerMethodAssignFloat(w)\n}\nfunc (g StringAssemblerTraits) EmitNodeAssemblerMethodAssignBytes(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_String}.emitNodeAssemblerMethodAssignBytes(w)\n}\nfunc (g StringAssemblerTraits) EmitNodeAssemblerMethodAssignLink(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_String}.emitNodeAssemblerMethodAssignLink(w)\n}\nfunc (g StringAssemblerTraits) EmitNodeAssemblerMethodPrototype(w io.Writer) {\n\tkindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, datamodel.Kind_String}.emitNodeAssemblerMethodPrototype(w)\n}\n"
  },
  {
    "path": "schema/gen/go/mixins/templateUtil.go",
    "content": "package mixins\n\nimport (\n\t\"io\"\n\t\"strings\"\n\t\"text/template\"\n\n\t\"github.com/ipld/go-ipld-prime/testutil\"\n)\n\nfunc doTemplate(tmplstr string, w io.Writer, data interface{}) {\n\ttmpl := template.Must(template.New(\"\").\n\t\tFuncs(template.FuncMap{\n\t\t\t\"title\": func(s string) string { return strings.Title(s) }, //lint:ignore SA1019 cases.Title doesn't work for this\n\t\t}).\n\t\tParse(testutil.Dedent(tmplstr)))\n\tif err := tmpl.Execute(w, data); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "schema/gen/go/templateUtil.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\t\"strings\"\n\t\"text/template\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/testutil\"\n)\n\nfunc doTemplate(tmplstr string, w io.Writer, adjCfg *AdjunctCfg, data interface{}) {\n\ttmpl := template.Must(template.New(\"\").\n\t\tFuncs(template.FuncMap{\n\n\t\t\t// These methods are used for symbol munging and appear constantly, so they need to be short.\n\t\t\t//  (You could also get at them through `.AdjCfg`, but going direct saves some screen real estate.)\n\t\t\t\"TypeSymbol\":       adjCfg.TypeSymbol,\n\t\t\t\"FieldSymbolLower\": adjCfg.FieldSymbolLower,\n\t\t\t\"FieldSymbolUpper\": adjCfg.FieldSymbolUpper,\n\t\t\t\"MaybeUsesPtr\":     adjCfg.MaybeUsesPtr,\n\t\t\t\"Comments\":         adjCfg.Comments,\n\n\t\t\t// The whole AdjunctConfig can be accessed.\n\t\t\t//  Access methods like UnionMemlayout through this, as e.g. `.AdjCfg.UnionMemlayout`.\n\t\t\t\"AdjCfg\": func() *AdjunctCfg { return adjCfg },\n\n\t\t\t// \"dot\" is a dummy value that's equal to the original `.` expression, but stays there.\n\t\t\t//  Use this if you're inside a range or other feature that shifted the dot and you want the original.\n\t\t\t//  (This may seem silly, but empirically, I found myself writing a dummy line to store the value of dot before endering a range clause >20 times; that's plenty.)\n\t\t\t\"dot\": func() interface{} { return data },\n\n\t\t\t\"KindPrim\": func(k datamodel.Kind) string {\n\t\t\t\tswitch k {\n\t\t\t\tcase datamodel.Kind_Map:\n\t\t\t\t\tpanic(\"this isn't useful for non-scalars\")\n\t\t\t\tcase datamodel.Kind_List:\n\t\t\t\t\tpanic(\"this isn't useful for non-scalars\")\n\t\t\t\tcase datamodel.Kind_Null:\n\t\t\t\t\tpanic(\"this isn't useful for null\")\n\t\t\t\tcase datamodel.Kind_Bool:\n\t\t\t\t\treturn \"bool\"\n\t\t\t\tcase datamodel.Kind_Int:\n\t\t\t\t\treturn \"int64\"\n\t\t\t\tcase datamodel.Kind_Float:\n\t\t\t\t\treturn \"float64\"\n\t\t\t\tcase datamodel.Kind_String:\n\t\t\t\t\treturn \"string\"\n\t\t\t\tcase datamodel.Kind_Bytes:\n\t\t\t\t\treturn \"[]byte\"\n\t\t\t\tcase datamodel.Kind_Link:\n\t\t\t\t\treturn \"datamodel.Link\"\n\t\t\t\tdefault:\n\t\t\t\t\tpanic(\"invalid enumeration value!\")\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"Kind\": func(s string) datamodel.Kind {\n\t\t\t\tswitch s {\n\t\t\t\tcase \"map\":\n\t\t\t\t\treturn datamodel.Kind_Map\n\t\t\t\tcase \"list\":\n\t\t\t\t\treturn datamodel.Kind_List\n\t\t\t\tcase \"null\":\n\t\t\t\t\treturn datamodel.Kind_Null\n\t\t\t\tcase \"bool\":\n\t\t\t\t\treturn datamodel.Kind_Bool\n\t\t\t\tcase \"int\":\n\t\t\t\t\treturn datamodel.Kind_Int\n\t\t\t\tcase \"float\":\n\t\t\t\t\treturn datamodel.Kind_Float\n\t\t\t\tcase \"string\":\n\t\t\t\t\treturn datamodel.Kind_String\n\t\t\t\tcase \"bytes\":\n\t\t\t\t\treturn datamodel.Kind_Bytes\n\t\t\t\tcase \"link\":\n\t\t\t\t\treturn datamodel.Kind_Link\n\t\t\t\tdefault:\n\t\t\t\t\tpanic(\"invalid enumeration value!\")\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"KindSymbol\": func(k datamodel.Kind) string {\n\t\t\t\tswitch k {\n\t\t\t\tcase datamodel.Kind_Map:\n\t\t\t\t\treturn \"datamodel.Kind_Map\"\n\t\t\t\tcase datamodel.Kind_List:\n\t\t\t\t\treturn \"datamodel.Kind_List\"\n\t\t\t\tcase datamodel.Kind_Null:\n\t\t\t\t\treturn \"datamodel.Kind_Null\"\n\t\t\t\tcase datamodel.Kind_Bool:\n\t\t\t\t\treturn \"datamodel.Kind_Bool\"\n\t\t\t\tcase datamodel.Kind_Int:\n\t\t\t\t\treturn \"datamodel.Kind_Int\"\n\t\t\t\tcase datamodel.Kind_Float:\n\t\t\t\t\treturn \"datamodel.Kind_Float\"\n\t\t\t\tcase datamodel.Kind_String:\n\t\t\t\t\treturn \"datamodel.Kind_String\"\n\t\t\t\tcase datamodel.Kind_Bytes:\n\t\t\t\t\treturn \"datamodel.Kind_Bytes\"\n\t\t\t\tcase datamodel.Kind_Link:\n\t\t\t\t\treturn \"datamodel.Kind_Link\"\n\t\t\t\tdefault:\n\t\t\t\t\tpanic(\"invalid enumeration value!\")\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"add\":   func(a, b int) int { return a + b },\n\t\t\t\"title\": func(s string) string { return strings.Title(s) }, //lint:ignore SA1019 cases.Title doesn't work for this\n\t\t}).\n\t\tParse(testutil.Dedent(tmplstr)))\n\tif err := tmpl.Execute(w, data); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// We really need to do some more composable stuff around here.\n// Generators should probably be carrying down their own doTemplate methods that curry customizations.\n// E.g., map generators would benefit hugely from being able to make a clause for \"entTypeStrung\", \"mTypeStrung\", etc.\n//\n// Open question: how exactly?  Should some of this stuff should be composed by:\n//   - composing template fragments;\n//   - amending the funcmap;\n//   - computing the whole result and injecting it as a string;\n//   - ... combinations of the above?\n// Adding to the complexity of the question is that sometimes we want to be\n//  doing composition inside the output (e.g. DRY by functions in the result,\n//   rather than by DRY'ing the templates).\n// Best practice to make this evolve nicely is not at all obvious to this author.\n//\n"
  },
  {
    "path": "schema/gen/go/testEngine_disabled_test.go",
    "content": "//go:build skipgenbehavtests || windows\n\npackage gengo\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\nfunc buildGennedCode(t *testing.T, prefix string, pkgName string) {\n\t// Emit a small file with a 'main' method.\n\t//  'go build' doesn't like it we're in a package called \"main\" and there isn't one\n\t//   (and at the same time, plugins demand that they be in a package called 'main',\n\t//    so 'pkgName' in practice is almost always \"main\").\n\t//  I dunno, friend.  I didn't write the rules.\n\tif pkgName == \"main\" {\n\t\twithFile(filepath.Join(tmpGenBuildDir, prefix, \"main.go\"), func(w io.Writer) {\n\t\t\tfmt.Fprintf(w, \"package %s\\n\\n\", pkgName)\n\t\t\tfmt.Fprintf(w, \"func main() {}\\n\")\n\t\t})\n\t}\n\n\t// If windows, remove all files in tmpGenBuildDir with the .exe extension so we don't get a \"already exists\" error\n\t// https://github.com/golang/go/issues/57039\n\tif runtime.GOOS == \"windows\" {\n\t\tfiles, err := filepath.Glob(filepath.Join(tmpGenBuildDir, prefix, \"*.exe\"))\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tfor _, file := range files {\n\t\t\tif err := os.Remove(file); err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Invoke 'go build' -- nothing fancy.\n\tfiles, err := filepath.Glob(filepath.Join(tmpGenBuildDir, prefix, \"*.go\"))\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\targs := []string{\"build\"}\n\targs = append(args, files...)\n\tcmd := exec.Command(\"go\", args...)\n\tcmd.Stdout = os.Stdout\n\tcmd.Stderr = os.Stderr\n\terr = cmd.Run()\n\tif err != nil {\n\t\tt.Fatalf(\"genned code failed to compile: %s\", err)\n\t}\n\n\tt.Skip(\"behavioral tests for generated code skipped: you used the 'skipgenbehavtests' build tag.\")\n}\n\nfunc fnPrototypeByName(prefix string) func(string) datamodel.NodePrototype {\n\treturn nil // unused\n}\n"
  },
  {
    "path": "schema/gen/go/testEngine_nocgo_test.go",
    "content": "//go:build !cgo && !skipgenbehavtests && !windows\n\n// Confession:\n// This build tag specification is NOT sufficient nor necessarily correct --\n// it's a vague approximation of what's present in the stdlib 'plugin' package.\n// It's also not at all a sure thing that cgo will actually *work* just\n// because a build tag hasn't explicitly stated that it *mayn't* -- cgo can\n// and will fail for environmental reasons at the point the compiler uses it.\n//\n// Ideally, there'd be a way to *ask* the plugin package if it's going to\n// work or not before we try to use it; unfortunately, at the time of writing,\n// it does not appear there is such an ability.\n//\n// If you run afoul of these build tags somehow (e.g., building plugins isn't\n// possible in your environment for some reason), use the 'skipgenbehavtests'\n// build tag to right yourself.  That's what it's there for.\n\npackage gengo\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\nfunc buildGennedCode(t *testing.T, prefix string, pkgName string) {\n\t// Emit a small file with a 'main' method.\n\t//  'go build' doesn't like it we're in a package called \"main\" and there isn't one\n\t//   (and at the same time, plugins demand that they be in a package called 'main',\n\t//    so 'pkgName' in practice is almost always \"main\").\n\t//  I dunno, friend.  I didn't write the rules.\n\tif pkgName == \"main\" {\n\t\twithFile(filepath.Join(tmpGenBuildDir, prefix, \"main.go\"), func(w io.Writer) {\n\t\t\tfmt.Fprintf(w, \"package %s\\n\\n\", pkgName)\n\t\t\tfmt.Fprintf(w, \"func main() {}\\n\")\n\t\t})\n\t}\n\n\t// Invoke 'go build' -- nothing fancy.\n\tfiles, err := filepath.Glob(filepath.Join(tmpGenBuildDir, prefix, \"*.go\"))\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\targs := []string{\"build\"}\n\targs = append(args, files...)\n\tcmd := exec.Command(\"go\", args...)\n\tcmd.Stdout = os.Stdout\n\tcmd.Stderr = os.Stderr\n\terr = cmd.Run()\n\tif err != nil {\n\t\tt.Fatalf(\"genned code failed to compile: %s\", err)\n\t}\n\n\tt.Skip(\"behavioral tests for generated code skipped: cgo is required for these tests\")\n}\n\nfunc fnPrototypeByName(prefix string) func(string) datamodel.NodePrototype {\n\treturn nil // unused\n}\n"
  },
  {
    "path": "schema/gen/go/testEngine_plugin_test.go",
    "content": "//go:build cgo && !skipgenbehavtests && !windows\n\npackage gengo\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"plugin\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\nfunc objPath(prefix string) string {\n\treturn filepath.Join(tmpGenBuildDir, prefix, \"obj.so\")\n}\n\nfunc buildGennedCode(t *testing.T, prefix string, _ string) {\n\t// Invoke `go build` with flags to create a plugin -- we'll be able to\n\t//  load into this plugin into this selfsame process momentarily.\n\t// Use globbing, because these are files outside our module.\n\tfiles, err := filepath.Glob(filepath.Join(tmpGenBuildDir, prefix, \"*.go\"))\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\targs := []string{\"build\", \"-o=\" + objPath(prefix), \"-buildmode=plugin\"}\n\targs = append(args, files...)\n\tcmd := exec.Command(\"go\", args...)\n\tcmd.Stdout = os.Stdout\n\tcmd.Stderr = os.Stderr\n\tif err := cmd.Run(); err != nil {\n\t\tt.Fatalf(\"genned code failed to compile: %s\", err)\n\t}\n}\n\nfunc fnPrototypeByName(prefix string) func(string) datamodel.NodePrototype {\n\tplg, err := plugin.Open(objPath(prefix))\n\tif err != nil {\n\t\tpanic(err) // Panic because if this was going to flunk, we expected it to flunk earlier when we ran 'go build'.\n\t}\n\tsym, err := plg.Lookup(\"GetPrototypeByName\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn sym.(func(string) datamodel.NodePrototype)\n}\n"
  },
  {
    "path": "schema/gen/go/testEngine_test.go",
    "content": "package gengo\n\nimport (\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nvar _ tests.Engine = (*genAndCompileEngine)(nil)\n\ntype genAndCompileEngine struct {\n\tsubtestName string\n\tprefix      string\n\n\tadjCfg AdjunctCfg\n\n\tprototypeByName func(string) datamodel.NodePrototype\n}\n\nvar tmpGenBuildDir = filepath.Join(os.TempDir(), \"test-go-ipld-prime-gengo\")\n\nfunc (e *genAndCompileEngine) Init(t *testing.T, ts schema.TypeSystem) {\n\t// Make directories for the package we're about to generate.\n\t// They will live in a temporary directory, usually\n\t// /tmp/test-go-ipld-prime-gengo on Linux. It can be removed at any time.\n\t// We don't by default because it's nicer to let go's builds of things cache.\n\t// If you change the names of types, though, you'll have garbage files leftover,\n\t// and that's currently a manual cleanup problem.  Sorry.\n\tdir := filepath.Join(tmpGenBuildDir, e.prefix)\n\tif err := os.MkdirAll(dir, 0755); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tpkgName := \"main\"\n\n\t// Generate... everything, really.\n\tGenerate(dir, pkgName, ts, &e.adjCfg)\n\n\t// Emit an exported top level function for getting NodePrototype.\n\t//  This part isn't necessary except for a special need we have with this plugin trick;\n\t//   normally, user code uses the `{pkgname}.Prototype.{TypeName}` constant (so-to-speak, anyway) to get a hold of NodePrototypes...\n\t//   but for plugins, we need a top-level exported symbol to grab ahold of, and we can't easily look through the `Prototype` value\n\t//    without an interface... so we generate this function to fit the bill instead.\n\twithFile(filepath.Join(dir, \"prototypeGetter.go\"), func(w io.Writer) {\n\t\tdoTemplate(`\n\t\t\tpackage `+pkgName+`\n\n\t\t\timport \"github.com/ipld/go-ipld-prime/datamodel\"\n\n\t\t\tfunc GetPrototypeByName(name string) datamodel.NodePrototype {\n\t\t\t\tswitch name {\n\t\t\t\t{{- range . }}\n\t\t\t\tcase \"{{ .Name }}\":\n\t\t\t\t\treturn _{{ . | TypeSymbol }}__Prototype{}\n\t\t\t\tcase \"{{ .Name }}.Repr\":\n\t\t\t\t\treturn _{{ . | TypeSymbol }}__ReprPrototype{}\n\t\t\t\t{{- end}}\n\t\t\t\tdefault:\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t`, w, &e.adjCfg, ts.GetTypes())\n\t})\n\n\t// Build the genned code.\n\t//  This will either make a plugin (which we can run behavioral tests on next!),\n\t//  or just build it quietly just to see if there are compile-time errors,\n\t//  depending on your build tags.\n\t// See 'HACKME_testing.md' for discussion.\n\tbuildGennedCode(t, e.prefix, pkgName)\n\n\te.prototypeByName = fnPrototypeByName(e.prefix)\n}\n\nfunc (e *genAndCompileEngine) PrototypeByName(name string) datamodel.NodePrototype {\n\treturn e.prototypeByName(name)\n}\n"
  },
  {
    "path": "schema/gen/go/testLinks_test.go",
    "content": "package gengo\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nfunc TestLinks(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tengine := &genAndCompileEngine{prefix: \"links\"}\n\ttests.SchemaTestLinks(t, engine)\n}\n"
  },
  {
    "path": "schema/gen/go/testLists_test.go",
    "content": "package gengo\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc TestListsContainingMaybe(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tfor _, engine := range []*genAndCompileEngine{\n\t\t{\n\t\t\tsubtestName: \"maybe-using-embed\",\n\t\t\tprefix:      \"lists-embed\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tmaybeUsesPtr: map[schema.TypeName]bool{\"String\": false},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tsubtestName: \"maybe-using-ptr\",\n\t\t\tprefix:      \"lists-mptr\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tmaybeUsesPtr: map[schema.TypeName]bool{\"String\": false},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(engine.subtestName, func(t *testing.T) {\n\t\t\ttests.SchemaTestListsContainingMaybe(t, engine)\n\t\t})\n\t}\n\n}\n\nfunc TestListsContainingLists(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tengine := &genAndCompileEngine{prefix: \"lists-of-lists\"}\n\ttests.SchemaTestListsContainingLists(t, engine)\n}\n"
  },
  {
    "path": "schema/gen/go/testMaps_test.go",
    "content": "package gengo\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc TestMapsContainingMaybe(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tfor _, engine := range []*genAndCompileEngine{\n\t\t{\n\t\t\tsubtestName: \"maybe-using-embed\",\n\t\t\tprefix:      \"maps-embed\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tmaybeUsesPtr: map[schema.TypeName]bool{\"String\": false},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tsubtestName: \"maybe-using-ptr\",\n\t\t\tprefix:      \"maps-mptr\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tmaybeUsesPtr: map[schema.TypeName]bool{\"String\": false},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(engine.subtestName, func(t *testing.T) {\n\t\t\ttests.SchemaTestMapsContainingMaybe(t, engine)\n\t\t})\n\t}\n}\n\nfunc TestMapsContainingMaps(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tengine := &genAndCompileEngine{prefix: \"maps-recursive\"}\n\ttests.SchemaTestMapsContainingMaps(t, engine)\n}\n\nfunc TestMapsWithComplexKeys(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tengine := &genAndCompileEngine{prefix: \"maps-cmplx-keys\"}\n\ttests.SchemaTestMapsWithComplexKeys(t, engine)\n}\n"
  },
  {
    "path": "schema/gen/go/testScalars_test.go",
    "content": "package gengo\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nfunc TestScalars(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tengine := &genAndCompileEngine{prefix: \"scalars\"}\n\ttests.SchemaTestScalars(t, engine)\n}\n"
  },
  {
    "path": "schema/gen/go/testStructReprStringjoin_test.go",
    "content": "package gengo\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nfunc TestStructReprStringjoin(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tengine := &genAndCompileEngine{prefix: \"struct-str-join\"}\n\ttests.SchemaTestStructReprStringjoin(t, engine)\n}\n"
  },
  {
    "path": "schema/gen/go/testStructReprTuple_test.go",
    "content": "package gengo\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nfunc TestStructReprTuple(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tengine := &genAndCompileEngine{prefix: \"struct-tuple\"}\n\ttests.SchemaTestStructReprTuple(t, engine)\n}\n"
  },
  {
    "path": "schema/gen/go/testStruct_test.go",
    "content": "package gengo\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n)\n\nfunc TestRequiredFields(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tengine := &genAndCompileEngine{prefix: \"struct-required-fields\"}\n\ttests.SchemaTestRequiredFields(t, engine)\n}\n"
  },
  {
    "path": "schema/gen/go/testStructsContainingMaybe_test.go",
    "content": "package gengo\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc TestStructsContainingMaybe(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tfor _, engine := range []*genAndCompileEngine{\n\t\t{\n\t\t\tsubtestName: \"maybe-using-embed\",\n\t\t\tprefix:      \"stroct\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tmaybeUsesPtr: map[schema.TypeName]bool{\"String\": false},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tsubtestName: \"maybe-using-ptr\",\n\t\t\tprefix:      \"stroct2\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tmaybeUsesPtr: map[schema.TypeName]bool{\"String\": false},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(engine.subtestName, func(t *testing.T) {\n\t\t\ttests.SchemaTestStructsContainingMaybe(t, engine)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "schema/gen/go/testUnionsKinded_test.go",
    "content": "package gengo\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc TestUnionKinded(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tfor _, engine := range []*genAndCompileEngine{\n\t\t{\n\t\t\tsubtestName: \"union-using-embed\",\n\t\t\tprefix:      \"union-kinded-using-embed\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tCfgUnionMemlayout: map[schema.TypeName]string{\"WheeUnion\": \"embedAll\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tsubtestName: \"union-using-interface\",\n\t\t\tprefix:      \"union-kinded-using-interface\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tCfgUnionMemlayout: map[schema.TypeName]string{\"WheeUnion\": \"interface\"},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(engine.subtestName, func(t *testing.T) {\n\t\t\ttests.SchemaTestUnionKinded(t, engine)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "schema/gen/go/testUnionsStringprefix_test.go",
    "content": "package gengo\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc TestUnionStringprefix(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tfor _, engine := range []*genAndCompileEngine{\n\t\t{\n\t\t\tsubtestName: \"union-using-embed\",\n\t\t\tprefix:      \"union-stringprefix-using-embed\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tCfgUnionMemlayout: map[schema.TypeName]string{\"WheeUnion\": \"embedAll\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tsubtestName: \"union-using-interface\",\n\t\t\tprefix:      \"union-stringprefix-using-interface\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tCfgUnionMemlayout: map[schema.TypeName]string{\"WheeUnion\": \"interface\"},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(engine.subtestName, func(t *testing.T) {\n\t\t\ttests.SchemaTestUnionStringprefix(t, engine)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "schema/gen/go/testUnions_test.go",
    "content": "package gengo\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/node/tests\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\nfunc TestUnionKeyed(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tfor _, engine := range []*genAndCompileEngine{\n\t\t{\n\t\t\tsubtestName: \"union-using-embed\",\n\t\t\tprefix:      \"union-keyed-using-embed\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tCfgUnionMemlayout: map[schema.TypeName]string{\"StrStr\": \"embedAll\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tsubtestName: \"union-using-ptr\",\n\t\t\tprefix:      \"union-keyed-using-interface\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tCfgUnionMemlayout: map[schema.TypeName]string{\"StrStr\": \"interface\"},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(engine.subtestName, func(t *testing.T) {\n\t\t\ttests.SchemaTestUnionKeyed(t, engine)\n\t\t})\n\t}\n}\n\nfunc TestUnionKeyedComplexChildren(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tfor _, engine := range []*genAndCompileEngine{\n\t\t{\n\t\t\tsubtestName: \"union-using-embed\",\n\t\t\tprefix:      \"union-keyed-complex-child-using-embed\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tCfgUnionMemlayout: map[schema.TypeName]string{\"WheeUnion\": \"embedAll\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tsubtestName: \"union-using-interface\",\n\t\t\tprefix:      \"union-keyed-complex-child-using-interface\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tCfgUnionMemlayout: map[schema.TypeName]string{\"WheeUnion\": \"interface\"},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(engine.subtestName, func(t *testing.T) {\n\t\t\ttests.SchemaTestUnionKeyedComplexChildren(t, engine)\n\t\t})\n\t}\n}\n\nfunc TestUnionKeyedReset(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" { // TODO: enable parallelism on macos\n\t\tt.Parallel()\n\t}\n\n\tfor _, engine := range []*genAndCompileEngine{\n\t\t{\n\t\t\tsubtestName: \"union-using-embed\",\n\t\t\tprefix:      \"union-keyed-reset-using-embed\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tCfgUnionMemlayout: map[schema.TypeName]string{\"WheeUnion\": \"embedAll\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tsubtestName: \"union-using-interface\",\n\t\t\tprefix:      \"union-keyed-reset-using-interface\",\n\t\t\tadjCfg: AdjunctCfg{\n\t\t\t\tCfgUnionMemlayout: map[schema.TypeName]string{\"WheeUnion\": \"interface\"},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(engine.subtestName, func(t *testing.T) {\n\t\t\ttests.SchemaTestUnionKeyedReset(t, engine)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "schema/kind.go",
    "content": "package schema\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// TypeKind is an enum of kind in the IPLD Schema system.\n//\n// Note that schema.TypeKind is distinct from datamodel.Kind!\n// Schema kinds include concepts such as \"struct\" and \"enum\", which are\n// concepts only introduced by the Schema layer, and not present in the\n// Data Model layer.\ntype TypeKind uint8\n\nconst (\n\tTypeKind_Invalid TypeKind = 0\n\tTypeKind_Map     TypeKind = '{'\n\tTypeKind_List    TypeKind = '['\n\tTypeKind_Unit    TypeKind = '1'\n\tTypeKind_Bool    TypeKind = 'b'\n\tTypeKind_Int     TypeKind = 'i'\n\tTypeKind_Float   TypeKind = 'f'\n\tTypeKind_String  TypeKind = 's'\n\tTypeKind_Bytes   TypeKind = 'x'\n\tTypeKind_Link    TypeKind = '/'\n\tTypeKind_Struct  TypeKind = '$'\n\tTypeKind_Union   TypeKind = '^'\n\tTypeKind_Enum    TypeKind = '%'\n\tTypeKind_Any     TypeKind = '?'\n)\n\nfunc (k TypeKind) String() string {\n\tswitch k {\n\tcase TypeKind_Invalid:\n\t\treturn \"invalid\"\n\tcase TypeKind_Map:\n\t\treturn \"map\"\n\tcase TypeKind_Any:\n\t\treturn \"any\"\n\tcase TypeKind_List:\n\t\treturn \"list\"\n\tcase TypeKind_Unit:\n\t\treturn \"unit\"\n\tcase TypeKind_Bool:\n\t\treturn \"bool\"\n\tcase TypeKind_Int:\n\t\treturn \"int\"\n\tcase TypeKind_Float:\n\t\treturn \"float\"\n\tcase TypeKind_String:\n\t\treturn \"string\"\n\tcase TypeKind_Bytes:\n\t\treturn \"bytes\"\n\tcase TypeKind_Link:\n\t\treturn \"link\"\n\tcase TypeKind_Struct:\n\t\treturn \"struct\"\n\tcase TypeKind_Union:\n\t\treturn \"union\"\n\tcase TypeKind_Enum:\n\t\treturn \"enum\"\n\tdefault:\n\t\tpanic(\"invalid enumeration value!\")\n\t}\n}\n\n// ActsLike returns a constant from the datamodel.Kind enum describing what\n// this schema.TypeKind acts like at the Data Model layer.\n//\n// Things with similar names are generally conserved\n// (e.g. \"map\" acts like \"map\");\n// concepts added by the schema layer have to be mapped onto something\n// (e.g. \"struct\" acts like \"map\").\n//\n// Note that this mapping describes how a typed Node will *act*, programmatically;\n// it does not necessarily describe how it will be *serialized*\n// (for example, a struct will always act like a map, even if it has a tuple\n// representation strategy and thus becomes a list when serialized).\nfunc (k TypeKind) ActsLike() datamodel.Kind {\n\tswitch k {\n\tcase TypeKind_Invalid:\n\t\treturn datamodel.Kind_Invalid\n\tcase TypeKind_Map:\n\t\treturn datamodel.Kind_Map\n\tcase TypeKind_List:\n\t\treturn datamodel.Kind_List\n\tcase TypeKind_Unit:\n\t\treturn datamodel.Kind_Bool // maps to 'true'.  // REVIEW: odd that this doesn't map to 'null'?  // TODO this should be standardized in the specs, in a table.\n\tcase TypeKind_Bool:\n\t\treturn datamodel.Kind_Bool\n\tcase TypeKind_Int:\n\t\treturn datamodel.Kind_Int\n\tcase TypeKind_Float:\n\t\treturn datamodel.Kind_Float\n\tcase TypeKind_String:\n\t\treturn datamodel.Kind_String\n\tcase TypeKind_Bytes:\n\t\treturn datamodel.Kind_Bytes\n\tcase TypeKind_Link:\n\t\treturn datamodel.Kind_Link\n\tcase TypeKind_Struct:\n\t\treturn datamodel.Kind_Map // clear enough: fields are keys.\n\tcase TypeKind_Union:\n\t\treturn datamodel.Kind_Map\n\tcase TypeKind_Enum:\n\t\treturn datamodel.Kind_String // 'AsString' is the one clear thing to define.\n\tcase TypeKind_Any:\n\t\treturn datamodel.Kind_Invalid // TODO: maybe ActsLike should return (Kind, bool)\n\tdefault:\n\t\tpanic(\"invalid enumeration value!\")\n\t}\n}\n"
  },
  {
    "path": "schema/maybe.go",
    "content": "package schema\n\ntype Maybe uint8\n\nconst (\n\tMaybe_Absent = Maybe(0)\n\tMaybe_Null   = Maybe(1)\n\tMaybe_Value  = Maybe(2)\n)\n"
  },
  {
    "path": "schema/tmpBuilders.go",
    "content": "package schema\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// Everything in this file is __a temporary hack__ and will be __removed__.\n//\n// These methods will only hang around until more of the \"ast\" packages are finished;\n// thereafter, building schema.Type and schema.TypeSystem values will only be\n// possible through first constructing a schema AST, and *then* using Reify(),\n// which will validate things correctly, cycle-check, cross-link, etc.\n//\n// (Meanwhile, we're using these methods in the codegen prototypes.)\n\n// These methods use Type objects as parameters when pointing to other things,\n//  but this is... turning out consistently problematic.\n//   Even when we're doing this hacky direct-call doesn't-need-to-be-serializable temp stuff,\n//    as written, this doesn't actually let us express cyclic things viably!\n//   The same initialization questions are also going to come up again when we try to make\n//    concrete values in the output of codegen.\n// Maybe it's actually just a bad idea to have our reified Type types use Type pointers at all.\n//  (I will never get tired of the tongue twisters, evidently.)\n//  I'm not actually using that much, and it's always avoidable (it's trivial to replace with a map lookup bouncing through a 'ts' variable somewhere).\n//  And having the AST gen'd types be... just... the thing... sounds nice.  It could save a lot of work.\n//   (It would mean the golang types don't tell you whether the values have been checked for global properties or not, but, eh.)\n//   (It's not really compatible with \"Prototype and Type are the same thing for codegen'd stuff\", either (or, we need more interfaces, and to *really* lean into them), but maybe that's okay.)\n\nfunc SpawnTypeSystem(types ...Type) (*TypeSystem, []error) {\n\tts := TypeSystem{}\n\tts.Init()\n\tfor _, typ := range types {\n\t\tts.Accumulate(typ)\n\t}\n\tif errs := ts.ValidateGraph(); errs != nil {\n\t\treturn nil, errs\n\t}\n\treturn &ts, nil\n}\nfunc MustTypeSystem(types ...Type) *TypeSystem {\n\tif ts, err := SpawnTypeSystem(types...); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\treturn ts\n\t}\n}\n\nfunc SpawnString(name TypeName) *TypeString {\n\treturn &TypeString{typeBase{name, nil}}\n}\n\nfunc SpawnBool(name TypeName) *TypeBool {\n\treturn &TypeBool{typeBase{name, nil}}\n}\n\nfunc SpawnInt(name TypeName) *TypeInt {\n\treturn &TypeInt{typeBase{name, nil}}\n}\n\nfunc SpawnFloat(name TypeName) *TypeFloat {\n\treturn &TypeFloat{typeBase{name, nil}}\n}\n\nfunc SpawnBytes(name TypeName) *TypeBytes {\n\treturn &TypeBytes{typeBase{name, nil}}\n}\n\nfunc SpawnLink(name TypeName) *TypeLink {\n\treturn &TypeLink{typeBase{name, nil}, \"\", false}\n}\n\nfunc SpawnLinkReference(name TypeName, pointsTo TypeName) *TypeLink {\n\treturn &TypeLink{typeBase{name, nil}, pointsTo, true}\n}\n\nfunc SpawnList(name TypeName, valueType TypeName, nullable bool) *TypeList {\n\treturn &TypeList{typeBase{name, nil}, false, valueType, nullable}\n}\n\nfunc SpawnMap(name TypeName, keyType TypeName, valueType TypeName, nullable bool) *TypeMap {\n\treturn &TypeMap{typeBase{name, nil}, false, keyType, valueType, nullable}\n}\n\nfunc SpawnAny(name TypeName) *TypeAny {\n\treturn &TypeAny{typeBase{name, nil}}\n}\n\nfunc SpawnStruct(name TypeName, fields []StructField, repr StructRepresentation) *TypeStruct {\n\tv := &TypeStruct{\n\t\ttypeBase{name, nil},\n\t\tfields,\n\t\tmake(map[string]StructField, len(fields)),\n\t\trepr,\n\t}\n\tfor i := range fields {\n\t\tfields[i].parent = v\n\t\tv.fieldsMap[fields[i].name] = fields[i]\n\t}\n\tswitch repr.(type) {\n\tcase StructRepresentation_Stringjoin:\n\t\tfor _, f := range fields {\n\t\t\tif f.IsMaybe() {\n\t\t\t\tpanic(\"neither nullable nor optional is supported on struct stringjoin representation\")\n\t\t\t}\n\t\t}\n\tcase nil:\n\t\tv.representation = SpawnStructRepresentationMap(nil)\n\t}\n\treturn v\n}\nfunc SpawnStructField(name string, typ TypeName, optional bool, nullable bool) StructField {\n\treturn StructField{nil /*populated later*/, name, typ, optional, nullable}\n}\nfunc SpawnStructRepresentationMap(renames map[string]string) StructRepresentation_Map {\n\treturn StructRepresentation_Map{renames, nil}\n}\nfunc SpawnStructRepresentationMap2(renames map[string]string, implicits map[string]ImplicitValue) StructRepresentation_Map {\n\treturn StructRepresentation_Map{renames, implicits}\n}\nfunc SpawnStructRepresentationTuple() StructRepresentation_Tuple {\n\treturn StructRepresentation_Tuple{}\n}\nfunc SpawnStructRepresentationListPairs() StructRepresentation_ListPairs {\n\treturn StructRepresentation_ListPairs{}\n}\nfunc SpawnStructRepresentationStringjoin(delim string) StructRepresentation_Stringjoin {\n\treturn StructRepresentation_Stringjoin{delim}\n}\n\nfunc SpawnUnion(name TypeName, members []TypeName, repr UnionRepresentation) *TypeUnion {\n\treturn &TypeUnion{typeBase{name, nil}, members, repr}\n}\nfunc SpawnUnionRepresentationKeyed(table map[string]TypeName) UnionRepresentation_Keyed {\n\treturn UnionRepresentation_Keyed{table}\n}\nfunc SpawnUnionRepresentationKinded(table map[datamodel.Kind]TypeName) UnionRepresentation_Kinded {\n\treturn UnionRepresentation_Kinded{table}\n}\nfunc SpawnUnionRepresentationStringprefix(delim string, table map[string]TypeName) UnionRepresentation_Stringprefix {\n\treturn UnionRepresentation_Stringprefix{delim, table}\n}\nfunc SpawnUnionRepresentationInline(discriminantKey string, table map[string]TypeName) UnionRepresentation_Inline {\n\treturn UnionRepresentation_Inline{discriminantKey, table}\n}\n\nfunc SpawnEnum(name TypeName, members []string, repr EnumRepresentation) *TypeEnum {\n\treturn &TypeEnum{typeBase{name, nil}, members, repr}\n}\n\n// Utility function adding default basic types to schema type system\nfunc SpawnDefaultBasicTypes(ts *TypeSystem) {\n\tts.Accumulate(SpawnBool(\"Bool\"))\n\tts.Accumulate(SpawnInt(\"Int\"))\n\tts.Accumulate(SpawnFloat(\"Float\"))\n\tts.Accumulate(SpawnString(\"String\"))\n\tts.Accumulate(SpawnBytes(\"Bytes\"))\n\n\tts.Accumulate(SpawnAny(\"Any\"))\n\n\tts.Accumulate(SpawnMap(\"Map\", \"String\", \"Any\", false))\n\tts.Accumulate(SpawnList(\"List\", \"Any\", false))\n\n\t// Should be &Any, really.\n\tts.Accumulate(SpawnLink(\"Link\"))\n\n\t// TODO: schema package lacks support?\n\t// ts.Accumulate(schema.SpawnUnit(\"Null\", NullRepr))\n}\n\n// Clone creates a copy of a type that is not in the original's universe (so it can be used elsewhere safely)\nfunc Clone(typ Type) Type {\n\tswitch kindedType := typ.(type) {\n\tcase *TypeBool:\n\t\treturn SpawnBool(kindedType.Name())\n\tcase *TypeString:\n\t\treturn SpawnString(kindedType.Name())\n\tcase *TypeBytes:\n\t\treturn SpawnBytes(kindedType.Name())\n\tcase *TypeInt:\n\t\treturn SpawnInt(kindedType.Name())\n\tcase *TypeFloat:\n\t\treturn SpawnFloat(kindedType.Name())\n\tcase *TypeAny:\n\t\treturn SpawnAny(kindedType.Name())\n\tcase *TypeMap:\n\t\treturn SpawnMap(kindedType.Name(),\n\t\t\tkindedType.KeyType().Name(),\n\t\t\tkindedType.ValueType().Name(),\n\t\t\tkindedType.ValueIsNullable())\n\tcase *TypeList:\n\t\treturn SpawnList(kindedType.Name(), kindedType.ValueType().Name(), kindedType.ValueIsNullable())\n\tcase *TypeLink:\n\t\tif kindedType.HasReferencedType() {\n\t\t\treturn SpawnLinkReference(kindedType.Name(), kindedType.ReferencedType().Name())\n\t\t} else {\n\t\t\treturn SpawnLink(kindedType.Name())\n\t\t}\n\tcase *TypeUnion:\n\t\tmembers := kindedType.Members()\n\t\tmemberNames := make([]TypeName, 0, len(members))\n\t\tfor _, member := range members {\n\t\t\tmemberNames = append(memberNames, member.Name())\n\t\t}\n\t\treturn SpawnUnion(kindedType.Name(), memberNames, kindedType.RepresentationStrategy())\n\tcase *TypeStruct:\n\t\toldFields := kindedType.Fields()\n\t\tnewFields := make([]StructField, 0, len(oldFields))\n\t\tfor _, oldField := range oldFields {\n\t\t\tnewFields = append(newFields, SpawnStructField(oldField.Name(), oldField.Type().Name(), oldField.IsOptional(), oldField.IsNullable()))\n\t\t}\n\t\treturn SpawnStruct(kindedType.Name(), newFields, kindedType.RepresentationStrategy())\n\tcase *TypeEnum:\n\t\treturn SpawnEnum(kindedType.Name(), kindedType.Members(), kindedType.RepresentationStrategy())\n\tdefault:\n\t\tpanic(\"unexpected type, don't know how to clone\")\n\t}\n}\n\nfunc MergeTypeSystem(target *TypeSystem, source *TypeSystem, ignoreDups bool) {\n\tfor _, name := range source.Names() {\n\t\ttyp := Clone(source.TypeByName(name))\n\t\tif ignoreDups {\n\t\t\taccumulateWithRecovery(target, typ)\n\t\t} else {\n\t\t\ttarget.Accumulate(typ)\n\t\t}\n\t}\n}\n\nfunc accumulateWithRecovery(ts *TypeSystem, typ Type) {\n\tdefer func() {\n\t\t_ = recover()\n\t}()\n\tts.Accumulate(typ)\n}\n\n// The methods relating to TypeSystem are also mutation-heavy and placeholdery.\n\nfunc (ts *TypeSystem) Init() {\n\tts.namedTypes = make(map[TypeName]Type)\n}\nfunc (ts *TypeSystem) Accumulate(typ Type) {\n\ttyp._Type(ts)\n\tname := typ.Name()\n\tif _, ok := ts.namedTypes[name]; ok {\n\t\tpanic(fmt.Sprintf(\"duplicate type name: %s\", name))\n\t}\n\tts.namedTypes[name] = typ\n\tts.names = append(ts.names, name)\n}\nfunc (ts TypeSystem) GetTypes() map[TypeName]Type {\n\treturn ts.namedTypes\n}\nfunc (ts TypeSystem) TypeByName(n string) Type {\n\treturn ts.namedTypes[n]\n}\nfunc (ts TypeSystem) Names() []TypeName {\n\treturn ts.names\n}\n\n// ValidateGraph checks that all type names referenced are defined.\n//\n// It does not do any other validations of individual type's sensibleness\n// (that should've happened when they were created\n// (although also note many of those validates are NYI,\n// and are roadmapped for after we research self-hosting)).\nfunc (ts TypeSystem) ValidateGraph() []error {\n\tvar ee []error\n\tfor tn, t := range ts.namedTypes {\n\t\tswitch t2 := t.(type) {\n\t\tcase *TypeBool,\n\t\t\t*TypeInt,\n\t\t\t*TypeFloat,\n\t\t\t*TypeString,\n\t\t\t*TypeBytes,\n\t\t\t*TypeEnum:\n\t\t\tcontinue // nothing to check: these are leaf nodes and refer to no other types.\n\t\tcase *TypeLink:\n\t\t\tif !t2.hasReferencedType {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif _, ok := ts.namedTypes[t2.referencedType]; !ok {\n\t\t\t\tee = append(ee, fmt.Errorf(\"type %s refers to missing type %s (as link reference type)\", tn, t2.referencedType))\n\t\t\t}\n\t\tcase *TypeStruct:\n\t\t\tfor _, f := range t2.fields {\n\t\t\t\tif _, ok := ts.namedTypes[f.typ]; !ok {\n\t\t\t\t\tee = append(ee, fmt.Errorf(\"type %s refers to missing type %s (in field %q)\", tn, f.typ, f.name))\n\t\t\t\t}\n\t\t\t}\n\t\tcase *TypeMap:\n\t\t\tif _, ok := ts.namedTypes[t2.keyType]; !ok {\n\t\t\t\tee = append(ee, fmt.Errorf(\"type %s refers to missing type %s (as key type)\", tn, t2.keyType))\n\t\t\t}\n\t\t\tif _, ok := ts.namedTypes[t2.valueType]; !ok {\n\t\t\t\tee = append(ee, fmt.Errorf(\"type %s refers to missing type %s (as value type)\", tn, t2.valueType))\n\t\t\t}\n\t\tcase *TypeList:\n\t\t\tif _, ok := ts.namedTypes[t2.valueType]; !ok {\n\t\t\t\tee = append(ee, fmt.Errorf(\"type %s refers to missing type %s (as value type)\", tn, t2.valueType))\n\t\t\t}\n\t\tcase *TypeUnion:\n\t\t\tfor _, mn := range t2.members {\n\t\t\t\tif _, ok := ts.namedTypes[mn]; !ok {\n\t\t\t\t\tee = append(ee, fmt.Errorf(\"type %s refers to missing type %s (as a member)\", tn, mn))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn ee\n}\n"
  },
  {
    "path": "schema/type.go",
    "content": "package schema\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\ntype TypeName = string\n\n// typesystem.Type is an union interface; each of the `Type*` concrete types\n// in this package are one of its members.\n//\n// Specifically,\n//\n//\tTypeBool\n//\tTypeString\n//\tTypeBytes\n//\tTypeInt\n//\tTypeFloat\n//\tTypeMap\n//\tTypeList\n//\tTypeLink\n//\tTypeUnion\n//\tTypeStruct\n//\tTypeEnum\n//\n// are all of the kinds of Type.\n//\n// This is a closed union; you can switch upon the above members without\n// including a default case.  The membership is closed by the unexported\n// '_Type' method; you may use the BurntSushi/go-sumtype tool to check\n// your switches for completeness.\n//\n// Many interesting properties of each Type are only defined for that specific\n// type, so it's typical to use a type switch to handle each type of Type.\n// (Your humble author is truly sorry for the word-mash that results from\n// attempting to describe the types that describe the typesystem.Type.)\n//\n// For example, to inspect the kind of fields in a struct: you might\n// cast a `Type` interface into `TypeStruct`, and then the `Fields()` on\n// that `TypeStruct` can be inspected.  (`Fields()` isn't defined for any\n// other kind of Type.)\ntype Type interface {\n\t// Unexported marker method to force the union closed.\n\t// Also used to set the internal pointer back to the universe its part of.\n\t_Type(*TypeSystem)\n\n\t// Returns a pointer to the TypeSystem this Type is a member of.\n\tTypeSystem() *TypeSystem\n\n\t// Returns the string name of the Type.  This name is unique within the\n\t// universe this type is a member of, *unless* this type is Anonymous,\n\t// in which case a string describing the type will still be returned, but\n\t// that string will not be required to be unique.\n\tName() TypeName\n\n\t// Returns the TypeKind of this Type.\n\t//\n\t// The returned value is a 1:1 association with which of the concrete\n\t// \"schema.Type*\" structs this interface can be cast to.\n\t//\n\t// Note that a schema.TypeKind is a different enum than datamodel.Kind;\n\t// and furthermore, there's no strict relationship between them.\n\t// schema.TypedNode values can be described by *two* distinct Kinds:\n\t// one which describes how the Node itself will act,\n\t// and another which describes how the Node presents for serialization.\n\t// For some combinations of Type and representation strategy, one or both\n\t// of the Kinds can be determined statically; but not always:\n\t// it can sometimes be necessary to inspect the value quite concretely\n\t// (e.g., `schema.TypedNode{}.Representation().Kind()`) in order to find\n\t// out exactly how a node will be serialized!  This is because some types\n\t// can vary in representation kind based on their value (specifically,\n\t// kinded-representation unions have this property).\n\tTypeKind() TypeKind\n\n\t// RepresentationBehavior returns a description of how the representation\n\t// of this type will behave in terms of the IPLD Data Model.\n\t// This property varies based on the representation strategy of a type.\n\t//\n\t// In one case, the representation behavior cannot be known statically,\n\t// and varies based on the data: kinded unions have this trait.\n\t//\n\t// This property is used by kinded unions, which require that their members\n\t// all have distinct representation behavior.\n\t// (It follows that a kinded union cannot have another kinded union as a member.)\n\t//\n\t// You may also be interested in a related property that might have been called \"TypeBehavior\".\n\t// However, this method doesn't exist, because it's a deterministic property of `TypeKind()`!\n\t// You can use `TypeKind.ActsLike()` to get type-level behavioral information.\n\tRepresentationBehavior() datamodel.Kind\n}\n\nvar (\n\t_ Type = &TypeBool{}\n\t_ Type = &TypeString{}\n\t_ Type = &TypeBytes{}\n\t_ Type = &TypeInt{}\n\t_ Type = &TypeFloat{}\n\t_ Type = &TypeAny{}\n\t_ Type = &TypeMap{}\n\t_ Type = &TypeList{}\n\t_ Type = &TypeLink{}\n\t_ Type = &TypeUnion{}\n\t_ Type = &TypeStruct{}\n\t_ Type = &TypeEnum{}\n)\n\ntype typeBase struct {\n\tname     TypeName\n\tuniverse *TypeSystem\n}\n\ntype TypeBool struct {\n\ttypeBase\n}\n\ntype TypeString struct {\n\ttypeBase\n}\n\ntype TypeBytes struct {\n\ttypeBase\n}\n\ntype TypeInt struct {\n\ttypeBase\n}\n\ntype TypeFloat struct {\n\ttypeBase\n}\n\ntype TypeAny struct {\n\ttypeBase\n}\n\ntype TypeMap struct {\n\ttypeBase\n\tanonymous     bool\n\tkeyType       TypeName // must be Kind==string (e.g. Type==String|Enum).\n\tvalueType     TypeName\n\tvalueNullable bool\n}\n\ntype TypeList struct {\n\ttypeBase\n\tanonymous     bool\n\tvalueType     TypeName\n\tvalueNullable bool\n}\n\ntype TypeLink struct {\n\ttypeBase\n\treferencedType    TypeName\n\thasReferencedType bool\n\t// ...?\n}\n\ntype TypeUnion struct {\n\ttypeBase\n\t// Members are listed in the order they appear in the schema.\n\t// To find the discriminant info, you must look inside the representation; they all contain a 'table' of some kind in which the member types are the values.\n\t// Note that multiple appearances of the same type as distinct members of the union is not possible.\n\t//  While we could do this... A: that's... odd, and nearly never called for; B: not possible with kinded mode; C: imagine the golang-native type switch!  it's impossible.\n\t//  We rely on this clarity in many ways: most visibly, the type-level Node implementation for a union always uses the type names as if they were map keys!  This behavior is consistent for all union representations.\n\tmembers        []TypeName\n\trepresentation UnionRepresentation\n}\n\ntype UnionRepresentation interface{ _UnionRepresentation() }\n\nfunc (UnionRepresentation_Keyed) _UnionRepresentation()        {}\nfunc (UnionRepresentation_Kinded) _UnionRepresentation()       {}\nfunc (UnionRepresentation_Envelope) _UnionRepresentation()     {}\nfunc (UnionRepresentation_Inline) _UnionRepresentation()       {}\nfunc (UnionRepresentation_Stringprefix) _UnionRepresentation() {}\n\n// A bunch of these tables in union representation might be easier to use if flipped;\n//  we almost always index into them by type (since that's what we have an ordered list of);\n//  and they're unique in both directions, so it's equally valid either way.\n//  The order they're currently written in matches the serial form in the schema AST.\n\ntype UnionRepresentation_Keyed struct {\n\ttable map[string]TypeName // key is user-defined freetext\n}\ntype UnionRepresentation_Kinded struct {\n\ttable map[datamodel.Kind]TypeName\n}\n\n//lint:ignore U1000 implementation TODO\ntype UnionRepresentation_Envelope struct {\n\tdiscriminantKey string\n\tcontentKey      string\n\ttable           map[string]TypeName // key is user-defined freetext\n}\n\n//lint:ignore U1000 implementation TODO\ntype UnionRepresentation_Inline struct {\n\tdiscriminantKey string\n\ttable           map[string]TypeName // key is user-defined freetext\n}\ntype UnionRepresentation_Stringprefix struct {\n\tdelim string\n\ttable map[string]TypeName // key is user-defined freetext\n}\n\ntype TypeStruct struct {\n\ttypeBase\n\t// n.b. `Fields` is an (order-preserving!) map in the schema-schema;\n\t//  but it's a list here, with the keys denormalized into the value,\n\t//   because that's typically how we use it.\n\tfields         []StructField\n\tfieldsMap      map[string]StructField // same content, indexed for lookup.\n\trepresentation StructRepresentation\n}\ntype StructField struct {\n\tparent   *TypeStruct\n\tname     string\n\ttyp      TypeName\n\toptional bool\n\tnullable bool\n}\n\ntype StructRepresentation interface{ _StructRepresentation() }\n\nfunc (StructRepresentation_Map) _StructRepresentation()         {}\nfunc (StructRepresentation_Tuple) _StructRepresentation()       {}\nfunc (StructRepresentation_ListPairs) _StructRepresentation()   {}\nfunc (StructRepresentation_StringPairs) _StructRepresentation() {}\nfunc (StructRepresentation_Stringjoin) _StructRepresentation()  {}\n\ntype StructRepresentation_Map struct {\n\trenames   map[string]string\n\timplicits map[string]ImplicitValue\n}\ntype StructRepresentation_Tuple struct{}\ntype StructRepresentation_ListPairs struct{}\n\n//lint:ignore U1000 implementation TODO\ntype StructRepresentation_StringPairs struct{ sep1, sep2 string }\ntype StructRepresentation_Stringjoin struct{ sep string }\n\ntype TypeEnum struct {\n\ttypeBase\n\tmembers        []string\n\trepresentation EnumRepresentation\n}\n\ntype EnumRepresentation interface{ _EnumRepresentation() }\n\nfunc (EnumRepresentation_String) _EnumRepresentation() {}\nfunc (EnumRepresentation_Int) _EnumRepresentation()    {}\n\ntype EnumRepresentation_String map[string]string\ntype EnumRepresentation_Int map[string]int\n\n// ImplicitValue is an sum type holding values that are implicits.\n// It's not an 'Any' value because it can't be recursive\n// (or to be slightly more specific, it can be one of the recursive kinds,\n// but if so, only its empty value is valid here).\ntype ImplicitValue interface{ _ImplicitValue() }\n\nfunc (ImplicitValue_EmptyList) _ImplicitValue() {}\nfunc (ImplicitValue_EmptyMap) _ImplicitValue()  {}\nfunc (ImplicitValue_String) _ImplicitValue()    {}\nfunc (ImplicitValue_Int) _ImplicitValue()       {}\nfunc (ImplicitValue_Bool) _ImplicitValue()      {}\n\ntype ImplicitValue_EmptyList struct{}\ntype ImplicitValue_EmptyMap struct{}\ntype ImplicitValue_String string\ntype ImplicitValue_Int int\ntype ImplicitValue_Bool bool\n"
  },
  {
    "path": "schema/typeMethods.go",
    "content": "package schema\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n/* cookie-cutter standard interface stuff */\n\nfunc (t *typeBase) _Type(ts *TypeSystem) {\n\tt.universe = ts\n}\nfunc (t typeBase) TypeSystem() *TypeSystem { return t.universe }\nfunc (t typeBase) Name() TypeName          { return t.name }\n\nfunc (TypeBool) TypeKind() TypeKind   { return TypeKind_Bool }\nfunc (TypeString) TypeKind() TypeKind { return TypeKind_String }\nfunc (TypeBytes) TypeKind() TypeKind  { return TypeKind_Bytes }\nfunc (TypeInt) TypeKind() TypeKind    { return TypeKind_Int }\nfunc (TypeFloat) TypeKind() TypeKind  { return TypeKind_Float }\nfunc (TypeAny) TypeKind() TypeKind    { return TypeKind_Any }\nfunc (TypeMap) TypeKind() TypeKind    { return TypeKind_Map }\nfunc (TypeList) TypeKind() TypeKind   { return TypeKind_List }\nfunc (TypeLink) TypeKind() TypeKind   { return TypeKind_Link }\nfunc (TypeUnion) TypeKind() TypeKind  { return TypeKind_Union }\nfunc (TypeStruct) TypeKind() TypeKind { return TypeKind_Struct }\nfunc (TypeEnum) TypeKind() TypeKind   { return TypeKind_Enum }\n\nfunc (TypeBool) RepresentationBehavior() datamodel.Kind   { return datamodel.Kind_Bool }\nfunc (TypeString) RepresentationBehavior() datamodel.Kind { return datamodel.Kind_String }\nfunc (TypeBytes) RepresentationBehavior() datamodel.Kind  { return datamodel.Kind_Bytes }\nfunc (TypeInt) RepresentationBehavior() datamodel.Kind    { return datamodel.Kind_Int }\nfunc (TypeFloat) RepresentationBehavior() datamodel.Kind  { return datamodel.Kind_Float }\nfunc (TypeMap) RepresentationBehavior() datamodel.Kind    { return datamodel.Kind_Map }\nfunc (TypeList) RepresentationBehavior() datamodel.Kind   { return datamodel.Kind_List }\nfunc (TypeLink) RepresentationBehavior() datamodel.Kind   { return datamodel.Kind_Link }\nfunc (t TypeUnion) RepresentationBehavior() datamodel.Kind {\n\tswitch t.representation.(type) {\n\tcase UnionRepresentation_Keyed:\n\t\treturn datamodel.Kind_Map\n\tcase UnionRepresentation_Kinded:\n\t\treturn datamodel.Kind_Invalid // you can't know with this one, until you see the value (and thus can its inhabitant's behavior)!\n\tcase UnionRepresentation_Envelope:\n\t\treturn datamodel.Kind_Map\n\tcase UnionRepresentation_Inline:\n\t\treturn datamodel.Kind_Map\n\tcase UnionRepresentation_Stringprefix:\n\t\treturn datamodel.Kind_String\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (t TypeStruct) RepresentationBehavior() datamodel.Kind {\n\tswitch t.representation.(type) {\n\tcase StructRepresentation_Map:\n\t\treturn datamodel.Kind_Map\n\tcase StructRepresentation_Tuple:\n\t\treturn datamodel.Kind_List\n\tcase StructRepresentation_ListPairs:\n\t\treturn datamodel.Kind_List\n\tcase StructRepresentation_StringPairs:\n\t\treturn datamodel.Kind_String\n\tcase StructRepresentation_Stringjoin:\n\t\treturn datamodel.Kind_String\n\tdefault:\n\t\tpanic(\"unreachable\")\n\t}\n}\nfunc (t TypeEnum) RepresentationBehavior() datamodel.Kind {\n\t// TODO: this should have a representation strategy switch too; sometimes that will indicate int representation behavior.\n\treturn datamodel.Kind_String\n}\nfunc (t TypeAny) RepresentationBehavior() datamodel.Kind {\n\treturn datamodel.Kind_Invalid // TODO: what can we possibly do here?\n}\n\n/* interesting methods per Type type */\n\n// beware: many of these methods will change when we successfully bootstrap self-hosting.\n//\n// The current methods return reified Type objects; in the future, there might be less of that.\n// Returning reified Type objects requires bouncing lookups through the typesystem map;\n// this is unavoidable because we need to handle cycles in definitions.\n// However, the extra (and cyclic) pointers that requires won't necessarily jive well if\n// we remake the Type types to have close resemblances to the Data Model tree data.)\n//\n// It's also unfortunate that some of the current methods collide in name with\n// the names of the Data Model fields.  We might reshuffling things to reduce this.\n//\n// At any rate, all of these changes will come as a sweep once we\n// get a self-hosting gen of the schema-schema, not before\n// (the effort of updating template references is substantial).\n\n// IsAnonymous is returns true if the type was unnamed.  Unnamed types will\n// claim to have a Name property like `{Foo:Bar}`, and this is not guaranteed\n// to be a unique string for all types in the universe.\nfunc (t TypeMap) IsAnonymous() bool {\n\treturn t.anonymous\n}\n\n// KeyType returns the Type of the map keys.\n//\n// Note that map keys will must always be some type which is representable as a\n// string in the IPLD Data Model (e.g. either TypeString or TypeEnum).\nfunc (t TypeMap) KeyType() Type {\n\treturn t.universe.namedTypes[t.keyType]\n}\n\n// ValueType returns the Type of the map values.\nfunc (t TypeMap) ValueType() Type {\n\treturn t.universe.namedTypes[t.valueType]\n}\n\n// ValueIsNullable returns a bool describing if the map values are permitted\n// to be null.\nfunc (t TypeMap) ValueIsNullable() bool {\n\treturn t.valueNullable\n}\n\n// IsAnonymous is returns true if the type was unnamed.  Unnamed types will\n// claim to have a Name property like `[Foo]`, and this is not guaranteed\n// to be a unique string for all types in the universe.\nfunc (t TypeList) IsAnonymous() bool {\n\treturn t.anonymous\n}\n\n// ValueType returns to the Type of the list values.\nfunc (t TypeList) ValueType() Type {\n\treturn t.universe.namedTypes[t.valueType]\n}\n\n// ValueIsNullable returns a bool describing if the list values are permitted\n// to be null.\nfunc (t TypeList) ValueIsNullable() bool {\n\treturn t.valueNullable\n}\n\n// Members returns the list of all types that are possible inhabitants of this union.\nfunc (t TypeUnion) Members() []Type {\n\ta := make([]Type, len(t.members))\n\tfor i := range t.members {\n\t\ta[i] = t.universe.namedTypes[t.members[i]]\n\t}\n\treturn a\n}\n\nfunc (t TypeUnion) RepresentationStrategy() UnionRepresentation {\n\treturn t.representation\n}\n\nfunc (r UnionRepresentation_Keyed) GetDiscriminant(t Type) string {\n\tfor d, t2 := range r.table {\n\t\tif t2 == t.Name() {\n\t\t\treturn d\n\t\t}\n\t}\n\tpanic(\"that type isn't a member of this union\")\n}\n\nfunc (r UnionRepresentation_Stringprefix) GetDelim() string {\n\treturn r.delim\n}\n\nfunc (r UnionRepresentation_Stringprefix) GetDiscriminant(t Type) string {\n\tfor d, t2 := range r.table {\n\t\tif t2 == t.Name() {\n\t\t\treturn d\n\t\t}\n\t}\n\tpanic(\"that type isn't a member of this union\")\n}\n\n// GetMember returns type info for the member matching the kind argument,\n// or may return nil if that kind is not mapped to a member of this union.\nfunc (r UnionRepresentation_Kinded) GetMember(k datamodel.Kind) TypeName {\n\treturn r.table[k]\n}\n\n// Fields returns a slice of descriptions of the object's fields.\nfunc (t TypeStruct) Fields() []StructField {\n\treturn t.fields\n}\n\n// Field looks up a StructField by name, or returns nil if no such field.\nfunc (t TypeStruct) Field(name string) *StructField {\n\tif v, ok := t.fieldsMap[name]; ok {\n\t\treturn &v\n\t}\n\treturn nil\n}\n\n// Parent returns the type information that this field describes a part of.\n//\n// While in many cases, you may know the parent already from context,\n// there may still be situations where want to pass around a field and\n// not need to continue passing down the parent type with it; this method\n// helps your code be less redundant in such a situation.\n// (You'll find this useful for looking up any rename directives, for example,\n// when holding onto a field, since that requires looking up information from\n// the representation strategy, which is a property of the type as a whole.)\nfunc (f StructField) Parent() *TypeStruct { return f.parent }\n\n// Name returns the string name of this field.  The name is the string that\n// will be used as a map key if the structure this field is a member of is\n// serialized as a map representation.\nfunc (f StructField) Name() string { return f.name }\n\n// Type returns the Type of this field's value.  Note the field may\n// also be unset if it is either Optional or Nullable.\nfunc (f StructField) Type() Type { return f.parent.universe.namedTypes[f.typ] }\n\n// IsOptional returns true if the field is allowed to be absent from the object.\n// If IsOptional is false, the field may be absent from the serial representation\n// of the object entirely.\n//\n// Note being optional is different than saying the value is permitted to be null!\n// A field may be both nullable and optional simultaneously, or either, or neither.\nfunc (f StructField) IsOptional() bool { return f.optional }\n\n// IsNullable returns true if the field value is allowed to be null.\n//\n// If is Nullable is false, note that it's still possible that the field value\n// will be absent if the field is Optional!  Being nullable is unrelated to\n// whether the field's presence is optional as a whole.\n//\n// Note that a field may be both nullable and optional simultaneously,\n// or either, or neither.\nfunc (f StructField) IsNullable() bool { return f.nullable }\n\n// IsMaybe returns true if the field value is allowed to be either null or absent.\n//\n// This is a simple \"or\" of the two properties,\n// but this method is a shorthand that turns out useful often.\nfunc (f StructField) IsMaybe() bool { return f.nullable || f.optional }\n\nfunc (t TypeStruct) RepresentationStrategy() StructRepresentation {\n\treturn t.representation\n}\n\nfunc (r StructRepresentation_Map) GetFieldKey(field StructField) string {\n\tif n, ok := r.renames[field.name]; ok {\n\t\treturn n\n\t}\n\treturn field.name\n}\n\nfunc (r StructRepresentation_Map) FieldHasRename(field StructField) bool {\n\t_, ok := r.renames[field.name]\n\treturn ok\n}\n\n// FieldImplicit returns the 'implicit' value for a field, or nil, if there isn't one.\n//\n// Because this returns the golang ImplicitValue type, which is an interface,\n// golang type switching is needed to distinguish what it holds.\n// (In other words, be warned that this function is not very friendly to use from templating engines.)\nfunc (r StructRepresentation_Map) FieldImplicit(field StructField) ImplicitValue {\n\tif r.implicits == nil {\n\t\treturn nil\n\t}\n\treturn r.implicits[field.name]\n}\n\nfunc (r StructRepresentation_Stringjoin) GetDelim() string {\n\treturn r.sep\n}\n\n// Members returns a slice the strings which are valid inhabitants of this enum.\nfunc (t TypeEnum) Members() []string {\n\treturn t.members\n}\n\nfunc (t TypeEnum) RepresentationStrategy() EnumRepresentation {\n\treturn t.representation\n}\n\n// Links can keep a referenced type, which is a hint only about the data on the\n// other side of the link, no something that can be explicitly validated without\n// loading the link\n\n// HasReferencedType returns true if the link has a hint about the type it references\n// false if it's generic\nfunc (t TypeLink) HasReferencedType() bool {\n\treturn t.hasReferencedType\n}\n\n// ReferencedType returns the type hint for the node on the other side of the link\nfunc (t TypeLink) ReferencedType() Type {\n\treturn t.universe.namedTypes[t.referencedType]\n}\n"
  },
  {
    "path": "schema/typedNode.go",
    "content": "package schema\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// schema.TypedNode is a superset of the datamodel.Node interface, and has additional behaviors.\n//\n// A schema.TypedNode can be inspected for its schema.Type and schema.TypeKind,\n// which conveys much more and richer information than the Data Model layer\n// datamodel.Kind.\n//\n// There are many different implementations of schema.TypedNode.\n// One implementation can wrap any other existing datamodel.Node (i.e., it's zero-copy)\n// and promises that it has *already* been validated to match the typesystem.Type;\n// another implementation similarly wraps any other existing datamodel.Node, but\n// defers to the typesystem validation checking to fields that are accessed;\n// and when using code generation tools, all of the generated native Golang\n// types produced by the codegen will each individually implement schema.TypedNode.\n//\n// Typed nodes sometimes have slightly different behaviors than plain nodes:\n// For example, when looking up fields on a typed node that's a struct,\n// the error returned for a lookup with a key that's not a field name will\n// be ErrNoSuchField (instead of ErrNotExists).\n// These behaviors apply to the schema.TypedNode only and not their representations;\n// continuing the example, the .Representation().LookupByString() method on\n// that same node for the same key as plain `.LookupByString()` will still\n// return ErrNotExists, because the representation isn't a schema.TypedNode!\ntype TypedNode interface {\n\t// schema.TypedNode acts just like a regular Node for almost all purposes;\n\t// which datamodel.Kind it acts as is determined by the TypeKind.\n\t// (Note that the representation strategy of the type does *not* affect\n\t// the Kind of schema.TypedNode -- rather, the representation strategy\n\t// affects the `.Representation().Kind()`.)\n\t//\n\t// For example: if the `.Type().TypeKind()` of this node is \"struct\",\n\t// it will act like Kind() == \"map\"\n\t// (even if Type().(Struct).ReprStrategy() is \"tuple\").\n\tdatamodel.Node\n\n\t// Type returns a reference to the reified schema.Type value.\n\tType() Type\n\n\t// Representation returns a datamodel.Node which sees the data in this node\n\t// in its representation form.\n\t//\n\t// For example: if the `.Type().TypeKind()` of this node is \"struct\",\n\t// `.Representation().TypeKind()` may vary based on its representation strategy:\n\t// if the representation strategy is \"map\", then it will be Kind==\"map\";\n\t// if the streatgy is \"tuple\", then it will be Kind==\"list\".\n\tRepresentation() datamodel.Node\n}\n\n// schema.TypedLinkNode is a superset of the schema.TypedNode interface, and has one additional behavior.\n//\n// A schema.TypedLinkNode contains a hint for the appropriate node builder to use for loading data\n// on the other side of the link contained within the node, so that it can be assembled\n// into a node representation and validated against the schema as quickly as possible\n//\n// So, for example, if you wanted to support loading the other side of a link\n// with a code-gen'd node builder while utilizing the automatic loading facilities\n// of the traversal package, you could write a LinkNodeBuilderChooser as follows:\n//\n//\tfunc LinkNodeBuilderChooser(lnk datamodel.Link, lnkCtx linking.LinkContext) datamodel.NodePrototype {\n//\t\tif tlnkNd, ok := lnkCtx.LinkNode.(schema.TypedLinkNode); ok {\n//\t\t\treturn tlnkNd.LinkTargetNodePrototype()\n//\t\t}\n//\t\treturn basicnode.Prototype.Any\n//\t}\ntype TypedLinkNode interface {\n\tLinkTargetNodePrototype() datamodel.NodePrototype\n}\n\n// TypedPrototype is a superset of the datamodel.Nodeprototype interface, and has\n// additional behaviors, much like TypedNode for datamodel.Node.\ntype TypedPrototype interface {\n\tdatamodel.NodePrototype\n\n\t// Type returns a reference to the reified schema.Type value.\n\tType() Type\n\n\t// Representation returns a datamodel.NodePrototype for the representation\n\t// form of the prototype.\n\tRepresentation() datamodel.NodePrototype\n}\n"
  },
  {
    "path": "schema/typesystem.go",
    "content": "package schema\n\ntype TypeSystem struct {\n\t// namedTypes is the set of all named types in this universe.\n\t// The map's key is the value's Name() property and must be unique.\n\t//\n\t// The IsAnonymous property is false for all values in this map that\n\t// support the IsAnonymous property.\n\t//\n\t// Each Type in the universe may only refer to other types in their\n\t// definition if those type are either A) in this namedTypes map,\n\t// or B) are IsAnonymous==true.\n\tnamedTypes map[TypeName]Type\n\n\t// names are the same set of names stored in namedTypes,\n\t// but in insertion order.\n\tnames []TypeName\n}\n"
  },
  {
    "path": "schema/validate.go",
    "content": "package schema\n\n/*\n\tOkay, so.  There are several fun considerations for a \"validate\" method.\n\n\t---\n\n\tThere's two radically different approaches to \"validate\"/\"reify\":\n\n\t- Option 1: Look at the schema.Type info and check if a data node seems\n\t  to match it -- recursing on the type info.\n\t- Option 2: Use the schema.Type{}.RepresentationNodeBuilder() to feed data\n      into it -- recursing on what the nodebuilder already expresses.\n\n\t(Option 2 also need to take a `memStorage ipld.NodeBuilder` param, btw,\n\tfor handling all the cases where we *aren't* doing codegen.)\n\n\tOption 1 provides a little more opportunity for returning multiple errors.\n\tOption 2 will generally have a hard time with that (nodebuilers are not\n\tnecessarily in a valid state after their first error encounter).\n\n\tAs a result of having these two options at all, we may indeed end up with\n\tat least two very different functions -- despite seeming to do similar\n\tthings, their interior will radically diverge.\n\n\t---\n\n\tWe may also need to consider distinct reification paths: we may want one\n\tthat returns a new node tree which is eagerly converted to schema.TypedNode\n\trecursively; and another that returns a lazyNode which wraps things\n\twith their typed node constraints only as they're requested.\n\t(Note that the latter would have interesting implications for any code\n\twhich has expectations about pointer equality consistency.)\n\n\t---\n\n\tA further fun issue which needs consideration: well, I'll just save a snip\n\tof prospective docs I wrote while trying to iterate on these functions:\n\n\t\t// Note that using Validate on a node that's already a schema.TypedNode is likely\n\t\t// to be nonsensical.  In many schemas, the schema.TypedNode tree is actually a\n\t\t// different depth than its representational tree (e.g. unions can cause this),\n\n\t... and that's ... that's a fairly sizable issue that needs resolving.\n\tThere's a couple of different ways to handle some of the behaviors around\n\tunions, and some of them make the tradeoff described above, and I'm really\n\tunsure if all the implications have been sussed out yet.  We should defer\n\twriting code that depends on this issue until gathering some more info.\n\n\t---\n\n\tOne more note: about returning multiple errors from a Validate function:\n\tthere's an upper bound of the utility of the thing.  Going farther than the\n\tfirst parse error is nice, but it will still hit limits: for example,\n\tupon encountering a union and failing to match it, we can't generally\n\tproduce further errors from anywhere deeper in the tree without them being\n\tcombinatorial \"if previous juncture X was type Y, then...\" nonsense.\n\t(This applies to all recursive kinds to some degree, but it's especially\n\trough with unions.  For most of the others, it's flatly a missing field,\n\tor an excessive field, or a leaf error; with unions it can be hard to tell.)\n\n\t---\n\n\tAnd finally: both \"Validate\" and \"Reify\" methods might actually belong\n\tin the schema.TypedNode package -- if they make *any* reference to `schema.TypedNode`,\n\tthen they have no choice (otherwise, cyclic imports would occur).\n\tIf we make a \"Validate\" that works purely on the schema.Type info, and\n\treturns *only* errors: only then we can have it in the schema package.\n\n*/\n"
  },
  {
    "path": "schema.go",
    "content": "package ipld\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\tschemadmt \"github.com/ipld/go-ipld-prime/schema/dmt\"\n\tschemadsl \"github.com/ipld/go-ipld-prime/schema/dsl\"\n)\n\n// LoadSchemaBytes is a shortcut for LoadSchema for the common case where\n// the schema is available as a buffer or a string, such as via go:embed.\nfunc LoadSchemaBytes(src []byte) (*schema.TypeSystem, error) {\n\treturn LoadSchema(\"\", bytes.NewReader(src))\n}\n\n// LoadSchemaBytes is a shortcut for LoadSchema for the common case where\n// the schema is a file on disk.\nfunc LoadSchemaFile(path string) (*schema.TypeSystem, error) {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer f.Close()\n\treturn LoadSchema(path, f)\n}\n\n// LoadSchema parses an IPLD Schema in its DSL form\n// and compiles its types into a standalone TypeSystem.\nfunc LoadSchema(name string, r io.Reader) (*schema.TypeSystem, error) {\n\tsch, err := schemadsl.Parse(name, r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tts := new(schema.TypeSystem)\n\tts.Init()\n\tif err := schemadmt.Compile(ts, sch); err != nil {\n\t\treturn nil, err\n\t}\n\treturn ts, nil\n}\n"
  },
  {
    "path": "storage/README_adapters.md",
    "content": "Storage Adapters\n================\n\nThe go-ipld-prime storage APIs were introduced in the v0.14.x ranges of go-ipld-prime,\nwhich happened in fall 2021.\n\nThere are many other pieces of code in the IPLD (and even more so, the IPFS) ecosystem\nwhich predate this, and have interfaces that are very _similar_, but not quite exactly the same.\n\nIn order to keep using that code, we've built a series of adapters.\n\nYou can see these in packages beneath this one:\n\n- `go-ipld-prime/storage/bsadapter` is an adapter to `github.com/ipfs/go-ipfs-blockstore`.\n- `go-ipld-prime/storage/dsadapter` is an adapter to `github.com/ipfs/go-datastore`.\n- `go-ipld-prime/storage/bsrvadapter` is an adapter to `github.com/ipfs/go-blockservice`.\n\nNote that there are also other packages which implement the go-ipld-prime storage APIs,\nbut are not considered \"adapters\" -- these just implement the storage APIs directly:\n\n- `go-ipld-prime/storage/memstore` is a simple in-memory storage system.\n- `go-ipld-prime/storage/fsstore` is a simple filesystem-backed storage system\n  (comparable to, and compatible with [flatfs](https://pkg.go.dev/github.com/ipfs/go-ds-flatfs),\n  if you're familiar with that -- but higher efficiency).\n\nFinally, note that there are some shared benchmarks across all this:\n\n- check out `go-ipld-prime/storage/benchmarks`!\n\n\nWhy structured like this?\n-------------------------\n\n### Why is there adapter code at all?\n\nThe `go-ipld-prime/storage` interfaces are a newer generation.\n\nA new generation of APIs was desirable because it unifies the old APIs,\nand also because we were able to improves and update several things in the process.\n(You can see some of the list of improvements in https://github.com/ipld/go-ipld-prime/pull/265,\nwhere these APIs were first introduced.)\nThe new generation of APIs avoids several types present in the old APIs which forced otherwise-avoidable allocations.\n(See notes later in this document about \"which adapter should I use\" for more on that.)\nFinally, the new generation of APIs is carefully designed to support minimal implementations,\nby carefully avoiding use of non-standard-library types in key API definitions,\nand by keeping most advanced features behind a standardized convention of feature detection.\n\nBecause the newer generation of APIs are not exactly the same as the multiple older APIs we're unifying and updating,\nsome amount of adapter code is necessary.\n\n(Fortunately, it's not much!  But it's not \"none\", either.)\n\n### Why have this code in a shared place?\n\nThe glue code to connect `go-datastore` and the other older APIs\nto the new `go-ipld-prime/storage` APIs is fairly minimal...\nbut there's also no reason for anyone to write it twice,\nso we want to put it somewhere easy to share.\n\n### Why do the adapters have their own go modules?\n\nA separate module is used because it's important that go-ipld-prime can be used\nwithout forming a dependency on `go-datastore` (or the other relevant modules, per adapter).\n\nWe want this so that there's a reasonable deprecation pathway -- it must be\npossible to write new code that doesn't take on transitive dependencies to old code.\n\n(As a bonus, looking at the module dependency graphs makes an interestingly\nclear statement about why minimal APIs that don't force transitive dependencies are a good idea!)\n\n### Why is this code all together in this repo?\n\nWe put these separate modules in the same git repo as `go-ipld-prime`... because we can.\n\nTechnically, neither the storage adapter modules nor the `go-ipld-prime` module depend on each other --\nthey just have interfaces that are aligned with each other -- so it's very easy to\nhold them as separate go modules in the same repo, even though that can otherwise sometimes be tricky.\n\nYou may want to make a point of pulling updated versions of the storage adapters that you use\nwhen pulling updates to go-ipld-prime, though.\n\n### Could we put these adapters upstream into the other relevant repos?\n\nCertainly!\n\nWe started with them here because it seemed developmentally lower-friction.\nThat may change; these APIs could move.\nThis code is just interface satisfaction, so even having multiple copies of it is utterly harmless.\n\n\nWhich of `dsadapter` vs `bsadapter` vs `bsrvadapter` should I use?\n------------------------------------------------------------------\n\nNone of them, ideally.\nA direct implementation of the storage APIs will almost certainly be able to perform better than any of these adapters.\n(Check out the `fsstore` package, for example.)\n\nFailing that: use the adapter matching whatever you've got on hand in your code.\n\nThere is no correct choice.\n\n`dsadapter` suffers avoidable excessive allocs in processing its key type,\ndue to choices in the interior of `github.com/ipfs/go-datastore`.\nIt is also unable to support streaming operation, should you desire it.\n\n`bsadapter` and `bsrvadapter` both also suffer overhead due to their key type,\nbecause they require a transformation back from the plain binary strings used in the storage API to the concrete go-cid type,\nwhich spends some avoidable CPU time (and also, at present, causes avoidable allocs because of some interesting absenses in `go-cid`).\nAdditionally, they suffer avoidable allocs because they wrap the raw binary data in a \"block\" type,\nwhich is an interface, and thus heap-escapes; and we need none of that in the storage APIs, and just return the raw data.\nThey are also unable to support streaming operation, should you desire it.\n\nIt's best to choose the shortest path and use the adapter to whatever layer you need to get to --\nfor example, if you really want to use a `go-datastore` implementation,\n*don't* use `bsadapter` and have it wrap a `go-blockstore` that wraps a `go-datastore` if you can help it:\ninstead, use `dsadapter` and wrap the `go-datastore` without any extra layers of indirection.\nYou should prefer this because most of the notes above about avoidable allocs are true when\nthe legacy interfaces are communicating with each other, as well...\nso the less you use the internal layering of the legacy interfaces, the better off you'll be.\n\nUsing a direct implementation of the storage APIs will suffer none of these overheads,\nand so will always be your best bet if possible.\n\nIf you have to use one of these adapters, hopefully the performance overheads fall within an acceptable margin.\nIf not: we'll be overjoyed to accept help porting things.\n"
  },
  {
    "path": "storage/api.go",
    "content": "package storage\n\nimport (\n\t\"context\"\n\t\"io\"\n)\n\n// --- basics --->\n\n// Storage is one of the base interfaces in the storage APIs.\n// This type is rarely seen by itself alone (and never useful to implement alone),\n// but is included in both ReadableStorage and WritableStorage.\n// Because it's included in both the of the other two useful base interfaces,\n// you can define functions that work on either one of them\n// by using this type to describe your function's parameters.\n//\n// Library functions that work with storage systems should take either\n// ReadableStorage, or WritableStorage, or Storage, as a parameter,\n// depending on whether the function deals with the reading of data,\n// or the writing of data, or may be found on either, respectively.\n//\n// An implementation of Storage may also support many other methods.\n// At the very least, it should also support one of either ReadableStorage or WritableStorage.\n// It may support even more interfaces beyond that for additional feature detection.\n// See the package-wide docs for more discussion of this design.\n//\n// The Storage interface does not include much of use in itself alone,\n// because ReadableStorage and WritableStorage are meant to be the most used types in declarations.\n// However, it does include the Has function, because that function is reasonable to require ubiquitously from all implementations,\n// and it serves as a reasonable marker to make sure the Storage interface is not trivially satisfied.\ntype Storage interface {\n\tHas(ctx context.Context, key string) (bool, error)\n}\n\n// ReadableStorage is one of the base interfaces in the storage APIs;\n// a storage system should implement at minimum either this, or WritableStorage,\n// depending on whether it supports reading or writing.\n// (One type may also implement both.)\n//\n// ReadableStorage implementations must at minimum provide\n// a way to ask the store whether it contains a key,\n// and a way to ask it to return the value.\n//\n// Library functions that work with storage systems should take either\n// ReadableStorage, or WritableStorage, or Storage, as a parameter,\n// depending on whether the function deals with the reading of data,\n// or the writing of data, or may be found on either, respectively.\n//\n// An implementation of ReadableStorage may also support many other methods --\n// for example, it may additionally match StreamingReadableStorage, or yet more interfaces.\n// Usually, you should not need to check for this yourself; instead,\n// you should use the storage package's functions to ask for the desired mode of interaction.\n// Those functions will will accept any ReadableStorage as an argument,\n// detect the additional interfaces automatically and use them if present,\n// or, fall back to synthesizing equivalent behaviors from the basics.\n// See the package-wide docs for more discussion of this design.\ntype ReadableStorage interface {\n\tStorage\n\tGet(ctx context.Context, key string) ([]byte, error)\n}\n\n// WritableStorage is one of the base interfaces in the storage APIs;\n// a storage system should implement at minimum either this, or ReadableStorage,\n// depending on whether it supports reading or writing.\n// (One type may also implement both.)\n//\n// WritableStorage implementations must at minimum provide\n// a way to ask the store whether it contains a key,\n// and a way to put a value into storage indexed by some key.\n//\n// Library functions that work with storage systems should take either\n// ReadableStorage, or WritableStorage, or Storage, as a parameter,\n// depending on whether the function deals with the reading of data,\n// or the writing of data, or may be found on either, respectively.\n//\n// An implementation of WritableStorage may also support many other methods --\n// for example, it may additionally match StreamingWritableStorage, or yet more interfaces.\n// Usually, you should not need to check for this yourself; instead,\n// you should use the storage package's functions to ask for the desired mode of interaction.\n// Those functions will will accept any WritableStorage as an argument,\n// detect the additional interfaces automatically and use them if present,\n// or, fall back to synthesizing equivalent behaviors from the basics.\n// See the package-wide docs for more discussion of this design.\ntype WritableStorage interface {\n\tStorage\n\tPut(ctx context.Context, key string, content []byte) error\n}\n\n// --- streaming --->\n\ntype StreamingReadableStorage interface {\n\tGetStream(ctx context.Context, key string) (io.ReadCloser, error)\n}\n\n// StreamingWritableStorage is a feature-detection interface that advertises support for streaming writes.\n// It is normal for APIs to use WritableStorage in their exported API surface,\n// and then internally check if that value implements StreamingWritableStorage if they wish to use streaming operations.\n//\n// Streaming writes can be preferable to the all-in-one style of writing of WritableStorage.Put,\n// because with streaming writes, the high water mark for memory usage can be kept lower.\n// On the other hand, streaming writes can incur slightly higher allocation counts,\n// which may cause some performance overhead when handling many small writes in sequence.\n//\n// The PutStream function returns three parameters: an io.Writer (as you'd expect), another function, and an error.\n// The function returned is called a \"WriteCommitter\".\n// The final error value is as usual: it will contain an error value if the write could not be begun.\n// (\"WriteCommitter\" will be referred to as such throughout the docs, but we don't give it a named type --\n// unfortunately, this is important, because we don't want to force implementers of storage systems to import this package just for a type name.)\n//\n// The WriteCommitter function should be called when you're done writing,\n// at which time you give it the key you want to commit the data as.\n// It will close and flush any streams, and commit the data to its final location under this key.\n// (If the io.Writer is also an io.WriteCloser, it is not necessary to call Close on it,\n// because using the WriteCommiter will do this for you.)\n//\n// Because these storage APIs are meant to work well for content-addressed systems,\n// the key argument is not provided at the start of the write -- it's provided at the end.\n// (This gives the opportunity to be computing a hash of the contents as they're written to the stream.)\n//\n// As a special case, giving a key of the zero string to the WriteCommiter will\n// instead close and remove any temp files, and store nothing.\n// An error may still be returned from the WriteCommitter if there is an error cleaning up\n// any temporary storage buffers that were created.\n//\n// Continuing to write to the io.Writer after calling the WriteCommitter function will result in errors.\n// Calling the WriteCommitter function more than once will result in errors.\ntype StreamingWritableStorage interface {\n\tPutStream(ctx context.Context) (io.Writer, func(key string) error, error)\n}\n\n// --- other specializations --->\n\n// VectorWritableStorage is an API for writing several slices of bytes at once into storage.\n// It's meant a feature-detection interface; not all storage implementations need to provide this feature.\n// This kind of API can be useful for maximizing performance in scenarios where\n// data is already loaded completely into memory, but scattered across several non-contiguous regions.\ntype VectorWritableStorage interface {\n\tPutVec(ctx context.Context, key string, blobVec [][]byte) error\n}\n\n// PeekableStorage is a feature-detection interface which a storage implementation can use to advertise\n// the ability to look at a piece of data, and return it in shared memory.\n// The PeekableStorage.Peek method is essentially the same as ReadableStorage.Get --\n// but by contrast, ReadableStorage is expected to return a safe copy.\n// PeekableStorage can be used when the caller knows they will not mutate the returned slice.\n//\n// An io.Closer is returned along with the byte slice.\n// The Close method on the Closer must be called when the caller is done with the byte slice;\n// otherwise, memory leaks may result.\n// (Implementers of this interface may be expecting to reuse the byte slice after Close is called.)\n//\n// Note that Peek does not imply that the caller can use the byte slice freely;\n// doing so may result in storage corruption or other undefined behavior.\ntype PeekableStorage interface {\n\tPeek(ctx context.Context, key string) ([]byte, io.Closer, error)\n}\n\n// the following are all hypothetical additional future interfaces (in varying degress of speculativeness):\n\n// FUTURE: an EnumerableStorage API, that lets you list all keys present?\n\n// FUTURE: a cleanup API (for getting rid of tmp files that might've been left behind on rough shutdown)?\n\n// FUTURE: a sync-forcing API?\n\n// FUTURE: a delete API?  sure.  (just document carefully what its consistency model is -- i.e. basically none.)\n//   (hunch: if you do want some sort of consistency model -- consider offering a whole family of methods that have some sort of generation or sequencing number on them.)\n\n// FUTURE: a force-overwrite API?  (not useful for a content-address system.  but maybe a gesture towards wider reusability is acceptable to have on offer.)\n\n// FUTURE: a size estimation API?  (unclear if we need to standardize this, but we could.  an offer, anyway.)\n\n// FUTURE: a GC API?  (dubious -- doing it well probably crosses logical domains, and should not be tied down here.)\n"
  },
  {
    "path": "storage/benchmarks/README.md",
    "content": "benchmarks\n==========\n\nThis is a small module that pulls in a bunch of storage implementations,\nas well as legacy implementations via the adapter modules,\nand benchmarks all of them on the same benchmarks.\n\nThere's no reason to import this code,\nso the go.mod file uses relative paths shamelessly.\n(You can create your own benchmarks using the code in `../tests`,\nwhich contains most of the engine; this package is just tables of setup.)\n\n\nWhat variations do the benchmarks exercise?\n------------------------------------------\n\n- the various storage implementations!\n\t- in some cases: variations of parameters to individual storage implementations.  (TODO)\n- puts and gets.  (TODO: currently only puts.)\n- various distributions of data size.  (TODO)\n- block mode vs streaming mode.  (TODO)\n- end-to-end use via linksystem with small cbor objects.  (TODO)\n\t- (this measures a lot of things that aren't to do with the storage itself -- but is useful to contextualize things.)\n\nRunning the benchmarks on variations in hardware and filesystem may also be important!\nMany of these storage systems use the disk in some way.\n\n\nWhy is the module structured like this?\n----------------------------------------\n\nBecause many of the storage implementations are also their own modules,\nand we don't want to have the go-ipld-prime module pull in a huge universe of transitive dependencies.\n\nSee similar discussion in `../README_adapters.md`.\n\nIt may be worth pulling this out into a new git repo in the future,\nespecially if we want to add more and more implementations to what we benchmark,\nor develop additional tools for deploying the benchmark on varying hardware, etc.\nFor now, it incubates here.\n"
  },
  {
    "path": "storage/benchmarks/go.mod",
    "content": "module github.com/ipld/go-ipld-prime/storage/benchmarks\n\ngo 1.25.7\n\nreplace github.com/ipld/go-ipld-prime => ../..\n\nreplace github.com/ipld/go-ipld-prime/storage/dsadapter => ../dsadapter\n\nrequire (\n\tgithub.com/ipfs/go-ds-flatfs v0.6.0\n\tgithub.com/ipld/go-ipld-prime v0.20.0\n\tgithub.com/ipld/go-ipld-prime/storage/dsadapter v0.20.0\n)\n\nrequire (\n\tgithub.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/ipfs/go-datastore v0.9.1 // indirect\n\tgithub.com/ipfs/go-log/v2 v2.9.0 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgo.uber.org/multierr v1.11.0 // indirect\n\tgo.uber.org/zap v1.27.0 // indirect\n\tgolang.org/x/sys v0.43.0 // indirect\n)\n"
  },
  {
    "path": "storage/benchmarks/go.sum",
    "content": "github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 h1:iW0a5ljuFxkLGPNem5Ui+KBjFJzKg4Fv2fnxe4dvzpM=\ngithub.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5/go.mod h1:Y2QMoi1vgtOIfc+6DhrMOGkLoGzqSV2rKp4Sm+opsyA=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/ipfs/go-datastore v0.9.1 h1:67Po2epre/o0UxrmkzdS9ZTe2GFGODgTd2odx8Wh6Yo=\ngithub.com/ipfs/go-datastore v0.9.1/go.mod h1:zi07Nvrpq1bQwSkEnx3bfjz+SQZbdbWyCNvyxMh9pN0=\ngithub.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=\ngithub.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=\ngithub.com/ipfs/go-ds-flatfs v0.6.0 h1:olAEnDNBK1VMoTRZvfzgo90H5kBP4qIZPpYMtNlBBws=\ngithub.com/ipfs/go-ds-flatfs v0.6.0/go.mod h1:p8a/YhmAFYyuonxDbvuIANlDCgS69uqVv+iH5f8fAxY=\ngithub.com/ipfs/go-log/v2 v2.9.0 h1:l4b06AwVXwldIzbVPZy5z7sKp9lHFTX0KWfTBCtHaOk=\ngithub.com/ipfs/go-log/v2 v2.9.0/go.mod h1:UhIYAwMV7Nb4ZmihUxfIRM2Istw/y9cAk3xaK+4Zs2c=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=\ngo.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=\ngo.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=\ngo.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=\ngolang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "storage/benchmarks/storageBenchmarks_test.go",
    "content": "package benchmarks\n\nimport (\n\t\"encoding/base32\"\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\n\tflatfs \"github.com/ipfs/go-ds-flatfs\"\n\t\"github.com/ipld/go-ipld-prime/storage\"\n\t\"github.com/ipld/go-ipld-prime/storage/dsadapter\"\n\t\"github.com/ipld/go-ipld-prime/storage/fsstore\"\n\t\"github.com/ipld/go-ipld-prime/storage/memstore\"\n\t\"github.com/ipld/go-ipld-prime/storage/tests\"\n)\n\nfunc BenchmarkPut(b *testing.B) {\n\t// - memstore\n\t// - dsadapter with flatfs\n\t// - bsrvadapter wrapped around that (todo)\n\t// - fsstore\n\ttt := []struct {\n\t\tstoreName        string // used in test name\n\t\tstoreConstructor func() storage.WritableStorage\n\t}{{\n\t\tstoreName: \"memstore\",\n\t\tstoreConstructor: func() storage.WritableStorage {\n\t\t\treturn &memstore.Store{}\n\t\t},\n\t}, {\n\t\tstoreName: \"dsadapter-flatfs-base32-defaultshard\",\n\t\tstoreConstructor: func() storage.WritableStorage {\n\t\t\tshardFn, err := flatfs.ParseShardFunc(\"/repo/flatfs/shard/v1/next-to-last/2\")\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tds, err := flatfs.CreateOrOpen(\".\", shardFn, false)\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\treturn &dsadapter.Adapter{\n\t\t\t\tWrapped: ds,\n\t\t\t\tEscapingFunc: func(raw string) string {\n\t\t\t\t\treturn base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString([]byte(raw))\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t}, {\n\t\tstoreName: \"fsstore-base32-defaultshard\",\n\t\tstoreConstructor: func() storage.WritableStorage {\n\t\t\tstore := &fsstore.Store{}\n\t\t\tif err := store.InitDefaults(\".\"); err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\treturn store\n\t\t},\n\t}}\n\tfor _, ttr := range tt {\n\t\tfor _, scale := range []int{\n\t\t\t// 1 << 8, // probably too small to be useful; b.N will always be much bigger than this.\n\t\t\t1 << 12,\n\t\t\t1 << 16,\n\t\t\t// 1 << 20, // already getting too big to fit the setup phase into the default benchmark time windows when using disk storage.\n\t\t\t// 1 << 24,\n\t\t} {\n\t\t\tb.Run(fmt.Sprintf(\"%s/scale=%d\", ttr.storeName, scale), func(b *testing.B) {\n\t\t\t\t// Make a tempdir.  Change cwd to it.\n\t\t\t\t//  We'll assume the storage system, if it needs filesystem, can use the cwd.\n\t\t\t\t//  Using b.TempDir means the cleanup happens handled by the test system (and critically, not on our clock).\n\t\t\t\tdir := b.TempDir()\n\t\t\t\tretreat, err := os.Getwd()\n\t\t\t\tif err != nil {\n\t\t\t\t\tpanic(err)\n\t\t\t\t}\n\t\t\t\tdefer os.Chdir(retreat)\n\t\t\t\tif err := os.Chdir(dir); err != nil {\n\t\t\t\t\tpanic(err)\n\t\t\t\t}\n\n\t\t\t\t// Create the store, and put it to work!\n\t\t\t\tstore := ttr.storeConstructor()\n\t\t\t\tgen := tests.NewCounterGen(1000000) // Use a large enough number that any sharding function kicks in (e.g. the b10 string is >=7 chars).\n\t\t\t\ttests.BenchPut(b, store, gen, scale)\n\t\t\t})\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "storage/bsadapter/README.md",
    "content": "bsadapter\n=========\n\nThe `bsadapter` package/module is a small piece of glue code to connect\nthe `github.com/ipfs/go-blockstore` package, and packages implementing its interfaces,\nforward into the `go-ipld-prime/storage` interfaces.\n\n\nWhy structured like this?\n-------------------------\n\nSee `../README_adapters.md` for details about why adapter code is needed,\nwhy this is in a module, why it's here, etc.\n\n\nWhich of `dsadapter` vs `bsadapter` vs `bsrvadapter` should I use?\n------------------------------------------------------------------\n\nIn short: you should prefer direct implementations of the storage APIs\nover any of these adapters, if one is available with the features you need.\n\nOtherwise, if that's not an option (yet) for some reason,\nuse whichever adapter gets you most directly connected to the code you need.\n\nSee `../README_adapters.md` for more details and discussion.\n"
  },
  {
    "path": "storage/bsadapter/bsadapter.go",
    "content": "package bsadapter\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/ipfs/boxo/blockstore\"\n\tblocks \"github.com/ipfs/go-block-format\"\n\t\"github.com/ipfs/go-cid\"\n)\n\n// Adapter implements go-ipld-prime/storage.ReadableStorage\n// and go-ipld-prime/storage.WritableStorage\n// backed by a go-ipfs-blockstore.Blockstore.\n//\n// The go-ipfs-blockstore.Blockstore may internally have other configuration.\n// We don't interfere with that here;\n// such configuration should be handled when creating the go-ipfs-blockstore value.\n//\n// Note that this system will only work for certain structures of keys --\n// this is because the blockstore API works on the level of CIDs.\n// As long as your key string is the binary form of a CID, it will work correctly.\n// Other keys are not possible to support with this adapter.\n//\n// Contexts given to this system are checked for errors at the beginning of an operation,\n// but otherwise have no effect, because the Blockstore API doesn't accept context parameters.\ntype Adapter struct {\n\tWrapped blockstore.Blockstore\n}\n\n// Has implements go-ipld-prime/storage.Storage.Has.\nfunc (a *Adapter) Has(ctx context.Context, key string) (bool, error) {\n\t// Return early if the context is already closed.\n\t// This is also the last time we'll check the context,\n\t// since the Has method on Blockstore doesn't take them.\n\tif ctx.Err() != nil {\n\t\treturn false, ctx.Err()\n\t}\n\n\t// Do the inverse of cid.KeyString(),\n\t// which is how a valid key for this adapter must've been produced.\n\tk, err := cidFromBinString(key)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// Delegate the Has call.\n\treturn a.Wrapped.Has(ctx, k)\n}\n\n// Get implements go-ipld-prime/storage.ReadableStorage.Get.\nfunc (a *Adapter) Get(ctx context.Context, key string) ([]byte, error) {\n\t// Return early if the context is already closed.\n\t// This is also the last time we'll check the context,\n\t// since the Put method on Blockstore doesn't take them.\n\tif ctx.Err() != nil {\n\t\treturn nil, ctx.Err()\n\t}\n\n\t// Do the inverse of cid.KeyString(),\n\t// which is how a valid key for this adapter must've been produced.\n\tk, err := cidFromBinString(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Delegate the Get call.\n\tblock, err := a.Wrapped.Get(ctx, k)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Unwrap the actual raw data for return.\n\t// Discard the rest.  (It's a shame there was an alloc for that structure.)\n\treturn block.RawData(), nil\n}\n\n// Put implements go-ipld-prime/storage.WritableStorage.Put.\nfunc (a *Adapter) Put(ctx context.Context, key string, content []byte) error {\n\t// Return early if the context is already closed.\n\t// This is also the last time we'll check the context,\n\t// since the Put method on Blockstore doesn't take them.\n\tif ctx.Err() != nil {\n\t\treturn ctx.Err()\n\t}\n\n\t// Do the inverse of cid.KeyString(),\n\t// which is how a valid key for this adapter must've been produced.\n\tk, err := cidFromBinString(key)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Create a structure that has the cid and the raw content together.\n\t// This is necessary because it's the format demanded by Blockstore.\n\t// (Unfortunately, it also provokes an allocation, because it uses interfaces;\n\t// but we can't avoid that without changing the code in go-ipfs-blockstore.)\n\t// The error is treated as a panic because it's only possible if a global debug var is set,\n\t// and is for behavior that is not meant to be part of the contract of the storage APIs.\n\tblock, err := blocks.NewBlockWithCid(content, k)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t// Delegate the Put call.\n\treturn a.Wrapped.Put(ctx, block)\n}\n\n// Do the inverse of cid.KeyString().\n// (Unclear why go-cid doesn't offer a function for this itself.)\nfunc cidFromBinString(key string) (cid.Cid, error) {\n\tl, k, err := cid.CidFromBytes([]byte(key))\n\tif err != nil {\n\t\treturn cid.Undef, fmt.Errorf(\"bsrvadapter: key was not a cid: %w\", err)\n\t}\n\tif l != len(key) {\n\t\treturn cid.Undef, fmt.Errorf(\"bsrvadapter: key was not a cid: had %d bytes leftover\", len(key)-l)\n\t}\n\treturn k, nil\n}\n"
  },
  {
    "path": "storage/bsadapter/go.mod",
    "content": "module github.com/ipld/go-ipld-prime/storage/bsadapter\n\ngo 1.25.7\n\nrequire (\n\tgithub.com/ipfs/boxo v0.39.0\n\tgithub.com/ipfs/go-block-format v0.2.3\n\tgithub.com/ipfs/go-cid v0.6.1\n)\n\nrequire (\n\tgithub.com/gammazero/chanqueue v1.1.2 // indirect\n\tgithub.com/gammazero/deque v1.2.1 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/hashicorp/golang-lru/v2 v2.0.7 // indirect\n\tgithub.com/ipfs/bbloom v0.1.0 // indirect\n\tgithub.com/ipfs/go-cidutil v0.1.1 // indirect\n\tgithub.com/ipfs/go-datastore v0.9.1 // indirect\n\tgithub.com/ipfs/go-dsqueue v0.2.0 // indirect\n\tgithub.com/ipfs/go-ipld-format v0.6.3 // indirect\n\tgithub.com/ipfs/go-log/v2 v2.9.1 // indirect\n\tgithub.com/ipfs/go-metrics-interface v0.3.0 // indirect\n\tgithub.com/ipld/go-ipld-prime v0.23.0 // indirect\n\tgithub.com/klauspost/cpuid/v2 v2.3.0 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/minio/sha256-simd v1.0.1 // indirect\n\tgithub.com/mr-tron/base58 v1.3.0 // indirect\n\tgithub.com/multiformats/go-base32 v0.1.0 // indirect\n\tgithub.com/multiformats/go-base36 v0.2.0 // indirect\n\tgithub.com/multiformats/go-multibase v0.3.0 // indirect\n\tgithub.com/multiformats/go-multicodec v0.10.0 // indirect\n\tgithub.com/multiformats/go-multihash v0.2.3 // indirect\n\tgithub.com/multiformats/go-varint v0.1.0 // indirect\n\tgithub.com/spaolacci/murmur3 v1.1.0 // indirect\n\tgo.uber.org/multierr v1.11.0 // indirect\n\tgo.uber.org/zap v1.27.1 // indirect\n\tgolang.org/x/crypto v0.50.0 // indirect\n\tgolang.org/x/sys v0.43.0 // indirect\n\tlukechampine.com/blake3 v1.4.1 // indirect\n)\n"
  },
  {
    "path": "storage/bsadapter/go.sum",
    "content": "github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=\ngithub.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0=\ngithub.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 h1:5RVFMOWjMyRy8cARdy79nAmgYw3hK/4HUq48LQ6Wwqo=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=\ngithub.com/filecoin-project/go-clock v0.1.0 h1:SFbYIM75M8NnFm1yMHhN9Ahy3W5bEZV9gd6MPfXbKVU=\ngithub.com/filecoin-project/go-clock v0.1.0/go.mod h1:4uB/O4PvOjlx1VCMdZ9MyDZXRm//gkj1ELEbxfI1AZs=\ngithub.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=\ngithub.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=\ngithub.com/gammazero/chanqueue v1.1.2 h1:dZEsxlyANZMyeTRemABqZF8QM9BnE4NBI43Oh3y5fIU=\ngithub.com/gammazero/chanqueue v1.1.2/go.mod h1:XDN1X/jjAbmSceNFOQbtKToeSkxtdVdpKu90LiEdBEE=\ngithub.com/gammazero/deque v1.2.1 h1:9fnQVFCCZ9/NOc7ccTNqzoKd1tCWOqeI05/lPqFPMGQ=\ngithub.com/gammazero/deque v1.2.1/go.mod h1:5nSFkzVm+afG9+gy0VIowlqVAW4N8zNcMne+CMQVD2g=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=\ngithub.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=\ngithub.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=\ngithub.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=\ngithub.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=\ngithub.com/ipfs/bbloom v0.1.0 h1:nIWwfIE3AaG7RCDQIsrUonGCOTp7qSXzxH7ab/ss964=\ngithub.com/ipfs/bbloom v0.1.0/go.mod h1:lDy3A3i6ndgEW2z1CaRFvDi5/ZTzgM1IxA/pkL7Wgts=\ngithub.com/ipfs/boxo v0.39.0 h1:u9jLf5pLx5SWROXjHtj8VMvv+iDlMbiTyZ/vVTQ4VhI=\ngithub.com/ipfs/boxo v0.39.0/go.mod h1:k9YCvMjytFguMHndEiGdCGMMj4b7CkdOT44vtgAxOdk=\ngithub.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=\ngithub.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=\ngithub.com/ipfs/go-block-format v0.2.3 h1:mpCuDaNXJ4wrBJLrtEaGFGXkferrw5eqVvzaHhtFKQk=\ngithub.com/ipfs/go-block-format v0.2.3/go.mod h1:WJaQmPAKhD3LspLixqlqNFxiZ3BZ3xgqxxoSR/76pnA=\ngithub.com/ipfs/go-cid v0.6.1 h1:T5TnNb08+ueovG76Z5gx1L4Y7QOaGTXHg1F6raWFxIc=\ngithub.com/ipfs/go-cid v0.6.1/go.mod h1:zrY0SwOhjrrIdfPQ/kf+k1sXyJ0QE7cMxfCployLBs0=\ngithub.com/ipfs/go-cidutil v0.1.1 h1:COuby6H8C2ml0alvHYX3WdbFM4F07YtbY0UlT5j+sgI=\ngithub.com/ipfs/go-cidutil v0.1.1/go.mod h1:SCoUftGEUgoXe5Hjeyw5CiLZF8cwYn/TbtpFQXJCP6k=\ngithub.com/ipfs/go-datastore v0.9.1 h1:67Po2epre/o0UxrmkzdS9ZTe2GFGODgTd2odx8Wh6Yo=\ngithub.com/ipfs/go-datastore v0.9.1/go.mod h1:zi07Nvrpq1bQwSkEnx3bfjz+SQZbdbWyCNvyxMh9pN0=\ngithub.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=\ngithub.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=\ngithub.com/ipfs/go-ds-leveldb v0.5.2 h1:6nmxlQ2zbp4LCNdJVsmHfs9GP0eylfBNxpmY1csp0x0=\ngithub.com/ipfs/go-ds-leveldb v0.5.2/go.mod h1:2fAwmcvD3WoRT72PzEekHBkQmBDhc39DJGoREiuGmYo=\ngithub.com/ipfs/go-dsqueue v0.2.0 h1:MBi9w3oSiX98Xc+Y7NuJ9G8MI6mAT4IGdO9dHEMCZzU=\ngithub.com/ipfs/go-dsqueue v0.2.0/go.mod h1:8FfNQC4DMF/KkzBXRNB9Rb3MKDW0Sh98HMtXYl1mLQE=\ngithub.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ=\ngithub.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=\ngithub.com/ipfs/go-ipfs-pq v0.0.4 h1:U7jjENWJd1jhcrR8X/xHTaph14PTAK9O+yaLJbjqgOw=\ngithub.com/ipfs/go-ipfs-pq v0.0.4/go.mod h1:9UdLOIIb99IFrgT0Fc53pvbvlJBhpUb4GJuAQf3+O2A=\ngithub.com/ipfs/go-ipld-format v0.6.3 h1:9/lurLDTotJpZSuL++gh3sTdmcFhVkCwsgx2+rAh4j8=\ngithub.com/ipfs/go-ipld-format v0.6.3/go.mod h1:74ilVN12NXVMIV+SrBAyC05UJRk0jVvGqdmrcYZvCBk=\ngithub.com/ipfs/go-ipld-legacy v0.3.0 h1:7XhFKkRyCvP5upOlQfKUFIqL3S5DEZnbUE4bQmQ/tNE=\ngithub.com/ipfs/go-ipld-legacy v0.3.0/go.mod h1:Ukef9ARQiX+RVetwH2XiReLgJvQDEXcUPszrZ1KRjKI=\ngithub.com/ipfs/go-log/v2 v2.9.1 h1:3JXwHWU31dsCpvQ+7asz6/QsFJHqFr4gLgQ0FWteujk=\ngithub.com/ipfs/go-log/v2 v2.9.1/go.mod h1:evFx7sBiohUN3AG12mXlZBw5hacBQld3ZPHrowlJYoo=\ngithub.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU=\ngithub.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY=\ngithub.com/ipfs/go-peertaskqueue v0.8.3 h1:tBPpGJy+A92RqtRFq5amJn0Uuj8Pw8tXi0X3eHfHM8w=\ngithub.com/ipfs/go-peertaskqueue v0.8.3/go.mod h1:OqVync4kPOcXEGdj/LKvox9DCB5mkSBeXsPczCxLtYA=\ngithub.com/ipfs/go-test v0.3.0 h1:0Y4Uve3tp9HI+2lIJjfOliOrOgv/YpXg/l1y3P4DEYE=\ngithub.com/ipfs/go-test v0.3.0/go.mod h1:JK+U8pRpATZb7lsYNSJlCj3WYB3cFfWIbI6nWRM/GFk=\ngithub.com/ipfs/go-unixfsnode v1.10.3 h1:c8sJjuGNkxXAQH75P+f5ngPda/9T+DrboVA0TcDGvGI=\ngithub.com/ipfs/go-unixfsnode v1.10.3/go.mod h1:2Jlc7DoEwr12W+7l8Hr6C7XF4NHST3gIkqSArLhGSxU=\ngithub.com/ipld/go-codec-dagpb v1.7.0 h1:hpuvQjCSVSLnTnHXn+QAMR0mLmb1gA6wl10LExo2Ts0=\ngithub.com/ipld/go-codec-dagpb v1.7.0/go.mod h1:rD3Zg+zub9ZnxcLwfol/OTQRVjaLzXypgy4UqHQvilM=\ngithub.com/ipld/go-ipld-prime v0.23.0 h1:csqdPZH60BsTC+AZrv7fpa27v+09I/oTqyHYYYE27eE=\ngithub.com/ipld/go-ipld-prime v0.23.0/go.mod h1:46YCFSFNFBJHPjB0pfMuv7Ly7df2eChpkpyPo5SE0bA=\ngithub.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=\ngithub.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=\ngithub.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=\ngithub.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=\ngithub.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU=\ngithub.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=\ngithub.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=\ngithub.com/libp2p/go-flow-metrics v0.3.0 h1:q31zcHUvHnwDO0SHaukewPYgwOBSxtt830uJtUx6784=\ngithub.com/libp2p/go-flow-metrics v0.3.0/go.mod h1:nuhlreIwEguM1IvHAew3ij7A8BMlyHQJ279ao24eZZo=\ngithub.com/libp2p/go-libp2p v0.48.0 h1:h2BrLAgrj7X8bEN05K7qmrjpNHYA+6tnsGRdprjTnvo=\ngithub.com/libp2p/go-libp2p v0.48.0/go.mod h1:Q1fBZNdmC2Hf82husCTfkKJVfHm2we5zk+NWmOGEmWk=\ngithub.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=\ngithub.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=\ngithub.com/libp2p/go-libp2p-record v0.3.1 h1:cly48Xi5GjNw5Wq+7gmjfBiG9HCzQVkiZOUZ8kUl+Fg=\ngithub.com/libp2p/go-libp2p-record v0.3.1/go.mod h1:T8itUkLcWQLCYMqtX7Th6r7SexyUJpIyPgks757td/E=\ngithub.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA=\ngithub.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg=\ngithub.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0=\ngithub.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM=\ngithub.com/libp2p/go-netroute v0.4.0 h1:sZZx9hyANYUx9PZyqcgE/E1GUG3iEtTZHUEvdtXT7/Q=\ngithub.com/libp2p/go-netroute v0.4.0/go.mod h1:Nkd5ShYgSMS5MUKy/MU2T57xFoOKvvLR92Lic48LEyA=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=\ngithub.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=\ngithub.com/mr-tron/base58 v1.3.0 h1:K6Y13R2h+dku0wOqKtecgRnBUBPrZzLZy5aIj8lCcJI=\ngithub.com/mr-tron/base58 v1.3.0/go.mod h1:2BuubE67DCSWwVfx37JWNG8emOC0sHEU4/HpcYgCLX8=\ngithub.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=\ngithub.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=\ngithub.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=\ngithub.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=\ngithub.com/multiformats/go-multiaddr v0.16.1 h1:fgJ0Pitow+wWXzN9do+1b8Pyjmo8m5WhGfzpL82MpCw=\ngithub.com/multiformats/go-multiaddr v0.16.1/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0=\ngithub.com/multiformats/go-multiaddr-dns v0.5.0 h1:p/FTyHKX0nl59f+S+dEUe8HRK+i5Ow/QHMw8Nh3gPCo=\ngithub.com/multiformats/go-multiaddr-dns v0.5.0/go.mod h1:yJ349b8TPIAANUyuOzn1oz9o22tV9f+06L+cCeMxC14=\ngithub.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=\ngithub.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=\ngithub.com/multiformats/go-multibase v0.3.0 h1:8helZD2+4Db7NNWFiktk2NePbF0boolBe6bDQvM4r68=\ngithub.com/multiformats/go-multibase v0.3.0/go.mod h1:MoBLQPCkRTOL3eveIPO81860j2AQY8JwcnNlRkGRUfI=\ngithub.com/multiformats/go-multicodec v0.10.0 h1:UpP223cig/Cx8J76jWt91njpK3GTAO1w02sdcjZDSuc=\ngithub.com/multiformats/go-multicodec v0.10.0/go.mod h1:wg88pM+s2kZJEQfRCKBNU+g32F5aWBEjyFHXvZLTcLI=\ngithub.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U=\ngithub.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=\ngithub.com/multiformats/go-multistream v0.6.1 h1:4aoX5v6T+yWmc2raBHsTvzmFhOI8WVOer28DeBBEYdQ=\ngithub.com/multiformats/go-multistream v0.6.1/go.mod h1:ksQf6kqHAb6zIsyw7Zm+gAuVo57Qbq84E27YlYqavqw=\ngithub.com/multiformats/go-varint v0.1.0 h1:i2wqFp4sdl3IcIxfAonHQV9qU5OsZ4Ts9IOoETFs5dI=\ngithub.com/multiformats/go-varint v0.1.0/go.mod h1:5KVAVXegtfmNQQm/lCY+ATvDzvJJhSkUlGQV9wgObdI=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/polydawn/refmt v0.89.1-0.20231129105047-37766d95467a h1:cgqrm0F3zwf9IPzca7xN4w+Zy6MC9ZkPvAC8QEWa/iQ=\ngithub.com/polydawn/refmt v0.89.1-0.20231129105047-37766d95467a/go.mod h1:ocZfO/tLSHqfScRDNTJbAJR1by4D1lewauX9OwTaPuY=\ngithub.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=\ngithub.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=\ngithub.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=\ngithub.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=\ngithub.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=\ngithub.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=\ngithub.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=\ngithub.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=\ngithub.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=\ngithub.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=\ngithub.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=\ngithub.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=\ngithub.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=\ngithub.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s=\ngithub.com/warpfork/go-testmark v0.12.1/go.mod h1:kHwy7wfvGSPh1rQJYKayD4AbtNaeyZdcGi9tNJTaa5Y=\ngo.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=\ngo.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=\ngo.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=\ngo.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=\ngo.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=\ngo.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI=\ngo.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=\ngo.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=\ngo.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=\ngo.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=\ngo.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=\ngo.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=\ngo.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=\ngolang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=\ngolang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=\ngolang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=\ngolang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=\ngolang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=\ngolang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=\ngolang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=\ngolang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=\ngolang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngolang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=\ngolang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=\ngoogle.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=\ngoogle.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nlukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=\nlukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=\n"
  },
  {
    "path": "storage/bsrvadapter/README.md",
    "content": "bsrvadapter\n===========\n\nThe `bsrvadapter` package/module is a small piece of glue code to connect\nthe `github.com/ipfs/go-blockservice` package, and packages implementing its interfaces,\nforward into the `go-ipld-prime/storage` interfaces.\n\nThis can be used to rig systems like Bitswap up behind go-ipld-prime storage APIs.\n\n(Whether or not this is a good idea is debatable.\nIt should be noted that both the `ipfs/go-blockservice` API,\nas well as Bitswap in particular as an implementation,\nare inherently prone to the infamous \"N+1 Query Problem\".\nTreating a remote network fetch as equivalent to a local low-latency operation\njust isn't a good idea for performance or predictability, no matter how you slice it.\nNonetheless: it's possible, using this code, if you really want to do it.)\n\n\nWhy structured like this?\n-------------------------\n\nSee `../README_adapters.md` for details about why adapter code is needed,\nwhy this is in a module, why it's here, etc.\n\n\nWhich of `dsadapter` vs `bsadapter` vs `bsrvadapter` should I use?\n------------------------------------------------------------------\n\nIn short: you should prefer direct implementations of the storage APIs\nover any of these adapters, if one is available with the features you need.\n\nOtherwise, if that's not an option (yet) for some reason,\nuse whichever adapter gets you most directly connected to the code you need.\n\nSee `../README_adapters.md` for more details and discussion.\n"
  },
  {
    "path": "storage/bsrvadapter/bsrvadapter.go",
    "content": "package bsrvadapter\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/ipfs/boxo/blockservice\"\n\tblocks \"github.com/ipfs/go-block-format\"\n\t\"github.com/ipfs/go-cid\"\n)\n\n// Adapter implements go-ipld-prime/storage.ReadableStorage\n// and go-ipld-prime/storage.WritableStorage\n// backed by a go-blockservice.BlockService.\n//\n// The go-blockservice.BlockService may internally have other configuration,\n// and contain whole other systems like Bitswap for transport.\n// We don't interfere with that here;\n// such configuration should be handled when creating the go-blockservice value.\n//\n// Note that this system will only work for certain structures of keys --\n// this is because the blockservice API works on the level of CIDs.\n// As long as your key string is the binary form of a CID, it will work correctly.\n// Other keys are not possible to support with this adapter.\n//\n// Contexts given to this system are passed through where possible, but it is not possible in all cases.\n// For operations where the underlying interface doesn't accept a context parameter,\n// this adapter will check the context for errors before beginning an operation,\n// but the context will otherwise have no effect.\n// For operations where BlockService does accept a context, we pass it on.\ntype Adapter struct {\n\tWrapped blockservice.BlockService\n}\n\n// Has implements go-ipld-prime/storage.Storage.Has.\n//\n// Note that for a BlockService, the Has operation has rather unusual semantics.\n// Has may return false, and an immediately subsequent Get for the same key might return data!\n// This is because the Has operation is defined as whether\n// the Blockstore that the BlockService wraps has the requested key, immediately, locally;\n// while the Get operation might use the BlockService to go _find_ the requested key\n// and its content, even remotely!\nfunc (a *Adapter) Has(ctx context.Context, key string) (bool, error) {\n\t// Return early if the context is already closed.\n\t// This is also the last time we'll check the context,\n\t// since the Has method is on Blockstore, which doesn't take them.\n\tif ctx.Err() != nil {\n\t\treturn false, ctx.Err()\n\t}\n\n\t// Do the inverse of cid.KeyString(),\n\t// which is how a valid key for this adapter must've been produced.\n\tk, err := cidFromBinString(key)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// Delegate the Has call.\n\treturn a.Wrapped.Blockstore().Has(ctx, k)\n}\n\n// Get implements go-ipld-prime/storage.ReadableStorage.Get.\nfunc (a *Adapter) Get(ctx context.Context, key string) ([]byte, error) {\n\t// No need to check the context proactively here --\n\t// the BlockService API actually accepts context.\n\n\t// Do the inverse of cid.KeyString(),\n\t// which is how a valid key for this adapter must've been produced.\n\tk, err := cidFromBinString(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Delegate the Get call.\n\t// It's called \"GetBlock\" in BlockService.\n\tblock, err := a.Wrapped.GetBlock(ctx, k)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Unwrap the actual raw data for return.\n\t// Discard the rest.  (It's a shame there was an alloc for that structure.)\n\treturn block.RawData(), nil\n}\n\n// Put implements go-ipld-prime/storage.WritableStorage.Put.\nfunc (a *Adapter) Put(ctx context.Context, key string, content []byte) error {\n\t// Return early if the context is already closed.\n\t// This is also the last time we'll check the context,\n\t// since the AddBlock method on BlockService that we'll eventually be delegating to doesn't take them.\n\tif ctx.Err() != nil {\n\t\treturn ctx.Err()\n\t}\n\n\t// Do the inverse of cid.KeyString(),\n\t// which is how a valid key for this adapter must've been produced.\n\tk, err := cidFromBinString(key)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Create a structure that has the cid and the raw content together.\n\t// This is necessary because it's the format demanded by BlockService.\n\t// (Unfortunately, it also provokes an allocation, because it uses interfaces;\n\t// but we can't avoid that without changing the code in go-blockservice.)\n\t// The error is treated as a panic because it's only possible if a global debug var is set,\n\t// and is for behavior that is not meant to be part of the contract of the storage APIs.\n\tblock, err := blocks.NewBlockWithCid(content, k)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t// Delegate the Put call.\n\t// It's called \"AddBlock\" in BlockService.\n\treturn a.Wrapped.AddBlock(ctx, block)\n}\n\n// Do the inverse of cid.KeyString().\n// (Unclear why go-cid doesn't offer a function for this itself.)\nfunc cidFromBinString(key string) (cid.Cid, error) {\n\tl, k, err := cid.CidFromBytes([]byte(key))\n\tif err != nil {\n\t\treturn cid.Undef, fmt.Errorf(\"bsrvadapter: key was not a cid: %w\", err)\n\t}\n\tif l != len(key) {\n\t\treturn cid.Undef, fmt.Errorf(\"bsrvadapter: key was not a cid: had %d bytes leftover\", len(key)-l)\n\t}\n\treturn k, nil\n}\n"
  },
  {
    "path": "storage/bsrvadapter/go.mod",
    "content": "module github.com/ipld/go-ipld-prime/storage/bsrvadapter\n\ngo 1.25.7\n\nrequire (\n\tgithub.com/ipfs/boxo v0.39.0\n\tgithub.com/ipfs/go-block-format v0.2.3\n\tgithub.com/ipfs/go-cid v0.6.1\n)\n\nrequire (\n\tgithub.com/cespare/xxhash/v2 v2.3.0 // indirect\n\tgithub.com/gammazero/chanqueue v1.1.2 // indirect\n\tgithub.com/gammazero/deque v1.2.1 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/hashicorp/golang-lru/v2 v2.0.7 // indirect\n\tgithub.com/ipfs/bbloom v0.1.0 // indirect\n\tgithub.com/ipfs/go-cidutil v0.1.1 // indirect\n\tgithub.com/ipfs/go-datastore v0.9.1 // indirect\n\tgithub.com/ipfs/go-dsqueue v0.2.0 // indirect\n\tgithub.com/ipfs/go-ipld-format v0.6.3 // indirect\n\tgithub.com/ipfs/go-log/v2 v2.9.1 // indirect\n\tgithub.com/ipfs/go-metrics-interface v0.3.0 // indirect\n\tgithub.com/ipld/go-ipld-prime v0.23.0 // indirect\n\tgithub.com/klauspost/cpuid/v2 v2.3.0 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/minio/sha256-simd v1.0.1 // indirect\n\tgithub.com/mr-tron/base58 v1.3.0 // indirect\n\tgithub.com/multiformats/go-base32 v0.1.0 // indirect\n\tgithub.com/multiformats/go-base36 v0.2.0 // indirect\n\tgithub.com/multiformats/go-multibase v0.3.0 // indirect\n\tgithub.com/multiformats/go-multicodec v0.10.0 // indirect\n\tgithub.com/multiformats/go-multihash v0.2.3 // indirect\n\tgithub.com/multiformats/go-varint v0.1.0 // indirect\n\tgithub.com/spaolacci/murmur3 v1.1.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.2.1 // indirect\n\tgo.opentelemetry.io/otel v1.42.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.42.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.42.0 // indirect\n\tgo.uber.org/multierr v1.11.0 // indirect\n\tgo.uber.org/zap v1.27.1 // indirect\n\tgolang.org/x/crypto v0.50.0 // indirect\n\tgolang.org/x/sys v0.43.0 // indirect\n\tlukechampine.com/blake3 v1.4.1 // indirect\n)\n"
  },
  {
    "path": "storage/bsrvadapter/go.sum",
    "content": "github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=\ngithub.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0=\ngithub.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 h1:5RVFMOWjMyRy8cARdy79nAmgYw3hK/4HUq48LQ6Wwqo=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=\ngithub.com/filecoin-project/go-clock v0.1.0 h1:SFbYIM75M8NnFm1yMHhN9Ahy3W5bEZV9gd6MPfXbKVU=\ngithub.com/filecoin-project/go-clock v0.1.0/go.mod h1:4uB/O4PvOjlx1VCMdZ9MyDZXRm//gkj1ELEbxfI1AZs=\ngithub.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=\ngithub.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=\ngithub.com/gammazero/chanqueue v1.1.2 h1:dZEsxlyANZMyeTRemABqZF8QM9BnE4NBI43Oh3y5fIU=\ngithub.com/gammazero/chanqueue v1.1.2/go.mod h1:XDN1X/jjAbmSceNFOQbtKToeSkxtdVdpKu90LiEdBEE=\ngithub.com/gammazero/deque v1.2.1 h1:9fnQVFCCZ9/NOc7ccTNqzoKd1tCWOqeI05/lPqFPMGQ=\ngithub.com/gammazero/deque v1.2.1/go.mod h1:5nSFkzVm+afG9+gy0VIowlqVAW4N8zNcMne+CMQVD2g=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=\ngithub.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=\ngithub.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=\ngithub.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=\ngithub.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=\ngithub.com/ipfs/bbloom v0.1.0 h1:nIWwfIE3AaG7RCDQIsrUonGCOTp7qSXzxH7ab/ss964=\ngithub.com/ipfs/bbloom v0.1.0/go.mod h1:lDy3A3i6ndgEW2z1CaRFvDi5/ZTzgM1IxA/pkL7Wgts=\ngithub.com/ipfs/boxo v0.39.0 h1:u9jLf5pLx5SWROXjHtj8VMvv+iDlMbiTyZ/vVTQ4VhI=\ngithub.com/ipfs/boxo v0.39.0/go.mod h1:k9YCvMjytFguMHndEiGdCGMMj4b7CkdOT44vtgAxOdk=\ngithub.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=\ngithub.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=\ngithub.com/ipfs/go-block-format v0.2.3 h1:mpCuDaNXJ4wrBJLrtEaGFGXkferrw5eqVvzaHhtFKQk=\ngithub.com/ipfs/go-block-format v0.2.3/go.mod h1:WJaQmPAKhD3LspLixqlqNFxiZ3BZ3xgqxxoSR/76pnA=\ngithub.com/ipfs/go-cid v0.6.1 h1:T5TnNb08+ueovG76Z5gx1L4Y7QOaGTXHg1F6raWFxIc=\ngithub.com/ipfs/go-cid v0.6.1/go.mod h1:zrY0SwOhjrrIdfPQ/kf+k1sXyJ0QE7cMxfCployLBs0=\ngithub.com/ipfs/go-cidutil v0.1.1 h1:COuby6H8C2ml0alvHYX3WdbFM4F07YtbY0UlT5j+sgI=\ngithub.com/ipfs/go-cidutil v0.1.1/go.mod h1:SCoUftGEUgoXe5Hjeyw5CiLZF8cwYn/TbtpFQXJCP6k=\ngithub.com/ipfs/go-datastore v0.9.1 h1:67Po2epre/o0UxrmkzdS9ZTe2GFGODgTd2odx8Wh6Yo=\ngithub.com/ipfs/go-datastore v0.9.1/go.mod h1:zi07Nvrpq1bQwSkEnx3bfjz+SQZbdbWyCNvyxMh9pN0=\ngithub.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=\ngithub.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=\ngithub.com/ipfs/go-ds-leveldb v0.5.2 h1:6nmxlQ2zbp4LCNdJVsmHfs9GP0eylfBNxpmY1csp0x0=\ngithub.com/ipfs/go-ds-leveldb v0.5.2/go.mod h1:2fAwmcvD3WoRT72PzEekHBkQmBDhc39DJGoREiuGmYo=\ngithub.com/ipfs/go-dsqueue v0.2.0 h1:MBi9w3oSiX98Xc+Y7NuJ9G8MI6mAT4IGdO9dHEMCZzU=\ngithub.com/ipfs/go-dsqueue v0.2.0/go.mod h1:8FfNQC4DMF/KkzBXRNB9Rb3MKDW0Sh98HMtXYl1mLQE=\ngithub.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ=\ngithub.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=\ngithub.com/ipfs/go-ipfs-pq v0.0.4 h1:U7jjENWJd1jhcrR8X/xHTaph14PTAK9O+yaLJbjqgOw=\ngithub.com/ipfs/go-ipfs-pq v0.0.4/go.mod h1:9UdLOIIb99IFrgT0Fc53pvbvlJBhpUb4GJuAQf3+O2A=\ngithub.com/ipfs/go-ipld-format v0.6.3 h1:9/lurLDTotJpZSuL++gh3sTdmcFhVkCwsgx2+rAh4j8=\ngithub.com/ipfs/go-ipld-format v0.6.3/go.mod h1:74ilVN12NXVMIV+SrBAyC05UJRk0jVvGqdmrcYZvCBk=\ngithub.com/ipfs/go-ipld-legacy v0.3.0 h1:7XhFKkRyCvP5upOlQfKUFIqL3S5DEZnbUE4bQmQ/tNE=\ngithub.com/ipfs/go-ipld-legacy v0.3.0/go.mod h1:Ukef9ARQiX+RVetwH2XiReLgJvQDEXcUPszrZ1KRjKI=\ngithub.com/ipfs/go-log/v2 v2.9.1 h1:3JXwHWU31dsCpvQ+7asz6/QsFJHqFr4gLgQ0FWteujk=\ngithub.com/ipfs/go-log/v2 v2.9.1/go.mod h1:evFx7sBiohUN3AG12mXlZBw5hacBQld3ZPHrowlJYoo=\ngithub.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU=\ngithub.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY=\ngithub.com/ipfs/go-peertaskqueue v0.8.3 h1:tBPpGJy+A92RqtRFq5amJn0Uuj8Pw8tXi0X3eHfHM8w=\ngithub.com/ipfs/go-peertaskqueue v0.8.3/go.mod h1:OqVync4kPOcXEGdj/LKvox9DCB5mkSBeXsPczCxLtYA=\ngithub.com/ipfs/go-test v0.3.0 h1:0Y4Uve3tp9HI+2lIJjfOliOrOgv/YpXg/l1y3P4DEYE=\ngithub.com/ipfs/go-test v0.3.0/go.mod h1:JK+U8pRpATZb7lsYNSJlCj3WYB3cFfWIbI6nWRM/GFk=\ngithub.com/ipfs/go-unixfsnode v1.10.3 h1:c8sJjuGNkxXAQH75P+f5ngPda/9T+DrboVA0TcDGvGI=\ngithub.com/ipfs/go-unixfsnode v1.10.3/go.mod h1:2Jlc7DoEwr12W+7l8Hr6C7XF4NHST3gIkqSArLhGSxU=\ngithub.com/ipld/go-codec-dagpb v1.7.0 h1:hpuvQjCSVSLnTnHXn+QAMR0mLmb1gA6wl10LExo2Ts0=\ngithub.com/ipld/go-codec-dagpb v1.7.0/go.mod h1:rD3Zg+zub9ZnxcLwfol/OTQRVjaLzXypgy4UqHQvilM=\ngithub.com/ipld/go-ipld-prime v0.23.0 h1:csqdPZH60BsTC+AZrv7fpa27v+09I/oTqyHYYYE27eE=\ngithub.com/ipld/go-ipld-prime v0.23.0/go.mod h1:46YCFSFNFBJHPjB0pfMuv7Ly7df2eChpkpyPo5SE0bA=\ngithub.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=\ngithub.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=\ngithub.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=\ngithub.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=\ngithub.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU=\ngithub.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=\ngithub.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=\ngithub.com/libp2p/go-flow-metrics v0.3.0 h1:q31zcHUvHnwDO0SHaukewPYgwOBSxtt830uJtUx6784=\ngithub.com/libp2p/go-flow-metrics v0.3.0/go.mod h1:nuhlreIwEguM1IvHAew3ij7A8BMlyHQJ279ao24eZZo=\ngithub.com/libp2p/go-libp2p v0.48.0 h1:h2BrLAgrj7X8bEN05K7qmrjpNHYA+6tnsGRdprjTnvo=\ngithub.com/libp2p/go-libp2p v0.48.0/go.mod h1:Q1fBZNdmC2Hf82husCTfkKJVfHm2we5zk+NWmOGEmWk=\ngithub.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=\ngithub.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=\ngithub.com/libp2p/go-libp2p-record v0.3.1 h1:cly48Xi5GjNw5Wq+7gmjfBiG9HCzQVkiZOUZ8kUl+Fg=\ngithub.com/libp2p/go-libp2p-record v0.3.1/go.mod h1:T8itUkLcWQLCYMqtX7Th6r7SexyUJpIyPgks757td/E=\ngithub.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA=\ngithub.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg=\ngithub.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0=\ngithub.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM=\ngithub.com/libp2p/go-netroute v0.4.0 h1:sZZx9hyANYUx9PZyqcgE/E1GUG3iEtTZHUEvdtXT7/Q=\ngithub.com/libp2p/go-netroute v0.4.0/go.mod h1:Nkd5ShYgSMS5MUKy/MU2T57xFoOKvvLR92Lic48LEyA=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=\ngithub.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=\ngithub.com/mr-tron/base58 v1.3.0 h1:K6Y13R2h+dku0wOqKtecgRnBUBPrZzLZy5aIj8lCcJI=\ngithub.com/mr-tron/base58 v1.3.0/go.mod h1:2BuubE67DCSWwVfx37JWNG8emOC0sHEU4/HpcYgCLX8=\ngithub.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=\ngithub.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=\ngithub.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=\ngithub.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=\ngithub.com/multiformats/go-multiaddr v0.16.1 h1:fgJ0Pitow+wWXzN9do+1b8Pyjmo8m5WhGfzpL82MpCw=\ngithub.com/multiformats/go-multiaddr v0.16.1/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0=\ngithub.com/multiformats/go-multiaddr-dns v0.5.0 h1:p/FTyHKX0nl59f+S+dEUe8HRK+i5Ow/QHMw8Nh3gPCo=\ngithub.com/multiformats/go-multiaddr-dns v0.5.0/go.mod h1:yJ349b8TPIAANUyuOzn1oz9o22tV9f+06L+cCeMxC14=\ngithub.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=\ngithub.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=\ngithub.com/multiformats/go-multibase v0.3.0 h1:8helZD2+4Db7NNWFiktk2NePbF0boolBe6bDQvM4r68=\ngithub.com/multiformats/go-multibase v0.3.0/go.mod h1:MoBLQPCkRTOL3eveIPO81860j2AQY8JwcnNlRkGRUfI=\ngithub.com/multiformats/go-multicodec v0.10.0 h1:UpP223cig/Cx8J76jWt91njpK3GTAO1w02sdcjZDSuc=\ngithub.com/multiformats/go-multicodec v0.10.0/go.mod h1:wg88pM+s2kZJEQfRCKBNU+g32F5aWBEjyFHXvZLTcLI=\ngithub.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U=\ngithub.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=\ngithub.com/multiformats/go-multistream v0.6.1 h1:4aoX5v6T+yWmc2raBHsTvzmFhOI8WVOer28DeBBEYdQ=\ngithub.com/multiformats/go-multistream v0.6.1/go.mod h1:ksQf6kqHAb6zIsyw7Zm+gAuVo57Qbq84E27YlYqavqw=\ngithub.com/multiformats/go-varint v0.1.0 h1:i2wqFp4sdl3IcIxfAonHQV9qU5OsZ4Ts9IOoETFs5dI=\ngithub.com/multiformats/go-varint v0.1.0/go.mod h1:5KVAVXegtfmNQQm/lCY+ATvDzvJJhSkUlGQV9wgObdI=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/polydawn/refmt v0.89.1-0.20231129105047-37766d95467a h1:cgqrm0F3zwf9IPzca7xN4w+Zy6MC9ZkPvAC8QEWa/iQ=\ngithub.com/polydawn/refmt v0.89.1-0.20231129105047-37766d95467a/go.mod h1:ocZfO/tLSHqfScRDNTJbAJR1by4D1lewauX9OwTaPuY=\ngithub.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=\ngithub.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=\ngithub.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=\ngithub.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=\ngithub.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=\ngithub.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=\ngithub.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=\ngithub.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=\ngithub.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=\ngithub.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=\ngithub.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=\ngithub.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=\ngithub.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=\ngithub.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s=\ngithub.com/warpfork/go-testmark v0.12.1/go.mod h1:kHwy7wfvGSPh1rQJYKayD4AbtNaeyZdcGi9tNJTaa5Y=\ngo.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=\ngo.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=\ngo.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=\ngo.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=\ngo.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=\ngo.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI=\ngo.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=\ngo.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=\ngo.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=\ngo.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=\ngo.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=\ngo.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=\ngo.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=\ngolang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=\ngolang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=\ngolang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=\ngolang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=\ngolang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=\ngolang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=\ngolang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=\ngolang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=\ngolang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngolang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=\ngolang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=\ngoogle.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=\ngoogle.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nlukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=\nlukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=\n"
  },
  {
    "path": "storage/doc.go",
    "content": "// The storage package contains interfaces for storage systems, and functions for using them.\n//\n// These are very low-level storage primitives.\n// The interfaces here deal only with raw keys and raw binary blob values.\n//\n// In IPLD, you can often avoid dealing with storage directly yourself,\n// and instead use linking.LinkSystem to handle serialization, hashing, and storage all at once.\n// (You'll hand some values that match interfaces from this package to LinkSystem when configuring it.)\n// It's probably best to work at that level and above as much as possible.\n// If you do need to interact with storage more directly, the read on.\n//\n// The most basic APIs are ReadableStorage and WritableStorage.\n// When writing code that works with storage systems, these two interfaces should be seen in almost all situations:\n// user code is recommended to think in terms of these types;\n// functions provided by this package will accept parameters of these types and work on them;\n// implementations are expected to provide these types first;\n// and any new library code is recommended to keep with the theme: use these interfaces preferentially.\n//\n// Users should decide which actions they want to take using a storage system,\n// find the appropriate function in this package (n.b., package function -- not a method on an interface!\n// You will likely find one of each, with the same name: pick the package function!),\n// and use that function, providing it the storage system (e.g. either ReadableStorage, WritableStorage, or sometimes just Storage)\n// as a parameter.\n// That function will then use feature-detection (checking for matches to the other,\n// more advanced and more specific interfaces in this package) and choose the best way\n// to satisfy the request; or, if it can't feature-detect any relevant features,\n// the function will fall back to synthesizing the requested behavior out of the most basic API.\n// Using the package functions, and letting them do the feature detection for you,\n// should provide the most consistent user experience and minimize the amount of work you need to do.\n// (Bonus: It also gives us a convenient place to smooth out any future library migrations for you!)\n//\n// If writing new APIs that are meant to work reusably for any storage implementation:\n// APIs should usually be designed around accepting ReadableStorage or WritableStorage as parameters\n// (depending on which direction of data flow the API is regarding).\n// and use the other interfaces (e.g. StreamingReadableStorage) thereafter internally for feature detection.\n// For APIs which may sometimes be found relating to either a read or a write direction of data flow,\n// the Storage interface may be used in order to define a function that should accept either ReadableStorage or WritableStorage.\n// In other words: when writing reusable APIs, one should follow the same pattern as this package's own functions do.\n//\n// Similarly, implementers of storage systems should always implement either ReadableStorage or WritableStorage first.\n// Only after satisfying one of those should the implementation then move on to further supporting\n// additional interfaces in this package (all of which are meant to support feature-detection).\n// Beyond one of the basic two, all the other interfaces are optional:\n// you can implement them if you want to advertise additional features,\n// or advertise fastpaths that your storage system supports;\n// but you don't have implement any of those additional interfaces if you don't want to,\n// or if your implementation can't offer useful fastpaths for them.\n//\n// Storage systems as described by this package are allowed to make some interesting trades.\n// Generally, write operations are allowed to be first-write-wins.\n// Furthermore, there is no requirement that the system return an error if a subsequent write to the same key has different content.\n// These rules are reasonable for a content-addressed storage system, and allow great optimizations to be made.\n//\n// Note that all of the interfaces in this package only use types that are present in the golang standard library.\n// This is intentional, and was done very carefully.\n// If implementing a storage system, you should find it possible to do so *without* importing this package.\n// Because only standard library types are present in the interface contracts,\n// it's possible to implement types that align with the interfaces without referring to them.\n//\n// Note that where keys are discussed in this package, they use the golang string type --\n// however, they may be binary.  (The golang string type allows arbitrary bytes in general,\n// and here, we both use that, and explicitly disavow the usual \"norm\" that the string type implies UTF-8.\n// This is roughly the same as the practical truth that appears when using e.g. os.OpenFile and other similar functions.)\n// If you are creating a storage implementation where the underlying medium does not support arbitrary binary keys,\n// then it is strongly recommend that your storage implementation should support being configured with\n// an \"escaping function\", which should typically simply be of the form `func(string) string`.\n// Additional, your storage implementation's documentation should also clearly describe its internal limitations,\n// so that users have enough information to write an escaping function which\n// maps their domain into the domain your storage implementation can handle.\npackage storage\n\n// also note:\n// LinkContext stays *out* of this package.  It's a chooser-related thing.\n// LinkSystem can think about it (and your callbacks over there can think about it), and that's the end of its road.\n// (Future: probably LinkSystem should have SetStorage and SetupStorageChooser methods for helping you set things up -- where the former doesn't discuss LinkContext at all.)\n"
  },
  {
    "path": "storage/dsadapter/README.md",
    "content": "dsadapter\n=========\n\nThe `dsadapter` package/module is a small piece of glue code to connect\nthe `github.com/ipfs/go-datastore` package, and packages implementing its interfaces,\nforward into the `go-ipld-prime/storage` interfaces.\n\nFor example, this can be used to use \"flatfs\" and other datastore plugins\nwith go-ipld-prime storage APIs.\n\n\nWhy structured like this?\n-------------------------\n\nSee `../README_adapters.md` for details about why adapter code is needed,\nwhy this is in a module, why it's here, etc.\n\n\nWhich of `dsadapter` vs `bsadapter` vs `bsrvadapter` should I use?\n------------------------------------------------------------------\n\nIn short: you should prefer direct implementations of the storage APIs\nover any of these adapters, if one is available with the features you need.\n\nOtherwise, if that's not an option (yet) for some reason,\nuse whichever adapter gets you most directly connected to the code you need.\n\nSee `../README_adapters.md` for more details and discussion.\n"
  },
  {
    "path": "storage/dsadapter/dsadapter.go",
    "content": "package dsadapter\n\nimport (\n\t\"context\"\n\n\t\"github.com/ipfs/go-datastore\"\n)\n\n// Adapter implements go-ipld-prime/storage.ReadableStorage\n// and go-ipld-prime/storage.WritableStorage\n// backed by a go-datastore.Datastore.\n//\n// Optionally, an EscapingFunc may also be set,\n// which transforms the (possibly binary) keys considered acceptable\n// by the go-ipld-prime/storage APIs into a subset that\n// the go-datastore can accept.\n// (Be careful to use any escaping consistently,\n// and be wary of potential unexpected behavior if the escaping function might\n// collapse two distinct keys into the same \"escaped\" key.)\n//\n// The go-datastore.Datastore may internally have other configuration,\n// such as key sharding functions, etc, and we don't interfere with that here;\n// such configuration should be handled when creating the go-datastore value.\n//\n// Contexts given to this system are checked for errors at the beginning of an operation,\n// but otherwise have no effect, because the Datastore API doesn't accept context parameters.\ntype Adapter struct {\n\tWrapped      datastore.Datastore\n\tEscapingFunc func(string) string\n}\n\n// Has implements go-ipld-prime/storage.Storage.Has.\nfunc (a *Adapter) Has(ctx context.Context, key string) (bool, error) {\n\t// Return early if the context is already closed.\n\t// This is also the last time we'll check the context,\n\t// since go-datastore doesn't take them.\n\tif ctx.Err() != nil {\n\t\treturn false, ctx.Err()\n\t}\n\n\t// If we have an EscapingFunc, apply it.\n\tif a.EscapingFunc != nil {\n\t\tkey = a.EscapingFunc(key)\n\t}\n\n\t// Wrap the key into go-datastore's concrete type that it requires.\n\t// Note that this does a bunch of actual work, which may be surprising.\n\t// The key may be transformed (as per path.Clean).\n\t// There will also be an allocation, if the key doesn't start with \"/\".\n\t// (Avoiding these performance drags is part of why we started\n\t// new interfaces in go-ipld-prime/storage.)\n\tk := datastore.NewKey(key)\n\n\t// Delegate the has call.\n\t// Note that for some datastore implementations, this will do *yet more*\n\t// validation on the key, and may return errors from that.\n\treturn a.Wrapped.Has(ctx, k)\n}\n\n// Get implements go-ipld-prime/storage.ReadableStorage.Get.\nfunc (a *Adapter) Get(ctx context.Context, key string) ([]byte, error) {\n\t// Return early if the context is already closed.\n\t// This is also the last time we'll check the context,\n\t// since go-datastore doesn't take them.\n\tif ctx.Err() != nil {\n\t\treturn nil, ctx.Err()\n\t}\n\n\t// If we have an EscapingFunc, apply it.\n\tif a.EscapingFunc != nil {\n\t\tkey = a.EscapingFunc(key)\n\t}\n\n\t// Wrap the key into go-datastore's concrete type that it requires.\n\t// Note that this does a bunch of actual work, which may be surprising.\n\t// The key may be transformed (as per path.Clean).\n\t// There will also be an allocation, if the key doesn't start with \"/\".\n\t// (Avoiding these performance drags is part of why we started\n\t// new interfaces in go-ipld-prime/storage.)\n\tk := datastore.NewKey(key)\n\n\t// Delegate the get call.\n\t// Note that for some datastore implementations, this will do *yet more*\n\t// validation on the key, and may return errors from that.\n\treturn a.Wrapped.Get(ctx, k)\n}\n\n// Put implements go-ipld-prime/storage.WritableStorage.Put.\nfunc (a *Adapter) Put(ctx context.Context, key string, content []byte) error {\n\t// Return early if the context is already closed.\n\t// This is also the last time we'll check the context,\n\t// since go-datastore doesn't take them.\n\tif ctx.Err() != nil {\n\t\treturn ctx.Err()\n\t}\n\n\t// If we have an EscapingFunc, apply it.\n\tif a.EscapingFunc != nil {\n\t\tkey = a.EscapingFunc(key)\n\t}\n\n\t// Wrap the key into go-datastore's concrete type that it requires.\n\t// Note that this does a bunch of actual work, which may be surprising.\n\t// The key may be transformed (as per path.Clean).\n\t// There will also be an allocation, if the key doesn't start with \"/\".\n\t// (Avoiding these performance drags is part of why we started\n\t// new interfaces in go-ipld-prime/storage.)\n\tk := datastore.NewKey(key)\n\n\t// Delegate the put call.\n\t// Note that for some datastore implementations, this will do *yet more*\n\t// validation on the key, and may return errors from that.\n\treturn a.Wrapped.Put(ctx, k, content)\n}\n"
  },
  {
    "path": "storage/dsadapter/go.mod",
    "content": "module github.com/ipld/go-ipld-prime/storage/dsadapter\n\ngo 1.25\n\nrequire github.com/ipfs/go-datastore v0.9.1\n\nrequire github.com/google/uuid v1.6.0 // indirect\n"
  },
  {
    "path": "storage/dsadapter/go.sum",
    "content": "github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/ipfs/go-datastore v0.9.1 h1:67Po2epre/o0UxrmkzdS9ZTe2GFGODgTd2odx8Wh6Yo=\ngithub.com/ipfs/go-datastore v0.9.1/go.mod h1:zi07Nvrpq1bQwSkEnx3bfjz+SQZbdbWyCNvyxMh9pN0=\ngithub.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=\ngithub.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "storage/fsstore/fsstore.go",
    "content": "package fsstore\n\nimport (\n\t\"context\"\n\t\"crypto/rand\"\n\t\"encoding/base32\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/ipld/go-ipld-prime/storage/sharding\"\n)\n\n// Store is implements storage.ReadableStorage and storage.WritableStorage,\n// as well as quite a few of the other extended storage feature interfaces,\n// backing it with simple filesystem operations.\n//\n// This implementation uses golang's usual `os` package for IO,\n// so it should be highly portable.\n//\n// Both the sharding and escaping functions are configurable,\n// but a typical recommended setup is to use base32 encoding,\n// and a sharding function that returns two shards of two characters each.\n// The escaping and sharding functions should be chosen with regard to each other --\n// the sharding function is applied to the escaped form.\ntype Store struct {\n\tbasepath     string\n\tescapingFunc func(string) string\n\tshardingFunc func(key string, shards *[]string)\n}\n\nfunc (store *Store) InitDefaults(basepath string) error {\n\treturn store.Init(\n\t\tbasepath,\n\t\tb32enc,             // The same function as go-ipfs uses: see https://github.com/ipfs/go-ipfs-ds-help/blob/48b9cc210923d23b39582b5fa6670ed0d08dc2af/key.go#L20-L22 .\n\t\tsharding.Shard_r12, // Equivalent to what go-ipfs uses by default with flatfs: see https://github.com/ipfs/go-ipfs/blob/52a747763f6c4e85b33ca051cda9cc4b75c815f9/docs/config.md#datastorespec and grep for \"shard/v1/next-to-last/2\".\n\t)\n}\n\nfunc (store *Store) Init(\n\tbasepath string,\n\tescapingFunc func(string) string,\n\tshardingFunc func(key string, shards *[]string),\n) error {\n\t// Simple args and state check.\n\tif basepath == \"\" {\n\t\treturn fmt.Errorf(\"fsstore: invalid setup args: need a path\")\n\t}\n\tif store.basepath != \"\" {\n\t\treturn fmt.Errorf(\"fsstore: cannot init: is already initialized\")\n\t}\n\tstore.basepath = basepath\n\tstore.escapingFunc = escapingFunc\n\tstore.shardingFunc = shardingFunc\n\n\t// Make sure basepath is a dir, and make sure the staging and content dirs exist.\n\tif err := CheckAndMakeBasepath(basepath); err != nil {\n\t\treturn err\n\t}\n\n\t// That's it for setup on this one.\n\treturn nil\n}\n\nvar b32encoder = base32.StdEncoding.WithPadding(base32.NoPadding)\n\nfunc b32enc(in string) string {\n\treturn b32encoder.EncodeToString([]byte(in))\n}\n\n// pathForKey applies sharding funcs as well as adds the basepath prefix,\n// returning a string ready to use as a filesystem path.\nfunc (store *Store) pathForKey(key string) string {\n\tshards := make([]string, 1, 4) // future work: would be nice if we could reuse this rather than fresh allocating.\n\tshards[0] = store.basepath     // not part of the path shard, but will be a param to Join, so, practical to put here.\n\t//shards[1] = storageDir       // not part of the path shard, but will be a param to Join, so, practical to put here.\n\tstore.shardingFunc(key, &shards)\n\treturn filepath.Join(shards...)\n}\n\n// Has implements go-ipld-prime/storage.Storage.Has.\nfunc (store *Store) Has(ctx context.Context, key string) (bool, error) {\n\t_, err := os.Stat(store.pathForKey(key))\n\tif err == nil {\n\t\treturn true, nil\n\t}\n\tif os.IsNotExist(err) {\n\t\treturn false, nil\n\t}\n\treturn false, err\n}\n\n// Get implements go-ipld-prime/storage.ReadableStorage.Get.\nfunc (store *Store) Get(ctx context.Context, key string) ([]byte, error) {\n\tf, err := store.GetStream(ctx, key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer f.(io.Closer).Close()\n\treturn io.ReadAll(f)\n}\n\n// Put implements go-ipld-prime/storage.WritableStorage.Put.\nfunc (store *Store) Put(ctx context.Context, key string, content []byte) error {\n\t// We can't improve much on what we get by wrapping the stream interface;\n\t//  we always end up using a streaming action on the very bottom because that's how file writing works\n\t//   (especially since we care about controlling the write flow enough to be able to do the atomic move at the end).\n\twr, wrCommitter, err := store.PutStream(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// Write, all at once.\n\t// Note we can ignore the size return, because the contract of io.Writer states \"Write must return a non-nil error if it returns n < len(p)\".\n\t_, err = wr.Write(content)\n\tif err != nil {\n\t\twrCommitter(\"\")\n\t\treturn err\n\t}\n\t// Commit.\n\treturn wrCommitter(key)\n}\n\n// GetStream implements go-ipld-prime/storage.StreamingReadableStorage.GetStream.\nfunc (store *Store) GetStream(ctx context.Context, key string) (io.ReadCloser, error) {\n\tif ctx.Err() != nil {\n\t\treturn nil, ctx.Err()\n\t}\n\n\t// Figure out where we expect it to be.\n\tdestpath := store.pathForKey(key)\n\n\t// Open and return.\n\t// TODO: we should normalize things like \"not exists\" errors before hurling them up the stack.\n\treturn os.OpenFile(destpath, os.O_RDONLY, 0)\n}\n\n// PutStream implements go-ipld-prime/storage.StreamingWritableStorage.PutStream.\nfunc (store *Store) PutStream(ctx context.Context) (io.Writer, func(string) error, error) {\n\tfor {\n\t\tif ctx.Err() != nil {\n\t\t\treturn nil, nil, ctx.Err()\n\t\t}\n\t\t// Open a new file in the staging area, with a random name.\n\t\tvar bs [8]byte\n\t\trand.Read(bs[:])\n\t\tstagepath := filepath.Join(store.basepath, stagingDir, hex.EncodeToString(bs[:]))\n\t\tf, err := os.OpenFile(stagepath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0666)\n\t\tif os.IsExist(err) {\n\t\t\tcontinue\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"fsstore.BeginWrite: could not create a staging file: %w\", err)\n\t\t}\n\t\t// Okay, got a handle.  Return it... and its commit closure.\n\t\treturn f, func(key string) error {\n\t\t\t// Close the staging file.\n\t\t\tif err := f.Close(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif key == \"\" {\n\t\t\t\treturn os.Remove(stagepath)\n\t\t\t}\n\t\t\t// n.b. there is a lack of fsync here.  I am going to choose to believe that a sane filesystem will not let me do a 'move' without flushing somewhere in between.\n\t\t\t// Fun little note: there are some times in history where this belief is not backed -- but, mostly, the evolution of kernel and filesystem development seems to have considered that a mistake,\n\t\t\t// and things do again typically take 'move' as a strong cue to flush, unless you've actively configured your system oddly.\n\t\t\t// See https://en.wikipedia.org/wiki/Ext4#Delayed_allocation_and_potential_data_loss for some fun history regarding Ext4;\n\t\t\t// but ultimately, note that the kernel decided to again make 'move' cause flush, and has done so since 2.6.30, which came out sometime in 2009.\n\t\t\t// Accordingly, our lack of fsync here seems justified.\n\t\t\t// However, if you *really* find a system in the wild where this is problematic,\n\t\t\t// *and* you cannot make your application recover gracefully (which should be relatively easy, because... content addressing; you can't have inconsistency, at least!),\n\t\t\t// *and* you cannot configure your filesystem to have the level of durability and sanity that you want, so you must fix it in application land...\n\t\t\t// then... patches welcome.  :)\n\t\t\t//\n\t\t\t// History also seems to indicate that if we add fsyncs hereabouts, people will usually just turn around and seek to disable them for performance reasons;\n\t\t\t// so by default, it seems best to just not do the dance of having a default that people hate.\n\n\t\t\t// Figure out where we want it to go.\n\t\t\tdestpath := store.pathForKey(key)\n\n\t\t\t// Get it there.\n\t\t\treturn move(stagepath, destpath)\n\t\t}, nil\n\t}\n}\n\nconst stagingDir = \".temp\" // same as flatfs uses.\n\nfunc CheckAndMakeBasepath(basepath string) error {\n\t// Is this basepath a dir?\n\t// (This is TOCTOU, obviously, but also it's nice to sanity check early and return error quickly because it's probably a setup error.)\n\tif fi, err := os.Stat(basepath); err != nil {\n\t\treturn fmt.Errorf(\"fsstore: cannot init: basepath must be a directory: %w\", err)\n\t} else {\n\t\tif !fi.IsDir() {\n\t\t\treturn fmt.Errorf(\"fsstore: cannot init: basepath must be a directory\")\n\t\t}\n\t}\n\n\t// Make sure the staging dir exists.\n\terr := os.Mkdir(filepath.Join(basepath, stagingDir), 0777)\n\tswitch {\n\tcase err == nil:\n\t\t// excellent.\n\tcase os.IsExist(err):\n\t\t// sanity check it's a directory already.\n\t\tfi, err := os.Stat(filepath.Join(basepath, stagingDir))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"fsstore: failed to make staging dir: %w\", err)\n\t\t}\n\t\tif !fi.IsDir() {\n\t\t\treturn fmt.Errorf(\"fsstore: staging dir path contains not a dir\")\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"fsstore: failed to make staging dir: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// move file at stagepath to destpath.\n// First, attempt to directly rename to the destination;\n// if we get a ENOENT error code, that means the parent didn't exist, and we make that and then retry.\n// If making the parent failed: recurse, and use similar logic.\n//\n// This optimistic approach should have fewer syscall RTTs when most of the parents exist\n// than would be taken if we checked that each parent segment exists.\n//\n// (An alternative approach would be to blindly mkdir the parent segments every time,\n// rather than do this backwards stepping.  Have not benchmarked these against each other.)\nfunc move(stagepath, destpath string) error {\n\terr := os.Rename(stagepath, destpath)\n\tif os.IsNotExist(err) {\n\t\t// This probably means parent of destpath doesn't exist yet, so we'll make it.\n\t\t//  It's technically a race condition to assume that this is because destpath has no parents vs that stagepath hasn't been removed out from underneath us, but, alas; kernel ABIs.\n\t\t//   If we did this will all fds, it could be somewhat better.\n\t\t//    (This is certainly possible, at least in linux; but we'd have to import the syscall package and do it ourselves, which is not a rubicon we're willing to cross in this package.)\n\t\t//   In practice, this is probably not going to kerfuffle things.\n\t\tif err := haveDir(filepath.Dir(destpath)); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// Now try again.\n\t\t//  (And don't return quite yet; there's one more check to do, because someone might've raced us.)\n\t\terr = os.Rename(stagepath, destpath)\n\t}\n\tif os.IsExist(err) {\n\t\t// Oh!  Some content is already there?\n\t\t//  We're a write-once (presumed-to-be-)content-addressable blob store -- that means *we keep what already exists*.\n\t\t//  FIXME: no, I wish this is how the Rename function worked, but it is not, actually.\n\t\treturn os.Remove(stagepath)\n\t}\n\treturn err\n}\n\n// haveDir tries to make sure a directory exists at pth.\n// If this sounds a lot like os.MkdirAll: yes,\n// except this function is going to assume if it exists, it's a dir,\n// and that saves us some stat syscalls.\nfunc haveDir(pth string) error {\n\terr := os.Mkdir(pth, 0777)\n\tif os.IsNotExist(err) {\n\t\tif err := haveDir(filepath.Dir(pth)); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn os.Mkdir(pth, 0777)\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "storage/funcs.go",
    "content": "package storage\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n)\n\n/*\n\tThis file contains equivalents of every method that can be feature-detected on a storage system.\n\tYou can always call these functions, and give them the most basic storage interface,\n\tand they'll attempt to feature-detect their way to the best possible implementation of the behavior,\n\tor they'll fall back to synthesizing the same behavior from more basic interfaces.\n\n\tLong story short: you can always use these functions as an end user, and get the behavior you want --\n\tregardless of how much explicit support the storage implementation has for the exact behavior you requested.\n*/\n\nfunc Has(ctx context.Context, store Storage, key string) (bool, error) {\n\t// Okay, not much going on here -- this function is only here for consistency of style.\n\treturn store.Has(ctx, key)\n}\n\nfunc Get(ctx context.Context, store ReadableStorage, key string) ([]byte, error) {\n\t// Okay, not much going on here -- this function is only here for consistency of style.\n\treturn store.Get(ctx, key)\n}\n\nfunc Put(ctx context.Context, store WritableStorage, key string, content []byte) error {\n\t// Okay, not much going on here -- this function is only here for consistency of style.\n\treturn store.Put(ctx, key, content)\n}\n\n// GetStream returns a streaming reader.\n// This function will feature-detect the StreamingReadableStorage interface, and use that if possible;\n// otherwise it will fall back to using basic ReadableStorage methods transparently\n// (at the cost of loading all the data into memory at once and up front).\nfunc GetStream(ctx context.Context, store ReadableStorage, key string) (io.ReadCloser, error) {\n\t// Prefer the feature itself, first.\n\tif streamable, ok := store.(StreamingReadableStorage); ok {\n\t\treturn streamable.GetStream(ctx, key)\n\t}\n\t// Fallback to basic.\n\tblob, err := store.Get(ctx, key)\n\treturn noopCloser{bytes.NewReader(blob)}, err\n}\n\n// PutStream returns an io.Writer and a WriteCommitter callback.\n// (See the docs on StreamingWritableStorage.PutStream for details on what that means.)\n// This function will feature-detect the StreamingWritableStorage interface, and use that if possible;\n// otherwise it will fall back to using basic WritableStorage methods transparently\n// (at the cost of needing to buffer all of the content in memory while the write is in progress).\nfunc PutStream(ctx context.Context, store WritableStorage) (io.Writer, func(key string) error, error) {\n\t// Prefer the feature itself, first.\n\tif streamable, ok := store.(StreamingWritableStorage); ok {\n\t\treturn streamable.PutStream(ctx)\n\t}\n\t// Fallback to basic.\n\tvar buf bytes.Buffer\n\tvar written bool\n\treturn &buf, func(key string) error {\n\t\tif written {\n\t\t\treturn fmt.Errorf(\"WriteCommitter already used\")\n\t\t}\n\t\twritten = true\n\t\treturn store.Put(ctx, key, buf.Bytes())\n\t}, nil\n}\n\n// PutVec is an API for writing several slices of bytes at once into storage.\n// This kind of API can be useful for maximizing performance in scenarios where\n// data is already loaded completely into memory, but scattered across several non-contiguous regions.\n// This function will feature-detect the VectorWritableStorage interface, and use that if possible;\n// otherwise it will fall back to using StreamingWritableStorage,\n// or failing that, fall further back to basic WritableStorage methods, transparently.\nfunc PutVec(ctx context.Context, store WritableStorage, key string, blobVec [][]byte) error {\n\t// Prefer the feature itself, first.\n\tif putvable, ok := store.(VectorWritableStorage); ok {\n\t\treturn putvable.PutVec(ctx, key, blobVec)\n\t}\n\t// Fallback to streaming mode.\n\t// ... or, fallback to basic, and use emulated streaming.  Still presumably preferable to doing a big giant memcopy.\n\t// Conveniently, the PutStream function makes that transparent for our implementation, too.\n\twr, wrcommit, err := PutStream(ctx, store)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, blob := range blobVec {\n\t\t_, err := wr.Write(blob)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn wrcommit(key)\n}\n\n// Peek accessess the same data as Get, but indicates that the caller promises not to mutate the returned byte slice.\n// (By contrast, Get is expected to return a safe copy.)\n// This function will feature-detect the PeekableStorage interface, and use that if possible;\n// otherwise it will fall back to using basic ReadableStorage methods transparently\n// (meaning that a no-copy fastpath simply wasn't available).\n//\n// An io.Closer is returned along with the byte slice.\n// The Close method on the Closer must be called when the caller is done with the byte slice;\n// otherwise, memory leaks may result.\n// (Implementers of this interface may be expecting to reuse the byte slice after Close is called.)\nfunc Peek(ctx context.Context, store ReadableStorage, key string) ([]byte, io.Closer, error) {\n\t// Prefer the feature itself, first.\n\tif peekable, ok := store.(PeekableStorage); ok {\n\t\treturn peekable.Peek(ctx, key)\n\t}\n\t// Fallback to basic.\n\tbs, err := store.Get(ctx, key)\n\treturn bs, noopCloser{nil}, err\n}\n\ntype noopCloser struct {\n\tio.Reader\n}\n\nfunc (noopCloser) Close() error { return nil }\n"
  },
  {
    "path": "storage/memstore/memstore.go",
    "content": "package memstore\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n)\n\n// Store is a simple in-memory storage.\n// (It's little more than a map -- in fact, the map is exported,\n// and you can poke it directly.)\n//\n// Store conforms to the storage.ReadableStorage and storage.WritableStorage APIs.\n// Additionally, it supports storage.PeekableStorage and storage.StreamingReadableStorage,\n// because it can do so while provoking fewer copies.\n//\n// If you want to use this store with streaming APIs,\n// you can still do so by using the functions in the storage package,\n// such as storage.GetStream and storage.PutStream, which will synthesize the correct behavior.\n//\n// You can use this storage with a linking.LinkSystem easily,\n// by using the LinkSystem.SetReadStorage and/or LinkSystem.SetWriteStorage methods.\n//\n// There are no construction parameters for sharding functions nor escaping functions.\n// Any keys are acceptable.\n//\n// This storage is mostly expected to be used for testing and demos,\n// and as an example of how you can implement and integrate your own storage systems.\n// It does not provide persistence beyond memory.\ntype Store struct {\n\tBag map[string][]byte\n}\n\nfunc (store *Store) beInitialized() {\n\tif store.Bag != nil {\n\t\treturn\n\t}\n\tstore.Bag = make(map[string][]byte)\n}\n\n// Has implements go-ipld-prime/storage.Storage.Has.\nfunc (store *Store) Has(ctx context.Context, key string) (bool, error) {\n\tif store.Bag == nil {\n\t\treturn false, nil\n\t}\n\t_, exists := store.Bag[key]\n\treturn exists, nil\n}\n\n// Get implements go-ipld-prime/storage.ReadableStorage.Get.\n//\n// Note that this internally performs a defensive copy;\n// use Peek for higher performance if you are certain you won't mutate the returned slice.\nfunc (store *Store) Get(ctx context.Context, key string) ([]byte, error) {\n\tstore.beInitialized()\n\tcontent, exists := store.Bag[key]\n\tif !exists {\n\t\treturn nil, fmt.Errorf(\"404\") // FIXME this needs a standard error type\n\t}\n\tcpy := make([]byte, len(content))\n\tcopy(cpy, content)\n\treturn cpy, nil\n}\n\n// Put implements go-ipld-prime/storage.WritableStorage.Put.\nfunc (store *Store) Put(ctx context.Context, key string, content []byte) error {\n\tstore.beInitialized()\n\tif _, exists := store.Bag[key]; exists {\n\t\treturn nil\n\t}\n\tcpy := make([]byte, len(content))\n\tcopy(cpy, content)\n\tstore.Bag[key] = cpy\n\treturn nil\n}\n\n// GetStream implements go-ipld-prime/storage.StreamingReadableStorage.GetStream.\n//\n// It's useful for this storage implementation to explicitly support this,\n// because returning a reader gives us room to avoid needing a defensive copy.\nfunc (store *Store) GetStream(ctx context.Context, key string) (io.ReadCloser, error) {\n\tcontent, exists := store.Bag[key]\n\tif !exists {\n\t\treturn nil, fmt.Errorf(\"404\") // FIXME this needs a standard error type\n\t}\n\treturn noopCloser{bytes.NewReader(content)}, nil\n}\n\n// Peek implements go-ipld-prime/storage.PeekableStorage.Peek.\nfunc (store *Store) Peek(ctx context.Context, key string) ([]byte, io.Closer, error) {\n\tcontent, exists := store.Bag[key]\n\tif !exists {\n\t\treturn nil, nil, fmt.Errorf(\"404\") // FIXME this needs a standard error type\n\t}\n\treturn content, noopCloser{nil}, nil\n}\n\ntype noopCloser struct {\n\tio.Reader\n}\n\nfunc (noopCloser) Close() error { return nil }\n"
  },
  {
    "path": "storage/sharding/sharding.go",
    "content": "/*\nThis package contains several useful readymade sharding functions,\nwhich should plug nicely into most storage implementations.\n\nThe API contract for a sharding function is:\n\n\tfunc(key string, shards *[]string)\n\nIn other words, the return is actually by a pointer to a slice which will be mutated.\nThis API allows the calling code to hand in a slice with existing capacity,\nand thus allows for sharding functions to work without allocations.\n\nThere is not a named type for this contract, because we prefer that packages\nimplementing the storage APIs should be possible to write without\nbeing required to import any code from the go-ipld-prime module.\nHowever, the function type definition above can be seen in many packages.\n\nNot all packages use this API convention.  The `fsstore` package does;\nsome other storage implementations don't use sharding functions because they don't need them;\nmost of the adapter packages which target older code do not,\nbecause those modules have their own sharding APIs already.\n*/\npackage sharding\n\n// Shard_r133 is a sharding function which will return three hunks,\n// the last of which is the full original key,\n// and the first two of which are three bytes long.\n// The prefix hunks are taken from the end of the original key,\n// after skipping one byte.\n// If the key is too short, padding of the ascii \"0\" character is used.\n//\n// (This somewhat odd-sounding procedure is a useful one in practice,\n// because if applying it on a base32 string that's a CID or multihash (which is the typical usage),\n// it avoids the uneven distribution of the trailing characters of a base32 string,\n// and also avoids the uneven distribution of the prefixes of CIDs or mulithashes.)\n//\n// If the shards parameter is a pointer to a slice that starts at zero length\n// and a capacity of at least 3, this function will operate with no allocations.\n//\n// Supposing the key is a base32 string (where each byte effectively contains 2^5 bits),\n// if a sufficient range of keys is present that all shards are seen,\n// each group of shards will contain (2^5)^3=32768 entries.\nfunc Shard_r133(key string, shards *[]string) {\n\tl := len(key)\n\tswitch {\n\tcase l > 6:\n\t\t*shards = append(*shards, key[l-7:l-4], key[l-4:l-1], key)\n\tcase l > 3:\n\t\t*shards = append(*shards, \"000\", key[l-4:l-1], key)\n\tdefault:\n\t\t*shards = append(*shards, \"000\", \"000\", key)\n\t}\n}\n\n// Shard_r133 is a sharding function which will return three hunks.\n// It is very similar to Shard_r133, but with shorter hunks.\n// The last hunk is the full original key,\n// and the first two hunks are two bytes long each.\n// The prefix hunks are taken from the end of the original key,\n// after skipping one byte.\n// If the key is too short, padding of the ascii \"0\" character is used.\n//\n// If the shards parameter is a pointer to a slice that starts at zero length\n// and a capacity of at least 3, this function will operate with no allocations.\n//\n// Supposing the key is a base32 string (where each byte effectively contains 2^5 bits),\n// if a sufficient range of keys is present that all shards are seen,\n// each group of shards will contain (2^5)^2=1024 entries.\n// (This is often a useful number in practice, because if one is mapping shards\n// onto filesystem directories, 1024 entries is almost certainly going to fit\n// efficiently within any filesystem format you're likely to encounter;\n// 1024-within-1024 also means you'll see about a billion entries before\n// directories on the second layer of sharding will contain more than 1024 files.\n// (If we're assuming 1MB blocks of data asthe actual contents, that would be quite\n// a few terabytes of storage, so this is a very nice balanced trade for\n// most practical systems.))\nfunc Shard_r122(key string, shards *[]string) {\n\tl := len(key)\n\tswitch {\n\tcase l > 4:\n\t\t*shards = append(*shards, key[l-5:l-3], key[l-3:l-1], key)\n\tcase l > 2:\n\t\t*shards = append(*shards, \"00\", key[l-3:l-1], key)\n\tdefault:\n\t\t*shards = append(*shards, \"00\", \"00\", key)\n\t}\n}\n\n// Shard_r12 is a sharding function which will return two hunks.\n// The last hunk is the full original key,\n// and the first hunk is two bytes long.\n// The prefix is are taken from the end of the original key,\n// after skipping one byte.\n// If the key is too short, the first hunk is just the ascii characters \"00\" instead.\n//\n// If the shards parameter is a pointer to a slice that starts at zero length\n// and a capacity of at least 2, this function will operate with no allocations.\n//\n// Shard_r122 is functionally equivalent to \"flatfs/shard/v1/next-to-last/2\",\n// as it's known in some other code -- it may be familiar as the default\n// for block storage in go-ipfs.\nfunc Shard_r12(key string, shards *[]string) {\n\tl := len(key)\n\tswitch {\n\tcase l > 2:\n\t\t*shards = append(*shards, key[l-3:l-1], key)\n\tdefault:\n\t\t*shards = append(*shards, \"00\", key)\n\t}\n}\n"
  },
  {
    "path": "storage/sharding/sharding_bench_test.go",
    "content": "package sharding\n\nimport (\n\t\"testing\"\n)\n\nvar globalSink interface{}\n\n// This doesn't benchmark each of the sharding functions because... they're all roughly the same, really.\n// It's mainly to make sure that our documentation's claim about zero-alloc operation is true.\nfunc Benchmark(b *testing.B) {\n\tb.ReportAllocs()\n\tk := \"abcdefgh\"\n\tv := make([]string, 0, 3)\n\tvar sink string\n\tfor n := 0; n < b.N; n++ {\n\t\tv = v[0:0]\n\t\tShard_r133(k, &v)\n\t\tsink = v[1]\n\t}\n\tglobalSink = sink // make very very sure the compiler can't optimize our 'v' into oblivion.\n}\n"
  },
  {
    "path": "storage/sharding/sharding_test.go",
    "content": "package sharding\n\nimport (\n\t\"fmt\"\n\t\"path\"\n)\n\nfunc printShard(fn func(string, *[]string), key string) {\n\tv := make([]string, 0, 4)\n\tfn(key, &v)\n\tfmt.Printf(\"%s => %s\\n\", key, path.Join(v...))\n}\n\nfunc Example_shard_R133() {\n\tprintShard(Shard_r133, \"abcdefgh\")\n\tprintShard(Shard_r133, \"abcdefg\")\n\tprintShard(Shard_r133, \"abcdef\")\n\tprintShard(Shard_r133, \"abcde\")\n\tprintShard(Shard_r133, \"abcd\")\n\tprintShard(Shard_r133, \"abc\")\n\n\t// Output:\n\t// abcdefgh => bcd/efg/abcdefgh\n\t// abcdefg => abc/def/abcdefg\n\t// abcdef => 000/cde/abcdef\n\t// abcde => 000/bcd/abcde\n\t// abcd => 000/abc/abcd\n\t// abc => 000/000/abc\n\n}\n\nfunc Example_shard_r122() {\n\tprintShard(Shard_r122, \"abcdefgh\")\n\tprintShard(Shard_r122, \"abcdefg\")\n\tprintShard(Shard_r122, \"abcdef\")\n\tprintShard(Shard_r122, \"abcde\")\n\tprintShard(Shard_r122, \"abcd\")\n\tprintShard(Shard_r122, \"abc\")\n\n\t// Output:\n\t// abcdefgh => de/fg/abcdefgh\n\t// abcdefg => cd/ef/abcdefg\n\t// abcdef => bc/de/abcdef\n\t// abcde => ab/cd/abcde\n\t// abcd => 00/bc/abcd\n\t// abc => 00/ab/abc\n}\n\nfunc Example_shard_r12() {\n\tprintShard(Shard_r12, \"abcde\")\n\tprintShard(Shard_r12, \"abcd\")\n\tprintShard(Shard_r12, \"abc\")\n\tprintShard(Shard_r12, \"ab\")\n\n\t// Output:\n\t// abcde => cd/abcde\n\t// abcd => bc/abcd\n\t// abc => ab/abc\n\t// ab => 00/ab\n}\n"
  },
  {
    "path": "storage/tests/benchmarks.go",
    "content": "package tests\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/ipld/go-ipld-prime/storage\"\n)\n\n/*\n\tGeneral note:\n\tIt's important to be careful to benchmark the cost *per op* --\n\tand not mistake b.N for the scale of corpus to work on.\n\tThe corpus size should be a parameter that you supply,\n\tand your benchmark table should have a column for them!\n*/\n\nfunc BenchPut(b *testing.B, store storage.WritableStorage, gen Gen, scale int) {\n\tb.ReportAllocs()\n\tb.Logf(\"benchmarking with b.N=%d\", b.N)\n\n\t// Use a fixed context throughout; it's not really relevant.\n\tctx := context.Background()\n\n\t// Setup phase: create data up to the scale provided.\n\t// Reset the timer afterwards.\n\tb.Logf(\"prepopulating %d entries into storage...\", scale)\n\tfor n := 0; n < scale; n++ {\n\t\tkey, content := gen()\n\t\terr := store.Put(ctx, key, content)\n\t\tif err != nil {\n\t\t\tb.Fatal(err)\n\t\t}\n\t}\n\tb.Logf(\"prepopulating %d entries into storage: done.\", scale)\n\tb.ResetTimer()\n\n\t// Now continue doing puts in the benchmark loop.\n\t// Note that if 'scale' was initially small, and b.N is big, results may be skewed,\n\t//  because the last put of the series will actually be working at scale+b.N-1.\n\tfor n := 0; n < b.N; n++ {\n\t\t// Attempt to avoid counting any time spent by the gen func.\n\t\t//  ... except don't, because the overhead of starting and stopping is actually really high compared to a likely gen function;\n\t\t//   in practice, starting and stopping this frequently causes:\n\t\t//    - alloc count to be reported *correctly* (which is nice)\n\t\t//    - but reported ns/op to become erratic, and inflated (not at all nice)\n\t\t//    - and actual wall-clock run time to increase drastically (~22x!) (not deadly, but certainly unpleasant)\n\t\t//   It may be best to write a synthetic dummy benchmark to see how much the gen function costs, and subtract that from the other results.\n\t\t//b.StopTimer()\n\t\tkey, content := gen()\n\t\t//b.StartTimer()\n\n\t\t// Do the put.\n\t\terr := store.Put(ctx, key, content)\n\t\tif err != nil {\n\t\t\tb.Fatal(err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "storage/tests/generators.go",
    "content": "package tests\n\nimport (\n\t\"strconv\"\n)\n\n// Gen is a func which should generate key-value pairs.\n// It's used to configure benchmarks.\n//\n// How exactly to use this is up to you, but\n// a good gen function should probably return a wide variety of keys,\n// and some known distribution of key and content sizes.\n// If it returns the same key frequently, it should be documented,\n// because key collision rates will affect benchmark results.\ntype Gen func() (key string, content []byte)\n\n// NewCounterGen returns a Gen func which yields a unique value on each subsequent call,\n// which is simply the base-10 string representation of an incrementing integer.\n// The content and the key are the same.\nfunc NewCounterGen(start int64) Gen {\n\treturn func() (key string, content []byte) {\n\t\tk := strconv.FormatInt(start, 10)\n\t\tstart++\n\t\treturn k, []byte(k)\n\t}\n}\n"
  },
  {
    "path": "testutil/garbage/garbage.go",
    "content": "package garbage\n\nimport (\n\t\"math\"\n\tmathrand \"math/rand\"\n\t\"strings\"\n\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\tbasicnode \"github.com/ipld/go-ipld-prime/node/basic\"\n\t\"github.com/multiformats/go-multihash\"\n)\n\ntype Options struct {\n\tinitialWeights map[datamodel.Kind]int\n\tweights        map[datamodel.Kind]int\n\tblockSize      uint64\n}\n\ntype generator func(rand *mathrand.Rand, count uint64, opts Options) (uint64, datamodel.Node)\n\ntype hasher struct {\n\tcode   uint64\n\tlength int\n}\n\nconst charset = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#$%^&*()-_=+[]{}|\\\\:;'\\\",.<>?/ \\t\\n☺💩\"\n\nvar (\n\tcodecs     = []uint64{0x55, 0x70, 0x71, 0x0129}\n\thashes     = []hasher{{0x12, 256}, {0x16, 256}, {0x1b, 256}, {0xb220, 256}, {0x13, 512}, {0x15, 384}, {0x14, 512}}\n\tkinds      = append(datamodel.KindSet_Scalar, datamodel.KindSet_Recursive...)\n\trunes      = []rune(charset)\n\tgenerators map[datamodel.Kind]generator\n)\n\n// Generate produces random Nodes which can be useful for testing and benchmarking. By default, the\n// Nodes produced are relatively small, averaging near the 1024 byte range when encoded\n// (very roughly, with a wide spread).\n//\n// Options can be used to adjust the average size and weights of occurrences of different kinds\n// within the complete Node graph.\n//\n// Care should be taken when using a random source to generate garbage for testing purposes, that\n// the randomness is stable across test runs, or a seed is captured in such a way that a failure\n// can be reproduced (e.g. by printing it to stdout during the test run so it can be captured in\n// CI for a failure).\nfunc Generate(rand *mathrand.Rand, opts ...Option) datamodel.Node {\n\toptions := applyOptions(opts...)\n\t_, n := generate(rand, options.blockSize, options)\n\treturn n\n}\n\nfunc generate(rand *mathrand.Rand, count uint64, opts Options) (uint64, datamodel.Node) {\n\tweights := opts.weights\n\tif opts.initialWeights != nil {\n\t\tweights = opts.initialWeights\n\t\topts = Options{weights: opts.weights}\n\t}\n\ttotWeight := 0\n\tfor _, kind := range kinds {\n\t\ttotWeight += weights[kind]\n\t}\n\tr := rand.Float64() * float64(totWeight)\n\tvar wacc int\n\tfor _, kind := range kinds {\n\t\twacc += weights[kind]\n\t\tif float64(wacc) >= r {\n\t\t\treturn generators[kind](rand, count, opts)\n\t\t}\n\t}\n\tpanic(\"bad options\")\n}\n\nfunc rndSize(rand *mathrand.Rand, bias uint64) uint64 {\n\tif bias == 0 {\n\t\tpanic(\"size shouldn't be zero\")\n\t}\n\tmean := float64(bias)\n\tstdev := mean / 10\n\tfor {\n\t\ts := math.Abs(rand.NormFloat64())*stdev + mean\n\t\tif s >= 1 {\n\t\t\treturn uint64(s)\n\t\t}\n\t}\n}\n\nfunc rndRune(rand *mathrand.Rand) rune {\n\treturn runes[rand.Intn(len(runes))]\n}\n\nfunc listGenerator(rand *mathrand.Rand, count uint64, opts Options) (uint64, datamodel.Node) {\n\tlen := rndSize(rand, 10)\n\tlb := basicnode.Prototype.List.NewBuilder()\n\tla, err := lb.BeginList(int64(len))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tsize := uint64(0)\n\tfor i := uint64(0); i < len && size < count; i++ {\n\t\tc, n := generate(rand, count-size, opts)\n\t\terr := la.AssembleValue().AssignNode(n)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tsize += c\n\t}\n\terr = la.Finish()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn size, lb.Build()\n}\n\nfunc mapGenerator(rand *mathrand.Rand, count uint64, opts Options) (uint64, datamodel.Node) {\n\tlength := rndSize(rand, 10)\n\tmb := basicnode.Prototype.Map.NewBuilder()\n\tma, err := mb.BeginMap(int64(length))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tsize := uint64(0)\n\tkeys := make(map[string]struct{})\n\tfor i := uint64(0); i < length && size < count; i++ {\n\t\tvar key string\n\t\tfor {\n\t\t\tc, k := stringGenerator(rand, 5, opts)\n\t\t\tkey = must.String(k)\n\t\t\tif _, ok := keys[key]; !ok && len(key) > 0 {\n\t\t\t\tkeys[key] = struct{}{}\n\t\t\t\tsize += c\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tsz := count - size\n\t\tif size >= count { // the case where we've blown our budget already on the key\n\t\t\tsz = 5\n\t\t}\n\t\tc, value := generate(rand, sz, opts)\n\t\tsize += c\n\t\terr := ma.AssembleKey().AssignString(key)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\terr = ma.AssembleValue().AssignNode(value)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n\terr = ma.Finish()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn size, mb.Build()\n}\n\nfunc stringGenerator(rand *mathrand.Rand, count uint64, opts Options) (uint64, datamodel.Node) {\n\tlen := rndSize(rand, count/2+1)\n\tsb := strings.Builder{}\n\tfor i := uint64(0); i < len; i++ {\n\t\tsb.WriteRune(rndRune(rand))\n\t}\n\treturn len, basicnode.NewString(sb.String())\n}\n\nfunc bytesGenerator(rand *mathrand.Rand, count uint64, opts Options) (uint64, datamodel.Node) {\n\tlen := rndSize(rand, count/2+1)\n\tba := make([]byte, len)\n\t_, err := rand.Read(ba)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn len, basicnode.NewBytes(ba)\n}\n\nfunc boolGenerator(rand *mathrand.Rand, count uint64, opts Options) (uint64, datamodel.Node) {\n\treturn 0, basicnode.NewBool(rand.Float64() > 0.5)\n}\n\nfunc intGenerator(rand *mathrand.Rand, count uint64, opts Options) (uint64, datamodel.Node) {\n\ti := rand.Int63()\n\tif rand.Float64() > 0.5 {\n\t\ti = -i\n\t}\n\treturn 0, basicnode.NewInt(i)\n}\n\nfunc floatGenerator(rand *mathrand.Rand, count uint64, opts Options) (uint64, datamodel.Node) {\n\treturn 0, basicnode.NewFloat(math.Tan((rand.Float64() - 0.5) * math.Pi))\n}\n\nfunc nullGenerator(rand *mathrand.Rand, count uint64, opts Options) (uint64, datamodel.Node) {\n\treturn 0, datamodel.Null\n}\n\nfunc linkGenerator(rand *mathrand.Rand, count uint64, opts Options) (uint64, datamodel.Node) {\n\thasher := hashes[rand.Intn(len(hashes))]\n\tcodec := codecs[rand.Intn(len(codecs))]\n\tba := make([]byte, hasher.length/8)\n\trand.Read(ba)\n\tmh, err := multihash.Encode(ba, hasher.code)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn uint64(hasher.length / 8), basicnode.NewLink(cidlink.Link{Cid: cid.NewCidV1(codec, mh)})\n}\n\ntype Option func(*Options)\n\nfunc applyOptions(opt ...Option) Options {\n\topts := Options{\n\t\tblockSize:      1024,\n\t\tinitialWeights: DefaultInitialWeights(),\n\t\tweights:        DefaultWeights(),\n\t}\n\tfor _, o := range opt {\n\t\to(&opts)\n\t}\n\treturn opts\n}\n\n// DefaultInitialWeights provides the default map of weights that can be\n// overridden by the InitialWeights option. The default is an equal weighting\n// of 1 for every scalar kind and 10 for the recursive kinds.\nfunc DefaultInitialWeights() map[datamodel.Kind]int {\n\treturn map[datamodel.Kind]int{\n\t\tdatamodel.Kind_List:   10,\n\t\tdatamodel.Kind_Map:    10,\n\t\tdatamodel.Kind_Bool:   1,\n\t\tdatamodel.Kind_Bytes:  1,\n\t\tdatamodel.Kind_Float:  1,\n\t\tdatamodel.Kind_Int:    1,\n\t\tdatamodel.Kind_Link:   1,\n\t\tdatamodel.Kind_Null:   1,\n\t\tdatamodel.Kind_String: 1,\n\t}\n}\n\n// DefaultWeights provides the default map of weights that can be overridden by\n// the Weights option. The default is an equal weighting of 1 for every kind.\nfunc DefaultWeights() map[datamodel.Kind]int {\n\treturn map[datamodel.Kind]int{\n\t\tdatamodel.Kind_List:   1,\n\t\tdatamodel.Kind_Map:    1,\n\t\tdatamodel.Kind_Bool:   1,\n\t\tdatamodel.Kind_Bytes:  1,\n\t\tdatamodel.Kind_Float:  1,\n\t\tdatamodel.Kind_Int:    1,\n\t\tdatamodel.Kind_Link:   1,\n\t\tdatamodel.Kind_Null:   1,\n\t\tdatamodel.Kind_String: 1,\n\t}\n}\n\n// InitialWeights sets a per-kind weighting for the root node. That is, the weights\n// set here will determine the liklihood of the returned Node's direct .Kind().\n// These weights are ignored after the top-level Node (for recursive kinds,\n// obviously for scalar kinds there is only a top-level Node).\n//\n// The default initial weights bias toward Map and List kinds, by a ratio of\n// 10:1—i.e. the recursive kinds are more likely to appear at the top-level.\nfunc InitialWeights(initialWeights map[datamodel.Kind]int) Option {\n\treturn func(o *Options) {\n\t\to.initialWeights = initialWeights\n\t}\n}\n\n// Weights sets a per-kind weighting for nodes appearing throughout the returned\n// graph. When assembling a graph, these weights determine the liklihood that\n// a given kind will be selected for that node.\n//\n// A weight of 0 will turn that kind off entirely. So, for example, if you\n// wanted output data with no maps or bytes, then set both of those weights to\n// zero, leaving the rest >0 and do the same for InitialWeights.\n//\n// The default weights are set to 1—i.e. there is an equal liklihood that any of\n// the valid kinds will be selected for any point in the graph.\n//\n// This option is overridden by InitialWeights (which also has a default even\n// if not set explicitly) for the top-level node.\nfunc Weights(weights map[datamodel.Kind]int) Option {\n\treturn func(o *Options) {\n\t\to.weights = weights\n\t}\n}\n\n// TargetBlockSize sets a very rough bias in number of bytes that the resulting\n// Node may consume when encoded (i.e. the block size). This is a very\n// approximate measure, but over enough repeated Generate() calls, the resulting\n// Nodes, once encoded, should have a median that is somewhere in this vicinity.\n//\n// The default target block size is 1024. This should be tuned in accordance with\n// the anticipated average block size of the system under test.\nfunc TargetBlockSize(blockSize uint64) Option {\n\treturn func(o *Options) {\n\t\to.blockSize = blockSize\n\t}\n}\n\nfunc init() {\n\t// can't be declared statically because of some cycles through list & map to generate()\n\tgenerators = map[datamodel.Kind]generator{\n\t\tdatamodel.Kind_List:   listGenerator,\n\t\tdatamodel.Kind_Map:    mapGenerator,\n\t\tdatamodel.Kind_String: stringGenerator,\n\t\tdatamodel.Kind_Bytes:  bytesGenerator,\n\t\tdatamodel.Kind_Bool:   boolGenerator,\n\t\tdatamodel.Kind_Int:    intGenerator,\n\t\tdatamodel.Kind_Float:  floatGenerator,\n\t\tdatamodel.Kind_Null:   nullGenerator,\n\t\tdatamodel.Kind_Link:   linkGenerator,\n\t}\n}\n"
  },
  {
    "path": "testutil/garbage/garbage_test.go",
    "content": "package garbage\n\nimport (\n\t\"bytes\"\n\t\"math/rand\"\n\t\"testing\"\n\t\"time\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagcbor\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestGarbageProducesAllKinds(t *testing.T) {\n\tkindCount := make(map[datamodel.Kind]int)\n\tseed := time.Now().Unix()\n\tt.Logf(\"randomness seed: %v\\n\", seed)\n\trnd := rand.New(rand.NewSource(seed))\n\tfor i := 0; i < 10000; i++ {\n\t\tgbg := Generate(rnd)\n\t\tkindCount[gbg.Kind()]++\n\t}\n\tfor _, kind := range append(datamodel.KindSet_Scalar, datamodel.KindSet_Recursive...) {\n\t\tqt.Assert(t, kindCount[kind], qt.Not(qt.Equals), 0)\n\t}\n}\n\nfunc TestGarbageProducesValidNodes(t *testing.T) {\n\t// round-trip through a codec should pick up most possible problems with Node validity\n\tseed := time.Now().Unix()\n\tt.Logf(\"randomness seed: %v\\n\", seed)\n\trnd := rand.New(rand.NewSource(seed))\n\tfor i := 0; i < 1000; i++ {\n\t\tvar buf bytes.Buffer\n\t\tgbg := Generate(rnd)\n\t\terr := dagcbor.Encode(gbg, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\terr = dagcbor.Decode(nb, &buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tipld.DeepEqual(gbg, nb.Build())\n\t}\n}\n\nfunc TestGarbageProducesSameDataForSameRandomSource(t *testing.T) {\n\tgbg1 := Generate(rand.New(rand.NewSource(1)))\n\tgbg2 := Generate(rand.New(rand.NewSource(1)))\n\tqt.Assert(t, ipld.DeepEqual(gbg1, gbg2), qt.IsTrue)\n}\n\nfunc TestGarbageProducesSingleKind(t *testing.T) {\n\tseed := time.Now().Unix()\n\tt.Logf(\"randomness seed: %v\\n\", seed)\n\trnd := rand.New(rand.NewSource(seed))\n\tfor _, kind := range append(datamodel.KindSet_Scalar, datamodel.KindSet_Recursive...) {\n\t\tt.Run(kind.String(), func(t *testing.T) {\n\t\t\tkindCount := make(map[datamodel.Kind]int)\n\t\t\tfor i := 0; i < 1000; i++ {\n\t\t\t\tgbg := Generate(rnd, InitialWeights(map[datamodel.Kind]int{kind: 1}))\n\t\t\t\tkindCount[gbg.Kind()]++\n\t\t\t}\n\t\t\tfor _, k := range append(datamodel.KindSet_Scalar, datamodel.KindSet_Recursive...) {\n\t\t\t\tif k == kind {\n\t\t\t\t\tqt.Assert(t, kindCount[k], qt.Equals, 1000)\n\t\t\t\t} else {\n\t\t\t\t\tqt.Assert(t, kindCount[k], qt.Equals, 0)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "testutil/indent.go",
    "content": "package testutil\n\nimport \"bytes\"\n\n// Dedent strips leading tabs from every line of a string, taking a hint of\n// how many tabs should be stripped from the number of consecutive tabs found\n// on the first non-empty line.  Dedent also strips one leading blank\n// line if it contains nothing but the linebreak.\n//\n// If later lines have fewer leading tab characters than the depth we intuited\n// from the first line, then stripping will still only remove tab characters.\n//\n// Roughly, Dedent is \"Do What I Mean\" to normalize a heredoc string\n// that contains leading indentation to make it congruent with the\n// surrounding source code.\nfunc Dedent(s string) string {\n\t// Originally from: https://github.com/warpfork/go-wish/blob/master/indent.go\n\t// Forked here to reduce dependencies in go-ipld-prime.\n\treturn string(DedentBytes([]byte(s)))\n}\n\n// DedentBytes is identically to Dedent, but works on a byte slice.\nfunc DedentBytes(bs []byte) []byte {\n\tlines := bytes.SplitAfter(bs, []byte{'\\n'})\n\tbuf := bytes.Buffer{}\n\tif len(lines[0]) == 1 && lines[0][0] == '\\n' {\n\t\tlines = lines[1:]\n\t}\n\tif len(lines) == 0 {\n\t\treturn []byte{}\n\t}\n\tdepth := 0\n\tfor _, r := range lines[0] {\n\t\tdepth++\n\t\tif r != '\\t' {\n\t\t\tdepth--\n\t\t\tbreak\n\t\t}\n\t}\n\tfor _, line := range lines {\n\t\tfor i, r := range line {\n\t\t\tif i < depth && r == '\\t' {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tbuf.Write(line[i:])\n\t\t\tbreak\n\t\t}\n\t}\n\treturn buf.Bytes()\n}\n"
  },
  {
    "path": "testutil/indent_test.go",
    "content": "package testutil\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n)\n\nfunc TestDedent(t *testing.T) {\n\tfor _, tr := range []struct{ a, b string }{\n\t\t{\"\", \"\"},\n\t\t{\"\\t\", \"\"},\n\t\t{\"\\t\\t\", \"\"},\n\t\t{\"\\n\", \"\"},\n\t\t{\"\\n\\t\", \"\"},\n\t\t{\"\\n\\t\\t\", \"\"},\n\t\t{\"\\n\\n\", \"\\n\"},\n\t\t{\"\\n\\t\\n\", \"\\n\"},\n\t\t{\"\\n\\t\\t\\n\", \"\\n\"},\n\t\t{\"\\n\\n\", \"\\n\"},\n\t\t{\"\\n\\n\\t\", \"\\n\\t\"},\n\t\t{\"\\n\\n\\t\\t\", \"\\n\\t\\t\"},\n\t\t{\"a\\nb\\n\\tc\\n\", \"a\\nb\\n\\tc\\n\"},\n\t\t{\"\\ta\\nb\\n\\tc\\n\", \"a\\nb\\nc\\n\"},\n\t\t{\"\\t\\ta\\nb\\n\\tc\\n\", \"a\\nb\\nc\\n\"},\n\t\t{\"\\ta\\n\\t\\tb\\n\\tc\\n\", \"a\\n\\tb\\nc\\n\"},\n\t\t{\"\\ta\\n\\t\\t\\tb\\n\\tc\\n\", \"a\\n\\t\\tb\\nc\\n\"},\n\t\t{\"\\n\\t\\t\\ta\\n\\t\\tb\\n\\t\\t\\t\\n\\t\\t\\t\\tc\\n\\t\\t\", \"a\\nb\\n\\n\\tc\\n\"},\n\t} {\n\t\tactual := Dedent(tr.a)\n\t\tqt.Assert(t, actual, qt.Equals, tr.b)\n\t}\n}\n"
  },
  {
    "path": "testutil/multibytenode.go",
    "content": "package testutil\n\nimport (\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nvar _ datamodel.Node = MultiByteNode{}\nvar _ datamodel.LargeBytesNode = (*MultiByteNode)(nil)\n\n// MultiByteNode is a node that is a concatenation of multiple byte slices.\n// It's not particularly sophisticated but lets us exercise LargeBytesNode in a\n// non-trivial way.\n// The novel behaviour of Read() and Seek() on the AsLargeBytes is similar to\n// that which would be expected from a LBN ADL, such as UnixFS sharded files.\ntype MultiByteNode struct {\n\tbytes [][]byte\n}\n\nfunc NewMultiByteNode(bytes ...[]byte) MultiByteNode {\n\treturn MultiByteNode{bytes: bytes}\n}\n\nfunc (mbn MultiByteNode) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Bytes\n}\n\nfunc (mbn MultiByteNode) AsBytes() ([]byte, error) {\n\tret := make([]byte, 0, mbn.TotalLength())\n\tfor _, b := range mbn.bytes {\n\t\tret = append(ret, b...)\n\t}\n\treturn ret, nil\n}\n\nfunc (mbn MultiByteNode) TotalLength() int {\n\tvar size int\n\tfor _, b := range mbn.bytes {\n\t\tsize += len(b)\n\t}\n\treturn size\n}\n\nfunc (mbn MultiByteNode) AsLargeBytes() (io.ReadSeeker, error) {\n\treturn &mbnReadSeeker{node: mbn}, nil\n}\n\nfunc (mbn MultiByteNode) AsBool() (bool, error) {\n\treturn false, datamodel.ErrWrongKind{TypeName: \"bool\", MethodName: \"AsBool\", AppropriateKind: datamodel.KindSet_JustBytes}\n}\n\nfunc (mbn MultiByteNode) AsInt() (int64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: \"int\", MethodName: \"AsInt\", AppropriateKind: datamodel.KindSet_JustBytes}\n}\n\nfunc (mbn MultiByteNode) AsFloat() (float64, error) {\n\treturn 0, datamodel.ErrWrongKind{TypeName: \"float\", MethodName: \"AsFloat\", AppropriateKind: datamodel.KindSet_JustBytes}\n}\n\nfunc (mbn MultiByteNode) AsString() (string, error) {\n\treturn \"\", datamodel.ErrWrongKind{TypeName: \"string\", MethodName: \"AsString\", AppropriateKind: datamodel.KindSet_JustBytes}\n}\n\nfunc (mbn MultiByteNode) AsLink() (datamodel.Link, error) {\n\treturn nil, datamodel.ErrWrongKind{TypeName: \"link\", MethodName: \"AsLink\", AppropriateKind: datamodel.KindSet_JustBytes}\n}\n\nfunc (mbn MultiByteNode) AsNode() (datamodel.Node, error) {\n\treturn nil, nil\n}\n\nfunc (mbn MultiByteNode) Size() int {\n\treturn 0\n}\n\nfunc (mbn MultiByteNode) IsAbsent() bool {\n\treturn false\n}\n\nfunc (mbn MultiByteNode) IsNull() bool {\n\treturn false\n}\n\nfunc (mbn MultiByteNode) Length() int64 {\n\treturn 0\n}\n\nfunc (mbn MultiByteNode) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\n\nfunc (mbn MultiByteNode) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\n\nfunc (mbn MultiByteNode) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{}\n}\n\nfunc (mbn MultiByteNode) LookupByString(key string) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{}\n}\n\nfunc (mbn MultiByteNode) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{}\n}\n\nfunc (mbn MultiByteNode) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn nil, datamodel.ErrWrongKind{}\n}\n\nfunc (mbn MultiByteNode) Prototype() datamodel.NodePrototype {\n\treturn basicnode.Prototype.Bytes // not really ... but it'll do for this test\n}\n\ntype mbnReadSeeker struct {\n\tnode   MultiByteNode\n\toffset int\n}\n\nfunc (mbnrs *mbnReadSeeker) Read(p []byte) (int, error) {\n\tvar acc int\n\tfor _, byts := range mbnrs.node.bytes {\n\t\tif mbnrs.offset-acc >= len(byts) {\n\t\t\tacc += len(byts)\n\t\t\tcontinue\n\t\t}\n\t\tn := copy(p, byts[mbnrs.offset-acc:])\n\t\tmbnrs.offset += n\n\t\treturn n, nil\n\t}\n\treturn 0, io.EOF\n}\n\nfunc (mbnrs *mbnReadSeeker) Seek(offset int64, whence int) (int64, error) {\n\tswitch whence {\n\tcase io.SeekStart:\n\t\tmbnrs.offset = int(offset)\n\tcase io.SeekCurrent:\n\t\tmbnrs.offset += int(offset)\n\tcase io.SeekEnd:\n\t\tmbnrs.offset = mbnrs.node.TotalLength() + int(offset)\n\t}\n\treturn int64(mbnrs.offset), nil\n}\n"
  },
  {
    "path": "testutil/multibytenode_test.go",
    "content": "package testutil_test\n\nimport (\n\t\"io\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/testutil\"\n)\n\nfunc TestMultiByteNode(t *testing.T) {\n\tmbn := testutil.NewMultiByteNode(\n\t\t[]byte(\"foo\"),\n\t\t[]byte(\"bar\"),\n\t\t[]byte(\"baz\"),\n\t\t[]byte(\"!\"),\n\t)\n\t// Sanity check that the readseeker works.\n\t// (This is a test of the test, not the code under test.)\n\n\tfor _, rl := range []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} {\n\t\tt.Run(\"readseeker works with read length \"+qt.Format(rl), func(t *testing.T) {\n\t\t\trs, err := mbn.AsLargeBytes()\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tacc := make([]byte, 0, mbn.TotalLength())\n\t\t\tbuf := make([]byte, rl)\n\t\t\tfor {\n\t\t\t\tn, err := rs.Read(buf)\n\t\t\t\tif err == io.EOF {\n\t\t\t\t\tqt.Check(t, n, qt.Equals, 0)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t\tacc = append(acc, buf[0:n]...)\n\t\t\t}\n\t\t\tqt.Assert(t, string(acc), qt.DeepEquals, \"foobarbaz!\")\n\t\t})\n\t}\n\n\tt.Run(\"readseeker can seek and read middle bytes\", func(t *testing.T) {\n\t\trs, err := mbn.AsLargeBytes()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\t_, err = rs.Seek(2, io.SeekStart)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tbuf := make([]byte, 2)\n\t\tacc := make([]byte, 0, 5)\n\t\tfor len(acc) < 5 {\n\t\t\tn, err := rs.Read(buf)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\tacc = append(acc, buf[0:n]...)\n\t\t}\n\t\tqt.Assert(t, string(acc), qt.DeepEquals, \"obarba\")\n\t})\n\n\tt.Run(\"readseeker can seek and read last byte\", func(t *testing.T) {\n\t\trs, err := mbn.AsLargeBytes()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\t_, err = rs.Seek(-1, io.SeekEnd)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tbuf := make([]byte, 1)\n\t\tn, err := rs.Read(buf)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tqt.Check(t, n, qt.Equals, 1)\n\t\tqt.Check(t, string(buf[0]), qt.Equals, \"!\")\n\t})\n}\n"
  },
  {
    "path": "testutil/simplebytes.go",
    "content": "package testutil\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/node/mixins\"\n)\n\nvar _ datamodel.Node = simpleBytes(nil)\n\n// simpleBytes is like basicnode's plainBytes but it doesn't implement\n// LargeBytesNode so we can exercise the non-LBN case.\ntype simpleBytes []byte\n\n// NewSimpleBytes is identical to basicnode.NewBytes but the returned node\n// doesn't implement LargeBytesNode, which can be useful for testing cases\n// where we want to exercise non-LBN code paths.\nfunc NewSimpleBytes(value []byte) datamodel.Node {\n\tv := simpleBytes(value)\n\treturn &v\n}\n\n// -- Node interface methods -->\n\nfunc (simpleBytes) Kind() datamodel.Kind {\n\treturn datamodel.Kind_Bytes\n}\nfunc (simpleBytes) LookupByString(string) (datamodel.Node, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.LookupByString(\"\")\n}\nfunc (simpleBytes) LookupByNode(key datamodel.Node) (datamodel.Node, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.LookupByNode(nil)\n}\nfunc (simpleBytes) LookupByIndex(idx int64) (datamodel.Node, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.LookupByIndex(0)\n}\nfunc (simpleBytes) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.LookupBySegment(seg)\n}\nfunc (simpleBytes) MapIterator() datamodel.MapIterator {\n\treturn nil\n}\nfunc (simpleBytes) ListIterator() datamodel.ListIterator {\n\treturn nil\n}\nfunc (simpleBytes) Length() int64 {\n\treturn -1\n}\nfunc (simpleBytes) IsAbsent() bool {\n\treturn false\n}\nfunc (simpleBytes) IsNull() bool {\n\treturn false\n}\nfunc (simpleBytes) AsBool() (bool, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsBool()\n}\nfunc (simpleBytes) AsInt() (int64, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsInt()\n}\nfunc (simpleBytes) AsFloat() (float64, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsFloat()\n}\nfunc (simpleBytes) AsString() (string, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsString()\n}\nfunc (n simpleBytes) AsBytes() ([]byte, error) {\n\treturn []byte(n), nil\n}\nfunc (simpleBytes) AsLink() (datamodel.Link, error) {\n\treturn mixins.Bytes{TypeName: \"bytes\"}.AsLink()\n}\nfunc (simpleBytes) Prototype() datamodel.NodePrototype {\n\treturn basicnode.Prototype__Bytes{}\n}\n"
  },
  {
    "path": "traversal/common.go",
    "content": "package traversal\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n)\n\n// init sets all the values in TraveralConfig to reasonable defaults\n// if they're currently the zero value.\n//\n// Note that you're absolutely going to need to replace the\n// LinkLoader and LinkNodeBuilderChooser if you want automatic link traversal;\n// the defaults return error and/or panic.\nfunc (tc *Config) init() {\n\tif tc.Ctx == nil {\n\t\ttc.Ctx = context.Background()\n\t}\n\tif tc.LinkTargetNodePrototypeChooser == nil {\n\t\ttc.LinkTargetNodePrototypeChooser = func(lnk datamodel.Link, lnkCtx linking.LinkContext) (datamodel.NodePrototype, error) {\n\t\t\tif tlnkNd, ok := lnkCtx.LinkNode.(schema.TypedLinkNode); ok {\n\t\t\t\treturn tlnkNd.LinkTargetNodePrototype(), nil\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"no LinkTargetNodePrototypeChooser configured\")\n\t\t}\n\t}\n}\n\nfunc (prog *Progress) init() {\n\tif prog.Cfg == nil {\n\t\tprog.Cfg = &Config{}\n\t}\n\tprog.Cfg.init()\n\tif prog.Cfg.LinkVisitOnlyOnce {\n\t\tprog.SeenLinks = make(map[datamodel.Link]struct{})\n\t}\n}\n\n// asPathSegment figures out how to coerce a node into a PathSegment.\n// If it's a typed node: we take its representation.  (Could be a struct with some string representation.)\n// If it's a string or an int, that's it.\n// Any other case will panic.  (If you're using this one keys returned by a MapIterator, though, you can ignore this possibility;\n// any compliant map implementation should've already rejected that data long ago, and should not be able to yield it to you from an iterator.)\nfunc asPathSegment(n datamodel.Node) datamodel.PathSegment {\n\tif n2, ok := n.(schema.TypedNode); ok {\n\t\tn = n2.Representation()\n\t}\n\tswitch n.Kind() {\n\tcase datamodel.Kind_String:\n\t\ts, _ := n.AsString()\n\t\treturn datamodel.PathSegmentOfString(s)\n\tcase datamodel.Kind_Int:\n\t\ti, _ := n.AsInt()\n\t\treturn datamodel.PathSegmentOfInt(i)\n\tdefault:\n\t\tpanic(fmt.Errorf(\"cannot get pathsegment from a %s\", n.Kind()))\n\t}\n}\n"
  },
  {
    "path": "traversal/doc.go",
    "content": "// Package traversal provides functional utilities for traversing and\n// transforming IPLD graphs.\n//\n// Two primary types of traversal are implemented in this package: \"Focus\" and\n// \"Walk\". Both types have a \"Transforming\" variant, which supports mutation\n// through emulated copy-on-write tree rebuilding.\n//\n// Traversal operations use the Progress type for configuration and state\n// tracking. Helper functions such as Focus and Walk exist to avoid manual setup\n// of a Progress struct, but they cannot cross link boundaries without a\n// LinkSystem, which needs to be configured on the Progress struct.\n//\n// A typical traversal operation involves creating a Progress struct, setting up\n// the LinkSystem, and calling one of the Focus or Walk functions on the\n// Progress object. Various other configuration options are available when\n// traversing this way.\n//\n// # Focus\n//\n// \"Focus\" and \"Get\" functions provide syntactic sugar for using ipld.Path to\n// access Nodes deep within a graph.\n//\n// \"FocusedTransform\" resembles \"Focus\" but supports user-defined mutation using\n// its TransformFn.\n//\n// # Walk\n//\n// \"Walk\" functions perform a recursive walk of a Node graph, applying visitor\n// functions to matched parts of the graph.\n//\n// The selector sub-package offers a declarative mechanism for guiding\n// traversals and filtering relevant Nodes.\n// (Refer to the selector sub-package for more details.)\n//\n// \"WalkLocal\" is a special case of Walk that doesn't require a selector. It\n// walks a local graph, not crossing link boundaries, and calls its VisitFn for\n// each encountered Node.\n//\n// \"WalkMatching\" traverses according to a selector, calling the VisitFn for\n// each match based on the selector's matching rules.\n//\n// \"WalkAdv\" performs the same traversal as WalkMatching, but calls its\n// AdvVisitFn on every Node, regardless of whether it matches the selector.\n//\n// \"WalkTransforming\" resembles \"WalkMatching\" but supports user-defined\n// mutation using its TransformFn.\n//\n// # Usage Notes\n//\n// These functions work via callbacks, performing traversal and calling a\n// user-provided function with a handle to the reached Node(s). Further \"Focus\"\n// and \"Walk\" operations can be performed recursively within this callback if\n// desired.\n//\n// All traversal functions operate on a Progress object, except \"WalkLocal\",\n// which can be configured with a LinkSystem for automatic resolution and\n// loading of new Node trees when IPLD Links are encountered.\n//\n// The \"*Transform\" methods are best suited for point-mutation patterns. For\n// more general transformations, use the read-only systems (e.g., Focus,\n// Traverse) and handle accumulation in the visitor functions.\n//\n// A common use case for walking traversal is running a selector over a graph\n// and noting all the blocks it uses. This is achieved by configuring a\n// LinkSystem that can handle and observe block loads. Be aware that a selector\n// might visit the same block multiple times during a traversal, as IPLD graphs\n// often form \"diamond patterns\" with the same block referenced from multiple\n// locations.\n//\n// The LinkVisitOnlyOnce option can be used to avoid duplicate loads, but it\n// must be used carefully with non-trivial selectors, where repeat visits of\n// the same block may be essential for traversal or visit callbacks.\n//\n// A Budget can be set at the beginning of a traversal to limit the number of\n// Nodes and/or Links encountered before failing the traversal (with the\n// ErrBudgetExceeded error).\n//\n// The \"Preloader\" option provides a way to parallelize block loading in\n// environments where block loading is a high-latency operation (such as\n// fetching over the network).\n// The traversal operation itself is not parallel and will proceed strictly\n// according to path or selector order. However, a Preloader can be used to load\n// blocks asynchronously, and prepare the LinkSystem that the traversal is using\n// with already-loaded blocks.\n//\n// A Preloader and a Budget option can be used on the same traversal, BUT the\n// Preloader may not receive the same links that the traversal wants to load\n// from the LinkSystem. Use with care. See notes below.\npackage traversal\n\n// Why only \"point-mutation\"?  This use-case gets core library support because\n// it's both high utility and highly clear how to implement it.\n// More advanced transformations are nontrivial to provide generalized support\n// for, for three reasons: efficiency is hard; not all existing research into\n// categorical recursion schemes is necessarily applicable without modification\n// (efficient behavior in a merkle-tree context is not the same as efficient\n// behavior on uniform memory!); and we have the further compounding complexity\n// of the range of choices available for underlying Node implementation.\n// Therefore, attempts at generalization are not included here; handling these\n// issues in concrete cases is easy, so we call it an application logic concern.\n// However, exploring categorical recursion schemes as a library is encouraged!)\n"
  },
  {
    "path": "traversal/example_select_links_test.go",
    "content": "package traversal_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime\"\n\n\t// Import all the codecs so we can use them in our example; each of these will\n\t// set themselves up in our multicodec registry so the LinkSystem can use\n\t// them for encoding (when a LinkPrototype says so) and decoding (when a CID's\n\t// codec code says so).\n\n\t_ \"github.com/ipld/go-ipld-prime/codec/dagcbor\"\n\t_ \"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t_ \"github.com/ipld/go-ipld-prime/codec/raw\"\n\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent/qp\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/traversal\"\n\t\"github.com/multiformats/go-multihash\"\n)\n\nfunc ExampleSelectLinks() {\n\t// Setup: make some blocks, store them in our memory store\n\n\tblocks := make([]cid.Cid, 0)\n\n\t// make 3 raw blocks\n\tc1 := encodeAndStore(rawlp, basicnode.NewBytes([]byte{0xca, 0xfe, 0xbe, 0xef}))\n\tblocks = append(blocks, c1)\n\tc2 := encodeAndStore(rawlp, basicnode.NewBytes([]byte{0xde, 0xad, 0xbe, 0xef}))\n\tblocks = append(blocks, c2)\n\tc3 := encodeAndStore(rawlp, basicnode.NewBytes([]byte{0xba, 0xad, 0xf0, 0x0d}))\n\tblocks = append(blocks, c3)\n\n\t// Pretend we're doing a dag-pb encode here but since we don't want to pull in\n\t// the dagpb package we'll do it as dag-json. This should use\n\t// dagpb.Type.PBNode if it were real.\n\tpbn, err := qp.BuildMap(basicnode.Prototype.Map, 1, func(ma datamodel.MapAssembler) {\n\t\tqp.MapEntry(ma, \"Links\", qp.List(3, func(la datamodel.ListAssembler) {\n\t\t\tqp.ListEntry(la, qp.Map(2, func(ma datamodel.MapAssembler) {\n\t\t\t\tqp.MapEntry(ma, \"Name\", qp.String(\"01\"))\n\t\t\t\tqp.MapEntry(ma, \"Hash\", qp.Link(cidlink.Link{Cid: c1}))\n\t\t\t}))\n\t\t\tqp.ListEntry(la, qp.Map(2, func(ma datamodel.MapAssembler) {\n\t\t\t\tqp.MapEntry(ma, \"Name\", qp.String(\"02\"))\n\t\t\t\tqp.MapEntry(ma, \"Hash\", qp.Link(cidlink.Link{Cid: c2}))\n\t\t\t}))\n\t\t\tqp.ListEntry(la, qp.Map(2, func(ma datamodel.MapAssembler) {\n\t\t\t\tqp.MapEntry(ma, \"Name\", qp.String(\"03\"))\n\t\t\t\tqp.MapEntry(ma, \"Hash\", qp.Link(cidlink.Link{Cid: c3}))\n\t\t\t}))\n\t\t}))\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tcpb := encodeAndStore(pblp, pbn)\n\tblocks = append(blocks, cpb)\n\n\t// make a dag-cbor block with a bunch of links in it, stored in various ways\n\tcbn, err := qp.BuildList(basicnode.Prototype.List, -1, func(la datamodel.ListAssembler) {\n\t\tqp.ListEntry(la, qp.String(\"not a link!\"))\n\t\tqp.ListEntry(la, qp.Link(cidlink.Link{Cid: c1}))\n\t\tqp.ListEntry(la, qp.Link(cidlink.Link{Cid: c2}))\n\t\tqp.ListEntry(la, qp.Int(42))\n\t\tqp.ListEntry(la, qp.Link(cidlink.Link{Cid: c3}))\n\t\tqp.ListEntry(la, qp.Map(-1, func(ma datamodel.MapAssembler) {\n\t\t\tqp.MapEntry(ma, \"Boop!\", qp.String(\"boop!\"))\n\t\t\tqp.MapEntry(ma, \"This is a dag-pb link:\", qp.Link(cidlink.Link{Cid: cpb}))\n\t\t\tqp.MapEntry(ma, \"And this one the same link:\", qp.Link(cidlink.Link{Cid: cpb}))\n\t\t\tqp.MapEntry(ma, \"But thus one is a raw link:\", qp.Link(cidlink.Link{Cid: c2}))\n\t\t}))\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tccb := encodeAndStore(dclp, cbn)\n\tblocks = append(blocks, ccb)\n\n\t// Example code: load the blocks as datamodel.Node form and traverse\n\t// them using the SelectLinks function to find all the links\n\n\tfor _, c := range blocks {\n\t\t// load Node form of the block\n\t\tn := loadNode(c)\n\t\t// Select all links from the node\n\t\tlinks, err := traversal.SelectLinks(n)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tfmt.Printf(\"%s (%d links)\\n\", c, len(links))\n\t\t// Print the links\n\t\tfor _, l := range links {\n\t\t\tfmt.Printf(\"\\t➜ %s\\n\", l)\n\t\t}\n\t}\n\n\t// Demonstrating how we might do this if we don't have a LinkSystem but do\n\t// have the bytes of a block we want to traverse.\n\n\t// load bytes of the block\n\tbyts := loadBytes(ccb)\n\t// decode the block into Node form\n\tdecoder, err := cidlink.DefaultLinkSystem().DecoderChooser(cidlink.Link{Cid: ccb})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\t// we could just use `dagcbor.Decode` here, but by using the DecoderChooser\n\t// we make sure we get the right one for the CID.\n\tn, err := ipld.Decode(byts, decoder)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\t// Select all links from the node\n\tlinks, err := traversal.SelectLinks(n)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Printf(\"Manually decoded %s has %d links too, surprise!\\n\", ccb, len(links))\n\n\t// Output:\n\t// bafkreicwcm4sqhux7ipwbwro2inf4vbjoprzwoqnl3t4zta4gphofot7du (0 links)\n\t// bafkreic7pdbte5heh6u54vszezob3el6exadoiw4wc4ne7ny2x7kvajzkm (0 links)\n\t// bafkreiafc5f36dkaocd6iwysxkxboelue2cs745j4wgrfihlxgqqwqexim (0 links)\n\t// baguqeeraawfdfutq7b4dgmcelypy4r36d7ndngbzpbejzhjaxffcrbgq3wka (3 links)\n\t// \t➜ bafkreicwcm4sqhux7ipwbwro2inf4vbjoprzwoqnl3t4zta4gphofot7du\n\t// \t➜ bafkreic7pdbte5heh6u54vszezob3el6exadoiw4wc4ne7ny2x7kvajzkm\n\t// \t➜ bafkreiafc5f36dkaocd6iwysxkxboelue2cs745j4wgrfihlxgqqwqexim\n\t// bafyreietdfd5sh743y6c4f4zrhwkqdadwtcuvziot3mvwhyqojjtvtqoxi (6 links)\n\t// \t➜ bafkreicwcm4sqhux7ipwbwro2inf4vbjoprzwoqnl3t4zta4gphofot7du\n\t// \t➜ bafkreic7pdbte5heh6u54vszezob3el6exadoiw4wc4ne7ny2x7kvajzkm\n\t// \t➜ bafkreiafc5f36dkaocd6iwysxkxboelue2cs745j4wgrfihlxgqqwqexim\n\t// \t➜ baguqeeraawfdfutq7b4dgmcelypy4r36d7ndngbzpbejzhjaxffcrbgq3wka\n\t// \t➜ baguqeeraawfdfutq7b4dgmcelypy4r36d7ndngbzpbejzhjaxffcrbgq3wka\n\t// \t➜ bafkreic7pdbte5heh6u54vszezob3el6exadoiw4wc4ne7ny2x7kvajzkm\n\t// Manually decoded bafyreietdfd5sh743y6c4f4zrhwkqdadwtcuvziot3mvwhyqojjtvtqoxi has 6 links too, surprise!\n}\n\n// LinkPrototypes to tell the LinkSystem how to store the Nodes in our memory\n// store and how to generate the CIDs (i.e. codec to store, multihash to use in\n// the CID).\n\nvar dclp = cidlink.LinkPrototype{\n\tPrefix: cid.Prefix{\n\t\tVersion:  1,\n\t\tCodec:    cid.DagCBOR,\n\t\tMhType:   multihash.SHA2_256,\n\t\tMhLength: 32,\n\t},\n}\n\nvar pblp = cidlink.LinkPrototype{\n\tPrefix: cid.Prefix{\n\t\tVersion:  1,\n\t\tCodec:    cid.DagJSON, // cid.DagProtobuf, but we're pretending\n\t\tMhType:   multihash.SHA2_256,\n\t\tMhLength: 32,\n\t},\n}\n\nvar rawlp = cidlink.LinkPrototype{\n\tPrefix: cid.Prefix{\n\t\tVersion:  1,\n\t\tCodec:    cid.Raw,\n\t\tMhType:   multihash.SHA2_256,\n\t\tMhLength: 32,\n\t},\n}\n\n// Given a LinkPrototype and a Node, encode the Node and store it in our memory\n// store, returning the CID of the stored Node.\nfunc encodeAndStore(lp cidlink.LinkPrototype, n datamodel.Node) cid.Cid {\n\tlsys := cidlink.DefaultLinkSystem()\n\t// note this is in our package: var store = memstore.Store{}\n\tlsys.SetWriteStorage(&store)\n\tlsys.SetReadStorage(&store)\n\tlnk := lsys.MustStore(linking.LinkContext{}, lp, n)\n\treturn lnk.(cidlink.Link).Cid\n}\n\n// Given a CID, load the Node from our memory store and return it.\nfunc loadNode(c cid.Cid) datamodel.Node {\n\tlsys := cidlink.DefaultLinkSystem()\n\t// note this is in our package: var store = memstore.Store{}\n\tlsys.SetReadStorage(&store)\n\tnb := lsys.MustLoad(linking.LinkContext{}, cidlink.Link{Cid: c}, basicnode.Prototype.Any)\n\treturn nb\n}\n\n// Given a CID, load the bytes from our memory store and return them.\nfunc loadBytes(c cid.Cid) []byte {\n\tlsys := cidlink.DefaultLinkSystem()\n\t// note this is in our package: var store = memstore.Store{}\n\tlsys.SetReadStorage(&store)\n\tbyts, err := lsys.LoadRaw(linking.LinkContext{}, cidlink.Link{Cid: c})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn byts\n}\n"
  },
  {
    "path": "traversal/fns.go",
    "content": "package traversal\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\t\"github.com/ipld/go-ipld-prime/linking/preload\"\n)\n\n// This file defines interfaces for things users provide,\n//  plus a few of the parameters they'll need to receieve.\n//--------------------------------------------------------\n\n// VisitFn is a read-only visitor.\ntype VisitFn func(Progress, datamodel.Node) error\n\n// TransformFn is like a visitor that can also return a new Node to replace the visited one.\ntype TransformFn func(Progress, datamodel.Node) (datamodel.Node, error)\n\n// AdvVisitFn is like VisitFn, but for use with AdvTraversal: it gets additional arguments describing *why* this node is visited.\ntype AdvVisitFn func(Progress, datamodel.Node, VisitReason) error\n\n// VisitReason provides additional information to traversals using AdvVisitFn.\ntype VisitReason byte\n\nconst (\n\t// VisitReason_SelectionMatch tells AdvVisitFn that this node was explicitly selected.  (This is the set of nodes that VisitFn is called for.)\n\tVisitReason_SelectionMatch VisitReason = 'm'\n\t// VisitReason_SelectionParent tells AdvVisitFn that this node is a parent of one that will be explicitly selected.  (These calls only happen if the feature is enabled -- enabling parent detection requires a different algorithm and adds some overhead.)\n\tVisitReason_SelectionParent VisitReason = 'p'\n\t// VisitReason_SelectionCandidate tells AdvVisitFn that this node was visited while searching for selection matches.  It is not necessarily implied that any explicit match will be a child of this node; only that we had to consider it.  (Merkle-proofs generally need to include any node in this group.)\n\tVisitReason_SelectionCandidate VisitReason = 'x'\n)\n\n// Progress tracks a traversal as it proceeds. It is used initially to begin a traversal, and it is then passed to the visit function as the traversal proceeds.\n//\n// As the traversal descends into the graph, new Progress values are created and passed to the visit function with updated properties representing the current state of the traversal.\n//\n// Most customization of a traversal is done by setting a Cfg property on a Progress before beginning the traversal.\n// Typical customization involves setting a LinkSystem for link loading and/or tracking.\n//\n// Advanced traversal control options, such as LinkVisitOnlyOnce and StartAtPath, are also available in the Cfg but may have surprising effects on traversal behavior; be careful when using them.\n//\n// Budgets are set on the Progress option because a Budget, while set at the beginning of a traversal, is also updated as the traversal proceeds, with its fields being monotonically decremented.\n// Beware of using Budgets in tandem with a Preloader! The preloader discovers links in a lateral scan of a whole block, before rewinding for a depth-first walk for traversal-proper.\n// Budgets are intended to be used for the depth-first walk, and there is no way to know ahead of time how the budget may impact the lateral parts of the graph that the preloader encounters.\n// Currently a best-guess approach is used to try and have the preloader adhere to the budget, but with typical real-world graphs, this is likely to be inaccurate.\n// In the case of inaccuracies, the budget will be properly applied to the traversal-proper, but the preloader may receive a different set of links than the traversal-proper will.\ntype Progress struct {\n\t// Cfg is the configuration for the traversal, set by user.\n\tCfg *Config\n\n\t// Budget, if present, tracks \"budgets\" for how many more steps we're willing to take before we should halt.\n\t// Budget is initially set by user, but is then updated as the traversal proceeds.\n\tBudget *Budget\n\n\t// Path is how we reached the current point in the traversal.\n\tPath datamodel.Path\n\n\t// LastBlock stores the Path and Link of the last block edge we had to load.  (It will always be zero in traversals with no linkloader.)\n\tLastBlock struct {\n\t\tPath datamodel.Path\n\t\tLink datamodel.Link\n\t}\n\n\t// PastStartAtPath indicates whether the traversal has progressed passed the StartAtPath in the config -- use to avoid path checks when inside a sub portion of a DAG that is entirely inside the \"not-skipped\" portion of a traversal\n\tPastStartAtPath bool\n\n\t// SeenLinks is a set used to remember which links have been visited before, if Cfg.LinkVisitOnlyOnce is true.\n\tSeenLinks map[datamodel.Link]struct{}\n}\n\n// Config is a set of options for a traversal. Set a Config on a Progress to customize the traversal.\ntype Config struct {\n\t// Ctx is the context carried through a traversal.\n\t// Optional; use it if you need cancellation.\n\tCtx context.Context\n\n\t// LinkSystem is used for automatic link loading, and also any storing if mutation features (e.g. traversal.Transform) are used.\n\tLinkSystem linking.LinkSystem\n\n\t// LinkTargetNodePrototypeChooser is a chooser for Node implementations to produce during automatic link traversal.\n\tLinkTargetNodePrototypeChooser LinkTargetNodePrototypeChooser\n\n\t// LinkVisitOnlyOnce controls repeat-link visitation.\n\t// By default, we visit across links wherever we see them again, even if we've visited them before, because the reason for visiting might be different than it was before since we got to it via a different path.\n\t// If set to true, track links we've seen before in Progress.SeenLinks and do not visit them again.\n\t// Note that sufficiently complex selectors may require valid revisiting of some links, so setting this to true can change behavior noticably and should be done with care.\n\tLinkVisitOnlyOnce bool\n\n\t// StartAtPath, if set, causes a traversal to skip forward until passing this path, and only then begins calling visit functions.\n\t// Block loads will also be skipped wherever possible.\n\tStartAtPath datamodel.Path\n\n\t// Preloader receives links within each block prior to traversal-proper by performing a lateral scan of a block without descending into links themselves before backing up and doing a traversal-proper.\n\t// This can be used to asynchronously load blocks that will be required at a later phase of the retrieval, or even to load blocks in a different order than the traversal would otherwise do.\n\t// Preload calls are not de-duplicated, it is up to the receiver to do so if desired.\n\t// Beware of using both Budget and Preloader!  See the documentation on Progress for more information on this usage and the likely surprising effects.\n\tPreloader preload.Loader\n}\n\n// Budget is a set of monotonically-decrementing \"budgets\" for how many more steps we're willing to take before we should halt.\n//\n// The fields of Budget are described as \"monotonically-decrementing\", because that's what the traversal library will do with them,\n// but they are user-accessable and can be reset to higher numbers again by code in the visitor callbacks.  This is not recommended (why?), but possible.\n\n// If you set any budgets (by having a non-nil Progress.Budget field), you must set some value for all of them.\n// Traversal halts when _any_ of the budgets reaches zero.\n// The max value of an int (math.MaxInt64) is acceptable for any budget you don't care about.\n//\n// Beware of using both Budget and Preloader!  See the documentation on Progress for more information on this usage and the likely surprising effects.\ntype Budget struct {\n\t// NodeBudget is a monotonically-decrementing \"budget\" for how many more nodes we're willing to visit before halting.\n\tNodeBudget int64\n\t// LinkBudget is a monotonically-decrementing \"budget\" for how many more links we're willing to load before halting.\n\t// (This is not aware of any caching; it's purely in terms of links encountered and traversed.)\n\tLinkBudget int64\n}\n\n// Clone returns a copy of the budget.\nfunc (b *Budget) Clone() *Budget {\n\tif b == nil {\n\t\treturn nil\n\t}\n\treturn &Budget{\n\t\tNodeBudget: b.NodeBudget,\n\t\tLinkBudget: b.LinkBudget,\n\t}\n}\n\n// LinkTargetNodePrototypeChooser is a function that returns a NodePrototype based on\n// the information in a Link and/or its LinkContext.\n//\n// A LinkTargetNodePrototypeChooser can be used in a traversal.Config to be clear about\n// what kind of Node implementation to use when loading a Link.\n// In a simple example, it could constantly return a `basicnode.Prototype.Any`.\n// In a more complex example, a program using `bind` over native Go types\n// could decide what kind of native type is expected, and return a\n// `bind.NodeBuilder` for that specific concrete native type.\ntype LinkTargetNodePrototypeChooser func(datamodel.Link, linking.LinkContext) (datamodel.NodePrototype, error)\n\n// SkipMe is a signalling \"error\" which can be used to tell traverse to skip some data.\n//\n// SkipMe can be returned by the Config.LinkLoader to skip entire blocks without aborting the walk.\n// (This can be useful if you know you don't have data on hand,\n// but want to continue the walk in other areas anyway;\n// or, if you're doing a way where you know that it's valid to memoize seen\n// areas based on Link alone.)\ntype SkipMe struct{}\n\nfunc (SkipMe) Error() string {\n\treturn \"skip\"\n}\n\ntype ErrBudgetExceeded struct {\n\tBudgetKind string // \"node\"|\"link\"\n\tPath       datamodel.Path\n\tLink       datamodel.Link // only present if BudgetKind==\"link\"\n}\n\nfunc (e *ErrBudgetExceeded) Error() string {\n\tmsg := fmt.Sprintf(\"traversal budget exceeded: budget for %ss reached zero while on path %q\", e.BudgetKind, e.Path)\n\tif e.Link != nil {\n\t\tmsg += fmt.Sprintf(\" (link: %q)\", e.Link)\n\t}\n\treturn msg\n}\n\nfunc (e *ErrBudgetExceeded) Is(target error) bool {\n\t_, ok := target.(*ErrBudgetExceeded)\n\treturn ok\n}\n"
  },
  {
    "path": "traversal/focus.go",
    "content": "package traversal\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n)\n\n// Focus traverses a Node graph according to a path, reaches a single Node,\n// and calls the given VisitFn on that reached node.\n//\n// This function is a helper function which starts a new traversal with default configuration.\n// It cannot cross links automatically (since this requires configuration).\n// Use the equivalent Focus function on the Progress structure\n// for more advanced and configurable walks.\nfunc Focus(n datamodel.Node, p datamodel.Path, fn VisitFn) error {\n\treturn Progress{}.Focus(n, p, fn)\n}\n\n// Get is the equivalent of Focus, but returns the reached node (rather than invoking a callback at the target),\n// and does not yield Progress information.\n//\n// This function is a helper function which starts a new traversal with default configuration.\n// It cannot cross links automatically (since this requires configuration).\n// Use the equivalent Get function on the Progress structure\n// for more advanced and configurable walks.\nfunc Get(n datamodel.Node, p datamodel.Path) (datamodel.Node, error) {\n\treturn Progress{}.Get(n, p)\n}\n\n// FocusedTransform traverses a datamodel.Node graph, reaches a single Node,\n// and calls the given TransformFn to decide what new node to replace the visited node with.\n// A new Node tree will be returned (the original is unchanged).\n//\n// This function is a helper function which starts a new traversal with default configuration.\n// It cannot cross links automatically (since this requires configuration).\n// Use the equivalent FocusedTransform function on the Progress structure\n// for more advanced and configurable walks.\nfunc FocusedTransform(n datamodel.Node, p datamodel.Path, fn TransformFn, createParents bool) (datamodel.Node, error) {\n\treturn Progress{}.FocusedTransform(n, p, fn, createParents)\n}\n\n// Focus traverses a Node graph according to a path, reaches a single Node,\n// and calls the given VisitFn on that reached node.\n//\n// Focus is a read-only traversal.\n// See FocusedTransform if looking for a way to do an \"update\" to a Node.\n//\n// Provide configuration to this process using the Config field in the Progress object.\n//\n// This walk will automatically cross links, but requires some configuration\n// with link loading functions to do so.\n//\n// Focus (and the other traversal functions) can be used again again inside the VisitFn!\n// By using the traversal.Progress handed to the VisitFn,\n// the Path recorded of the traversal so far will continue to be extended,\n// and thus continued nested uses of Walk and Focus will see the fully contextualized Path.\nfunc (prog Progress) Focus(n datamodel.Node, p datamodel.Path, fn VisitFn) error {\n\tn, err := prog.get(n, p, true)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn fn(prog, n)\n}\n\n// Get is the equivalent of Focus, but returns the reached node (rather than invoking a callback at the target),\n// and does not yield Progress information.\n//\n// Provide configuration to this process using the Config field in the Progress object.\n//\n// This walk will automatically cross links, but requires some configuration\n// with link loading functions to do so.\n//\n// If doing several traversals which are nested, consider using the Focus funcion in preference to Get;\n// the Focus functions provide updated Progress objects which can be used to do nested traversals while keeping consistent track of progress,\n// such that continued nested uses of Walk or Focus or Get will see the fully contextualized Path.\nfunc (prog Progress) Get(n datamodel.Node, p datamodel.Path) (datamodel.Node, error) {\n\treturn prog.get(n, p, false)\n}\n\n// get is the internal implementation for Focus and Get.\n// It *mutates* the Progress object it's called on, and returns reached nodes.\n// For Get calls, trackProgress=false, which avoids some allocations for state tracking that's not needed by that call.\nfunc (prog *Progress) get(n datamodel.Node, p datamodel.Path, trackProgress bool) (datamodel.Node, error) {\n\tprog.init()\n\tsegments := p.Segments()\n\tvar prev datamodel.Node // for LinkContext\n\tfor i, seg := range segments {\n\t\t// Check the budget!\n\t\tif prog.Budget != nil {\n\t\t\tprog.Budget.NodeBudget--\n\t\t\tif prog.Budget.NodeBudget <= 0 {\n\t\t\t\treturn nil, &ErrBudgetExceeded{BudgetKind: \"node\", Path: prog.Path}\n\t\t\t}\n\t\t}\n\t\t// Traverse the segment.\n\t\tswitch n.Kind() {\n\t\tcase datamodel.Kind_Invalid:\n\t\t\tpanic(fmt.Errorf(\"invalid node encountered at %q\", p.Truncate(i)))\n\t\tcase datamodel.Kind_Map:\n\t\t\tnext, err := n.LookupByString(seg.String())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error traversing segment %q on node at %q: %w\", seg, p.Truncate(i), err)\n\t\t\t}\n\t\t\tprev, n = n, next\n\t\tcase datamodel.Kind_List:\n\t\t\tintSeg, err := seg.Index()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error traversing segment %q on node at %q: the segment cannot be parsed as a number and the node is a list\", seg, p.Truncate(i))\n\t\t\t}\n\t\t\tnext, err := n.LookupByIndex(intSeg)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error traversing segment %q on node at %q: %w\", seg, p.Truncate(i), err)\n\t\t\t}\n\t\t\tprev, n = n, next\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"cannot traverse node at %q: %w\", p.Truncate(i), fmt.Errorf(\"cannot traverse terminals\"))\n\t\t}\n\t\t// Dereference any links.\n\t\tfor n.Kind() == datamodel.Kind_Link {\n\t\t\tlnk, _ := n.AsLink()\n\t\t\t// Check the budget!\n\t\t\tif prog.Budget != nil {\n\t\t\t\tif prog.Budget.LinkBudget <= 0 {\n\t\t\t\t\treturn nil, &ErrBudgetExceeded{BudgetKind: \"link\", Path: prog.Path, Link: lnk}\n\t\t\t\t}\n\t\t\t\tprog.Budget.LinkBudget--\n\t\t\t}\n\t\t\t// Put together the context info we'll offer to the loader and prototypeChooser.\n\t\t\tlnkCtx := linking.LinkContext{\n\t\t\t\tCtx:        prog.Cfg.Ctx,\n\t\t\t\tLinkPath:   p.Truncate(i),\n\t\t\t\tLinkNode:   n,\n\t\t\t\tParentNode: prev,\n\t\t\t}\n\t\t\t// Pick what in-memory format we will build.\n\t\t\tnp, err := prog.Cfg.LinkTargetNodePrototypeChooser(lnk, lnkCtx)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error traversing node at %q: could not load link %q: %w\", p.Truncate(i+1), lnk, err)\n\t\t\t}\n\t\t\t// Load link!\n\t\t\tprev = n\n\t\t\tn, err = prog.Cfg.LinkSystem.Load(lnkCtx, lnk, np)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error traversing node at %q: could not load link %q: %w\", p.Truncate(i+1), lnk, err)\n\t\t\t}\n\t\t\tif trackProgress {\n\t\t\t\tprog.LastBlock.Path = p.Truncate(i + 1)\n\t\t\t\tprog.LastBlock.Link = lnk\n\t\t\t}\n\t\t}\n\t}\n\tif trackProgress {\n\t\tprog.Path = prog.Path.Join(p)\n\t}\n\treturn n, nil\n}\n\n// FocusedTransform traverses a datamodel.Node graph, reaches a single Node,\n// and calls the given TransformFn to decide what new node to replace the visited node with.\n// A new Node tree will be returned (the original is unchanged).\n//\n// If the TransformFn returns the same Node which it was called with,\n// then the transform is a no-op, and the Node returned from the\n// FocusedTransform call as a whole will also be the same as its starting Node.\n//\n// Otherwise, the reached node will be \"replaced\" with the new Node -- meaning\n// that new intermediate nodes will be constructed to also replace each\n// parent Node that was traversed to get here, thus propagating the changes in\n// a copy-on-write fashion -- and the FocusedTransform function as a whole will\n// return a new Node containing identical children except for those replaced.\n//\n// Returning nil from the TransformFn as the replacement node means \"remove this\".\n//\n// FocusedTransform can be used again inside the applied function!\n// This kind of composition can be useful for doing batches of updates.\n// E.g. if have a large Node graph which contains a 100-element list, and\n// you want to replace elements 12, 32, and 95 of that list:\n// then you should FocusedTransform to the list first, and inside that\n// TransformFn's body, you can replace the entire list with a new one\n// that is composed of copies of everything but those elements -- including\n// using more TransformFn calls as desired to produce the replacement elements\n// if it so happens that those replacement elements are easiest to construct\n// by regarding them as incremental updates to the previous values.\n// (This approach can also be used when doing other modifications like insertion\n// or reordering -- which would otherwise be tricky to define, since\n// each operation could change the meaning of subsequently used indexes.)\n//\n// As a special case, list appending is supported by using the path segment \"-\".\n// (This is determined by the node it applies to -- if that path segment\n// is applied to a map, it's just a regular map key of the string of dash.)\n//\n// Note that anything you can do with the Transform function, you can also\n// do with regular Node and NodeBuilder usage directly.  Transform just\n// does a large amount of the intermediate bookkeeping that's useful when\n// creating new values which are partial updates to existing values.\nfunc (prog Progress) FocusedTransform(n datamodel.Node, p datamodel.Path, fn TransformFn, createParents bool) (datamodel.Node, error) {\n\tprog.init()\n\tnb := n.Prototype().NewBuilder()\n\tif err := prog.focusedTransform(n, nb, p, fn, createParents); err != nil {\n\t\treturn nil, err\n\t}\n\treturn nb.Build(), nil\n}\n\n// focusedTransform assumes that an update will actually happen, and as it recurses deeper,\n// begins building an updated node tree.\n//\n// As implemented, this is not actually efficient if the update will be a no-op; it won't notice until it gets there.\nfunc (prog Progress) focusedTransform(n datamodel.Node, na datamodel.NodeAssembler, p datamodel.Path, fn TransformFn, createParents bool) error {\n\tat := prog.Path\n\t// Base case: if we've reached the end of the path, do the replacement here.\n\t//  (Note: in some cases within maps, there is another branch that is the base case, for reasons involving removes.)\n\tif p.Len() == 0 {\n\t\tn2, err := fn(prog, n)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn na.AssignNode(n2)\n\t}\n\tseg, p2 := p.Shift()\n\t// Check the budget!\n\tif prog.Budget != nil {\n\t\tif prog.Budget.NodeBudget <= 0 {\n\t\t\treturn &ErrBudgetExceeded{BudgetKind: \"node\", Path: prog.Path}\n\t\t}\n\t\tprog.Budget.NodeBudget--\n\t}\n\t// Special branch for if we've entered createParent mode in an earlier step.\n\t//  This needs slightly different logic because there's no prior node to reference\n\t//   (and we wouldn't want to waste time creating a dummy one).\n\tif n == nil {\n\t\tma, err := na.BeginMap(1)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tprog.Path = at.AppendSegment(seg)\n\t\tif err := ma.AssembleKey().AssignString(seg.String()); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := prog.focusedTransform(nil, ma.AssembleValue(), p2, fn, createParents); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn ma.Finish()\n\t}\n\t// Handle node based on kind.\n\t//  If it's a recursive kind (map or list), we'll be recursing on it.\n\t//  If it's a link, load it!  And recurse on it.\n\t//  If it's a scalar kind (any of the rest), we'll... be erroring, actually;\n\t//   if we're at the end, it was already handled at the top of the function,\n\t//   so we only get to this case if we were expecting to go deeper.\n\tswitch n.Kind() {\n\tcase datamodel.Kind_Map:\n\t\tma, err := na.BeginMap(n.Length())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// If we're approaching the end of the path, call the TransformFunc.\n\t\t//  We need to know if it returns nil (meaning: do a deletion) _before_ we do the AssembleKey step.\n\t\t//  (This results in the entire map branch having a different base case.)\n\t\tvar end bool\n\t\tvar n2 datamodel.Node\n\t\tif p2.Len() == 0 {\n\t\t\tend = true\n\t\t\tn3, err := n.LookupBySegment(seg)\n\t\t\tif n3 != datamodel.Absent && err != nil { // TODO badly need to simplify the standard treatment of \"not found\" here.  Can't even fit it all in one line!  See https://github.com/ipld/go-ipld-prime/issues/360.\n\t\t\t\tif _, ok := err.(datamodel.ErrNotExists); !ok {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tprog.Path = at.AppendSegment(seg)\n\t\t\tn2, err = fn(prog, n3)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\t// Copy children over.  Replace the target (preserving its current position!) while doing this, if found.\n\t\t//  Note that we don't recurse into copying children (assuming AssignNode doesn't); this is as shallow/COW as the AssignNode implementation permits.\n\t\tvar replaced bool\n\t\tfor itr := n.MapIterator(); !itr.Done(); {\n\t\t\tk, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif asPathSegment(k).Equals(seg) { // for the segment that's either update, update within, or being removed:\n\t\t\t\tif end { // the last path segment in the overall instruction gets a different case because it may need to handle deletion\n\t\t\t\t\tif n2 == nil {\n\t\t\t\t\t\treplaced = true\n\t\t\t\t\t\tcontinue // replace with nil means delete, which means continue early here: don't even copy the key.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// as long as we're not deleting, then this key will exist in the new data.\n\t\t\t\tif err := ma.AssembleKey().AssignNode(k); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treplaced = true\n\t\t\t\tif n2 != nil { // if we already produced the replacement because we're at the end...\n\t\t\t\t\tif err := ma.AssembleValue().AssignNode(n2); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t} else { // ... otherwise, recurse:\n\t\t\t\t\tprog.Path = at.AppendSegment(seg)\n\t\t\t\t\tif err := prog.focusedTransform(v, ma.AssembleValue(), p2, fn, createParents); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else { // for any other siblings of the target: just copy.\n\t\t\t\tif err := ma.AssembleKey().AssignNode(k); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := ma.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif replaced {\n\t\t\treturn ma.Finish()\n\t\t}\n\t\t// If we didn't find the target yet: append it.\n\t\t//  If we're at the end, always do this;\n\t\t//  if we're in the middle, only do this if createParents mode is enabled.\n\t\tprog.Path = at.AppendSegment(seg)\n\t\tif p.Len() > 1 && !createParents {\n\t\t\treturn fmt.Errorf(\"transform: parent position at %q did not exist (and createParents was false)\", prog.Path)\n\t\t}\n\t\tif err := ma.AssembleKey().AssignString(seg.String()); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := prog.focusedTransform(nil, ma.AssembleValue(), p2, fn, createParents); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn ma.Finish()\n\tcase datamodel.Kind_List:\n\t\tla, err := na.BeginList(n.Length())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// First figure out if this path segment can apply to a list sanely at all.\n\t\t//  Simultaneously, get it in numeric format, so subsequent operations are cheaper.\n\t\tti, err := seg.Index()\n\t\tif err != nil {\n\t\t\tif seg.String() == \"-\" {\n\t\t\t\tti = -1\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"transform: cannot navigate path segment %q at %q because a list is here\", seg, prog.Path)\n\t\t\t}\n\t\t}\n\t\t// Copy children over.  Replace the target (preserving its current position!) while doing this, if found.\n\t\t//  Note that we don't recurse into copying children (assuming AssignNode doesn't); this is as shallow/COW as the AssignNode implementation permits.\n\t\tvar replaced bool\n\t\tfor itr := n.ListIterator(); !itr.Done(); {\n\t\t\ti, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif ti == i {\n\t\t\t\tprog.Path = prog.Path.AppendSegment(seg)\n\t\t\t\tif err := prog.focusedTransform(v, la.AssembleValue(), p2, fn, createParents); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treplaced = true\n\t\t\t} else {\n\t\t\t\tif err := la.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif replaced {\n\t\t\treturn la.Finish()\n\t\t}\n\t\t// If we didn't find the target yet: hopefully this was an append operation;\n\t\t//  if it wasn't, then it's index out of bounds.  We don't arbitrarily extend lists with filler.\n\t\tif ti >= 0 {\n\t\t\treturn fmt.Errorf(\"transform: cannot navigate path segment %q at %q because it is beyond the list bounds\", seg, prog.Path)\n\t\t}\n\t\tprog.Path = prog.Path.AppendSegment(datamodel.PathSegmentOfInt(n.Length()))\n\t\tif err := prog.focusedTransform(nil, la.AssembleValue(), p2, fn, createParents); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn la.Finish()\n\tcase datamodel.Kind_Link:\n\t\tlnk, _ := n.AsLink()\n\t\t// Check the budget!\n\t\tif prog.Budget != nil {\n\t\t\tif prog.Budget.LinkBudget <= 0 {\n\t\t\t\treturn &ErrBudgetExceeded{BudgetKind: \"link\", Path: prog.Path, Link: lnk}\n\t\t\t}\n\t\t\tprog.Budget.LinkBudget--\n\t\t}\n\t\t// Put together the context info we'll offer to the loader and prototypeChooser.\n\t\tlnkCtx := linking.LinkContext{\n\t\t\tCtx:        prog.Cfg.Ctx,\n\t\t\tLinkPath:   prog.Path,\n\t\t\tLinkNode:   n,\n\t\t\tParentNode: nil, // TODO inconvenient that we don't have this.  maybe this whole case should be a helper function.\n\t\t}\n\t\t// Pick what in-memory format we will build.\n\t\tnp, err := prog.Cfg.LinkTargetNodePrototypeChooser(lnk, lnkCtx)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"transform: error traversing node at %q: could not load link %q: %w\", prog.Path, lnk, err)\n\t\t}\n\t\t// Load link!\n\t\t//  We'll use LinkSystem.Fill here rather than Load,\n\t\t//   because there's a nice opportunity to reuse the builder shortly.\n\t\tnb := np.NewBuilder()\n\t\terr = prog.Cfg.LinkSystem.Fill(lnkCtx, lnk, nb)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"transform: error traversing node at %q: could not load link %q: %w\", prog.Path, lnk, err)\n\t\t}\n\t\tprog.LastBlock.Path = prog.Path\n\t\tprog.LastBlock.Link = lnk\n\t\tn = nb.Build()\n\t\t// Recurse.\n\t\t//  Start a new builder for this, using the same prototype we just used for loading the link.\n\t\t//   (Or more specifically: this is an opportunity for just resetting a builder and reusing memory!)\n\t\t//  When we come back... we'll have to engage serialization and storage on the new node!\n\t\t//  Path isn't updated here (neither progress nor to-go).\n\t\tnb.Reset()\n\t\tif err := prog.focusedTransform(n, nb, p, fn, createParents); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tn = nb.Build()\n\t\tlnk, err = prog.Cfg.LinkSystem.Store(lnkCtx, lnk.Prototype(), n)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"transform: error storing transformed node at %q: %w\", prog.Path, err)\n\t\t}\n\t\treturn na.AssignLink(lnk)\n\tdefault:\n\t\treturn fmt.Errorf(\"transform: parent position at %q was a scalar, cannot go deeper\", prog.Path)\n\t}\n}\n"
  },
  {
    "path": "traversal/focus_test.go",
    "content": "package traversal_test\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/ipfs/go-cid\"\n\n\t_ \"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/must\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\tnodetests \"github.com/ipld/go-ipld-prime/node/tests\"\n\t\"github.com/ipld/go-ipld-prime/storage/memstore\"\n\t\"github.com/ipld/go-ipld-prime/traversal\"\n)\n\n// Do some fixture fabrication.\n// We assume all the builders and serialization must Just Work here.\n\nvar deepEqualsAllowAllUnexported = qt.CmpEquals(cmp.Exporter(func(reflect.Type) bool { return true }))\n\nvar store = memstore.Store{}\nvar (\n\t// baguqeeyexkjwnfy\n\tleafAlpha, leafAlphaLnk = encode(basicnode.NewString(\"alpha\"))\n\t// baguqeeyeqvc7t3a\n\tleafBeta, leafBetaLnk = encode(basicnode.NewString(\"beta\"))\n\t// baguqeeyezhlahvq\n\tmiddleMapNode, middleMapNodeLnk = encode(fluent.MustBuildMap(basicnode.Prototype.Map, 3, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"foo\").AssignBool(true)\n\t\tna.AssembleEntry(\"bar\").AssignBool(false)\n\t\tna.AssembleEntry(\"nested\").CreateMap(2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(\"alink\").AssignLink(leafAlphaLnk)\n\t\t\tna.AssembleEntry(\"nonlink\").AssignString(\"zoo\")\n\t\t})\n\t}))\n\t// baguqeeyehfkkfwa\n\tmiddleListNode, middleListNodeLnk = encode(fluent.MustBuildList(basicnode.Prototype.List, 4, func(na fluent.ListAssembler) {\n\t\tna.AssembleValue().AssignLink(leafAlphaLnk)\n\t\tna.AssembleValue().AssignLink(leafAlphaLnk)\n\t\tna.AssembleValue().AssignLink(leafBetaLnk)\n\t\tna.AssembleValue().AssignLink(leafAlphaLnk)\n\t}))\n\t// note that using `rootNode` directly will have a different field ordering than\n\t// the encoded form if you were to load `rootNodeLnk` due to dag-json field\n\t// reordering on encode, beware the difference for traversal order between\n\t// created, in-memory nodes and those that have passed through a codec with\n\t// field ordering rules\n\t// baguqeeyeie4ajfy\n\trootNode, rootNodeLnk = encode(fluent.MustBuildMap(basicnode.Prototype.Map, 4, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"plain\").AssignString(\"olde string\")\n\t\tna.AssembleEntry(\"linkedString\").AssignLink(leafAlphaLnk)\n\t\tna.AssembleEntry(\"linkedMap\").AssignLink(middleMapNodeLnk)\n\t\tna.AssembleEntry(\"linkedList\").AssignLink(middleListNodeLnk)\n\t}))\n)\n\n// encode hardcodes some encoding choices for ease of use in fixture generation;\n// just gimme a link and stuff the bytes in a map.\n// (also return the node again for convenient assignment.)\nfunc encode(n datamodel.Node) (datamodel.Node, datamodel.Link) {\n\tlp := cidlink.LinkPrototype{Prefix: cid.Prefix{\n\t\tVersion:  1,\n\t\tCodec:    0x0129,\n\t\tMhType:   0x13,\n\t\tMhLength: 4,\n\t}}\n\tlsys := cidlink.DefaultLinkSystem()\n\tlsys.SetWriteStorage(&store)\n\n\tlnk, err := lsys.Store(linking.LinkContext{}, lp, n)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn n, lnk\n}\n\n// covers Focus used on one already-loaded Node; no link-loading exercised.\nfunc TestFocusSingleTree(t *testing.T) {\n\tt.Run(\"empty path on scalar node returns start node\", func(t *testing.T) {\n\t\terr := traversal.Focus(basicnode.NewString(\"x\"), datamodel.Path{}, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"x\"))\n\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, datamodel.Path{}.String())\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t})\n\tt.Run(\"one step path on map node works\", func(t *testing.T) {\n\t\terr := traversal.Focus(middleMapNode, datamodel.ParsePath(\"foo\"), func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewBool(true))\n\t\t\tqt.Check(t, prog.Path, deepEqualsAllowAllUnexported, datamodel.ParsePath(\"foo\"))\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t})\n\tt.Run(\"two step path on map node works\", func(t *testing.T) {\n\t\terr := traversal.Focus(middleMapNode, datamodel.ParsePath(\"nested/nonlink\"), func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"zoo\"))\n\t\t\tqt.Check(t, prog.Path, deepEqualsAllowAllUnexported, datamodel.ParsePath(\"nested/nonlink\"))\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t})\n}\n\n// covers Get used on one already-loaded Node; no link-loading exercised.\n// same fixtures as the test for Focus; just has fewer assertions, since Get does no progress tracking.\nfunc TestGetSingleTree(t *testing.T) {\n\tt.Run(\"empty path on scalar node returns start node\", func(t *testing.T) {\n\t\tn, err := traversal.Get(basicnode.NewString(\"x\"), datamodel.Path{})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"x\"))\n\t})\n\tt.Run(\"one step path on map node works\", func(t *testing.T) {\n\t\tn, err := traversal.Get(middleMapNode, datamodel.ParsePath(\"foo\"))\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewBool(true))\n\t})\n\tt.Run(\"two step path on map node works\", func(t *testing.T) {\n\t\tn, err := traversal.Get(middleMapNode, datamodel.ParsePath(\"nested/nonlink\"))\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"zoo\"))\n\t})\n}\n\nfunc TestFocusWithLinkLoading(t *testing.T) {\n\tt.Run(\"link traversal with no configured loader should fail\", func(t *testing.T) {\n\t\tt.Run(\"terminal link should fail\", func(t *testing.T) {\n\t\t\terr := traversal.Focus(middleMapNode, datamodel.ParsePath(\"nested/alink\"), func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\t\tt.Errorf(\"should not be reached; no way to load this path\")\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tqt.Check(t, err.Error(), qt.Equals, `error traversing node at \"nested/alink\": could not load link \"`+leafAlphaLnk.String()+`\": no LinkTargetNodePrototypeChooser configured`)\n\t\t})\n\t\tt.Run(\"mid-path link should fail\", func(t *testing.T) {\n\t\t\terr := traversal.Focus(rootNode, datamodel.ParsePath(\"linkedMap/nested/nonlink\"), func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\t\tt.Errorf(\"should not be reached; no way to load this path\")\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tqt.Check(t, err.Error(), qt.Equals, `error traversing node at \"linkedMap\": could not load link \"`+middleMapNodeLnk.String()+`\": no LinkTargetNodePrototypeChooser configured`)\n\t\t})\n\t})\n\tt.Run(\"link traversal with loader should work\", func(t *testing.T) {\n\t\tlsys := cidlink.DefaultLinkSystem()\n\t\tlsys.SetReadStorage(&store)\n\t\terr := traversal.Progress{\n\t\t\tCfg: &traversal.Config{\n\t\t\t\tLinkSystem:                     lsys,\n\t\t\t\tLinkTargetNodePrototypeChooser: basicnode.Chooser,\n\t\t\t},\n\t\t}.Focus(rootNode, datamodel.ParsePath(\"linkedMap/nested/nonlink\"), func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"zoo\"))\n\t\t\tqt.Check(t, prog.Path, deepEqualsAllowAllUnexported, datamodel.ParsePath(\"linkedMap/nested/nonlink\"))\n\t\t\tqt.Check(t, prog.LastBlock.Link, deepEqualsAllowAllUnexported, middleMapNodeLnk)\n\t\t\tqt.Check(t, prog.LastBlock.Path, deepEqualsAllowAllUnexported, datamodel.ParsePath(\"linkedMap\"))\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t})\n}\n\nfunc TestGetWithLinkLoading(t *testing.T) {\n\tt.Run(\"link traversal with no configured loader should fail\", func(t *testing.T) {\n\t\tt.Run(\"terminal link should fail\", func(t *testing.T) {\n\t\t\t_, err := traversal.Get(middleMapNode, datamodel.ParsePath(\"nested/alink\"))\n\t\t\tqt.Check(t, err.Error(), qt.Equals, `error traversing node at \"nested/alink\": could not load link \"`+leafAlphaLnk.String()+`\": no LinkTargetNodePrototypeChooser configured`)\n\t\t})\n\t\tt.Run(\"mid-path link should fail\", func(t *testing.T) {\n\t\t\t_, err := traversal.Get(rootNode, datamodel.ParsePath(\"linkedMap/nested/nonlink\"))\n\t\t\tqt.Check(t, err.Error(), qt.Equals, `error traversing node at \"linkedMap\": could not load link \"`+middleMapNodeLnk.String()+`\": no LinkTargetNodePrototypeChooser configured`)\n\t\t})\n\t})\n\tt.Run(\"link traversal with loader should work\", func(t *testing.T) {\n\t\tlsys := cidlink.DefaultLinkSystem()\n\t\tlsys.SetReadStorage(&store)\n\t\tn, err := traversal.Progress{\n\t\t\tCfg: &traversal.Config{\n\t\t\t\tLinkSystem:                     lsys,\n\t\t\t\tLinkTargetNodePrototypeChooser: basicnode.Chooser,\n\t\t\t},\n\t\t}.Get(rootNode, datamodel.ParsePath(\"linkedMap/nested/nonlink\"))\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"zoo\"))\n\t})\n}\n\nfunc TestFocusedTransform(t *testing.T) {\n\tt.Run(\"UpdateMapEntry\", func(t *testing.T) {\n\t\tn, err := traversal.FocusedTransform(rootNode, datamodel.ParsePath(\"plain\"), func(progress traversal.Progress, prev datamodel.Node) (datamodel.Node, error) {\n\t\t\tqt.Check(t, progress.Path.String(), qt.Equals, \"plain\")\n\t\t\tqt.Check(t, must.String(prev), qt.Equals, \"olde string\")\n\t\t\tnb := prev.Prototype().NewBuilder()\n\t\t\tnb.AssignString(\"new string!\")\n\t\t\treturn nb.Build(), nil\n\t\t}, false)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t// updated value should be there\n\t\tqt.Check(t, must.Node(n.LookupByString(\"plain\")), nodetests.NodeContentEquals, basicnode.NewString(\"new string!\"))\n\t\t// everything else should be there\n\t\tqt.Check(t, must.Node(n.LookupByString(\"linkedString\")), qt.Equals, must.Node(rootNode.LookupByString(\"linkedString\")))\n\t\tqt.Check(t, must.Node(n.LookupByString(\"linkedMap\")), qt.Equals, must.Node(rootNode.LookupByString(\"linkedMap\")))\n\t\tqt.Check(t, must.Node(n.LookupByString(\"linkedList\")), qt.Equals, must.Node(rootNode.LookupByString(\"linkedList\")))\n\t\t// everything should still be in the same order\n\t\tqt.Check(t, keys(n), qt.DeepEquals, []string{\"plain\", \"linkedString\", \"linkedMap\", \"linkedList\"})\n\t})\n\tt.Run(\"UpdateDeeperMap\", func(t *testing.T) {\n\t\tn, err := traversal.FocusedTransform(middleMapNode, datamodel.ParsePath(\"nested/alink\"), func(progress traversal.Progress, prev datamodel.Node) (datamodel.Node, error) {\n\t\t\tqt.Check(t, progress.Path.String(), qt.Equals, \"nested/alink\")\n\t\t\tqt.Check(t, prev, nodetests.NodeContentEquals, basicnode.NewLink(leafAlphaLnk))\n\t\t\treturn basicnode.NewString(\"new string!\"), nil\n\t\t}, false)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t// updated value should be there\n\t\tqt.Check(t, must.Node(must.Node(n.LookupByString(\"nested\")).LookupByString(\"alink\")), nodetests.NodeContentEquals, basicnode.NewString(\"new string!\"))\n\t\t// everything else in the parent map should should be there!\n\t\tqt.Check(t, must.Node(n.LookupByString(\"foo\")), qt.Equals, must.Node(middleMapNode.LookupByString(\"foo\")))\n\t\tqt.Check(t, must.Node(n.LookupByString(\"bar\")), qt.Equals, must.Node(middleMapNode.LookupByString(\"bar\")))\n\t\t// everything should still be in the same order\n\t\tqt.Check(t, keys(n), qt.DeepEquals, []string{\"foo\", \"bar\", \"nested\"})\n\t})\n\tt.Run(\"AppendIfNotExists\", func(t *testing.T) {\n\t\tn, err := traversal.FocusedTransform(rootNode, datamodel.ParsePath(\"newpart\"), func(progress traversal.Progress, prev datamodel.Node) (datamodel.Node, error) {\n\t\t\tqt.Check(t, progress.Path.String(), qt.Equals, \"newpart\")\n\t\t\tqt.Check(t, prev, qt.IsNil) // REVIEW: should datamodel.Absent be used here?  I lean towards \"no\" but am unsure what's least surprising here.\n\t\t\t// An interesting thing to note about inserting a value this way is that you have no `prev.Prototype().NewBuilder()` to use if you wanted to.\n\t\t\t//  But if that's an issue, then what you do is a focus or walk (transforming or not) to the parent node, get its child prototypes, and go from there.\n\t\t\treturn basicnode.NewString(\"new string!\"), nil\n\t\t}, false)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t// updated value should be there\n\t\tqt.Check(t, must.Node(n.LookupByString(\"newpart\")), nodetests.NodeContentEquals, basicnode.NewString(\"new string!\"))\n\t\t// everything should still be in the same order... with the new entry at the end.\n\t\tqt.Check(t, keys(n), qt.DeepEquals, []string{\"plain\", \"linkedString\", \"linkedMap\", \"linkedList\", \"newpart\"})\n\t})\n\tt.Run(\"CreateParents\", func(t *testing.T) {\n\t\tn, err := traversal.FocusedTransform(rootNode, datamodel.ParsePath(\"newsection/newpart\"), func(progress traversal.Progress, prev datamodel.Node) (datamodel.Node, error) {\n\t\t\tqt.Check(t, progress.Path.String(), qt.Equals, \"newsection/newpart\")\n\t\t\tqt.Check(t, prev, qt.IsNil) // REVIEW: should datamodel.Absent be used here?  I lean towards \"no\" but am unsure what's least surprising here.\n\t\t\treturn basicnode.NewString(\"new string!\"), nil\n\t\t}, true)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t// a new map node in the middle should've been created\n\t\tn2 := must.Node(n.LookupByString(\"newsection\"))\n\t\tqt.Check(t, n2.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t// updated value should in there\n\t\tqt.Check(t, must.Node(n2.LookupByString(\"newpart\")), nodetests.NodeContentEquals, basicnode.NewString(\"new string!\"))\n\t\t// everything in the root map should still be in the same order... with the new entry at the end.\n\t\tqt.Check(t, keys(n), qt.DeepEquals, []string{\"plain\", \"linkedString\", \"linkedMap\", \"linkedList\", \"newsection\"})\n\t\t// and the created intermediate map of course has just one entry.\n\t\tqt.Check(t, keys(n2), qt.DeepEquals, []string{\"newpart\"})\n\t})\n\tt.Run(\"CreateParentsRequiresPermission\", func(t *testing.T) {\n\t\t_, err := traversal.FocusedTransform(rootNode, datamodel.ParsePath(\"newsection/newpart\"), func(progress traversal.Progress, prev datamodel.Node) (datamodel.Node, error) {\n\t\t\tqt.Check(t, true, qt.IsFalse) // ought not be reached\n\t\t\treturn nil, nil\n\t\t}, false)\n\t\tqt.Check(t, err.Error(), qt.Equals, \"transform: parent position at \\\"newsection\\\" did not exist (and createParents was false)\")\n\t})\n\tt.Run(\"UpdateListEntry\", func(t *testing.T) {\n\t\tn, err := traversal.FocusedTransform(middleListNode, datamodel.ParsePath(\"2\"), func(progress traversal.Progress, prev datamodel.Node) (datamodel.Node, error) {\n\t\t\tqt.Check(t, progress.Path.String(), qt.Equals, \"2\")\n\t\t\tqt.Check(t, prev, nodetests.NodeContentEquals, basicnode.NewLink(leafBetaLnk))\n\t\t\treturn basicnode.NewString(\"new string!\"), nil\n\t\t}, false)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t// updated value should be there\n\t\tqt.Check(t, must.Node(n.LookupByIndex(2)), nodetests.NodeContentEquals, basicnode.NewString(\"new string!\"))\n\t\t// everything else should be there\n\t\tqt.Check(t, n.Length(), qt.Equals, int64(4))\n\t\tqt.Check(t, must.Node(n.LookupByIndex(0)), nodetests.NodeContentEquals, basicnode.NewLink(leafAlphaLnk))\n\t\tqt.Check(t, must.Node(n.LookupByIndex(1)), nodetests.NodeContentEquals, basicnode.NewLink(leafAlphaLnk))\n\t\tqt.Check(t, must.Node(n.LookupByIndex(3)), nodetests.NodeContentEquals, basicnode.NewLink(leafAlphaLnk))\n\t})\n\tt.Run(\"AppendToList\", func(t *testing.T) {\n\t\tn, err := traversal.FocusedTransform(middleListNode, datamodel.ParsePath(\"-\"), func(progress traversal.Progress, prev datamodel.Node) (datamodel.Node, error) {\n\t\t\tqt.Check(t, progress.Path.String(), qt.Equals, \"4\")\n\t\t\tqt.Check(t, prev, qt.IsNil)\n\t\t\treturn basicnode.NewString(\"new string!\"), nil\n\t\t}, false)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_List)\n\t\t// updated value should be there\n\t\tqt.Check(t, must.Node(n.LookupByIndex(4)), nodetests.NodeContentEquals, basicnode.NewString(\"new string!\"))\n\t\t// everything else should be there\n\t\tqt.Check(t, n.Length(), qt.Equals, int64(5))\n\t})\n\tt.Run(\"ListBounds\", func(t *testing.T) {\n\t\t_, err := traversal.FocusedTransform(middleListNode, datamodel.ParsePath(\"4\"), func(progress traversal.Progress, prev datamodel.Node) (datamodel.Node, error) {\n\t\t\tqt.Check(t, true, qt.IsFalse) // ought not be reached\n\t\t\treturn nil, nil\n\t\t}, false)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"transform: cannot navigate path segment \\\"4\\\" at \\\"\\\" because it is beyond the list bounds\")\n\t})\n\tt.Run(\"ReplaceRoot\", func(t *testing.T) { // a fairly degenerate case and no reason to do this, but should work.\n\t\tn, err := traversal.FocusedTransform(middleListNode, datamodel.ParsePath(\"\"), func(progress traversal.Progress, prev datamodel.Node) (datamodel.Node, error) {\n\t\t\tqt.Check(t, progress.Path.String(), qt.Equals, \"\")\n\t\t\tqt.Check(t, prev, nodetests.NodeContentEquals, middleListNode)\n\t\t\tnb := basicnode.Prototype.Any.NewBuilder()\n\t\t\tla, _ := nb.BeginList(0)\n\t\t\tla.Finish()\n\t\t\treturn nb.Build(), nil\n\t\t}, false)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_List)\n\t\tqt.Check(t, n.Length(), qt.Equals, int64(0))\n\t})\n}\n\nfunc TestFocusedTransformWithLinks(t *testing.T) {\n\tvar store2 = memstore.Store{}\n\tlsys := cidlink.DefaultLinkSystem()\n\tlsys.SetReadStorage(&store)\n\tlsys.SetWriteStorage(&store2)\n\tcfg := traversal.Config{\n\t\tLinkSystem:                     lsys,\n\t\tLinkTargetNodePrototypeChooser: basicnode.Chooser,\n\t}\n\tt.Run(\"UpdateMapBeyondLink\", func(t *testing.T) {\n\t\tn, err := traversal.Progress{\n\t\t\tCfg: &cfg,\n\t\t}.FocusedTransform(rootNode, datamodel.ParsePath(\"linkedMap/nested/nonlink\"), func(progress traversal.Progress, prev datamodel.Node) (datamodel.Node, error) {\n\t\t\tqt.Check(t, progress.Path.String(), qt.Equals, \"linkedMap/nested/nonlink\")\n\t\t\tqt.Check(t, must.String(prev), qt.Equals, \"zoo\")\n\t\t\tqt.Check(t, progress.LastBlock.Path.String(), qt.Equals, \"linkedMap\")\n\t\t\tqt.Check(t, progress.LastBlock.Link.String(), qt.Equals, \"baguqeeyezhlahvq\")\n\t\t\tnb := prev.Prototype().NewBuilder()\n\t\t\tnb.AssignString(\"new string!\")\n\t\t\treturn nb.Build(), nil\n\t\t}, false)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t// there should be a new object in our new storage!\n\t\tqt.Check(t, store2.Bag, qt.HasLen, 1)\n\t\t// cleanup for next test\n\t\tstore2 = memstore.Store{}\n\t})\n\tt.Run(\"UpdateNotBeyondLink\", func(t *testing.T) {\n\t\t// This is replacing a link with a non-link.  Doing so shouldn't hit storage.\n\t\tn, err := traversal.Progress{\n\t\t\tCfg: &cfg,\n\t\t}.FocusedTransform(rootNode, datamodel.ParsePath(\"linkedMap\"), func(progress traversal.Progress, prev datamodel.Node) (datamodel.Node, error) {\n\t\t\tqt.Check(t, progress.Path.String(), qt.Equals, \"linkedMap\")\n\t\t\tnb := prev.Prototype().NewBuilder()\n\t\t\tnb.AssignString(\"new string!\")\n\t\t\treturn nb.Build(), nil\n\t\t}, false)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Map)\n\t\t// there should be no new objects in our new storage!\n\t\tqt.Check(t, store2.Bag, qt.HasLen, 0)\n\t\t// cleanup for next test\n\t\tstore2 = memstore.Store{}\n\t})\n\n\t// link traverse to scalar // this is unspecifiable using the current path syntax!  you'll just end up replacing the link with the scalar!\n}\n\nfunc keys(n datamodel.Node) []string {\n\tv := make([]string, 0, n.Length())\n\tfor itr := n.MapIterator(); !itr.Done(); {\n\t\tk, _, _ := itr.Next()\n\t\tv = append(v, must.String(k))\n\t}\n\treturn v\n}\n"
  },
  {
    "path": "traversal/patch/eval.go",
    "content": "// Package patch provides an implementation of the IPLD Patch specification.\n// IPLD Patch is a system for declaratively specifying patches to a document,\n// which can then be applied to produce a new, modified document.\n//\n// This package is EXPERIMENTAL; its behavior and API might change as it's still\n// in development.\npackage patch\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/traversal\"\n)\n\ntype Op string\n\nconst (\n\tOp_Add     = \"add\"\n\tOp_Remove  = \"remove\"\n\tOp_Replace = \"replace\"\n\tOp_Move    = \"move\"\n\tOp_Copy    = \"copy\"\n\tOp_Test    = \"test\"\n)\n\ntype Operation struct {\n\tOp    Op             // Always required.\n\tPath  datamodel.Path // Always required.\n\tValue datamodel.Node // Present on 'add', 'replace', 'test'.\n\tFrom  datamodel.Path // Present on 'move', 'copy'.\n}\n\nfunc Eval(n datamodel.Node, ops []Operation) (datamodel.Node, error) {\n\tvar err error\n\tfor _, op := range ops {\n\t\tn, err = EvalOne(n, op)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn n, nil\n}\n\nfunc EvalOne(n datamodel.Node, op Operation) (datamodel.Node, error) {\n\tswitch op.Op {\n\tcase Op_Add:\n\t\t// The behavior of the 'add' op in jsonpatch varies based on if the parent of the target path is a list.\n\t\t// If the parent of the target path is a list, then 'add' is really more of an 'insert': it should slide the rest of the values down.\n\t\t// There's also a special case for \"-\", which means \"append to the end of the list\".\n\t\t// Otherwise, if the destination path exists, it's an error.  (No upserting.)\n\t\t// Handling this requires looking at the parent of the destination node, so we split this into *two* traversal.FocusedTransform calls.\n\t\treturn traversal.FocusedTransform(n, op.Path.Pop(), func(prog traversal.Progress, parent datamodel.Node) (datamodel.Node, error) {\n\t\t\tif parent.Kind() == datamodel.Kind_List {\n\t\t\t\tseg := op.Path.Last()\n\t\t\t\tvar idx int64\n\t\t\t\tif seg.String() == \"-\" {\n\t\t\t\t\tidx = -1\n\t\t\t\t}\n\t\t\t\tvar err error\n\t\t\t\tidx, err = seg.Index()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"patch-invalid-path-through-list: at %q\", op.Path) // TODO error structuralization and review the code\n\t\t\t\t}\n\n\t\t\t\tnb := parent.Prototype().NewBuilder()\n\t\t\t\tla, err := nb.BeginList(parent.Length() + 1)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tfor itr := n.ListIterator(); !itr.Done(); {\n\t\t\t\t\ti, v, err := itr.Next()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tif idx == i {\n\t\t\t\t\t\tla.AssembleValue().AssignNode(op.Value)\n\t\t\t\t\t}\n\t\t\t\t\tif err := la.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// TODO: is one-past-the-end supposed to be supported or supposed to be ruled out?\n\t\t\t\tif idx == -1 {\n\t\t\t\t\tla.AssembleValue().AssignNode(op.Value)\n\t\t\t\t}\n\t\t\t\tif err := la.Finish(); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\treturn nb.Build(), nil\n\t\t\t}\n\t\t\treturn prog.FocusedTransform(parent, datamodel.NewPath([]datamodel.PathSegment{op.Path.Last()}), func(prog traversal.Progress, point datamodel.Node) (datamodel.Node, error) {\n\t\t\t\tif point != nil && !point.IsAbsent() {\n\t\t\t\t\treturn nil, fmt.Errorf(\"patch-target-exists: at %q\", op.Path) // TODO error structuralization and review the code\n\t\t\t\t}\n\t\t\t\treturn op.Value, nil\n\t\t\t}, false)\n\t\t}, false)\n\tcase \"remove\":\n\t\treturn traversal.FocusedTransform(n, op.Path, func(_ traversal.Progress, point datamodel.Node) (datamodel.Node, error) {\n\t\t\treturn nil, nil // Returning a nil value here means \"remove what's here\".\n\t\t}, false)\n\tcase \"replace\":\n\t\t// TODO i think you need a check that it's not landing under itself here\n\t\treturn traversal.FocusedTransform(n, op.Path, func(_ traversal.Progress, point datamodel.Node) (datamodel.Node, error) {\n\t\t\treturn op.Value, nil // is this right?  what does FocusedTransform do re upsert?\n\t\t}, false)\n\tcase \"move\":\n\t\t// TODO i think you need a check that it's not landing under itself here\n\t\tsource, err := traversal.Get(n, op.From)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tn, err := traversal.FocusedTransform(n, op.Path, func(_ traversal.Progress, point datamodel.Node) (datamodel.Node, error) {\n\t\t\treturn source, nil // is this right?  what does FocusedTransform do re upsert?\n\t\t}, false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn traversal.FocusedTransform(n, op.From, func(_ traversal.Progress, point datamodel.Node) (datamodel.Node, error) {\n\t\t\treturn nil, nil // Returning a nil value here means \"remove what's here\".\n\t\t}, false)\n\tcase \"copy\":\n\t\t// TODO i think you need a check that it's not landing under itself here\n\t\tsource, err := traversal.Get(n, op.From)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn traversal.FocusedTransform(n, op.Path, func(_ traversal.Progress, point datamodel.Node) (datamodel.Node, error) {\n\t\t\treturn source, nil // is this right?  what does FocusedTransform do re upsert?\n\t\t}, false)\n\tcase \"test\":\n\t\tpoint, err := traversal.Get(n, op.Path)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif datamodel.DeepEqual(point, op.Value) {\n\t\t\treturn n, nil\n\t\t}\n\t\treturn n, fmt.Errorf(\"test failed\") // TODO real error handling and a code\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"misuse: invalid operation: %s\", op.Op) // TODO real error handling and a code\n\t}\n}\n"
  },
  {
    "path": "traversal/patch/parse.go",
    "content": "package patch\n\nimport (\n\t_ \"embed\"\n\n\t\"bytes\"\n\t\"io\"\n\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/codec\"\n\t\"github.com/ipld/go-ipld-prime/node/bindnode\"\n\t\"github.com/ipld/go-ipld-prime/schema\"\n\n\t\"github.com/ipld/go-ipld-prime/codec/json\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n//go:embed patch.ipldsch\nvar embedSchema []byte\n\nvar ts = func() *schema.TypeSystem {\n\tts, err := ipld.LoadSchemaBytes(embedSchema)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn ts\n}()\n\nfunc ParseBytes(b []byte, dec codec.Decoder) ([]Operation, error) {\n\treturn Parse(bytes.NewReader(b), dec)\n}\n\nfunc Parse(r io.Reader, dec codec.Decoder) ([]Operation, error) {\n\tnpt := bindnode.Prototype((*[]operationRaw)(nil), ts.TypeByName(\"OperationSequence\"))\n\tnb := npt.Representation().NewBuilder()\n\tif err := json.Decode(nb, r); err != nil {\n\t\treturn nil, err\n\t}\n\topsRaw := bindnode.Unwrap(nb.Build()).(*[]operationRaw)\n\tvar ops []Operation\n\tfor _, opRaw := range *opsRaw {\n\t\t// TODO check the Op string\n\t\top := Operation{\n\t\t\tOp:    Op(opRaw.Op),\n\t\t\tPath:  datamodel.ParsePath(opRaw.Path),\n\t\t\tValue: opRaw.Value,\n\t\t}\n\t\tif opRaw.From != nil {\n\t\t\top.From = datamodel.ParsePath(*opRaw.From)\n\t\t}\n\t\tops = append(ops, op)\n\t}\n\treturn ops, nil\n}\n\n// operationRaw is roughly the same structure as Operation, but more amenable to serialization\n// (it doesn't use high level library types that don't have a data model equivalent).\ntype operationRaw struct {\n\tOp    string\n\tPath  string\n\tValue datamodel.Node\n\tFrom  *string\n}\n"
  },
  {
    "path": "traversal/patch/patch.ipldsch",
    "content": "# Op represents the kind of operation to perform\n# The current set is based on the JSON Patch specification\n# We may end up adding more operations in the future\ntype Op enum {\n  | add\n  | remove\n  | replace\n  | move\n  | copy\n  | test\n}\n\n# Operation and OperationSequence are the types that describe operations (but not what to apply them on).\n# See the Instruction type for describing both operations and what to apply them on.\ntype Operation struct {\n  op Op\n  path String\n  value optional Any\n  from optional String\n}\n\ntype OperationSequence [Operation]\n\ntype Instruction struct {\n  startAt Link\n  operations OperationSequence\n  # future: optional field for adl signalling and/or other lenses\n}\n\ntype InstructionResult union {\n  | Error \"error\"\n  | Link \"result\"\n} representation keyed\n\ntype Error struct {\n  code String # enum forthcoming\n  message String\n  details {String:String}\n}"
  },
  {
    "path": "traversal/patch/patch_test.go",
    "content": "package patch\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/warpfork/go-testmark\"\n\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/codec\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n)\n\nfunc TestSpecFixtures(t *testing.T) {\n\tdir := \"../../.ipld/specs/patch/fixtures/\"\n\ttestOneSpecFixtureFile(t, dir+\"fixtures-1.md\")\n}\n\nfunc testOneSpecFixtureFile(t *testing.T, filename string) {\n\tdoc, err := testmark.ReadFile(filename)\n\tif os.IsNotExist(err) {\n\t\tt.Skipf(\"not running spec suite: %s (did you clone the submodule with the data?)\", err)\n\t}\n\tif err != nil {\n\t\tt.Fatalf(\"spec file parse failed?!: %s\", err)\n\t}\n\n\t// Data hunk in this spec file are in \"directories\" of a test scenario each.\n\tdoc.BuildDirIndex()\n\n\tfor _, dir := range doc.DirEnt.ChildrenList {\n\t\tt.Run(dir.Name, func(t *testing.T) {\n\t\t\t// Grab all the data hunks.\n\t\t\t//  Each \"directory\" contains three piece of data:\n\t\t\t//   - `initial` -- this is the \"block\".  It's arbitrary example data.  They're all in json (or dag-json) format, for simplicity.\n\t\t\t//   - `patch` -- this is a list of patch ops.  Again, as json.\n\t\t\t//   - `result` -- this is the expected result object.  Again, as json.\n\t\t\tinitialBlob := dir.Children[\"initial\"].Hunk.Body\n\t\t\tpatchBlob := dir.Children[\"patch\"].Hunk.Body\n\t\t\tresultBlob := dir.Children[\"result\"].Hunk.Body\n\n\t\t\t// Parse everything.\n\t\t\tinitial, err := ipld.Decode(initialBlob, dagjson.Decode)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"failed to parse fixture data: %s\", err)\n\t\t\t}\n\t\t\tops, err := ParseBytes(patchBlob, dagjson.Decode)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"failed to parse fixture patch: %s\", err)\n\t\t\t}\n\t\t\t// We don't actually keep the decoded result object.  We're just gonna serialize the result and textually diff that instead.\n\t\t\t_, err = ipld.Decode(resultBlob, dagjson.Decode)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"failed to parse fixture data: %s\", err)\n\t\t\t}\n\n\t\t\t// Do the thing!\n\t\t\tactualResult, err := Eval(initial, ops)\n\t\t\tif strings.HasSuffix(dir.Name, \"-fail\") {\n\t\t\t\tif err == nil {\n\t\t\t\t\tt.Fatalf(\"patch was expected to fail\")\n\t\t\t\t} else {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Fatalf(\"patch did not apply: %s\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Serialize (and pretty print) result, so that we can diff it.\n\t\t\tactualResultBlob, err := ipld.Encode(actualResult, dagjson.EncodeOptions{\n\t\t\t\tEncodeLinks: true,\n\t\t\t\tEncodeBytes: true,\n\t\t\t\tMapSortMode: codec.MapSortMode_None,\n\t\t\t}.Encode)\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"failed to reserialize result: %s\", err)\n\t\t\t}\n\t\t\tvar actualResultBlobPretty bytes.Buffer\n\t\t\tjson.Indent(&actualResultBlobPretty, actualResultBlob, \"\", \"\\t\")\n\n\t\t\t// Diff!\n\t\t\tqt.Assert(t, actualResultBlobPretty.String()+\"\\n\", qt.Equals, string(resultBlob))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "traversal/select_links.go",
    "content": "package traversal\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// SelectLinks walks a Node tree and returns a slice of all Links encountered.\n// SelectLinks will recurse down into any maps and lists,\n// but does not attempt to load any of the links it encounters nor recurse further through them\n// (in other words, it's confined to one \"block\").\n//\n// SelectLinks only returns the list of links; it does not return any other information\n// about them such as position in the tree, etc.\n//\n// An error may be returned if any of the nodes returns errors during iteration;\n// this is generally only possible if one of the Nodes is an ADL,\n// and unable to be fully walked because of the inability to load or process some data inside the ADL.\n// Nodes already fully in memory should not encounter such errors,\n// and it should be safe to ignore errors from this method when used in that situation.\n// In case of an error, a partial list will still be returned.\n//\n// If an identical link is found several times during the walk,\n// it is reported several times in the resulting list;\n// no deduplication is performed by this method.\nfunc SelectLinks(n datamodel.Node) ([]datamodel.Link, error) {\n\tvar answer []datamodel.Link\n\terr := accumulateLinks(&answer, n)\n\treturn answer, err\n}\n\nfunc accumulateLinks(a *[]datamodel.Link, n datamodel.Node) error {\n\tswitch n.Kind() {\n\tcase datamodel.Kind_Map:\n\t\tfor itr := n.MapIterator(); !itr.Done(); {\n\t\t\t_, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\taccumulateLinks(a, v)\n\t\t}\n\tcase datamodel.Kind_List:\n\t\tfor itr := n.ListIterator(); !itr.Done(); {\n\t\t\t_, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\taccumulateLinks(a, v)\n\t\t}\n\tcase datamodel.Kind_Link:\n\t\tlnk, _ := n.AsLink()\n\t\t*a = append(*a, lnk)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "traversal/select_links_test.go",
    "content": "package traversal_test\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/traversal\"\n)\n\nfunc TestSelectLinks(t *testing.T) {\n\n\tt.Run(\"Scalar\", func(t *testing.T) {\n\t\tlnks, _ := traversal.SelectLinks(leafAlpha)\n\t\tqt.Check(t, lnks, deepEqualsAllowAllUnexported, []datamodel.Link(nil))\n\t})\n\tt.Run(\"DeepMap\", func(t *testing.T) {\n\t\tlnks, _ := traversal.SelectLinks(middleMapNode)\n\t\tqt.Check(t, lnks, deepEqualsAllowAllUnexported, []datamodel.Link{leafAlphaLnk})\n\t})\n\tt.Run(\"List\", func(t *testing.T) {\n\t\tlnks, _ := traversal.SelectLinks(rootNode)\n\t\tqt.Check(t, lnks, deepEqualsAllowAllUnexported, []datamodel.Link{leafAlphaLnk, middleMapNodeLnk, middleListNodeLnk})\n\t})\n}\n"
  },
  {
    "path": "traversal/selector/builder/builder.go",
    "content": "package builder\n\nimport (\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/traversal/selector\"\n)\n\n// SelectorSpec is a specification for a selector that can build\n// a selector datamodel.Node or an actual parsed Selector\ntype SelectorSpec interface {\n\tNode() datamodel.Node\n\tSelector() (selector.Selector, error)\n}\n\n// SelectorSpecBuilder is a utility interface to build selector ipld nodes\n// quickly.\n//\n// It serves two purposes:\n// 1. Save the user of go-ipld time and mental overhead with an easy\n// interface for making selector nodes in much less code without having to remember\n// the selector sigils\n// 2. Provide a level of protection from selector schema changes, at least in terms\n// of naming, if not structure\ntype SelectorSpecBuilder interface {\n\tExploreRecursiveEdge() SelectorSpec\n\tExploreRecursive(limit selector.RecursionLimit, sequence SelectorSpec) SelectorSpec\n\tExploreUnion(...SelectorSpec) SelectorSpec\n\tExploreAll(next SelectorSpec) SelectorSpec\n\tExploreIndex(index int64, next SelectorSpec) SelectorSpec\n\tExploreRange(start, end int64, next SelectorSpec) SelectorSpec\n\tExploreFields(ExploreFieldsSpecBuildingClosure) SelectorSpec\n\tExploreInterpretAs(as string, next SelectorSpec) SelectorSpec\n\tMatcher() SelectorSpec\n\tMatcherSubset(from, to int64) SelectorSpec\n}\n\n// ExploreFieldsSpecBuildingClosure is a function that provided to SelectorSpecBuilder's\n// ExploreFields method that assembles the fields map in the selector using\n// an ExploreFieldsSpecBuilder\ntype ExploreFieldsSpecBuildingClosure func(ExploreFieldsSpecBuilder)\n\n// ExploreFieldsSpecBuilder is an interface for assemble the map of fields to\n// selectors in ExploreFields\ntype ExploreFieldsSpecBuilder interface {\n\tInsert(k string, v SelectorSpec)\n}\n\ntype selectorSpecBuilder struct {\n\tnp datamodel.NodePrototype\n}\n\ntype selectorSpec struct {\n\tn datamodel.Node\n}\n\nfunc (ss selectorSpec) Node() datamodel.Node {\n\treturn ss.n\n}\n\nfunc (ss selectorSpec) Selector() (selector.Selector, error) {\n\treturn selector.ParseSelector(ss.n)\n}\n\n// NewSelectorSpecBuilder creates a SelectorSpecBuilder which will store\n// data in the format determined by the given datamodel.NodePrototype.\nfunc NewSelectorSpecBuilder(np datamodel.NodePrototype) SelectorSpecBuilder {\n\treturn &selectorSpecBuilder{np}\n}\n\nfunc (ssb *selectorSpecBuilder) ExploreRecursiveEdge() SelectorSpec {\n\treturn selectorSpec{\n\t\tfluent.MustBuildMap(ssb.np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreRecursiveEdge).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t}),\n\t}\n}\n\nfunc (ssb *selectorSpecBuilder) ExploreRecursive(limit selector.RecursionLimit, sequence SelectorSpec) SelectorSpec {\n\treturn selectorSpec{\n\t\tfluent.MustBuildMap(ssb.np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreRecursive).CreateMap(2, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Limit).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tswitch limit.Mode() {\n\t\t\t\t\tcase selector.RecursionLimit_Depth:\n\t\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_LimitDepth).AssignInt(limit.Depth())\n\t\t\t\t\tcase selector.RecursionLimit_None:\n\t\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_LimitNone).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tpanic(\"Unsupported recursion limit type\")\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Sequence).AssignNode(sequence.Node())\n\t\t\t})\n\t\t}),\n\t}\n}\n\nfunc (ssb *selectorSpecBuilder) ExploreAll(next SelectorSpec) SelectorSpec {\n\treturn selectorSpec{\n\t\tfluent.MustBuildMap(ssb.np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreAll).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Next).AssignNode(next.Node())\n\t\t\t})\n\t\t}),\n\t}\n}\nfunc (ssb *selectorSpecBuilder) ExploreIndex(index int64, next SelectorSpec) SelectorSpec {\n\treturn selectorSpec{\n\t\tfluent.MustBuildMap(ssb.np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreIndex).CreateMap(2, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Index).AssignInt(index)\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Next).AssignNode(next.Node())\n\t\t\t})\n\t\t}),\n\t}\n}\n\nfunc (ssb *selectorSpecBuilder) ExploreRange(start, end int64, next SelectorSpec) SelectorSpec {\n\treturn selectorSpec{\n\t\tfluent.MustBuildMap(ssb.np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreRange).CreateMap(3, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Start).AssignInt(start)\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_End).AssignInt(end)\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Next).AssignNode(next.Node())\n\t\t\t})\n\t\t}),\n\t}\n}\n\nfunc (ssb *selectorSpecBuilder) ExploreUnion(members ...SelectorSpec) SelectorSpec {\n\treturn selectorSpec{\n\t\tfluent.MustBuildMap(ssb.np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreUnion).CreateList(int64(len(members)), func(na fluent.ListAssembler) {\n\t\t\t\tfor _, member := range members {\n\t\t\t\t\tna.AssembleValue().AssignNode(member.Node())\n\t\t\t\t}\n\t\t\t})\n\t\t}),\n\t}\n}\n\nfunc (ssb *selectorSpecBuilder) ExploreFields(specBuilder ExploreFieldsSpecBuildingClosure) SelectorSpec {\n\treturn selectorSpec{\n\t\tfluent.MustBuildMap(ssb.np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreFields).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Fields).CreateMap(-1, func(na fluent.MapAssembler) {\n\t\t\t\t\tspecBuilder(exploreFieldsSpecBuilder{na})\n\t\t\t\t})\n\t\t\t})\n\t\t}),\n\t}\n}\n\nfunc (ssb *selectorSpecBuilder) ExploreInterpretAs(as string, next SelectorSpec) SelectorSpec {\n\treturn selectorSpec{\n\t\tfluent.MustBuildMap(ssb.np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreInterpretAs).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_As).AssignString(as)\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Next).AssignNode(next.Node())\n\t\t\t})\n\t\t}),\n\t}\n}\n\nfunc (ssb *selectorSpecBuilder) Matcher() SelectorSpec {\n\treturn selectorSpec{\n\t\tfluent.MustBuildMap(ssb.np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t}),\n\t}\n}\n\nfunc (ssb *selectorSpecBuilder) MatcherSubset(from, to int64) SelectorSpec {\n\treturn selectorSpec{\n\t\tfluent.MustBuildMap(ssb.np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_Matcher).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Subset).CreateMap(2, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_From).AssignInt(from)\n\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_To).AssignInt(to)\n\t\t\t\t})\n\t\t\t})\n\t\t}),\n\t}\n}\n\ntype exploreFieldsSpecBuilder struct {\n\tna fluent.MapAssembler\n}\n\nfunc (efsb exploreFieldsSpecBuilder) Insert(field string, s SelectorSpec) {\n\tefsb.na.AssembleEntry(field).AssignNode(s.Node())\n}\n"
  },
  {
    "path": "traversal/selector/builder/builder_test.go",
    "content": "package builder_test\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\tnodetests \"github.com/ipld/go-ipld-prime/node/tests\"\n\t\"github.com/ipld/go-ipld-prime/traversal/selector\"\n\t\"github.com/ipld/go-ipld-prime/traversal/selector/builder\"\n)\n\nfunc TestBuildingSelectors(t *testing.T) {\n\tnp := basicnode.Prototype.Any\n\tssb := builder.NewSelectorSpecBuilder(np)\n\tt.Run(\"Matcher builds matcher nodes\", func(t *testing.T) {\n\t\tsn := ssb.Matcher().Node()\n\t\tesn := fluent.MustBuildMap(np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t})\n\t\tqt.Check(t, sn, nodetests.NodeContentEquals, esn)\n\t})\n\tt.Run(\"ExploreRecursiveEdge builds ExploreRecursiveEdge nodes\", func(t *testing.T) {\n\t\tsn := ssb.ExploreRecursiveEdge().Node()\n\t\tesn := fluent.MustBuildMap(np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreRecursiveEdge).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t})\n\t\tqt.Check(t, sn, nodetests.NodeContentEquals, esn)\n\t})\n\tt.Run(\"ExploreAll builds ExploreAll nodes\", func(t *testing.T) {\n\t\tsn := ssb.ExploreAll(ssb.Matcher()).Node()\n\t\tesn := fluent.MustBuildMap(np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreAll).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tqt.Check(t, sn, nodetests.NodeContentEquals, esn)\n\t})\n\tt.Run(\"ExploreIndex builds ExploreIndex nodes\", func(t *testing.T) {\n\t\tsn := ssb.ExploreIndex(2, ssb.Matcher()).Node()\n\t\tesn := fluent.MustBuildMap(np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreIndex).CreateMap(2, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Index).AssignInt(2)\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tqt.Check(t, sn, nodetests.NodeContentEquals, esn)\n\t})\n\tt.Run(\"ExploreRange builds ExploreRange nodes\", func(t *testing.T) {\n\t\tsn := ssb.ExploreRange(2, 3, ssb.Matcher()).Node()\n\t\tesn := fluent.MustBuildMap(np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreRange).CreateMap(3, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Start).AssignInt(2)\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_End).AssignInt(3)\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tqt.Check(t, sn, nodetests.NodeContentEquals, esn)\n\t})\n\tt.Run(\"ExploreRecursive builds ExploreRecursive nodes\", func(t *testing.T) {\n\t\tsn := ssb.ExploreRecursive(selector.RecursionLimitDepth(2), ssb.ExploreAll(ssb.ExploreRecursiveEdge())).Node()\n\t\tesn := fluent.MustBuildMap(np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreRecursive).CreateMap(2, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Limit).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_LimitDepth).AssignInt(2)\n\t\t\t\t})\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Sequence).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreAll).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreRecursiveEdge).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tqt.Check(t, sn, nodetests.NodeContentEquals, esn)\n\t\tsn = ssb.ExploreRecursive(selector.RecursionLimitNone(), ssb.ExploreAll(ssb.ExploreRecursiveEdge())).Node()\n\t\tesn = fluent.MustBuildMap(np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreRecursive).CreateMap(2, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Limit).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_LimitNone).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t})\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Sequence).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreAll).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreRecursiveEdge).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tqt.Check(t, sn, nodetests.NodeContentEquals, esn)\n\t})\n\tt.Run(\"ExploreUnion builds ExploreUnion nodes\", func(t *testing.T) {\n\t\tsn := ssb.ExploreUnion(ssb.Matcher(), ssb.ExploreIndex(2, ssb.Matcher())).Node()\n\t\tesn := fluent.MustBuildMap(np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreUnion).CreateList(2, func(na fluent.ListAssembler) {\n\t\t\t\tna.AssembleValue().CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t})\n\t\t\t\tna.AssembleValue().CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreIndex).CreateMap(2, func(na fluent.MapAssembler) {\n\t\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_Index).AssignInt(2)\n\t\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tqt.Check(t, sn, nodetests.NodeContentEquals, esn)\n\t})\n\tt.Run(\"ExploreFields builds ExploreFields nodes\", func(t *testing.T) {\n\t\tsn := ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) { efsb.Insert(\"applesauce\", ssb.Matcher()) }).Node()\n\t\tesn := fluent.MustBuildMap(np, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreFields).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_Fields).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(\"applesauce\").CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tqt.Check(t, sn, nodetests.NodeContentEquals, esn)\n\t})\n}\n"
  },
  {
    "path": "traversal/selector/condition.go",
    "content": "package selector\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n)\n\n// Condition provides a mechanism for matching and limiting matching and\n// exploration of selectors.\n// Not all types of conditions which are imagined in the selector specification\n// are encoded at present, instead we currently only implement a subset that\n// is sufficient for initial pressing use cases.\ntype Condition struct {\n\tmode  ConditionMode\n\tmatch datamodel.Node\n}\n\n// A ConditionMode is the keyed representation for the union that is the condition\ntype ConditionMode string\n\nconst (\n\tConditionMode_Link ConditionMode = \"/\"\n)\n\n// Match decides if a given datamodel.Node matches the condition.\nfunc (c *Condition) Match(n datamodel.Node) bool {\n\tswitch c.mode {\n\tcase ConditionMode_Link:\n\t\tif n.Kind() != datamodel.Kind_Link {\n\t\t\treturn false\n\t\t}\n\t\tlnk, err := n.AsLink()\n\t\tif err != nil {\n\t\t\treturn false\n\t\t}\n\t\tmatch, err := c.match.AsLink()\n\t\tif err != nil {\n\t\t\treturn false\n\t\t}\n\t\tcidlnk, ok := lnk.(cidlink.Link)\n\t\tcidmatch, ok2 := match.(cidlink.Link)\n\t\tif ok && ok2 {\n\t\t\treturn cidmatch.Equals(cidlnk.Cid)\n\t\t}\n\t\treturn match.String() == lnk.String()\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// ParseCondition assembles a Condition from a condition selector node\nfunc (pc ParseContext) ParseCondition(n datamodel.Node) (Condition, error) {\n\tif n.Kind() != datamodel.Kind_Map {\n\t\treturn Condition{}, fmt.Errorf(\"selector spec parse rejected: condition body must be a map\")\n\t}\n\tif n.Length() != 1 {\n\t\treturn Condition{}, fmt.Errorf(\"selector spec parse rejected: condition is a keyed union and thus must be single-entry map\")\n\t}\n\tkn, v, _ := n.MapIterator().Next()\n\tkstr, _ := kn.AsString()\n\t// Switch over the single key to determine which condition body comes next.\n\t//  (This switch is where the keyed union discriminators concretely happen.)\n\tswitch ConditionMode(kstr) {\n\tcase ConditionMode_Link:\n\t\tif _, err := v.AsLink(); err != nil {\n\t\t\treturn Condition{}, fmt.Errorf(\"selector spec parse rejected: condition_link must be a link\")\n\t\t}\n\t\treturn Condition{mode: ConditionMode_Link, match: v}, nil\n\tdefault:\n\t\treturn Condition{}, fmt.Errorf(\"selector spec parse rejected: %q is not a known member of the condition union\", kstr)\n\t}\n}\n"
  },
  {
    "path": "traversal/selector/condition_test.go",
    "content": "package selector\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/ipfs/go-cid\"\n\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nvar deepEqualsAllowAllUnexported = qt.CmpEquals(cmp.Exporter(func(reflect.Type) bool { return true }))\n\nfunc TestParseCondition(t *testing.T) {\n\tt.Run(\"parsing non map node should error\", func(t *testing.T) {\n\t\tsn := basicnode.NewInt(0)\n\t\t_, err := ParseContext{}.ParseCondition(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: condition body must be a map\")\n\t})\n\tt.Run(\"parsing map node without field should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype.Map, 0, func(na fluent.MapAssembler) {})\n\t\t_, err := ParseContext{}.ParseCondition(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: condition is a keyed union and thus must be single-entry map\")\n\t})\n\n\tt.Run(\"parsing map node keyed to invalid type should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype.Map, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(string(ConditionMode_Link)).AssignInt(0)\n\t\t})\n\t\t_, err := ParseContext{}.ParseCondition(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: condition_link must be a link\")\n\t})\n\tt.Run(\"parsing map node with condition field with valid selector node should parse\", func(t *testing.T) {\n\t\tlnk := cidlink.Link{Cid: cid.Undef}\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype.Map, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(string(ConditionMode_Link)).AssignLink(lnk)\n\t\t})\n\t\ts, err := ParseContext{}.ParseCondition(sn)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tlnkNode := basicnode.NewLink(lnk)\n\t\tqt.Check(t, s, deepEqualsAllowAllUnexported, Condition{mode: ConditionMode_Link, match: lnkNode})\n\t})\n}\n"
  },
  {
    "path": "traversal/selector/exploreAll.go",
    "content": "package selector\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// ExploreAll is similar to a `*` -- it traverses all elements of an array,\n// or all entries in a map, and applies a next selector to the reached nodes.\ntype ExploreAll struct {\n\tnext Selector // selector for element we're interested in\n}\n\n// Interests for ExploreAll is nil (meaning traverse everything)\nfunc (s ExploreAll) Interests() []datamodel.PathSegment {\n\treturn nil\n}\n\n// Explore returns the node's selector for all fields\nfunc (s ExploreAll) Explore(n datamodel.Node, p datamodel.PathSegment) (Selector, error) {\n\treturn s.next, nil\n}\n\n// Decide always returns false because this is not a matcher\nfunc (s ExploreAll) Decide(n datamodel.Node) bool {\n\treturn false\n}\n\n// Match always returns false because this is not a matcher\nfunc (s ExploreAll) Match(node datamodel.Node) (datamodel.Node, error) {\n\treturn nil, nil\n}\n\n// ParseExploreAll assembles a Selector from a ExploreAll selector node\nfunc (pc ParseContext) ParseExploreAll(n datamodel.Node) (Selector, error) {\n\tif n.Kind() != datamodel.Kind_Map {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector body must be a map\")\n\t}\n\tnext, err := n.LookupByString(SelectorKey_Next)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: next field must be present in ExploreAll selector\")\n\t}\n\tselector, err := pc.ParseSelector(next)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn ExploreAll{selector}, nil\n}\n"
  },
  {
    "path": "traversal/selector/exploreAll_test.go",
    "content": "package selector\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestParseExploreAll(t *testing.T) {\n\tt.Run(\"parsing non map node should error\", func(t *testing.T) {\n\t\tsn := basicnode.NewInt(0)\n\t\t_, err := ParseContext{}.ParseExploreAll(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: selector body must be a map\")\n\t})\n\tt.Run(\"parsing map node without next field should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype.Map, 0, func(na fluent.MapAssembler) {})\n\t\t_, err := ParseContext{}.ParseExploreAll(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: next field must be present in ExploreAll selector\")\n\t})\n\n\tt.Run(\"parsing map node without next field with invalid selector node should return child's error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype.Map, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Next).AssignInt(0)\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreAll(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: selector is a keyed union and thus must be a map\")\n\t})\n\tt.Run(\"parsing map node with next field with valid selector node should parse\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype.Map, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\ts, err := ParseContext{}.ParseExploreAll(sn)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, s, qt.Equals, ExploreAll{Matcher{}})\n\t})\n}\n"
  },
  {
    "path": "traversal/selector/exploreFields.go",
    "content": "package selector\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// ExploreFields traverses named fields in a map (or equivalently, struct, if\n// traversing on typed/schema nodes) and applies a next selector to the\n// reached nodes.\n//\n// Note that a concept of \"ExplorePath\" (e.g. \"foo/bar/baz\") can be represented\n// as a set of three nexted ExploreFields selectors, each specifying one field.\n// (For this reason, we don't have a special \"ExplorePath\" feature; use this.)\n//\n// ExploreFields also works for selecting specific elements out of a list;\n// if a \"field\" is a base-10 int, it will be coerced and do the right thing.\n// ExploreIndex or ExploreRange is more appropriate, however, and should be preferred.\ntype ExploreFields struct {\n\tselections map[string]Selector\n\tinterests  []datamodel.PathSegment // keys of above; already boxed as that's the only way we consume them\n}\n\n// Interests for ExploreFields are the fields listed in the selector node\nfunc (s ExploreFields) Interests() []datamodel.PathSegment {\n\treturn s.interests\n}\n\n// Explore returns the selector for the given path if it is a field in\n// the selector node or nil if not\nfunc (s ExploreFields) Explore(n datamodel.Node, p datamodel.PathSegment) (Selector, error) {\n\treturn s.selections[p.String()], nil\n}\n\n// Decide always returns false because this is not a matcher\nfunc (s ExploreFields) Decide(n datamodel.Node) bool {\n\treturn false\n}\n\n// Match always returns false because this is not a matcher\nfunc (s ExploreFields) Match(node datamodel.Node) (datamodel.Node, error) {\n\treturn nil, nil\n}\n\n// ParseExploreFields assembles a Selector\n// from a ExploreFields selector node\nfunc (pc ParseContext) ParseExploreFields(n datamodel.Node) (Selector, error) {\n\tif n.Kind() != datamodel.Kind_Map {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector body must be a map\")\n\t}\n\tfields, err := n.LookupByString(SelectorKey_Fields)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: fields in ExploreFields selector must be present\")\n\t}\n\tif fields.Kind() != datamodel.Kind_Map {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: fields in ExploreFields selector must be a map\")\n\t}\n\tx := ExploreFields{\n\t\tmake(map[string]Selector, fields.Length()),\n\t\tmake([]datamodel.PathSegment, 0, fields.Length()),\n\t}\n\tfor itr := fields.MapIterator(); !itr.Done(); {\n\t\tkn, v, err := itr.Next()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error during selector spec parse: %w\", err)\n\t\t}\n\n\t\tkstr, _ := kn.AsString()\n\t\tx.interests = append(x.interests, datamodel.PathSegmentOfString(kstr))\n\t\tx.selections[kstr], err = pc.ParseSelector(v)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn x, nil\n}\n"
  },
  {
    "path": "traversal/selector/exploreFields_test.go",
    "content": "package selector\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestParseExploreFields(t *testing.T) {\n\tt.Run(\"parsing non map node should error\", func(t *testing.T) {\n\t\tsn := basicnode.NewInt(0)\n\t\t_, err := ParseContext{}.ParseExploreFields(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: selector body must be a map\")\n\t})\n\tt.Run(\"parsing map node without fields value should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype.Map, 0, func(na fluent.MapAssembler) {})\n\t\t_, err := ParseContext{}.ParseExploreFields(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: fields in ExploreFields selector must be present\")\n\t})\n\tt.Run(\"parsing map node with fields value that is not a map should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype.Map, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Fields).AssignString(\"cheese\")\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreFields(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: fields in ExploreFields selector must be a map\")\n\t})\n\tt.Run(\"parsing map node with selector node in fields that is invalid should return child's error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype.Map, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Fields).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(\"applesauce\").AssignInt(0)\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreFields(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: selector is a keyed union and thus must be a map\")\n\t})\n\tt.Run(\"parsing map node with fields value that is map of only valid selector node should parse\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype.Map, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Fields).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(\"applesauce\").CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\ts, err := ParseContext{}.ParseExploreFields(sn)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, s, deepEqualsAllowAllUnexported, ExploreFields{map[string]Selector{\"applesauce\": Matcher{}}, []datamodel.PathSegment{datamodel.PathSegmentOfString(\"applesauce\")}})\n\t})\n}\n"
  },
  {
    "path": "traversal/selector/exploreIndex.go",
    "content": "package selector\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// ExploreIndex traverses a specific index in a list, and applies a next\n// selector to the reached node.\ntype ExploreIndex struct {\n\tnext     Selector                 // selector for element we're interested in\n\tinterest [1]datamodel.PathSegment // index of element we're interested in\n}\n\n// Interests for ExploreIndex is just the index specified by the selector node\nfunc (s ExploreIndex) Interests() []datamodel.PathSegment {\n\treturn s.interest[:]\n}\n\n// Explore returns the node's selector if\n// the path matches the index for this selector or nil if not\nfunc (s ExploreIndex) Explore(n datamodel.Node, p datamodel.PathSegment) (Selector, error) {\n\tif n.Kind() != datamodel.Kind_List {\n\t\treturn nil, nil\n\t}\n\texpectedIndex, expectedErr := p.Index()\n\tactualIndex, actualErr := s.interest[0].Index()\n\tif expectedErr != nil || actualErr != nil || expectedIndex != actualIndex {\n\t\treturn nil, nil\n\t}\n\treturn s.next, nil\n}\n\n// Decide always returns false because this is not a matcher\nfunc (s ExploreIndex) Decide(n datamodel.Node) bool {\n\treturn false\n}\n\n// Match always returns false because this is not a matcher\nfunc (s ExploreIndex) Match(node datamodel.Node) (datamodel.Node, error) {\n\treturn nil, nil\n}\n\n// ParseExploreIndex assembles a Selector\n// from a ExploreIndex selector node\nfunc (pc ParseContext) ParseExploreIndex(n datamodel.Node) (Selector, error) {\n\tif n.Kind() != datamodel.Kind_Map {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector body must be a map\")\n\t}\n\tindexNode, err := n.LookupByString(SelectorKey_Index)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: index field must be present in ExploreIndex selector\")\n\t}\n\tindexValue, err := indexNode.AsInt()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: index field must be a number in ExploreIndex selector\")\n\t}\n\tnext, err := n.LookupByString(SelectorKey_Next)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: next field must be present in ExploreIndex selector\")\n\t}\n\tselector, err := pc.ParseSelector(next)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn ExploreIndex{selector, [1]datamodel.PathSegment{datamodel.PathSegmentOfInt(indexValue)}}, nil\n}\n"
  },
  {
    "path": "traversal/selector/exploreIndex_test.go",
    "content": "package selector\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestParseExploreIndex(t *testing.T) {\n\tt.Run(\"parsing non map node should error\", func(t *testing.T) {\n\t\tsn := basicnode.NewInt(0)\n\t\t_, err := ParseContext{}.ParseExploreIndex(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: selector body must be a map\")\n\t})\n\tt.Run(\"parsing map node without next field should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Index).AssignInt(2)\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreIndex(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: next field must be present in ExploreIndex selector\")\n\t})\n\tt.Run(\"parsing map node without index field should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreIndex(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: index field must be present in ExploreIndex selector\")\n\t})\n\tt.Run(\"parsing map node with index field that is not an int should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Index).AssignString(\"cheese\")\n\t\t\tna.AssembleEntry(SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreIndex(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: index field must be a number in ExploreIndex selector\")\n\t})\n\tt.Run(\"parsing map node with next field with invalid selector node should return child's error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Index).AssignInt(2)\n\t\t\tna.AssembleEntry(SelectorKey_Next).AssignInt(0)\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreIndex(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: selector is a keyed union and thus must be a map\")\n\t})\n\tt.Run(\"parsing map node with next field with valid selector node should parse\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Index).AssignInt(2)\n\t\t\tna.AssembleEntry(SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\ts, err := ParseContext{}.ParseExploreIndex(sn)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, s, qt.Equals, ExploreIndex{Matcher{}, [1]datamodel.PathSegment{datamodel.PathSegmentOfInt(2)}})\n\t})\n}\n\nfunc TestExploreIndexExplore(t *testing.T) {\n\ts := ExploreIndex{Matcher{}, [1]datamodel.PathSegment{datamodel.PathSegmentOfInt(3)}}\n\tt.Run(\"exploring should return nil unless node is a list\", func(t *testing.T) {\n\t\tn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 0, func(na fluent.MapAssembler) {})\n\t\treturnedSelector, _ := s.Explore(n, datamodel.PathSegmentOfInt(3))\n\t\tqt.Check(t, returnedSelector, qt.IsNil)\n\t})\n\tn := fluent.MustBuildList(basicnode.Prototype__List{}, 4, func(na fluent.ListAssembler) {\n\t\tna.AssembleValue().AssignInt(0)\n\t\tna.AssembleValue().AssignInt(1)\n\t\tna.AssembleValue().AssignInt(2)\n\t\tna.AssembleValue().AssignInt(3)\n\t})\n\tt.Run(\"exploring should return nil when given a path segment with a different index\", func(t *testing.T) {\n\t\treturnedSelector, _ := s.Explore(n, datamodel.PathSegmentOfInt(2))\n\t\tqt.Check(t, returnedSelector, qt.IsNil)\n\t})\n\tt.Run(\"exploring should return nil when given a path segment that isn't an index\", func(t *testing.T) {\n\t\treturnedSelector, _ := s.Explore(n, datamodel.PathSegmentOfString(\"cheese\"))\n\t\tqt.Check(t, returnedSelector, qt.IsNil)\n\t})\n\tt.Run(\"exploring should return the next selector when given a path segment with the right index\", func(t *testing.T) {\n\t\treturnedSelector, _ := s.Explore(n, datamodel.PathSegmentOfInt(3))\n\t\tqt.Check(t, returnedSelector, qt.Equals, Matcher{})\n\t})\n}\n"
  },
  {
    "path": "traversal/selector/exploreInterpretAs.go",
    "content": "package selector\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\ntype ExploreInterpretAs struct {\n\tnext Selector // selector for element we're interested in\n\tadl  string   // reifier for the ADL we're interested in\n}\n\n// Interests for ExploreIndex is just the index specified by the selector node\nfunc (s ExploreInterpretAs) Interests() []datamodel.PathSegment {\n\treturn s.next.Interests()\n}\n\n// Explore returns the node's selector if\n// the path matches the index for this selector or nil if not\nfunc (s ExploreInterpretAs) Explore(n datamodel.Node, p datamodel.PathSegment) (Selector, error) {\n\treturn s.next, nil\n}\n\n// Decide always returns false because this is not a matcher\nfunc (s ExploreInterpretAs) Decide(n datamodel.Node) bool {\n\treturn false\n}\n\n// Match always returns false because this is not a matcher\nfunc (s ExploreInterpretAs) Match(node datamodel.Node) (datamodel.Node, error) {\n\treturn nil, nil\n}\n\n// NamedReifier indicates how this selector expects to Reify the current datamodel.Node.\nfunc (s ExploreInterpretAs) NamedReifier() string {\n\treturn s.adl\n}\n\n// Reifiable provides a feature detection interface on selectors to understand when\n// and if Reification of the datamodel.node should be attempted when performing traversals.\ntype Reifiable interface {\n\tNamedReifier() string\n}\n\n// ParseExploreInterpretAs assembles a Selector\n// from a ExploreInterpretAs selector node\nfunc (pc ParseContext) ParseExploreInterpretAs(n datamodel.Node) (Selector, error) {\n\tif n.Kind() != datamodel.Kind_Map {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector body must be a map\")\n\t}\n\tadlNode, err := n.LookupByString(SelectorKey_As)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: the 'as' field must be present in ExploreInterpretAs clause\")\n\t}\n\tnext, err := n.LookupByString(SelectorKey_Next)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: the 'next' field must be present in ExploreInterpretAs clause\")\n\t}\n\tselector, err := pc.ParseSelector(next)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tadl, err := adlNode.AsString()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ExploreInterpretAs{selector, adl}, nil\n}\n"
  },
  {
    "path": "traversal/selector/exploreRange.go",
    "content": "package selector\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// ExploreRange traverses a list, and for each element in the range specified,\n// will apply a next selector to those reached nodes.\ntype ExploreRange struct {\n\tnext     Selector // selector for element we're interested in\n\tstart    int64\n\tend      int64\n\tinterest []datamodel.PathSegment // index of element we're interested in\n}\n\n// Interests for ExploreRange are all path segments within the iteration range\nfunc (s ExploreRange) Interests() []datamodel.PathSegment {\n\treturn s.interest\n}\n\n// Explore returns the node's selector if\n// the path matches an index in the range of this selector\nfunc (s ExploreRange) Explore(n datamodel.Node, p datamodel.PathSegment) (Selector, error) {\n\tif n.Kind() != datamodel.Kind_List {\n\t\treturn nil, nil\n\t}\n\tindex, err := p.Index()\n\tif err != nil {\n\t\treturn nil, nil\n\t}\n\tif index < s.start || index >= s.end {\n\t\treturn nil, nil\n\t}\n\treturn s.next, nil\n}\n\n// Decide always returns false because this is not a matcher\nfunc (s ExploreRange) Decide(n datamodel.Node) bool {\n\treturn false\n}\n\n// Match always returns false because this is not a matcher\nfunc (s ExploreRange) Match(node datamodel.Node) (datamodel.Node, error) {\n\treturn nil, nil\n}\n\n// ParseExploreRange assembles a Selector\n// from a ExploreRange selector node\nfunc (pc ParseContext) ParseExploreRange(n datamodel.Node) (Selector, error) {\n\tif n.Kind() != datamodel.Kind_Map {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector body must be a map\")\n\t}\n\tstartNode, err := n.LookupByString(SelectorKey_Start)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: start field must be present in ExploreRange selector\")\n\t}\n\tstartValue, err := startNode.AsInt()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: start field must be a number in ExploreRange selector\")\n\t}\n\tendNode, err := n.LookupByString(SelectorKey_End)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: end field must be present in ExploreRange selector\")\n\t}\n\tendValue, err := endNode.AsInt()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: end field must be a number in ExploreRange selector\")\n\t}\n\tif startValue >= endValue {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: end field must be greater than start field in ExploreRange selector\")\n\t}\n\tnext, err := n.LookupByString(SelectorKey_Next)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: next field must be present in ExploreRange selector\")\n\t}\n\tselector, err := pc.ParseSelector(next)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := ExploreRange{\n\t\tselector,\n\t\tstartValue,\n\t\tendValue,\n\t\tmake([]datamodel.PathSegment, 0, endValue-startValue),\n\t}\n\tfor i := startValue; i < endValue; i++ {\n\t\tx.interest = append(x.interest, datamodel.PathSegmentOfInt(i))\n\t}\n\treturn x, nil\n}\n"
  },
  {
    "path": "traversal/selector/exploreRange_test.go",
    "content": "package selector\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestParseExploreRange(t *testing.T) {\n\tt.Run(\"parsing non map node should error\", func(t *testing.T) {\n\t\tsn := basicnode.NewInt(0)\n\t\t_, err := ParseContext{}.ParseExploreRange(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: selector body must be a map\")\n\t})\n\tt.Run(\"parsing map node without next field should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Start).AssignInt(2)\n\t\t\tna.AssembleEntry(SelectorKey_End).AssignInt(3)\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRange(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: next field must be present in ExploreRange selector\")\n\t})\n\tt.Run(\"parsing map node without start field should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_End).AssignInt(3)\n\t\t\tna.AssembleEntry(SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRange(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: start field must be present in ExploreRange selector\")\n\t})\n\tt.Run(\"parsing map node with start field that is not an int should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 3, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Start).AssignString(\"cheese\")\n\t\t\tna.AssembleEntry(SelectorKey_End).AssignInt(3)\n\t\t\tna.AssembleEntry(SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRange(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: start field must be a number in ExploreRange selector\")\n\t})\n\tt.Run(\"parsing map node without end field should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Start).AssignInt(2)\n\t\t\tna.AssembleEntry(SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRange(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: end field must be present in ExploreRange selector\")\n\t})\n\tt.Run(\"parsing map node with end field that is not an int should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 3, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Start).AssignInt(2)\n\t\t\tna.AssembleEntry(SelectorKey_End).AssignString(\"cheese\")\n\t\t\tna.AssembleEntry(SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRange(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: end field must be a number in ExploreRange selector\")\n\t})\n\tt.Run(\"parsing map node where end is not greater than start should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 3, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Start).AssignInt(3)\n\t\t\tna.AssembleEntry(SelectorKey_End).AssignInt(2)\n\t\t\tna.AssembleEntry(SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRange(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: end field must be greater than start field in ExploreRange selector\")\n\t})\n\tt.Run(\"parsing map node with next field with invalid selector node should return child's error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 3, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Start).AssignInt(2)\n\t\t\tna.AssembleEntry(SelectorKey_End).AssignInt(3)\n\t\t\tna.AssembleEntry(SelectorKey_Next).AssignInt(0)\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRange(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: selector is a keyed union and thus must be a map\")\n\t})\n\n\tt.Run(\"parsing map node with next field with valid selector node should parse\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 3, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Start).AssignInt(2)\n\t\t\tna.AssembleEntry(SelectorKey_End).AssignInt(3)\n\t\t\tna.AssembleEntry(SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\ts, err := ParseContext{}.ParseExploreRange(sn)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, s, deepEqualsAllowAllUnexported, ExploreRange{Matcher{}, 2, 3, []datamodel.PathSegment{datamodel.PathSegmentOfInt(2)}})\n\t})\n}\n\nfunc TestExploreRangeExplore(t *testing.T) {\n\ts := ExploreRange{Matcher{}, 3, 4, []datamodel.PathSegment{datamodel.PathSegmentOfInt(3)}}\n\tt.Run(\"exploring should return nil unless node is a list\", func(t *testing.T) {\n\t\tn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 0, func(na fluent.MapAssembler) {})\n\t\treturnedSelector, _ := s.Explore(n, datamodel.PathSegmentOfInt(3))\n\t\tqt.Check(t, returnedSelector, qt.IsNil)\n\t})\n\tn := fluent.MustBuildList(basicnode.Prototype__List{}, 4, func(na fluent.ListAssembler) {\n\t\tna.AssembleValue().AssignInt(0)\n\t\tna.AssembleValue().AssignInt(1)\n\t\tna.AssembleValue().AssignInt(2)\n\t\tna.AssembleValue().AssignInt(3)\n\t})\n\tt.Run(\"exploring should return nil when given a path segment out of range\", func(t *testing.T) {\n\t\treturnedSelector, _ := s.Explore(n, datamodel.PathSegmentOfInt(2))\n\t\tqt.Check(t, returnedSelector, qt.IsNil)\n\t})\n\tt.Run(\"exploring should return nil when given a path segment that isn't an index\", func(t *testing.T) {\n\t\treturnedSelector, _ := s.Explore(n, datamodel.PathSegmentOfString(\"cheese\"))\n\t\tqt.Check(t, returnedSelector, qt.IsNil)\n\t})\n\tt.Run(\"exploring should return the next selector when given a path segment with index in range\", func(t *testing.T) {\n\t\treturnedSelector, _ := s.Explore(n, datamodel.PathSegmentOfInt(3))\n\t\tqt.Check(t, returnedSelector, qt.Equals, Matcher{})\n\t})\n}\n"
  },
  {
    "path": "traversal/selector/exploreRecursive.go",
    "content": "package selector\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// ExploreRecursive traverses some structure recursively.\n// To guide this exploration, it uses a \"sequence\", which is another Selector\n// tree; some leaf node in this sequence should contain an ExploreRecursiveEdge\n// selector, which denotes the place recursion should occur.\n//\n// In implementation, whenever evaluation reaches an ExploreRecursiveEdge marker\n// in the recursion sequence's Selector tree, the implementation logically\n// produces another new Selector which is a copy of the original\n// ExploreRecursive selector, but with a decremented maxDepth parameter, and\n// continues evaluation thusly.\n//\n// It is not valid for an ExploreRecursive selector's sequence to contain\n// no instances of ExploreRecursiveEdge; it *is* valid for it to contain\n// more than one ExploreRecursiveEdge.\n//\n// ExploreRecursive can contain a nested ExploreRecursive!\n// This is comparable to a nested for-loop.\n// In these cases, any ExploreRecursiveEdge instance always refers to the\n// nearest parent ExploreRecursive (in other words, ExploreRecursiveEdge can\n// be thought of like the 'continue' statement, or end of a for-loop body;\n// it is *not* a 'goto' statement).\n//\n// Be careful when using ExploreRecursive with a large maxDepth parameter;\n// it can easily cause very large traversals (especially if used in combination\n// with selectors like ExploreAll inside the sequence).\ntype ExploreRecursive struct {\n\tsequence Selector       // selector for element we're interested in\n\tcurrent  Selector       // selector to apply to the current node\n\tlimit    RecursionLimit // the limit for this recursive selector\n\tstopAt   *Condition     // a condition for not exploring the node or children\n}\n\n// RecursionLimit_Mode is an enum that represents the type of a recursion limit\n// -- either \"depth\" or \"none\" for now\ntype RecursionLimit_Mode uint8\n\nconst (\n\t// RecursionLimit_None means there is no recursion limit\n\tRecursionLimit_None RecursionLimit_Mode = 0\n\t// RecursionLimit_Depth mean recursion stops after the recursive selector\n\t// is copied to a given depth\n\tRecursionLimit_Depth RecursionLimit_Mode = 1\n)\n\n// RecursionLimit is a union type that captures all data about the recursion\n// limit (both its type and data specific to the type)\ntype RecursionLimit struct {\n\tmode  RecursionLimit_Mode\n\tdepth int64\n}\n\n// Mode returns the type for this recursion limit\nfunc (rl RecursionLimit) Mode() RecursionLimit_Mode {\n\treturn rl.mode\n}\n\n// Depth returns the depth for a depth recursion limit, or 0 otherwise\nfunc (rl RecursionLimit) Depth() int64 {\n\tif rl.mode != RecursionLimit_Depth {\n\t\treturn 0\n\t}\n\treturn rl.depth\n}\n\n// RecursionLimitDepth returns a depth limited recursion to the given depth\nfunc RecursionLimitDepth(depth int64) RecursionLimit {\n\treturn RecursionLimit{RecursionLimit_Depth, depth}\n}\n\n// RecursionLimitNone return recursion with no limit\nfunc RecursionLimitNone() RecursionLimit {\n\treturn RecursionLimit{RecursionLimit_None, 0}\n}\n\n// Interests for ExploreRecursive is empty (meaning traverse everything)\nfunc (s ExploreRecursive) Interests() []datamodel.PathSegment {\n\treturn s.current.Interests()\n}\n\n// Explore returns the node's selector for all fields\nfunc (s ExploreRecursive) Explore(n datamodel.Node, p datamodel.PathSegment) (Selector, error) {\n\t// Check any stopAt conditions right away.\n\tif s.stopAt != nil {\n\t\ttarget, err := n.LookupBySegment(p)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif s.stopAt.Match(target) {\n\t\t\treturn nil, nil\n\t\t}\n\t}\n\n\t// Fence against edge case: if the next selector is a recursion edge, nope, we're out.\n\t//  (This is only reachable if a recursion contains nothing but an edge -- which is probably somewhat rare,\n\t//   because it's certainly rather useless -- but it's not explicitly rejected as a malformed selector during compile, either, so it must be handled.)\n\tif _, ok := s.current.(ExploreRecursiveEdge); ok {\n\t\treturn nil, nil\n\t}\n\n\t// Apply the current selector clause.  (This could be midway through something resembling the initially specified sequence.)\n\tnextSelector, _ := s.current.Explore(n, p)\n\n\t// We have to wrap the nextSelector yielded by the current clause in recursion information before returning it,\n\t//  so that future levels of recursion (as well as their limits) can continue to operate correctly.\n\tif nextSelector == nil {\n\t\treturn nil, nil\n\t}\n\tlimit := s.limit\n\tif !s.hasRecursiveEdge(nextSelector) {\n\t\treturn ExploreRecursive{s.sequence, nextSelector, limit, s.stopAt}, nil\n\t}\n\tswitch limit.mode {\n\tcase RecursionLimit_Depth:\n\t\tif limit.depth < 2 {\n\t\t\treturn s.replaceRecursiveEdge(nextSelector, nil), nil\n\t\t}\n\t\treturn ExploreRecursive{s.sequence, s.replaceRecursiveEdge(nextSelector, s.sequence), RecursionLimit{RecursionLimit_Depth, limit.depth - 1}, s.stopAt}, nil\n\tcase RecursionLimit_None:\n\t\treturn ExploreRecursive{s.sequence, s.replaceRecursiveEdge(nextSelector, s.sequence), limit, s.stopAt}, nil\n\tdefault:\n\t\tpanic(\"Unsupported recursion limit type\")\n\t}\n}\n\nfunc (s ExploreRecursive) hasRecursiveEdge(nextSelector Selector) bool {\n\t_, isRecursiveEdge := nextSelector.(ExploreRecursiveEdge)\n\tif isRecursiveEdge {\n\t\treturn true\n\t}\n\texploreUnion, isUnion := nextSelector.(ExploreUnion)\n\tif isUnion {\n\t\tfor _, selector := range exploreUnion.Members {\n\t\t\tif s.hasRecursiveEdge(selector) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (s ExploreRecursive) replaceRecursiveEdge(nextSelector Selector, replacement Selector) Selector {\n\t_, isRecursiveEdge := nextSelector.(ExploreRecursiveEdge)\n\tif isRecursiveEdge {\n\t\treturn replacement\n\t}\n\texploreUnion, isUnion := nextSelector.(ExploreUnion)\n\tif isUnion {\n\t\treplacementMembers := make([]Selector, 0, len(exploreUnion.Members))\n\t\tfor _, selector := range exploreUnion.Members {\n\t\t\tnewSelector := s.replaceRecursiveEdge(selector, replacement)\n\t\t\tif newSelector != nil {\n\t\t\t\treplacementMembers = append(replacementMembers, newSelector)\n\t\t\t}\n\t\t}\n\t\tif len(replacementMembers) == 0 {\n\t\t\treturn nil\n\t\t}\n\t\tif len(replacementMembers) == 1 {\n\t\t\treturn replacementMembers[0]\n\t\t}\n\t\treturn ExploreUnion{replacementMembers}\n\t}\n\treturn nextSelector\n}\n\n// Decide if a node directly matches\nfunc (s ExploreRecursive) Decide(n datamodel.Node) bool {\n\treturn s.current.Decide(n)\n}\n\n// Match always returns false because this is not a matcher\nfunc (s ExploreRecursive) Match(node datamodel.Node) (datamodel.Node, error) {\n\treturn s.current.Match(node)\n}\n\ntype exploreRecursiveContext struct {\n\tedgesFound int\n}\n\nfunc (erc *exploreRecursiveContext) Link(s Selector) bool {\n\t_, ok := s.(ExploreRecursiveEdge)\n\tif ok {\n\t\terc.edgesFound++\n\t}\n\treturn ok\n}\n\n// ParseExploreRecursive assembles a Selector from a ExploreRecursive selector node\nfunc (pc ParseContext) ParseExploreRecursive(n datamodel.Node) (Selector, error) {\n\tif n.Kind() != datamodel.Kind_Map {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector body must be a map\")\n\t}\n\n\tlimitNode, err := n.LookupByString(SelectorKey_Limit)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: limit field must be present in ExploreRecursive selector\")\n\t}\n\tlimit, err := parseLimit(limitNode)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsequence, err := n.LookupByString(SelectorKey_Sequence)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: sequence field must be present in ExploreRecursive selector\")\n\t}\n\terc := &exploreRecursiveContext{}\n\tselector, err := pc.PushParent(erc).ParseSelector(sequence)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif erc.edgesFound == 0 {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: ExploreRecursive must have at least one ExploreRecursiveEdge\")\n\t}\n\tvar stopCondition *Condition\n\tstop, err := n.LookupByString(SelectorKey_StopAt)\n\tif err == nil {\n\t\tcondition, err := pc.ParseCondition(stop)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tstopCondition = &condition\n\t}\n\treturn ExploreRecursive{selector, selector, limit, stopCondition}, nil\n}\n\nfunc parseLimit(n datamodel.Node) (RecursionLimit, error) {\n\tif n.Kind() != datamodel.Kind_Map {\n\t\treturn RecursionLimit{}, fmt.Errorf(\"selector spec parse rejected: limit in ExploreRecursive is a keyed union and thus must be a map\")\n\t}\n\tif n.Length() != 1 {\n\t\treturn RecursionLimit{}, fmt.Errorf(\"selector spec parse rejected: limit in ExploreRecursive is a keyed union and thus must be a single-entry map\")\n\t}\n\tkn, v, _ := n.MapIterator().Next()\n\tkstr, _ := kn.AsString()\n\tswitch kstr {\n\tcase SelectorKey_LimitDepth:\n\t\tmaxDepthValue, err := v.AsInt()\n\t\tif err != nil {\n\t\t\treturn RecursionLimit{}, fmt.Errorf(\"selector spec parse rejected: limit field of type depth must be a number in ExploreRecursive selector\")\n\t\t}\n\t\treturn RecursionLimit{RecursionLimit_Depth, maxDepthValue}, nil\n\tcase SelectorKey_LimitNone:\n\t\treturn RecursionLimit{RecursionLimit_None, 0}, nil\n\tdefault:\n\t\treturn RecursionLimit{}, fmt.Errorf(\"selector spec parse rejected: %q is not a known member of the limit union in ExploreRecursive\", kstr)\n\t}\n}\n"
  },
  {
    "path": "traversal/selector/exploreRecursiveEdge.go",
    "content": "package selector\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// ExploreRecursiveEdge is a special sentinel value which is used to mark\n// the end of a sequence started by an ExploreRecursive selector: the recursion\n// goes back to the initial state of the earlier ExploreRecursive selector,\n// and proceeds again (with a decremented maxDepth value).\n//\n// An ExploreRecursive selector that doesn't contain an ExploreRecursiveEdge\n// is nonsensical.  Containing more than one ExploreRecursiveEdge is valid.\n// An ExploreRecursiveEdge without an enclosing ExploreRecursive is an error.\ntype ExploreRecursiveEdge struct{}\n\n// Interests should almost never get called for an ExploreRecursiveEdge selector\nfunc (s ExploreRecursiveEdge) Interests() []datamodel.PathSegment {\n\treturn []datamodel.PathSegment{}\n}\n\n// Explore should ultimately never get called for an ExploreRecursiveEdge selector\nfunc (s ExploreRecursiveEdge) Explore(n datamodel.Node, p datamodel.PathSegment) (Selector, error) {\n\tpanic(\"Traversed Explore Recursive Edge Node With No Parent\")\n}\n\n// Decide should almost never get called for an ExploreRecursiveEdge selector\nfunc (s ExploreRecursiveEdge) Decide(n datamodel.Node) bool {\n\treturn false\n}\n\n// Match always returns false because this is not a matcher\nfunc (s ExploreRecursiveEdge) Match(node datamodel.Node) (datamodel.Node, error) {\n\treturn nil, nil\n}\n\n// ParseExploreRecursiveEdge assembles a Selector\n// from a exploreRecursiveEdge selector node\nfunc (pc ParseContext) ParseExploreRecursiveEdge(n datamodel.Node) (Selector, error) {\n\tif n.Kind() != datamodel.Kind_Map {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector body must be a map\")\n\t}\n\ts := ExploreRecursiveEdge{}\n\tfor _, parent := range pc.parentStack {\n\t\tif parent.Link(s) {\n\t\t\treturn s, nil\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"selector spec parse rejected: ExploreRecursiveEdge must be beneath ExploreRecursive\")\n}\n"
  },
  {
    "path": "traversal/selector/exploreRecursive_test.go",
    "content": "package selector\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestParseExploreRecursive(t *testing.T) {\n\tt.Run(\"parsing non map node should error\", func(t *testing.T) {\n\t\tsn := basicnode.NewInt(0)\n\t\t_, err := ParseContext{}.ParseExploreRecursive(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: selector body must be a map\")\n\t})\n\tt.Run(\"parsing map node without sequence field should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Limit).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_LimitDepth).AssignInt(2)\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRecursive(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: sequence field must be present in ExploreRecursive selector\")\n\t})\n\tt.Run(\"parsing map node without limit field should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 1, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Sequence).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRecursive(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: limit field must be present in ExploreRecursive selector\")\n\t})\n\tt.Run(\"parsing map node with limit field that is not a map should fail\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Limit).AssignString(\"cheese\")\n\t\t\tna.AssembleEntry(SelectorKey_Sequence).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRecursive(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: limit in ExploreRecursive is a keyed union and thus must be a map\")\n\t})\n\tt.Run(\"parsing map node with limit field that is not a single entry map should fail\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Limit).CreateMap(2, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_LimitDepth).AssignInt(2)\n\t\t\t\tna.AssembleEntry(SelectorKey_LimitNone).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t\tna.AssembleEntry(SelectorKey_Sequence).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRecursive(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: limit in ExploreRecursive is a keyed union and thus must be a single-entry map\")\n\t})\n\tt.Run(\"parsing map node with limit field that does not have a known key should fail\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Limit).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(\"applesauce\").AssignInt(2)\n\t\t\t})\n\t\t\tna.AssembleEntry(SelectorKey_Sequence).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRecursive(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: \\\"applesauce\\\" is not a known member of the limit union in ExploreRecursive\")\n\t})\n\tt.Run(\"parsing map node with limit field of type depth that is not an int should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Limit).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_LimitDepth).AssignString(\"cheese\")\n\t\t\t})\n\t\t\tna.AssembleEntry(SelectorKey_Sequence).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRecursive(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: limit field of type depth must be a number in ExploreRecursive selector\")\n\t})\n\tt.Run(\"parsing map node with sequence field with invalid selector node should return child's error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Limit).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_LimitDepth).AssignInt(2)\n\t\t\t})\n\t\t\tna.AssembleEntry(SelectorKey_Sequence).AssignInt(0)\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRecursive(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: selector is a keyed union and thus must be a map\")\n\t})\n\tt.Run(\"parsing map node with sequence field with valid selector w/o ExploreRecursiveEdge should not parse\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Limit).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_LimitDepth).AssignInt(2)\n\t\t\t})\n\t\t\tna.AssembleEntry(SelectorKey_Sequence).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_ExploreAll).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreRecursive(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: ExploreRecursive must have at least one ExploreRecursiveEdge\")\n\t})\n\tt.Run(\"parsing map node that is ExploreRecursiveEdge without ExploreRecursive parent should not parse\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 0, func(na fluent.MapAssembler) {})\n\t\t_, err := ParseContext{}.ParseExploreRecursiveEdge(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: ExploreRecursiveEdge must be beneath ExploreRecursive\")\n\t})\n\tt.Run(\"parsing map node with sequence field with valid selector node should parse\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Limit).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_LimitDepth).AssignInt(2)\n\t\t\t})\n\t\t\tna.AssembleEntry(SelectorKey_Sequence).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_ExploreAll).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\t\tna.AssembleEntry(SelectorKey_ExploreRecursiveEdge).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\ts, err := ParseContext{}.ParseExploreRecursive(sn)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, s, qt.Equals, ExploreRecursive{ExploreAll{ExploreRecursiveEdge{}}, ExploreAll{ExploreRecursiveEdge{}}, RecursionLimit{RecursionLimit_Depth, 2}, nil})\n\t})\n\n\tt.Run(\"parsing map node with sequence field with valid selector node and limit type none should parse\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(SelectorKey_Limit).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_LimitNone).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t\tna.AssembleEntry(SelectorKey_Sequence).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_ExploreAll).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\t\tna.AssembleEntry(SelectorKey_ExploreRecursiveEdge).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\ts, err := ParseContext{}.ParseExploreRecursive(sn)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, s, qt.Equals, ExploreRecursive{ExploreAll{ExploreRecursiveEdge{}}, ExploreAll{ExploreRecursiveEdge{}}, RecursionLimit{RecursionLimit_None, 0}, nil})\n\t})\n\n}\n\n/*\n\n{\n\texploreRecursive: {\n\t\tmaxDepth: 3\n\t\tsequence: {\n\t\t\texploreFields: {\n\t\t\t\tfields: {\n\t\t\t\t\tParents: {\n\t\t\t\t\t\texploreAll: {\n\t\t\t\t\t\t\texploreRecursiveEdge: {}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n }\n\n*/\n\nfunc TestExploreRecursiveExplore(t *testing.T) {\n\trecursiveEdge := ExploreRecursiveEdge{}\n\tmaxDepth := int64(3)\n\tvar rs Selector\n\tt.Run(\"exploring should traverse until we get to maxDepth\", func(t *testing.T) {\n\t\tparentsSelector := ExploreAll{recursiveEdge}\n\t\tsubTree := ExploreFields{map[string]Selector{\"Parents\": parentsSelector}, []datamodel.PathSegment{datamodel.PathSegmentOfString(\"Parents\")}}\n\t\trs = ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil}\n\t\tnodeString := `{\n\t\t\t\"Parents\": [\n\t\t\t\t{\n\t\t\t\t\t\"Parents\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"Parents\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"Parents\": []\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t\t`\n\t\tnb := basicnode.Prototype__Any{}.NewBuilder()\n\t\terr := dagjson.Decode(nb, strings.NewReader(nodeString))\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trn := nb.Build()\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Parents\"))\n\t\trn, err = rn.LookupByString(\"Parents\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfInt(0))\n\t\trn, err = rn.LookupByIndex(0)\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Parents\"))\n\n\t\trn, err = rn.LookupByString(\"Parents\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfInt(0))\n\t\trn, err = rn.LookupByIndex(0)\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_Depth, maxDepth - 2}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Parents\"))\n\t\trn, err = rn.LookupByString(\"Parents\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 2}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfInt(0))\n\t\t_, err = rn.LookupByIndex(0)\n\t\tqt.Check(t, rs, qt.IsNil)\n\t\tqt.Check(t, err, qt.IsNil)\n\t})\n\n\tt.Run(\"exploring should traverse indefinitely if no depth specified\", func(t *testing.T) {\n\t\tparentsSelector := ExploreAll{recursiveEdge}\n\t\tsubTree := ExploreFields{map[string]Selector{\"Parents\": parentsSelector}, []datamodel.PathSegment{datamodel.PathSegmentOfString(\"Parents\")}}\n\t\trs = ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_None, 0}, nil}\n\t\tnodeString := `{\n\t\t\t\"Parents\": [\n\t\t\t\t{\n\t\t\t\t\t\"Parents\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"Parents\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"Parents\": []\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t\t`\n\t\tnb := basicnode.Prototype__Any{}.NewBuilder()\n\t\terr := dagjson.Decode(nb, strings.NewReader(nodeString))\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trn := nb.Build()\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Parents\"))\n\t\trn, err = rn.LookupByString(\"Parents\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_None, 0}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfInt(0))\n\t\trn, err = rn.LookupByIndex(0)\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_None, 0}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Parents\"))\n\t\trn, err = rn.LookupByString(\"Parents\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_None, 0}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfInt(0))\n\t\trn, err = rn.LookupByIndex(0)\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_None, 0}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Parents\"))\n\t\trn, err = rn.LookupByString(\"Parents\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_None, 0}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfInt(0))\n\t\trn, err = rn.LookupByIndex(0)\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_None, 0}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Parents\"))\n\t\t_, err = rn.LookupByString(\"Parents\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_None, 0}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t})\n\n\tt.Run(\"exploring should continue till we get to selector that returns nil on explore\", func(t *testing.T) {\n\t\tparentsSelector := ExploreIndex{recursiveEdge, [1]datamodel.PathSegment{datamodel.PathSegmentOfInt(1)}}\n\t\tsubTree := ExploreFields{map[string]Selector{\"Parents\": parentsSelector}, []datamodel.PathSegment{datamodel.PathSegmentOfString(\"Parents\")}}\n\t\trs = ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil}\n\t\tnodeString := `{\n\t\t\t\"Parents\": {\n\t\t\t}\n\t\t}\n\t\t`\n\t\tnb := basicnode.Prototype__Any{}.NewBuilder()\n\t\terr := dagjson.Decode(nb, strings.NewReader(nodeString))\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trn := nb.Build()\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Parents\"))\n\t\trn, err = rn.LookupByString(\"Parents\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfInt(0))\n\t\tqt.Check(t, rs, qt.IsNil)\n\t})\n\tt.Run(\"exploring should work when there is nested recursion\", func(t *testing.T) {\n\t\tparentsSelector := ExploreAll{recursiveEdge}\n\t\tsideSelector := ExploreAll{recursiveEdge}\n\t\tsubTree := ExploreFields{map[string]Selector{\n\t\t\t\"Parents\": parentsSelector,\n\t\t\t\"Side\":    ExploreRecursive{sideSelector, sideSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil},\n\t\t}, []datamodel.PathSegment{\n\t\t\tdatamodel.PathSegmentOfString(\"Parents\"),\n\t\t\tdatamodel.PathSegmentOfString(\"Side\"),\n\t\t},\n\t\t}\n\t\ts := ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil}\n\t\tnodeString := `{\n\t\t\t\"Parents\": [\n\t\t\t\t{\n\t\t\t\t\t\"Parents\": [],\n\t\t\t\t\t\"Side\": {\n\t\t\t\t\t\t\"cheese\": {\n\t\t\t\t\t\t\t\"whiz\": {\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"Side\": {\n\t\t\t\t\"real\": {\n\t\t\t\t\t\"apple\": {\n\t\t\t\t\t\t\"sauce\": {\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t`\n\t\tnb := basicnode.Prototype__Any{}.NewBuilder()\n\t\terr := dagjson.Decode(nb, strings.NewReader(nodeString))\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tn := nb.Build()\n\n\t\t// traverse down Parent nodes\n\t\trn := n\n\t\trs = s\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Parents\"))\n\t\trn, err = rn.LookupByString(\"Parents\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfInt(0))\n\t\trn, err = rn.LookupByIndex(0)\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Parents\"))\n\t\t_, err = rn.LookupByString(\"Parents\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\n\t\t// traverse down top level Side tree (nested recursion)\n\t\trn = n\n\t\trs = s\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Side\"))\n\t\trn, err = rn.LookupByString(\"Side\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, ExploreRecursive{sideSelector, sideSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil}, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"real\"))\n\t\trn, err = rn.LookupByString(\"real\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, ExploreRecursive{sideSelector, sideSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil}, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"apple\"))\n\t\trn, err = rn.LookupByString(\"apple\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, ExploreRecursive{sideSelector, sideSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 2}, nil}, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"sauce\"))\n\t\t_, err = rn.LookupByString(\"sauce\")\n\t\tqt.Check(t, rs, qt.IsNil)\n\t\tqt.Check(t, err, qt.IsNil)\n\n\t\t// traverse once down Parent (top level recursion) then down Side tree (nested recursion)\n\t\trn = n\n\t\trs = s\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Parents\"))\n\t\trn, err = rn.LookupByString(\"Parents\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfInt(0))\n\t\trn, err = rn.LookupByIndex(0)\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Side\"))\n\t\trn, err = rn.LookupByString(\"Side\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, ExploreRecursive{sideSelector, sideSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil}, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"cheese\"))\n\t\trn, err = rn.LookupByString(\"cheese\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, ExploreRecursive{sideSelector, sideSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil}, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"whiz\"))\n\t\t_, err = rn.LookupByString(\"whiz\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, ExploreRecursive{sideSelector, sideSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 2}, nil}, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t})\n\tt.Run(\"exploring should work with explore union and recursion\", func(t *testing.T) {\n\t\tparentsSelector := ExploreUnion{[]Selector{ExploreAll{Matcher{}}, ExploreIndex{recursiveEdge, [1]datamodel.PathSegment{datamodel.PathSegmentOfInt(0)}}}}\n\t\tsubTree := ExploreFields{map[string]Selector{\"Parents\": parentsSelector}, []datamodel.PathSegment{datamodel.PathSegmentOfString(\"Parents\")}}\n\t\trs = ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil}\n\t\tnodeString := `{\n\t\t\t\"Parents\": [\n\t\t\t\t{\n\t\t\t\t\t\"Parents\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"Parents\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"Parents\": []\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t\t`\n\t\tnb := basicnode.Prototype__Any{}.NewBuilder()\n\t\terr := dagjson.Decode(nb, strings.NewReader(nodeString))\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trn := nb.Build()\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Parents\"))\n\t\trn, err = rn.LookupByString(\"Parents\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfInt(0))\n\t\trn, err = rn.LookupByIndex(0)\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, ExploreUnion{[]Selector{Matcher{}, subTree}}, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfString(\"Parents\"))\n\n\t\trn, err = rn.LookupByString(\"Parents\")\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\trs, _ = rs.Explore(rn, datamodel.PathSegmentOfInt(0))\n\t\t_, err = rn.LookupByIndex(0)\n\t\tqt.Check(t, rs, deepEqualsAllowAllUnexported, ExploreRecursive{subTree, ExploreUnion{[]Selector{Matcher{}, subTree}}, RecursionLimit{RecursionLimit_Depth, maxDepth - 2}, nil})\n\t\tqt.Check(t, err, qt.IsNil)\n\t})\n}\n"
  },
  {
    "path": "traversal/selector/exploreUnion.go",
    "content": "package selector\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// ExploreUnion allows selection to continue with two or more distinct selectors\n// while exploring the same tree of data.\n//\n// ExploreUnion can be used to apply a Matcher on one node (causing it to\n// be considered part of a (possibly labelled) result set), while simultaneously\n// continuing to explore deeper parts of the tree with another selector,\n// for example.\ntype ExploreUnion struct {\n\tMembers []Selector\n}\n\n// Interests for ExploreUnion is:\n// - nil (aka all) if any member selector has nil interests\n// - the union of values returned by all member selectors otherwise\nfunc (s ExploreUnion) Interests() []datamodel.PathSegment {\n\t// Check for any high-cardinality selectors first; if so, shortcircuit.\n\t//  (n.b. we're assuming the 'Interests' method is cheap here.)\n\tfor _, m := range s.Members {\n\t\tif m.Interests() == nil {\n\t\t\treturn nil\n\t\t}\n\t}\n\t// Accumulate the whitelist of interesting path segments.\n\t// TODO: Dedup?\n\tv := []datamodel.PathSegment{}\n\tfor _, m := range s.Members {\n\t\tv = append(v, m.Interests()...)\n\t}\n\treturn v\n}\n\n// Explore for a Union selector calls explore for each member selector\n// and returns:\n// - a new union selector if more than one member returns a selector\n// - if exactly one member returns a selector, that selector\n// - nil if no members return a selector\nfunc (s ExploreUnion) Explore(n datamodel.Node, p datamodel.PathSegment) (Selector, error) {\n\t// TODO: memory efficient?\n\tnonNilResults := make([]Selector, 0, len(s.Members))\n\tfor _, member := range s.Members {\n\t\tresultSelector, err := member.Explore(n, p)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif resultSelector != nil {\n\t\t\tnonNilResults = append(nonNilResults, resultSelector)\n\t\t}\n\t}\n\tif len(nonNilResults) == 0 {\n\t\treturn nil, nil\n\t}\n\tif len(nonNilResults) == 1 {\n\t\treturn nonNilResults[0], nil\n\t}\n\treturn ExploreUnion{nonNilResults}, nil\n}\n\n// Decide returns true for a Union selector if any of the member selectors\n// return true\nfunc (s ExploreUnion) Decide(n datamodel.Node) bool {\n\tfor _, m := range s.Members {\n\t\tif m.Decide(n) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Match returns true for a Union selector based on the matched union.\nfunc (s ExploreUnion) Match(n datamodel.Node) (datamodel.Node, error) {\n\tfor _, m := range s.Members {\n\t\tif mn, err := m.Match(n); mn != nil {\n\t\t\treturn mn, nil\n\t\t} else if err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn nil, nil\n}\n\n// ParseExploreUnion assembles a Selector\n// from an ExploreUnion selector node\nfunc (pc ParseContext) ParseExploreUnion(n datamodel.Node) (Selector, error) {\n\tif n.Kind() != datamodel.Kind_List {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: explore union selector must be a list\")\n\t}\n\tx := ExploreUnion{\n\t\tmake([]Selector, 0, n.Length()),\n\t}\n\tfor itr := n.ListIterator(); !itr.Done(); {\n\t\t_, v, err := itr.Next()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error during selector spec parse: %w\", err)\n\t\t}\n\t\tmember, err := pc.ParseSelector(v)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tx.Members = append(x.Members, member)\n\t}\n\treturn x, nil\n}\n"
  },
  {
    "path": "traversal/selector/exploreUnion_test.go",
    "content": "package selector\n\nimport (\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\nfunc TestParseExploreUnion(t *testing.T) {\n\tt.Run(\"parsing non list node should error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildMap(basicnode.Prototype__Map{}, 0, func(na fluent.MapAssembler) {})\n\t\t_, err := ParseContext{}.ParseExploreUnion(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: explore union selector must be a list\")\n\t})\n\tt.Run(\"parsing list node where one node is invalid should return child's error\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildList(basicnode.Prototype__List{}, 2, func(na fluent.ListAssembler) {\n\t\t\tna.AssembleValue().CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t\tna.AssembleValue().AssignInt(2)\n\t\t})\n\t\t_, err := ParseContext{}.ParseExploreUnion(sn)\n\t\tqt.Check(t, err, qt.ErrorMatches, \"selector spec parse rejected: selector is a keyed union and thus must be a map\")\n\t})\n\n\tt.Run(\"parsing map node with next field with valid selector node should parse\", func(t *testing.T) {\n\t\tsn := fluent.MustBuildList(basicnode.Prototype__List{}, 2, func(na fluent.ListAssembler) {\n\t\t\tna.AssembleValue().CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t})\n\t\t\tna.AssembleValue().CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(SelectorKey_ExploreIndex).CreateMap(2, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(SelectorKey_Index).AssignInt(2)\n\t\t\t\t\tna.AssembleEntry(SelectorKey_Next).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\t\t\tna.AssembleEntry(SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\ts, err := ParseContext{}.ParseExploreUnion(sn)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, s, deepEqualsAllowAllUnexported, ExploreUnion{[]Selector{Matcher{}, ExploreIndex{Matcher{}, [1]datamodel.PathSegment{datamodel.PathSegmentOfInt(2)}}}})\n\t})\n}\n\nfunc TestExploreUnionExplore(t *testing.T) {\n\tn := fluent.MustBuildList(basicnode.Prototype__List{}, 4, func(na fluent.ListAssembler) {\n\t\tna.AssembleValue().AssignInt(0)\n\t\tna.AssembleValue().AssignInt(1)\n\t\tna.AssembleValue().AssignInt(2)\n\t\tna.AssembleValue().AssignInt(3)\n\t})\n\tt.Run(\"exploring should return nil if all member selectors return nil when explored\", func(t *testing.T) {\n\t\ts := ExploreUnion{[]Selector{Matcher{}, ExploreIndex{Matcher{}, [1]datamodel.PathSegment{datamodel.PathSegmentOfInt(2)}}}}\n\t\treturnedSelector, _ := s.Explore(n, datamodel.PathSegmentOfInt(3))\n\t\tqt.Check(t, returnedSelector, qt.IsNil)\n\t})\n\n\tt.Run(\"if exactly one member selector returns a non-nil selector when explored, exploring should return that value\", func(t *testing.T) {\n\t\ts := ExploreUnion{[]Selector{Matcher{}, ExploreIndex{Matcher{}, [1]datamodel.PathSegment{datamodel.PathSegmentOfInt(2)}}}}\n\n\t\treturnedSelector, _ := s.Explore(n, datamodel.PathSegmentOfInt(2))\n\t\tqt.Check(t, returnedSelector, qt.Equals, Matcher{})\n\t})\n\tt.Run(\"exploring should return a new union selector if more than one member selector returns a non nil selector when explored\", func(t *testing.T) {\n\t\ts := ExploreUnion{[]Selector{\n\t\t\tMatcher{},\n\t\t\tExploreIndex{Matcher{}, [1]datamodel.PathSegment{datamodel.PathSegmentOfInt(2)}},\n\t\t\tExploreRange{Matcher{}, 2, 3, []datamodel.PathSegment{datamodel.PathSegmentOfInt(2)}},\n\t\t\tExploreFields{map[string]Selector{\"applesauce\": Matcher{}}, []datamodel.PathSegment{datamodel.PathSegmentOfString(\"applesauce\")}},\n\t\t}}\n\n\t\treturnedSelector, _ := s.Explore(n, datamodel.PathSegmentOfInt(2))\n\t\tqt.Check(t, returnedSelector, deepEqualsAllowAllUnexported, ExploreUnion{[]Selector{Matcher{}, Matcher{}}})\n\t})\n}\n\nfunc TestExploreUnionInterests(t *testing.T) {\n\tt.Run(\"if any member selector is high-cardinality, interests should be high-cardinality\", func(t *testing.T) {\n\t\ts := ExploreUnion{[]Selector{\n\t\t\tExploreAll{Matcher{}},\n\t\t\tMatcher{},\n\t\t\tExploreIndex{Matcher{}, [1]datamodel.PathSegment{datamodel.PathSegmentOfInt(2)}},\n\t\t}}\n\t\tqt.Check(t, s.Interests(), deepEqualsAllowAllUnexported, []datamodel.PathSegment(nil))\n\t})\n\tt.Run(\"if no member selector is high-cardinality, interests should be combination of member selectors interests\", func(t *testing.T) {\n\t\ts := ExploreUnion{[]Selector{\n\t\t\tExploreFields{map[string]Selector{\"applesauce\": Matcher{}}, []datamodel.PathSegment{datamodel.PathSegmentOfString(\"applesauce\")}},\n\t\t\tMatcher{},\n\t\t\tExploreIndex{Matcher{}, [1]datamodel.PathSegment{datamodel.PathSegmentOfInt(2)}},\n\t\t}}\n\t\tqt.Check(t, s.Interests(), deepEqualsAllowAllUnexported, []datamodel.PathSegment{datamodel.PathSegmentOfString(\"applesauce\"), datamodel.PathSegmentOfInt(2)})\n\t})\n}\n\nfunc TestExploreUnionDecide(t *testing.T) {\n\tn := basicnode.NewInt(2)\n\tt.Run(\"if any member selector returns true, decide should be true\", func(t *testing.T) {\n\t\ts := ExploreUnion{[]Selector{\n\t\t\tExploreAll{Matcher{}},\n\t\t\tMatcher{},\n\t\t\tExploreIndex{Matcher{}, [1]datamodel.PathSegment{datamodel.PathSegmentOfInt(2)}},\n\t\t}}\n\t\tqt.Check(t, s.Decide(n), qt.IsTrue)\n\t})\n\tt.Run(\"if no member selector returns true, decide should be false\", func(t *testing.T) {\n\t\ts := ExploreUnion{[]Selector{\n\t\t\tExploreFields{map[string]Selector{\"applesauce\": Matcher{}}, []datamodel.PathSegment{datamodel.PathSegmentOfString(\"applesauce\")}},\n\t\t\tExploreAll{Matcher{}},\n\t\t\tExploreIndex{Matcher{}, [1]datamodel.PathSegment{datamodel.PathSegmentOfInt(2)}},\n\t\t}}\n\t\tqt.Check(t, s.Decide(n), qt.IsFalse)\n\t})\n}\n"
  },
  {
    "path": "traversal/selector/fieldKeys.go",
    "content": "package selector\n\nconst (\n\tSelectorKey_Matcher              = \".\"\n\tSelectorKey_ExploreAll           = \"a\"\n\tSelectorKey_ExploreFields        = \"f\"\n\tSelectorKey_ExploreIndex         = \"i\"\n\tSelectorKey_ExploreRange         = \"r\"\n\tSelectorKey_ExploreRecursive     = \"R\"\n\tSelectorKey_ExploreUnion         = \"|\"\n\tSelectorKey_ExploreConditional   = \"&\"\n\tSelectorKey_ExploreRecursiveEdge = \"@\"\n\tSelectorKey_ExploreInterpretAs   = \"~\"\n\tSelectorKey_Next                 = \">\"\n\tSelectorKey_Fields               = \"f>\"\n\tSelectorKey_Index                = \"i\"\n\tSelectorKey_Start                = \"^\"\n\tSelectorKey_End                  = \"$\"\n\tSelectorKey_Sequence             = \":>\"\n\tSelectorKey_Limit                = \"l\"\n\tSelectorKey_LimitDepth           = \"depth\"\n\tSelectorKey_LimitNone            = \"none\"\n\tSelectorKey_StopAt               = \"!\"\n\tSelectorKey_Condition            = \"&\"\n\tSelectorKey_As                   = \"as\"\n\tSelectorKey_Subset               = \"subset\"\n\tSelectorKey_From                 = \"[\"\n\tSelectorKey_To                   = \"]\"\n\t// not filling conditional keys since it's not complete\n)\n"
  },
  {
    "path": "traversal/selector/matcher.go",
    "content": "package selector\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n)\n\n// Matcher marks a node to be included in the \"result\" set.\n// (All nodes traversed by a selector are in the \"covered\" set (which is a.k.a.\n// \"the merkle proof\"); the \"result\" set is a subset of the \"covered\" set.)\n//\n// In libraries using selectors, the \"result\" set is typically provided to\n// some user-specified callback.\n//\n// A selector tree with only \"explore*\"-type selectors and no Matcher selectors\n// is valid; it will just generate a \"covered\" set of nodes and no \"result\" set.\n// TODO: From spec: implement conditions and labels\ntype Matcher struct {\n\t*Slice\n}\n\n// Slice limits a result node to a subset of the node.\n// The returned node will be limited based on slicing the specified range of the\n// node into a new node, or making use of the `AsLargeBytes` io.ReadSeeker to\n// restrict response with a SectionReader.\n//\n// Slice supports [From,To) ranges, where From is inclusive and To is exclusive.\n// Negative values for From and To are interpreted as offsets from the end of\n// the node. If To is greater than the node length, it will be truncated to the\n// node length. If From is greater than the node length or greater than To, the\n// result will be a non-match.\ntype Slice struct {\n\tFrom int64\n\tTo   int64\n}\n\nfunc sliceBounds(from, to, length int64) (bool, int64, int64) {\n\tif to < 0 {\n\t\tto = length + to\n\t} else if length < to {\n\t\tto = length\n\t}\n\tif from < 0 {\n\t\tfrom = length + from\n\t\tif from < 0 {\n\t\t\tfrom = 0\n\t\t}\n\t}\n\tif from > to || from >= length {\n\t\treturn false, 0, 0\n\t}\n\treturn true, from, to\n}\n\nfunc (s Slice) Slice(n datamodel.Node) (datamodel.Node, error) {\n\tvar from, to int64\n\tswitch n.Kind() {\n\tcase datamodel.Kind_String:\n\t\tstr, err := n.AsString()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tvar match bool\n\t\tmatch, from, to = sliceBounds(s.From, s.To, int64(len(str)))\n\t\tif !match {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn basicnode.NewString(str[from:to]), nil\n\tcase datamodel.Kind_Bytes:\n\t\tto = s.To\n\t\tfrom = s.From\n\t\tvar length int64 = math.MaxInt64\n\t\tvar rdr io.ReadSeeker\n\t\tvar bytes []byte\n\t\tvar err error\n\n\t\tif lbn, ok := n.(datamodel.LargeBytesNode); ok {\n\t\t\trdr, err = lbn.AsLargeBytes()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\t// calculate length from seeker\n\t\t\tlength, err = rdr.Seek(0, io.SeekEnd)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\t// reset\n\t\t\t_, err = rdr.Seek(0, io.SeekStart)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t} else {\n\t\t\tbytes, err = n.AsBytes()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tlength = int64(len(bytes))\n\t\t}\n\n\t\tvar match bool\n\t\tmatch, from, to = sliceBounds(from, to, length)\n\t\tif !match {\n\t\t\treturn nil, nil\n\t\t}\n\t\tif rdr != nil {\n\t\t\tsr := io.NewSectionReader(&readerat{rdr, 0}, from, to-from)\n\t\t\treturn basicnode.NewBytesFromReader(sr), nil\n\t\t}\n\t\treturn basicnode.NewBytes(bytes[from:to]), nil\n\tdefault:\n\t\treturn nil, nil\n\t}\n}\n\n// Interests are empty for a matcher (for now) because\n// It is always just there to match, not explore further\nfunc (s Matcher) Interests() []datamodel.PathSegment {\n\treturn []datamodel.PathSegment{}\n}\n\n// Explore will return nil because a matcher is a terminal selector\nfunc (s Matcher) Explore(n datamodel.Node, p datamodel.PathSegment) (Selector, error) {\n\treturn nil, nil\n}\n\n// Decide is always true for a match cause it's in the result set\n// Deprecated: use Match instead\nfunc (s Matcher) Decide(n datamodel.Node) bool {\n\treturn true\n}\n\n// Match is always true for a match cause it's in the result set\nfunc (s Matcher) Match(node datamodel.Node) (datamodel.Node, error) {\n\tif s.Slice != nil {\n\t\treturn s.Slice.Slice(node)\n\t}\n\treturn node, nil\n}\n\n// ParseMatcher assembles a Selector\n// from a matcher selector node\n// TODO: Parse labels and conditions\nfunc (pc ParseContext) ParseMatcher(n datamodel.Node) (Selector, error) {\n\tif n.Kind() != datamodel.Kind_Map {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector body must be a map\")\n\t}\n\n\t// check if a slice is specified\n\tif subset, err := n.LookupByString(\"subset\"); err == nil {\n\t\tif subset.Kind() != datamodel.Kind_Map {\n\t\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: subset body must be a map\")\n\t\t}\n\t\tfrom, err := subset.LookupByString(\"[\")\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector body must be a map with a from '[' key\")\n\t\t}\n\t\tfromN, err := from.AsInt()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector body must be a map with a 'from' key that is a number\")\n\t\t}\n\t\tto, err := subset.LookupByString(\"]\")\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector body must be a map with a to ']' key\")\n\t\t}\n\t\ttoN, err := to.AsInt()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector body must be a map with a 'to' key that is a number\")\n\t\t}\n\t\tif toN >= 0 && fromN > toN {\n\t\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector body must be a map with a 'from' key that is less than or equal to the 'to' key\")\n\t\t}\n\t\treturn Matcher{&Slice{\n\t\t\tFrom: fromN,\n\t\t\tTo:   toN,\n\t\t}}, nil\n\t}\n\treturn Matcher{}, nil\n}\n"
  },
  {
    "path": "traversal/selector/matcher_test.go",
    "content": "package selector_test\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"regexp\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent/qp\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/testutil\"\n\t\"github.com/ipld/go-ipld-prime/traversal\"\n\t\"github.com/ipld/go-ipld-prime/traversal/selector\"\n)\n\nfunc TestSubsetMatch(t *testing.T) {\n\texpectedString := \"foobarbaz!\"\n\tnodes := []struct {\n\t\tname string\n\t\tnode datamodel.Node\n\t}{\n\t\t{\"stringNode\", basicnode.NewString(expectedString)},\n\t\t{\"bytesNode\", testutil.NewSimpleBytes([]byte(expectedString))},\n\t\t{\"largeBytesNode\", testutil.NewMultiByteNode(\n\t\t\t[]byte(\"foo\"),\n\t\t\t[]byte(\"bar\"),\n\t\t\t[]byte(\"baz\"),\n\t\t\t[]byte(\"!\"),\n\t\t)},\n\t}\n\n\t// selector for a slice of the value of the \"bipbop\" field within a map\n\tmkRangeSelector := func(from int64, to int64) (datamodel.Node, error) {\n\t\treturn qp.BuildMap(basicnode.Prototype.Map, 1, func(na datamodel.MapAssembler) {\n\t\t\tqp.MapEntry(na, selector.SelectorKey_ExploreFields, qp.Map(1, func(na datamodel.MapAssembler) {\n\t\t\t\tqp.MapEntry(na, selector.SelectorKey_Fields, qp.Map(1, func(na datamodel.MapAssembler) {\n\t\t\t\t\tqp.MapEntry(na, \"bipbop\", qp.Map(1, func(na datamodel.MapAssembler) {\n\t\t\t\t\t\tqp.MapEntry(na, selector.SelectorKey_Matcher, qp.Map(1, func(na datamodel.MapAssembler) {\n\t\t\t\t\t\t\tqp.MapEntry(na, selector.SelectorKey_Subset, qp.Map(1, func(na datamodel.MapAssembler) {\n\t\t\t\t\t\t\t\tqp.MapEntry(na, selector.SelectorKey_From, qp.Int(from))\n\t\t\t\t\t\t\t\tqp.MapEntry(na, selector.SelectorKey_To, qp.Int(to))\n\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t}))\n\t\t\t\t\t}))\n\t\t\t\t}))\n\t\t\t}))\n\t\t})\n\t}\n\n\tfor _, tc := range []struct {\n\t\tfrom  int64\n\t\tto    int64\n\t\texp   string\n\t\tmatch bool\n\t}{\n\t\t{0, math.MaxInt64, expectedString, true},\n\t\t{0, int64(len(expectedString)), expectedString, true},\n\t\t{0, 0, \"\", true},\n\t\t{0, 1, \"f\", true},\n\t\t{0, 2, \"fo\", true},\n\t\t{0, 3, \"foo\", true},\n\t\t{0, 4, \"foob\", true},\n\t\t{1, 4, \"oob\", true},\n\t\t{2, 4, \"ob\", true},\n\t\t{3, 4, \"b\", true},\n\t\t{4, 4, \"\", true},\n\t\t{4, math.MaxInt64, \"arbaz!\", true},\n\t\t{4, int64(len(expectedString)), \"arbaz!\", true},\n\t\t{4, int64(len(expectedString) - 1), \"arbaz\", true},\n\t\t{0, int64(len(expectedString) - 1), expectedString[0 : len(expectedString)-1], true},\n\t\t{0, int64(len(expectedString) - 2), expectedString[0 : len(expectedString)-2], true},\n\t\t{0, -1, expectedString[0 : len(expectedString)-1], true},\n\t\t{0, -2, expectedString[0 : len(expectedString)-2], true},\n\t\t{-2, -1, \"z\", true},\n\t\t{-1, math.MaxInt64, \"!\", true},\n\t\t{-int64(len(expectedString)), math.MaxInt64, expectedString, true},\n\t\t{math.MaxInt64 - 1, math.MaxInt64, \"\", false},\n\t\t{int64(len(expectedString)), math.MaxInt64, \"\", false},\n\t\t{-1, -2, \"\", false},                 // To < From, no match\n\t\t{-1, -1, \"\", true},                  // To==From, match zero bytes\n\t\t{-1000, -100, \"\", false},            // From undeflow, adjusted to 0, To underflow, not adjusted, To < From, no match\n\t\t{-100, -1000, \"\", false},            // From undeflow, adjusted to 0, To underflow, adjusted to 0, To < From, no match\n\t\t{-1000, 1000, expectedString, true}, // From undeflow, adjusted to 0, To overflow, adjusted to len, match all\n\t} {\n\t\tfor _, variant := range nodes {\n\t\t\tt.Run(fmt.Sprintf(\"%s[%d:%d]\", variant.name, tc.from, tc.to), func(t *testing.T) {\n\t\t\t\tselNode, err := mkRangeSelector(tc.from, tc.to)\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t\tss, err := selector.ParseSelector(selNode)\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\t\t\t// node that the selector will match, with our variant node embedded in the \"bipbop\" field\n\t\t\t\tn, err := qp.BuildMap(basicnode.Prototype.Map, 1, func(na datamodel.MapAssembler) {\n\t\t\t\t\tqp.MapEntry(na, \"bipbop\", qp.Node(variant.node))\n\t\t\t\t})\n\n\t\t\t\tvar got datamodel.Node\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t\terr = traversal.WalkMatching(n, ss, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\t\t\tqt.Assert(t, got, qt.IsNil)\n\t\t\t\t\tgot = n\n\t\t\t\t\treturn nil\n\t\t\t\t})\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\t\t\tif tc.match {\n\t\t\t\t\tqt.Assert(t, got, qt.IsNotNil)\n\t\t\t\t\tqt.Assert(t, got.Kind(), qt.Equals, variant.node.Kind())\n\t\t\t\t\tvar gotString string\n\t\t\t\t\tswitch got.Kind() {\n\t\t\t\t\tcase datamodel.Kind_String:\n\t\t\t\t\t\tgotString, err = got.AsString()\n\t\t\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t\t\tcase datamodel.Kind_Bytes:\n\t\t\t\t\t\tbyts, err := got.AsBytes()\n\t\t\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t\t\t\tgotString = string(byts)\n\t\t\t\t\t}\n\t\t\t\t\tqt.Assert(t, gotString, qt.DeepEquals, tc.exp)\n\t\t\t\t} else {\n\t\t\t\t\tqt.Assert(t, got, qt.IsNil)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n\n\t// when both are positive, we can validate ranges up-front\n\tt.Run(\"invalid range\", func(t *testing.T) {\n\t\tselNode, err := mkRangeSelector(1000, 100)\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tre, err := regexp.Compile(\"from.*less than or equal to.*to\")\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tss, err := selector.ParseSelector(selNode)\n\t\tqt.Assert(t, ss, qt.IsNil)\n\t\tqt.Assert(t, err, qt.ErrorMatches, re)\n\t})\n}\n"
  },
  {
    "path": "traversal/selector/matcher_util.go",
    "content": "package selector\n\nimport (\n\t\"io\"\n)\n\ntype readerat struct {\n\trs  io.ReadSeeker\n\toff int64\n}\n\n// ReadAt provides the io.ReadAt method over a ReadSeeker. It will track the\n// current offset and seek if necessary.\nfunc (r *readerat) ReadAt(p []byte, off int64) (n int, err error) {\n\tif off != r.off {\n\t\tif _, err = r.rs.Seek(off, io.SeekStart); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tr.off = off\n\t}\n\tc, err := r.rs.Read(p)\n\tif err != nil {\n\t\treturn c, err\n\t}\n\tr.off += int64(c)\n\treturn c, nil\n}\n"
  },
  {
    "path": "traversal/selector/parse/selector_parse.go",
    "content": "/*\nselectorparse package contains some helpful functions for parsing the serial form of Selectors.\n\nSome common selectors are also exported as pre-compiled variables,\nboth for convenience of use and to be readable as examples.\n*/\npackage selectorparse\n\nimport (\n\t\"strings\"\n\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/traversal/selector\"\n)\n\n// ParseJSONSelector accepts a string of json which will be parsed as a selector,\n// and returns a datamodel.Node of the parsed Data Model.\n// The returned datamodel.Node is suitable to hand to `selector.CompileSelector`,\n// or, could be composed programmatically with other Data Model selector clauses\n// and then compiled later.\n//\n// The selector will be checked for compileability, and an error returned if it is not.\nfunc ParseJSONSelector(jsonStr string) (datamodel.Node, error) {\n\tnb := basicnode.Prototype.Any.NewBuilder()\n\tif err := dagjson.Decode(nb, strings.NewReader(jsonStr)); err != nil {\n\t\treturn nil, err\n\t}\n\t// Compile it, because that's where all of our error checking is right now.\n\t// ... but throw that result away, because the point of this method is to return nodes that you can compose further.\n\t// Ideally, we'd have just used Schemas for this check,\n\t// which would be cheaper than running the full compile,\n\t// and also more correct (because it would let us parse incomplete phrases that won't compile alone),\n\t// but that's not currently how the Selectors code is implemented.  Future work!\n\tn := nb.Build()\n\tif _, err := selector.CompileSelector(n); err != nil {\n\t\treturn nil, err\n\t}\n\treturn n, nil\n}\n\n// ParseJSONSelector accepts a string of json which will be parsed as a selector,\n// and returns a compiled and ready-to-run Selector.\n//\n// ParseJSONSelector is functionally equivalent to combining ParseJSONSelector and CompileSelector into one step.\nfunc ParseAndCompileJSONSelector(jsonStr string) (selector.Selector, error) {\n\tnb := basicnode.Prototype.Any.NewBuilder()\n\tif err := dagjson.Decode(nb, strings.NewReader(jsonStr)); err != nil {\n\t\treturn nil, err\n\t}\n\tif s, err := selector.CompileSelector(nb.Build()); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\treturn s, nil\n\t}\n}\n\nfunc must(s datamodel.Node, e error) datamodel.Node {\n\tif e != nil {\n\t\tpanic(e)\n\t}\n\treturn s\n}\n\n// CommonSelector_MatchPoint is a selector that matches exactly one thing: the first node it touches.\n// It doesn't walk anywhere at all.\n//\n// This is not a very useful selector, but is an example of how selectors can be written.\nvar CommonSelector_MatchPoint = must(ParseJSONSelector(`{\".\":{}}`))\n\n// CommonSelector_MatchChildren will examine the node it is applied to,\n// walk to each of its children, and match the children.\n// It does not recurse.\n// Note that the root node itself is visited (necessarily!) but it is not \"matched\".\nvar CommonSelector_MatchChildren = must(ParseJSONSelector(`{\"a\":{\">\":{\".\":{}}}}`))\n\n// CommonSelector_ExploreAllRecursively is a selector that walks over a graph of data,\n// recursively, without limit (!) until it reaches every part of the graph.\n// (This is safe to assume will halt eventually, because in IPLD, we work with DAGs --\n// although it still may be a bad idea to do this in practice,\n// because you could accidentally do this on terabytes of linked data, and that would still take a while!)\n//\n// It does not actually _match_ anything at all.\n// That means if you're intercepting block loads (e.g. you're looking at calls to LinkSystem.StorageReadOpener), you'll see them;\n// and if you're using `traversal.AdvVisitFn`, you'll still hear about nodes visited during the exploration;\n// however, if you're using just `traversal.VisitFn`, nothing is considered \"matched\", so that callback will never be called.\nvar CommonSelector_ExploreAllRecursively = must(ParseJSONSelector(`{\"R\":{\"l\":{\"none\":{}},\":>\":{\"a\":{\">\":{\"@\":{}}}}}}`))\n\n// CommonSelector_MatchAllRecursively is like CommonSelector_ExploreAllRecursively, but also matching everything it touches.\n// The first thing inside the recursion is an ExploreUnion clause (which means the selection continues with multiple logical paths);\n// the first thing inside that union clause is a Matcher clause;\n// the second thing inside that union is the ExploreAll clause, which gets us deeper, and then that contains the ExploreRecursiveEdge.\nvar CommonSelector_MatchAllRecursively = must(ParseJSONSelector(`{\"R\":{\"l\":{\"none\":{}},\":>\":{\"|\":[{\".\":{}},{\"a\":{\">\":{\"@\":{}}}}]}}}`))\n"
  },
  {
    "path": "traversal/selector/parse/selector_parse_test.go",
    "content": "package selectorparse\n\n// nothing -- this file just makes sure the vars get initialized, which is a defacto test.\n"
  },
  {
    "path": "traversal/selector/selector.go",
    "content": "package selector\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n)\n\n// Selector is a \"compiled\" and executable IPLD Selector.\n// It can be put to work with functions like traversal.Walk,\n// which will use the Selector's guidance to decide how to traverse an IPLD data graph.\n// A user will not generally call any of the methods of Selector themselves, nor implement the interface;\n// it is produced by \"compile\" functions in this package, and used by functions in the `traversal` package.\n//\n// A Selector is created by parsing an IPLD Data Model document that declares a Selector\n// (this is accomplished with functions like CompileSelector).\n// To make this even easier, there is a `parse` subpackage,\n// which contains helper methods for parsing direction from a JSON Selector document to a compiled Selector value.\n// Alternatively, there is a `builder` subpackage,\n// which may be useful if you would rather create the Selector declaration programmatically in golang\n// (however, we recommend using this sparingly, because part of what makes Selectors cool is their language-agnostic declarative nature).\n//\n// There is no way to go backwards from this \"compiled\" Selector type into the declarative IPLD data model information that produced it.\n// That declaration information is discarded after compilation in order to limit the amount of memory held.\n// Therefore, if you're building APIs about Selector composition, keep in mind that\n// you'll probably want to approach this be composing the Data Model declaration documents,\n// and you should *not* attempt to be composing this type, which is only for the \"compiled\" result.\ntype Selector interface {\n\t// Notes for you who implements a Selector:\n\t// this type holds the state describing what we will do at one step in a traversal.\n\t// The actual traversal stepping is applied *from the outside* (and this is implemented mostly in the `traversal` package;\n\t// this type just gives it instructions on how to step.\n\t// Each of the functions on this type should be pure; they can can read the Selector's fields, but should treat them as config, not as state -- the Selector should never mutate.\n\t//\n\t// The traversal process will ask things of a Selector in three phases,\n\t// and control flow will bounce back and forth between traversal logic and selector evaluation --\n\t// traversal owns the actual walking (and any data loading), and just briefly dips down into the Selector so it can answer questions:\n\t//   T1. Traversal starts at some Node with some Selector.\n\t//   S1. First, the traversal asks the Selector what its \"interests\" are.\n\t//        This lets the Selector hint to the traversal process what it should load,\n\t//        which can be important for performance if not all of the next data elements are in memory already.\n\t//        (This is applicable to ADLs which contain large sharded data, for example.)\n\t//        (The \"interests\" phase should be _fast_; more complicated checks, and anything that actually looks at the children, should wait until the \"explore\" phase;\n\t//        in fact, for this reason, the `Interests` function doesn't even get to look at the data at all yet.)\n\t//   T2. The traversal looks at the Node and its actual fields, and what the Selector just said are interesting,\n\t//        and between the two of them figures out what's actually here to act on.\n\t//        (Note that the Selector can say that certain paths are interesting, and that path can then not be there.)\n\t//   S2. Second, the code driving the traversal will ask us to \"explore\", **stepwise**.\n\t//        The \"explore\" step is applied **repeatedly**: once per pathSegment that identifies a child in the Node.\n\t//        (If `Interests()` returned a list, `Explore` will be called for each element in the list (as long as that pathSegment actually existed in the Node, of course);\n\t//        or if `Interest()` returned no guidance, `Explore` will be called for everything in the object.)\n\t//   S2.a.  The \"explore\" step returns a new Selector object, with instructions about how to continue the walk for the reached object and beneath.\n\t//            (Note that the \"explore\" step can also return `nil` here to say \"actually, don't look any further\",\n\t//            and it may do so even if the \"interests\" phase suggested there might be something to follow up on here.  (Remember \"interests\" had to be fast, and was a first pass only.))\n\t//   T2.a.  ***Recursion time!***\n\t//            The traversal now takes that pathSegment and that subsequent Selector produced by `Explore`,\n\t//            gets the child Node at that pathSegment, and recurses into traversing on that Node with that Selector!\n\t//            It is also possibly ***link load time***, right before recursing:\n\t//            if the child node is a Link, the traversal may choose to load it now,\n\t//            and then do the recursion on the loaded Node (instead of on the actual direct child Node, which was a Link) with the next Selector.\n\t//   T2.b.  When the recursion is done, the traversal goes on to repeat S2, with the next pathSegment,\n\t//            until it runs out of things to do.\n\t//   T3.  The traversal asks the Selector to \"decide\" if this current Node is one that is \"matched or not.\n\t//        See the Selector specs for discussion on \"matched\" vs \"reached\"/\"visited\" nodes.\n\t//        (Long story short: the traversal probably fires off callbacks for \"matched\" nodes, aka if `Decide` says `true`.)\n\t//   S3.  The selector does so.\n\t//   T4.  The traversal for this node is done.\n\t//\n\t// Phase T3+S3 can also be T0+S0, which makes for a pre-order traversal instead of a post-order traversal.\n\t// The Selector doesn't know the difference.\n\t// (In particular, a Selector implementation absolutely may **not** assume `Decide` will be called before `Interests`, and may **not** hold onto a Node statefully, etc.)\n\t//\n\t// Note that it's not until phase T2.a that the traversal actually loads child Nodes.\n\t// This is interesting because it's *after* when the Selector is asked to `Explore` and yield a subsequent Selector to use on that upcoming Node.\n\t//\n\t// Can `Explore` and `Decide` do Link loading on their own?  Do they need to?\n\t// Right now, no, they can't.  (Sort of.)  They don't have access to a LinkLoader; the traversal would have to give them one.\n\t// This might be needed in the future, e.g. if the Selector has a Condition clause that requires looking deeper; so far, we don't have those features, so it hasn't been needed.\n\t// The \"sort of\" is for ADLs.  ADLs that work with large sharded data sometimes hold onto their own LinkLoader and apply it transparently.\n\t// In that case, of course, `Explore` and `Decide` can just interrogate the Node they've been given, and that may cause link loading.\n\t// (If that happens, we're currently assuming the ADL has a reasonable caching behavior.  It's very likely that the traversal will look up the same paths that Explore just looked up (assuming the Condition told exploration to continue).)\n\t//\n\n\t// Interests should return either a list of PathSegment we're likely interested in,\n\t// **or nil**, which indicates we're a high-cardinality or expression-based selection clause and thus we'll need all segments proposed to us.\n\t// Note that a non-nil zero length list of PathSegment is distinguished from nil: this would mean this selector is interested absolutely nothing.\n\t//\n\t// Traversal will call this before calling Explore, and use it to try to call Explore less often (or even avoid iterating on the data node at all).\n\tInterests() []datamodel.PathSegment\n\n\t// Explore is told about the node we're at, and the pathSegment inside it to consider,\n\t// and returns either nil, if we shouldn't explore that path any further,\n\t// or returns a Selector, which should then be used to explore the child at that path.\n\t//\n\t// Note that the node parameter is not the child, it's the node we're currently at.\n\t// (Often, this is sufficient information: consider ExploreFields,\n\t// which only even needs to regard the pathSegment, and not the node at all.)\n\t//\n\t// Remember that Explore does **not** iterate `node` itself; the visits to any children of `node` will be driven from the outside, by the traversal function.\n\t// (The Selector's job is just guiding that process by returning information.)\n\t// The architecture works this way so that a sufficiently clever traversal function could consider several reasons for exploring a node before deciding whether to do so.\n\tExplore(node datamodel.Node, child datamodel.PathSegment) (subsequent Selector, err error)\n\n\t// Decide returns true if the subject node is \"matched\".\n\t//\n\t// Only \"Matcher\" clauses actually implement this in a way that ever returns \"true\".\n\t// See the Selector specs for discussion on \"matched\" vs \"reached\"/\"visited\" nodes.\n\tDecide(node datamodel.Node) bool\n\n\t// Match is an extension to Decide allowing the matcher to `decide` a transformation of\n\t// the matched node. This is used for `Subset` match behavior. If the node is matched,\n\t// the first argument will be the matched node. If it is not matched, the first argument\n\t// will be null. If there is an error, the first argument will be null.\n\tMatch(node datamodel.Node) (datamodel.Node, error)\n}\n\n// REVIEW: do ParsedParent and ParseContext need to be exported?  They're mostly used during the compilation process.\n\n// ParsedParent is created whenever you are parsing a selector node that may have\n// child selectors nodes that need to know it\ntype ParsedParent interface {\n\tLink(s Selector) bool\n}\n\n// ParseContext tracks the progress when parsing a selector\ntype ParseContext struct {\n\tparentStack []ParsedParent\n}\n\n// CompileSelector accepts a datamodel.Node which should contain data that declares a Selector.\n// The data layout expected for this declaration is documented in https://datamodel.io/specs/selectors/ .\n//\n// If the Selector is compiled successfully, it is returned.\n// Otherwise, if the given data Node doesn't match the expected shape for a Selector declaration,\n// or there are any other problems compiling the selector\n// (such as a recursion edge with no enclosing recursion declaration, etc),\n// then nil and an error will be returned.\nfunc CompileSelector(dmt datamodel.Node) (Selector, error) {\n\treturn ParseContext{}.ParseSelector(dmt)\n}\n\n// ParseSelector is an alias for CompileSelector, and is deprecated.\n// Prefer CompileSelector.\nfunc ParseSelector(dmt datamodel.Node) (Selector, error) {\n\treturn CompileSelector(dmt)\n}\n\n// ParseSelector creates a Selector from an IPLD Selector Node with the given context\nfunc (pc ParseContext) ParseSelector(n datamodel.Node) (Selector, error) {\n\tif n.Kind() != datamodel.Kind_Map {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector is a keyed union and thus must be a map\")\n\t}\n\tif n.Length() != 1 {\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: selector is a keyed union and thus must be single-entry map\")\n\t}\n\tkn, v, _ := n.MapIterator().Next()\n\tkstr, _ := kn.AsString()\n\t// Switch over the single key to determine which selector body comes next.\n\t//  (This switch is where the keyed union discriminators concretely happen.)\n\tswitch kstr {\n\tcase SelectorKey_ExploreFields:\n\t\treturn pc.ParseExploreFields(v)\n\tcase SelectorKey_ExploreAll:\n\t\treturn pc.ParseExploreAll(v)\n\tcase SelectorKey_ExploreIndex:\n\t\treturn pc.ParseExploreIndex(v)\n\tcase SelectorKey_ExploreRange:\n\t\treturn pc.ParseExploreRange(v)\n\tcase SelectorKey_ExploreUnion:\n\t\treturn pc.ParseExploreUnion(v)\n\tcase SelectorKey_ExploreRecursive:\n\t\treturn pc.ParseExploreRecursive(v)\n\tcase SelectorKey_ExploreRecursiveEdge:\n\t\treturn pc.ParseExploreRecursiveEdge(v)\n\tcase SelectorKey_ExploreInterpretAs:\n\t\treturn pc.ParseExploreInterpretAs(v)\n\tcase SelectorKey_Matcher:\n\t\treturn pc.ParseMatcher(v)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"selector spec parse rejected: %q is not a known member of the selector union\", kstr)\n\t}\n}\n\n// PushParent puts a parent onto the stack of parents for a parse context\nfunc (pc ParseContext) PushParent(parent ParsedParent) ParseContext {\n\tl := len(pc.parentStack)\n\tparents := make([]ParsedParent, 0, l+1)\n\tparents = append(parents, parent)\n\tparents = append(parents, pc.parentStack...)\n\treturn ParseContext{parents}\n}\n\n// SegmentIterator iterates either a list or a map, generating PathSegments\n// instead of indexes or keys\ntype SegmentIterator interface {\n\tNext() (pathSegment datamodel.PathSegment, value datamodel.Node, err error)\n\tDone() bool\n}\n\n// NewSegmentIterator generates a new iterator based on the node type\nfunc NewSegmentIterator(n datamodel.Node) SegmentIterator {\n\tif n.Kind() == datamodel.Kind_List {\n\t\treturn listSegmentIterator{n.ListIterator()}\n\t}\n\treturn mapSegmentIterator{n.MapIterator()}\n}\n\ntype listSegmentIterator struct {\n\tdatamodel.ListIterator\n}\n\nfunc (lsi listSegmentIterator) Next() (pathSegment datamodel.PathSegment, value datamodel.Node, err error) {\n\ti, v, err := lsi.ListIterator.Next()\n\treturn datamodel.PathSegmentOfInt(i), v, err\n}\n\nfunc (lsi listSegmentIterator) Done() bool {\n\treturn lsi.ListIterator.Done()\n}\n\ntype mapSegmentIterator struct {\n\tdatamodel.MapIterator\n}\n\nfunc (msi mapSegmentIterator) Next() (pathSegment datamodel.PathSegment, value datamodel.Node, err error) {\n\tk, v, err := msi.MapIterator.Next()\n\tif err != nil {\n\t\treturn datamodel.PathSegment{}, v, err\n\t}\n\tkstr, _ := k.AsString()\n\treturn datamodel.PathSegmentOfString(kstr), v, err\n}\n\nfunc (msi mapSegmentIterator) Done() bool {\n\treturn msi.MapIterator.Done()\n}\n"
  },
  {
    "path": "traversal/selector/spec_test.go",
    "content": "package selector_test\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"os\"\n\t\"regexp\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\t\"github.com/warpfork/go-testmark\"\n\n\t\"github.com/ipld/go-ipld-prime\"\n\t\"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/codec/json\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent/qp\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\t\"github.com/ipld/go-ipld-prime/traversal\"\n\tselectorparse \"github.com/ipld/go-ipld-prime/traversal/selector/parse\"\n)\n\nfunc TestSpecFixtures(t *testing.T) {\n\tdir := \"../../.ipld/specs/selectors/fixtures/\"\n\ttestOneSpecFixtureFile(t, dir+\"selector-fixtures-1.md\")\n\ttestOneSpecFixtureFile(t, dir+\"selector-fixtures-recursion.md\")\n}\n\nfunc testOneSpecFixtureFile(t *testing.T, filename string) {\n\tdata, err := os.ReadFile(filename)\n\tif os.IsNotExist(err) {\n\t\tt.Skipf(\"not running spec suite: %s (did you clone the submodule with the data?)\", err)\n\t}\n\tcrre := regexp.MustCompile(`\\r?\\n`)\n\tdata = []byte(crre.ReplaceAllString(string(data), \"\\n\")) // fix windows carriage-return\n\n\tdoc, err := testmark.Parse(data)\n\tqt.Assert(t, err, qt.IsNil)\n\n\t// Data hunk in this spec file are in \"directories\" of a test scenario each.\n\tdoc.BuildDirIndex()\n\tfor _, dir := range doc.DirEnt.ChildrenList {\n\t\tt.Run(dir.Name, func(t *testing.T) {\n\t\t\t// Each \"directory\" contains three piece of data:\n\t\t\t//  - `data` -- this is the \"block\". It's arbitrary example data. They're all in json (or dag-json) format, for simplicity.\n\t\t\t//  - `selector` -- this is the selector. Again, as json.\n\t\t\t//  - `expect-visit` -- these are json lines (one json object on each line) containing description of each node that should be visited, in order.\n\t\t\tfixtureData := dir.Children[\"data\"].Hunk.Body\n\t\t\tfixtureSelector := dir.Children[\"selector\"].Hunk.Body\n\t\t\tfixtureExpect := dir.Children[\"expect-visit\"].Hunk.Body\n\n\t\t\t// Parse data into DMT form.\n\t\t\tdataDmt, err := ipld.Decode(fixtureData, dagjson.Decode)\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\t\t// Parse and compile Selector.\n\t\t\t// (This is already arguably a test event on its own.\n\t\t\tselector, err := selectorparse.ParseAndCompileJSONSelector(string(fixtureSelector))\n\t\t\tqt.Assert(t, err, qt.IsNil)\n\n\t\t\t// Go!\n\t\t\t//  We'll store the logs of our visit events as... ipld Nodes, actually.\n\t\t\t//  This will make them easy to serialize, which is good for two reasons:\n\t\t\t//   at the end, we're actually going to... do that, and use string diffs for the final assertion\n\t\t\t//    (because string diffing is actually really nice for aggregate feedback in a system like this);\n\t\t\t//   and also that means we're ready to save updated serial data into the fixture files, if we did want to patch them.\n\t\t\tvar visitLogs []datamodel.Node\n\t\t\ttraversal.WalkAdv(dataDmt, selector, func(prog traversal.Progress, n datamodel.Node, reason traversal.VisitReason) error {\n\t\t\t\t// Munge info about where we are into DMT shaped like the expectation records in the fixture.\n\t\t\t\tvisitEventDescr, err := qp.BuildMap(basicnode.Prototype.Any, 3, func(ma datamodel.MapAssembler) {\n\t\t\t\t\tqp.MapEntry(ma, \"path\", qp.String(prog.Path.String()))\n\t\t\t\t\tqp.MapEntry(ma, \"node\", qp.Map(1, func(ma datamodel.MapAssembler) {\n\t\t\t\t\t\tqp.MapEntry(ma, n.Kind().String(), func(na datamodel.NodeAssembler) {\n\t\t\t\t\t\t\tswitch n.Kind() {\n\t\t\t\t\t\t\tcase datamodel.Kind_Map, datamodel.Kind_List:\n\t\t\t\t\t\t\t\tna.AssignNull()\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tna.AssignNode(n)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t}))\n\t\t\t\t\tqp.MapEntry(ma, \"matched\", qp.Bool(reason == traversal.VisitReason_SelectionMatch))\n\t\t\t\t})\n\t\t\t\tif reason == traversal.VisitReason_SelectionMatch && n.Kind() == datamodel.Kind_Bytes {\n\t\t\t\t\tif lbn, ok := n.(datamodel.LargeBytesNode); ok {\n\t\t\t\t\t\trdr, err := lbn.AsLargeBytes()\n\t\t\t\t\t\tif err == nil {\n\t\t\t\t\t\t\tio.Copy(io.Discard, rdr)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t_, err := n.AsBytes()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tpanic(\"insanity at a deeper level than this test's target\")\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif err != nil {\n\t\t\t\t\tpanic(\"insanity at a deeper level than this test's target\")\n\t\t\t\t}\n\t\t\t\tvisitLogs = append(visitLogs, visitEventDescr)\n\t\t\t\treturn nil\n\t\t\t})\n\n\t\t\t// Brief detour -- we're going to bounce the fixture data through our own deserialize and serialize.\n\t\t\t//  Just to normalize the heck out of it.  I'm not really interested in if the fixture files have non-normative whitespace in them.\n\t\t\tvar fixtureExpectNormBuf bytes.Buffer\n\t\t\tfor _, line := range bytes.Split(fixtureExpect, []byte{'\\n'}) {\n\t\t\t\tif len(line) == 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\texp, err := ipld.Decode(line, json.Decode)\n\t\t\t\tqt.Assert(t, err, qt.IsNil)\n\t\t\t\tqt.Assert(t, ipld.EncodeStreaming(&fixtureExpectNormBuf, exp, json.Encode), qt.IsNil)\n\t\t\t\tfixtureExpectNormBuf.WriteByte('\\n')\n\t\t\t}\n\n\t\t\t// Serialize our own visit logs now too.\n\t\t\tvar visitLogString bytes.Buffer\n\t\t\tfor _, logEnt := range visitLogs {\n\t\t\t\tqt.Assert(t, ipld.EncodeStreaming(&visitLogString, logEnt, json.Encode), qt.IsNil)\n\t\t\t\tvisitLogString.WriteByte('\\n')\n\t\t\t}\n\n\t\t\t// DIFF TIME.\n\t\t\tqt.Assert(t, visitLogString.String(), qt.CmpEquals(), fixtureExpectNormBuf.String())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "traversal/walk.go",
    "content": "package traversal\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\t\"github.com/ipld/go-ipld-prime/linking/preload\"\n\t\"github.com/ipld/go-ipld-prime/traversal/selector\"\n)\n\n// phase is an internal enum used to track the current phase of a walk. It's\n// used to control for a preload pass over a block if one is required.\ntype phase int\n\nconst (\n\tphasePreload  phase = iota\n\tphaseTraverse phase = iota\n)\n\n// WalkLocal walks a tree of Nodes, visiting each of them,\n// and calling the given VisitFn on all of them;\n// it does not traverse any links.\n//\n// WalkLocal can skip subtrees if the VisitFn returns SkipMe,\n// but lacks any other options for controlling or directing the visit;\n// consider using some of the various Walk functions with Selector parameters if you want more control.\nfunc WalkLocal(n datamodel.Node, fn VisitFn) error {\n\treturn Progress{}.WalkLocal(n, fn)\n}\n\n// WalkMatching walks a graph of Nodes, deciding which to visit by applying a Selector,\n// and calling the given VisitFn on those that the Selector deems a match.\n//\n// This function is a helper function which starts a new walk with default configuration.\n// It cannot cross links automatically (since this requires configuration).\n// Use the equivalent WalkMatching function on the Progress structure\n// for more advanced and configurable walks.\nfunc WalkMatching(n datamodel.Node, s selector.Selector, fn VisitFn) error {\n\treturn Progress{}.WalkMatching(n, s, fn)\n}\n\n// WalkAdv is identical to WalkMatching, except it is called for *all* nodes\n// visited (not just matching nodes), together with the reason for the visit.\n// An AdvVisitFn is used instead of a VisitFn, so that the reason can be provided.\n//\n// This function is a helper function which starts a new walk with default configuration.\n// It cannot cross links automatically (since this requires configuration).\n// Use the equivalent WalkAdv function on the Progress structure\n// for more advanced and configurable walks.\nfunc WalkAdv(n datamodel.Node, s selector.Selector, fn AdvVisitFn) error {\n\treturn Progress{}.WalkAdv(n, s, fn)\n}\n\n// WalkTransforming walks a graph of Nodes, deciding which to alter by applying a Selector,\n// and calls the given TransformFn to decide what new node to replace the visited node with.\n// A new Node tree will be returned (the original is unchanged).\n//\n// This function is a helper function which starts a new walk with default configuration.\n// It cannot cross links automatically (since this requires configuration).\n// Use the equivalent WalkTransforming function on the Progress structure\n// for more advanced and configurable walks.\nfunc WalkTransforming(n datamodel.Node, s selector.Selector, fn TransformFn) (datamodel.Node, error) {\n\treturn Progress{}.WalkTransforming(n, s, fn)\n}\n\n// WalkMatching walks a graph of Nodes, deciding which to visit by applying a Selector,\n// and calling the given VisitFn on those that the Selector deems a match.\n//\n// WalkMatching is a read-only traversal.\n// See WalkTransforming if looking for a way to do \"updates\" to a tree of nodes.\n//\n// Provide configuration to this process using the Config field in the Progress object.\n//\n// This walk will automatically cross links, but requires some configuration\n// with link loading functions to do so.\n//\n// Traversals are defined as visiting a (node,path) tuple.\n// This is important to note because when walking DAGs with Links,\n// it means you may visit the same node multiple times\n// due to having reached it via a different path.\n// (You can prevent this by using a LinkLoader function which memoizes a set of\n// already-visited Links, and returns a SkipMe when encountering them again.)\n//\n// WalkMatching (and the other traversal functions) can be used again again inside the VisitFn!\n// By using the traversal.Progress handed to the VisitFn,\n// the Path recorded of the traversal so far will continue to be extended,\n// and thus continued nested uses of Walk and Focus will see the fully contextualized Path.\n//\n// WalkMatching can be configured to run with a Preloader.\n// When a Preloader is configured, the walk will first do a \"preload\" pass over the initial,\n// root tree up to link boundaries and report any links encountered to the preloader.\n// It will then perform a second pass over the tree, calling the VisitFn where necessary as per normal WalkMatching behavior.\n// This two-pass operation will continue for each block loaded, allowing the preloader to\n// potentially asynchronously preload any blocks that are going to be encountered at a future point in the walk.\nfunc (prog Progress) WalkMatching(n datamodel.Node, s selector.Selector, fn VisitFn) error {\n\tprog.init()\n\treturn prog.walkBlock(n, s, func(prog Progress, n datamodel.Node, tr VisitReason) error {\n\t\tif tr != VisitReason_SelectionMatch {\n\t\t\treturn nil\n\t\t}\n\t\treturn fn(prog, n)\n\t})\n}\n\n// WalkLocal is the same as the package-scope function of the same name,\n// but considers an existing Progress state (and any config it might reference).\nfunc (prog Progress) WalkLocal(n datamodel.Node, fn VisitFn) error {\n\tif err := prog.checkNodeBudget(); err != nil {\n\t\treturn err\n\t}\n\n\t// Visit the current node.\n\tif err := fn(prog, n); err != nil {\n\t\tif _, ok := err.(SkipMe); ok {\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\t// Recurse on nodes with a recursive kind; otherwise just return.\n\tswitch n.Kind() {\n\tcase datamodel.Kind_Map:\n\t\tfor itr := n.MapIterator(); !itr.Done(); {\n\t\t\tk, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tks, _ := k.AsString()\n\t\t\tprogNext := prog\n\t\t\tprogNext.Path = prog.Path.AppendSegmentString(ks)\n\t\t\tif err := progNext.WalkLocal(v, fn); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\tcase datamodel.Kind_List:\n\t\tfor itr := n.ListIterator(); !itr.Done(); {\n\t\t\tidx, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tprogNext := prog\n\t\t\tprogNext.Path = prog.Path.AppendSegmentInt(idx)\n\t\t\tif err := progNext.WalkLocal(v, fn); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// WalkAdv is identical to WalkMatching, except it is called for *all* nodes\n// visited (not just matching nodes), together with the reason for the visit.\n// An AdvVisitFn is used instead of a VisitFn, so that the reason can be provided.\nfunc (prog Progress) WalkAdv(n datamodel.Node, s selector.Selector, fn AdvVisitFn) error {\n\tprog.init()\n\treturn prog.walkBlock(n, s, fn)\n}\n\n// walkBlock anchors a walk at the beginning of the traversal and at the\n// beginning of each new link traversed. This allows us to do a preload phase if\n// we have a preloader configured.\nfunc (prog Progress) walkBlock(n datamodel.Node, s selector.Selector, visitFn AdvVisitFn) error {\n\tph := phaseTraverse\n\tvar budget *Budget\n\n\tif prog.Cfg.Preloader != nil {\n\t\tph = phasePreload\n\t\t// preserve the budget so we can reset it for the second pass; it will\n\t\t// likely not correctly apply during the preload phase because it\n\t\t// doesn't descend into links first. But we'll use it anyway as a\n\t\t// best-guess because we have nothing better\n\t\tbudget = prog.Budget.Clone()\n\t}\n\n\t// First pass.\n\terr := prog.walkAdv(ph, n, s, visitFn)\n\tif err != nil && (ph != phasePreload || !errors.Is(&ErrBudgetExceeded{}, err)) {\n\t\treturn err\n\t}\n\n\tif ph == phasePreload {\n\t\t// First past was a preload; now do the _real_ pass.\n\t\tprog.Budget = budget // reset\n\t\treturn prog.walkAdv(phaseTraverse, n, s, visitFn)\n\t}\n\n\treturn nil\n}\n\n// walkAdv is the main recursive walk function, called to iterate through\n// recursive nodes (root node, maps, lists and new link root nodes).\nfunc (prog Progress) walkAdv(ph phase, n datamodel.Node, s selector.Selector, visitFn AdvVisitFn) error {\n\tif err := prog.checkNodeBudget(); err != nil {\n\t\treturn err\n\t}\n\n\t// If we need to interpret this node in an alternative form, reify and replace.\n\tif rn, rs, err := prog.reify(n, s); err != nil {\n\t\treturn err\n\t} else if rn != nil {\n\t\tn = rn\n\t\ts = rs\n\t}\n\n\t// Call the visit function if necessary.\n\tif err := prog.visit(ph, n, s, visitFn); err != nil {\n\t\treturn err\n\t}\n\n\t// If we're handling scalars (e.g. not maps and lists) we can return now.\n\tswitch n.Kind() {\n\tcase datamodel.Kind_Map, datamodel.Kind_List: // continue\n\tdefault:\n\t\treturn nil\n\t}\n\n\t// For maps and lists: recurse (in one of two ways, depending on if the selector also states specific interests).\n\n\thaveStartAtPath := prog.Cfg.StartAtPath.Len() > 0\n\tvar reachedStartAtPath bool\n\trecurse := func(v datamodel.Node, ps datamodel.PathSegment) error {\n\t\t// First, make sure we're past the start path; if one is specified.\n\t\tif haveStartAtPath {\n\t\t\tif reachedStartAtPath {\n\t\t\t\tprog.PastStartAtPath = reachedStartAtPath\n\t\t\t} else if !prog.PastStartAtPath && prog.Path.Len() < prog.Cfg.StartAtPath.Len() {\n\t\t\t\tif ps.Equals(prog.Cfg.StartAtPath.Segments()[prog.Path.Len()]) {\n\t\t\t\t\treachedStartAtPath = true\n\t\t\t\t}\n\t\t\t\tif !reachedStartAtPath {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err := prog.explore(ph, s, n, visitFn, v, ps); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tattn := s.Interests()\n\n\tif attn == nil { // no specific interests; recurse on all children.\n\t\tfor itr := selector.NewSegmentIterator(n); !itr.Done(); {\n\t\t\tps, v, err := itr.Next()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := recurse(v, ps); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tif len(attn) == 0 { // nothing to see here\n\t\treturn nil\n\t}\n\n\t// specific interests, recurse on those.\n\tfor _, ps := range attn {\n\t\tif v, err := n.LookupBySegment(ps); err != nil {\n\t\t\tcontinue\n\t\t} else if err := recurse(v, ps); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (prog Progress) checkNodeBudget() error {\n\tif prog.Budget != nil {\n\t\tif prog.Budget.NodeBudget <= 0 {\n\t\t\treturn &ErrBudgetExceeded{BudgetKind: \"node\", Path: prog.Path}\n\t\t}\n\t\tprog.Budget.NodeBudget--\n\t}\n\treturn nil\n}\n\nfunc (prog Progress) checkLinkBudget(lnk datamodel.Link) error {\n\tif prog.Budget != nil {\n\t\tif prog.Budget.LinkBudget <= 0 {\n\t\t\treturn &ErrBudgetExceeded{BudgetKind: \"link\", Path: prog.Path, Link: lnk}\n\t\t}\n\t\tprog.Budget.LinkBudget--\n\t}\n\treturn nil\n}\n\nfunc (prog Progress) reify(n datamodel.Node, s selector.Selector) (datamodel.Node, selector.Selector, error) {\n\t// refiy the node if advised.\n\tif rs, ok := s.(selector.Reifiable); ok {\n\t\tadl := rs.NamedReifier()\n\t\tif prog.Cfg.LinkSystem.KnownReifiers == nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"adl requested but not supported by link system: %q\", adl)\n\t\t}\n\n\t\treifier, ok := prog.Cfg.LinkSystem.KnownReifiers[adl]\n\t\tif !ok {\n\t\t\treturn nil, nil, fmt.Errorf(\"unregistered adl requested: %q\", adl)\n\t\t}\n\n\t\trn, err := reifier(linking.LinkContext{\n\t\t\tCtx:      prog.Cfg.Ctx,\n\t\t\tLinkPath: prog.Path,\n\t\t}, n, &prog.Cfg.LinkSystem)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to reify node as %q: %w\", adl, err)\n\t\t}\n\n\t\t// explore into the `InterpretAs` clause to the child selector.\n\t\ts, err = s.Explore(n, datamodel.EmptyPathSegment)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\treturn rn, s, nil\n\t}\n\n\treturn nil, nil, nil\n}\n\n// visit calls the visitor if required\nfunc (prog Progress) visit(ph phase, n datamodel.Node, s selector.Selector, visitFn AdvVisitFn) error {\n\tif ph != phaseTraverse {\n\t\treturn nil\n\t}\n\n\tif !prog.PastStartAtPath && prog.Path.Len() < prog.Cfg.StartAtPath.Len() {\n\t\treturn nil\n\t}\n\n\t// Decide if this node is matched -- do callbacks as appropriate.\n\tmatch, err := s.Match(n)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif match != nil {\n\t\treturn visitFn(prog, match, VisitReason_SelectionMatch)\n\t}\n\treturn visitFn(prog, n, VisitReason_SelectionCandidate)\n}\n\n// explore is called to explore a single node, and recurse into it if necessary,\n// including loading and recursing into links if the node is a link.\nfunc (prog Progress) explore(\n\tph phase,\n\ts selector.Selector,\n\tn datamodel.Node,\n\tvisitFn AdvVisitFn,\n\tv datamodel.Node,\n\tps datamodel.PathSegment,\n) error {\n\tsNext, err := s.Explore(n, ps)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif sNext == nil {\n\t\treturn nil\n\t}\n\n\tprogNext := prog\n\tprogNext.Path = prog.Path.AppendSegment(ps)\n\n\tif v.Kind() != datamodel.Kind_Link {\n\t\treturn progNext.walkAdv(ph, v, sNext, visitFn)\n\t}\n\n\tlnk, _ := v.AsLink()\n\tif prog.Cfg.LinkVisitOnlyOnce {\n\t\tif _, seen := prog.SeenLinks[lnk]; seen {\n\t\t\treturn nil\n\t\t}\n\t\tif ph == phaseTraverse {\n\t\t\tprog.SeenLinks[lnk] = struct{}{}\n\t\t}\n\t}\n\n\tif ph == phasePreload {\n\t\tif err := prog.checkLinkBudget(lnk); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tpctx := preload.PreloadContext{\n\t\t\tCtx:        prog.Cfg.Ctx,\n\t\t\tBasePath:   prog.Path,\n\t\t\tParentNode: n,\n\t\t}\n\t\tpl := preload.Link{\n\t\t\tSegment:  ps,\n\t\t\tLinkNode: v,\n\t\t\tLink:     lnk,\n\t\t}\n\t\tprog.Cfg.Preloader(pctx, pl)\n\t\treturn nil\n\t}\n\n\tprogNext.LastBlock.Path = progNext.Path\n\tprogNext.LastBlock.Link = lnk\n\n\tv, err = progNext.loadLink(lnk, v, n)\n\tif err != nil {\n\t\tif _, ok := err.(SkipMe); ok {\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\n\treturn progNext.walkBlock(v, sNext, visitFn)\n}\n\n// loadLink is called to load a link from the configured LinkSystem with the\n// appropriate prototype.\nfunc (prog Progress) loadLink(lnk datamodel.Link, v datamodel.Node, parent datamodel.Node) (datamodel.Node, error) {\n\tif err := prog.checkLinkBudget(lnk); err != nil {\n\t\treturn nil, err\n\t}\n\t// Put together the context info we'll offer to the loader and prototypeChooser.\n\tlnkCtx := linking.LinkContext{\n\t\tCtx:        prog.Cfg.Ctx,\n\t\tLinkPath:   prog.Path,\n\t\tLinkNode:   v,\n\t\tParentNode: parent,\n\t}\n\t// Pick what in-memory format we will build.\n\tnp, err := prog.Cfg.LinkTargetNodePrototypeChooser(lnk, lnkCtx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error traversing node at %q: could not load link %q: %w\", prog.Path, lnk, err)\n\t}\n\t// Load link!\n\tn, err := prog.Cfg.LinkSystem.Load(lnkCtx, lnk, np)\n\tif err != nil {\n\t\tif _, ok := err.(SkipMe); ok {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn nil, fmt.Errorf(\"error traversing node at %q: could not load link %q: %w\", prog.Path, lnk, err)\n\t}\n\treturn n, nil\n}\n\n// WalkTransforming walks a graph of Nodes, deciding which to alter by applying a Selector,\n// and calls the given TransformFn to decide what new node to replace the visited node with.\n// A new Node tree will be returned (the original is unchanged).\n//\n// If the TransformFn returns the same Node which it was called with,\n// then the transform is a no-op; if every visited node is a no-op,\n// then the root node returned from the walk as a whole will also be\n// the same as its starting Node (no new memory will be used).\n//\n// When a Node is replaced, no further recursion of this walk will occur on its contents.\n// (You can certainly do a additional traversals, including transforms,\n// from inside the TransformFn while building the replacement node.)\n//\n// The prototype (that is, implementation) of Node returned will be the same as the\n// prototype of the Nodes at the same positions in the existing tree\n// (literally, builders used to construct any new needed intermediate nodes\n// are chosen by asking the existing nodes about their prototype).\nfunc (prog Progress) WalkTransforming(n datamodel.Node, s selector.Selector, fn TransformFn) (datamodel.Node, error) {\n\tprog.init()\n\treturn prog.walkTransforming(n, s, fn)\n}\n\nfunc (prog Progress) walkTransforming(n datamodel.Node, s selector.Selector, fn TransformFn) (datamodel.Node, error) {\n\tif err := prog.checkNodeBudget(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif rn, rs, err := prog.reify(n, s); err != nil {\n\t\treturn nil, err\n\t} else if rn != nil {\n\t\tn = rn\n\t\ts = rs\n\t}\n\n\t// Decide if this node is matched -- do callbacks as appropriate.\n\tif s.Decide(n) {\n\t\tnew_n, err := fn(prog, n)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif new_n != n {\n\t\t\t// don't continue on transformed subtrees\n\t\t\treturn new_n, nil\n\t\t}\n\t}\n\n\t// If we're handling scalars (e.g. not maps and lists) we can return now.\n\tnk := n.Kind()\n\tswitch nk {\n\tcase datamodel.Kind_List:\n\t\treturn prog.walk_transform_iterateList(n, s, fn, s.Interests())\n\tcase datamodel.Kind_Map:\n\t\treturn prog.walk_transform_iterateMap(n, s, fn, s.Interests())\n\tdefault:\n\t\treturn n, nil\n\t}\n}\n\nfunc contains(interest []datamodel.PathSegment, candidate datamodel.PathSegment) bool {\n\tfor _, i := range interest {\n\t\tif i == candidate {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (prog Progress) walk_transform_iterateList(n datamodel.Node, s selector.Selector, fn TransformFn, attn []datamodel.PathSegment) (datamodel.Node, error) {\n\tbldr := n.Prototype().NewBuilder()\n\tlstBldr, err := bldr.BeginList(n.Length())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor itr := selector.NewSegmentIterator(n); !itr.Done(); {\n\t\tps, v, err := itr.Next()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif attn == nil || contains(attn, ps) {\n\t\t\tsNext, err := s.Explore(n, ps)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif sNext != nil {\n\t\t\t\tprogNext := prog\n\t\t\t\tprogNext.Path = prog.Path.AppendSegment(ps)\n\t\t\t\tif v.Kind() == datamodel.Kind_Link {\n\t\t\t\t\tlnk, _ := v.AsLink()\n\t\t\t\t\tif prog.Cfg.LinkVisitOnlyOnce {\n\t\t\t\t\t\tif _, seen := prog.SeenLinks[lnk]; seen {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tprog.SeenLinks[lnk] = struct{}{}\n\t\t\t\t\t}\n\t\t\t\t\tprogNext.LastBlock.Path = progNext.Path\n\t\t\t\t\tprogNext.LastBlock.Link = lnk\n\t\t\t\t\tv, err = progNext.loadLink(lnk, v, n)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tif _, ok := err.(SkipMe); ok {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tnext, err := progNext.WalkTransforming(v, sNext, fn)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tif err := lstBldr.AssembleValue().AssignNode(next); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := lstBldr.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif err := lstBldr.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\tif err := lstBldr.Finish(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn bldr.Build(), nil\n}\n\nfunc (prog Progress) walk_transform_iterateMap(n datamodel.Node, s selector.Selector, fn TransformFn, attn []datamodel.PathSegment) (datamodel.Node, error) {\n\tbldr := n.Prototype().NewBuilder()\n\tmapBldr, err := bldr.BeginMap(n.Length())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor itr := selector.NewSegmentIterator(n); !itr.Done(); {\n\t\tps, v, err := itr.Next()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := mapBldr.AssembleKey().AssignString(ps.String()); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif attn == nil || contains(attn, ps) {\n\t\t\tsNext, err := s.Explore(n, ps)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif sNext != nil {\n\t\t\t\tprogNext := prog\n\t\t\t\tprogNext.Path = prog.Path.AppendSegment(ps)\n\t\t\t\tif v.Kind() == datamodel.Kind_Link {\n\t\t\t\t\tlnk, _ := v.AsLink()\n\t\t\t\t\tif prog.Cfg.LinkVisitOnlyOnce {\n\t\t\t\t\t\tif _, seen := prog.SeenLinks[lnk]; seen {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tprog.SeenLinks[lnk] = struct{}{}\n\t\t\t\t\t}\n\t\t\t\t\tprogNext.LastBlock.Path = progNext.Path\n\t\t\t\t\tprogNext.LastBlock.Link = lnk\n\t\t\t\t\tv, err = progNext.loadLink(lnk, v, n)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tif _, ok := err.(SkipMe); ok {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tnext, err := progNext.WalkTransforming(v, sNext, fn)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tif err := mapBldr.AssembleValue().AssignNode(next); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := mapBldr.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif err := mapBldr.AssembleValue().AssignNode(v); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\tif err := mapBldr.Finish(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn bldr.Build(), nil\n}\n"
  },
  {
    "path": "traversal/walk_test.go",
    "content": "package traversal_test\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t\"github.com/ipld/go-ipld-prime\"\n\t_ \"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\t\"github.com/ipld/go-ipld-prime/linking\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/linking/preload\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\tnodetests \"github.com/ipld/go-ipld-prime/node/tests\"\n\t\"github.com/ipld/go-ipld-prime/storage\"\n\t\"github.com/ipld/go-ipld-prime/traversal\"\n\t\"github.com/ipld/go-ipld-prime/traversal/selector\"\n\t\"github.com/ipld/go-ipld-prime/traversal/selector/builder\"\n\tselectorparse \"github.com/ipld/go-ipld-prime/traversal/selector/parse\"\n)\n\n/* Remember, we've got the following fixtures in scope:\nvar (\n\t// baguqeeyexkjwnfy\n\tleafAlpha, leafAlphaLnk = encode(basicnode.NewString(\"alpha\"))\n\t// baguqeeyeqvc7t3a\n\tleafBeta, leafBetaLnk = encode(basicnode.NewString(\"beta\"))\n\t// baguqeeyezhlahvq\n\tmiddleMapNode, middleMapNodeLnk = encode(fluent.MustBuildMap(basicnode.Prototype.Map, 3, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"foo\").AssignBool(true)\n\t\tna.AssembleEntry(\"bar\").AssignBool(false)\n\t\tna.AssembleEntry(\"nested\").CreateMap(2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(\"alink\").AssignLink(leafAlphaLnk)\n\t\t\tna.AssembleEntry(\"nonlink\").AssignString(\"zoo\")\n\t\t})\n\t}))\n\t// baguqeeyehfkkfwa\n\tmiddleListNode, middleListNodeLnk = encode(fluent.MustBuildList(basicnode.Prototype.List, 4, func(na fluent.ListAssembler) {\n\t\tna.AssembleValue().AssignLink(leafAlphaLnk)\n\t\tna.AssembleValue().AssignLink(leafAlphaLnk)\n\t\tna.AssembleValue().AssignLink(leafBetaLnk)\n\t\tna.AssembleValue().AssignLink(leafAlphaLnk)\n\t}))\n\t// baguqeeyeie4ajfy\n\trootNode, rootNodeLnk = encode(fluent.MustBuildMap(basicnode.Prototype.Map, 4, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"plain\").AssignString(\"olde string\")\n\t\tna.AssembleEntry(\"linkedString\").AssignLink(leafAlphaLnk)\n\t\tna.AssembleEntry(\"linkedMap\").AssignLink(middleMapNodeLnk)\n\t\tna.AssembleEntry(\"linkedList\").AssignLink(middleListNodeLnk)\n\t})))\n*/\n\n// covers traverse using a variety of selectors.\n// all cases here use one already-loaded Node; no link-loading exercised.\n\nfunc TestWalkMatching(t *testing.T) {\n\tssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any)\n\tt.Run(\"traverse selecting true should visit the root\", func(t *testing.T) {\n\t\terr := traversal.WalkMatching(basicnode.NewString(\"x\"), selector.Matcher{}, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"x\"))\n\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, datamodel.Path{}.String())\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t})\n\tt.Run(\"traverse selecting true should visit only the root and no deeper\", func(t *testing.T) {\n\t\terr := traversal.WalkMatching(middleMapNode, selector.Matcher{}, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\tqt.Check(t, n, qt.Equals, middleMapNode)\n\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, datamodel.Path{}.String())\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t})\n\tt.Run(\"traverse selecting fields should work\", func(t *testing.T) {\n\t\tss := ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {\n\t\t\tefsb.Insert(\"foo\", ssb.Matcher())\n\t\t\tefsb.Insert(\"bar\", ssb.Matcher())\n\t\t})\n\t\ts, err := ss.Selector()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tvar order int\n\t\terr = traversal.WalkMatching(middleMapNode, s, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\tswitch order {\n\t\t\tcase 0:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewBool(true))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"foo\")\n\t\t\tcase 1:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewBool(false))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"bar\")\n\t\t\t}\n\t\t\torder++\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, order, qt.Equals, 2)\n\t})\n\tt.Run(\"traverse selecting fields recursively should work\", func(t *testing.T) {\n\t\tss := ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {\n\t\t\tefsb.Insert(\"foo\", ssb.Matcher())\n\t\t\tefsb.Insert(\"nested\", ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {\n\t\t\t\tefsb.Insert(\"nonlink\", ssb.Matcher())\n\t\t\t}))\n\t\t})\n\t\ts, err := ss.Selector()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tvar order int\n\t\terr = traversal.WalkMatching(middleMapNode, s, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\tswitch order {\n\t\t\tcase 0:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewBool(true))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"foo\")\n\t\t\tcase 1:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"zoo\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"nested/nonlink\")\n\t\t\t}\n\t\t\torder++\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, order, qt.Equals, 2)\n\t})\n\tt.Run(\"traversing across nodes should work\", func(t *testing.T) {\n\t\tss := ssb.ExploreRecursive(selector.RecursionLimitDepth(3), ssb.ExploreUnion(\n\t\t\tssb.Matcher(),\n\t\t\tssb.ExploreAll(ssb.ExploreRecursiveEdge()),\n\t\t))\n\t\ts, err := ss.Selector()\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tvar order int\n\t\tlsys := cidlink.DefaultLinkSystem()\n\t\tlsys.SetReadStorage(&store)\n\t\terr = traversal.Progress{\n\t\t\tCfg: &traversal.Config{\n\t\t\t\tLinkSystem:                     lsys,\n\t\t\t\tLinkTargetNodePrototypeChooser: basicnode.Chooser,\n\t\t\t},\n\t\t}.WalkMatching(middleMapNode, s, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\tswitch order {\n\t\t\tcase 0:\n\t\t\t\tqt.Check(t, n, qt.Equals, middleMapNode)\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"\")\n\t\t\tcase 1:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewBool(true))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"foo\")\n\t\t\tcase 2:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewBool(false))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"bar\")\n\t\t\tcase 3:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, fluent.MustBuildMap(basicnode.Prototype.Map, 2, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(\"alink\").AssignLink(leafAlphaLnk)\n\t\t\t\t\tna.AssembleEntry(\"nonlink\").AssignString(\"zoo\")\n\t\t\t\t}))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"nested\")\n\t\t\tcase 4:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"alpha\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"nested/alink\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Path.String(), qt.Equals, \"nested/alink\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Link.String(), qt.Equals, leafAlphaLnk.String())\n\n\t\t\tcase 5:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"zoo\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"nested/nonlink\")\n\t\t\t}\n\t\t\torder++\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, order, qt.Equals, 6)\n\t})\n\tt.Run(\"traversing lists should work\", func(t *testing.T) {\n\t\tss := ssb.ExploreRange(0, 3, ssb.Matcher())\n\t\ts, err := ss.Selector()\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tvar order int\n\t\tlsys := cidlink.DefaultLinkSystem()\n\t\tlsys.SetReadStorage(&store)\n\t\terr = traversal.Progress{\n\t\t\tCfg: &traversal.Config{\n\t\t\t\tLinkSystem:                     lsys,\n\t\t\t\tLinkTargetNodePrototypeChooser: basicnode.Chooser,\n\t\t\t},\n\t\t}.WalkMatching(middleListNode, s, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\tswitch order {\n\t\t\tcase 0:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"alpha\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"0\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Path.String(), qt.Equals, \"0\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Link.String(), qt.Equals, leafAlphaLnk.String())\n\t\t\tcase 1:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"alpha\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Path.String(), qt.Equals, \"1\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Link.String(), qt.Equals, leafAlphaLnk.String())\n\t\t\tcase 2:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"beta\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"2\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Path.String(), qt.Equals, \"2\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Link.String(), qt.Equals, leafBetaLnk.String())\n\t\t\t}\n\t\t\torder++\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, order, qt.Equals, 3)\n\t})\n\tt.Run(\"multiple layers of link traversal should work\", func(t *testing.T) {\n\t\tss := ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {\n\t\t\tefsb.Insert(\"linkedList\", ssb.ExploreAll(ssb.Matcher()))\n\t\t\tefsb.Insert(\"linkedMap\", ssb.ExploreRecursive(selector.RecursionLimitDepth(3), ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {\n\t\t\t\tefsb.Insert(\"foo\", ssb.Matcher())\n\t\t\t\tefsb.Insert(\"nonlink\", ssb.Matcher())\n\t\t\t\tefsb.Insert(\"alink\", ssb.Matcher())\n\t\t\t\tefsb.Insert(\"nested\", ssb.ExploreRecursiveEdge())\n\t\t\t})))\n\t\t})\n\t\ts, err := ss.Selector()\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tvar order int\n\t\tlsys := cidlink.DefaultLinkSystem()\n\t\tlsys.SetReadStorage(&store)\n\t\terr = traversal.Progress{\n\t\t\tCfg: &traversal.Config{\n\t\t\t\tLinkSystem:                     lsys,\n\t\t\t\tLinkTargetNodePrototypeChooser: basicnode.Chooser,\n\t\t\t},\n\t\t}.WalkMatching(rootNode, s, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\tswitch order {\n\t\t\tcase 0:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"alpha\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"linkedList/0\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Path.String(), qt.Equals, \"linkedList/0\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Link.String(), qt.Equals, leafAlphaLnk.String())\n\t\t\tcase 1:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"alpha\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"linkedList/1\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Path.String(), qt.Equals, \"linkedList/1\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Link.String(), qt.Equals, leafAlphaLnk.String())\n\t\t\tcase 2:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"beta\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"linkedList/2\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Path.String(), qt.Equals, \"linkedList/2\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Link.String(), qt.Equals, leafBetaLnk.String())\n\t\t\tcase 3:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"alpha\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"linkedList/3\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Path.String(), qt.Equals, \"linkedList/3\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Link.String(), qt.Equals, leafAlphaLnk.String())\n\t\t\tcase 4:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewBool(true))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"linkedMap/foo\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Path.String(), qt.Equals, \"linkedMap\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Link.String(), qt.Equals, middleMapNodeLnk.String())\n\t\t\tcase 5:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"zoo\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"linkedMap/nested/nonlink\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Path.String(), qt.Equals, \"linkedMap\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Link.String(), qt.Equals, middleMapNodeLnk.String())\n\t\t\tcase 6:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"alpha\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"linkedMap/nested/alink\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Path.String(), qt.Equals, \"linkedMap/nested/alink\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Link.String(), qt.Equals, leafAlphaLnk.String())\n\t\t\t}\n\t\t\torder++\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, order, qt.Equals, 7)\n\t})\n\n\tt.Run(\"no visiting of nodes before start path\", func(t *testing.T) {\n\t\tss := ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {\n\t\t\tefsb.Insert(\"linkedList\", ssb.ExploreRecursive(\n\t\t\t\tselector.RecursionLimitNone(),\n\t\t\t\tssb.ExploreUnion(ssb.Matcher(), ssb.ExploreAll(ssb.ExploreRecursiveEdge()))))\n\t\t\tefsb.Insert(\"plain\", ssb.ExploreAll(ssb.Matcher()))\n\t\t\tefsb.Insert(\"linkedString\", ssb.ExploreAll(ssb.Matcher()))\n\t\t\tefsb.Insert(\"linkedMap\", ssb.ExploreUnion(ssb.Matcher(),\n\t\t\t\tssb.ExploreRecursive(selector.RecursionLimitDepth(3), ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {\n\t\t\t\t\tefsb.Insert(\"foo\", ssb.Matcher())\n\t\t\t\t\tefsb.Insert(\"nonlink\", ssb.Matcher())\n\t\t\t\t\tefsb.Insert(\"alink\", ssb.Matcher())\n\t\t\t\t\tefsb.Insert(\"nested\", ssb.ExploreRecursiveEdge())\n\t\t\t\t}))))\n\t\t})\n\t\ts, err := ss.Selector()\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tvar order int\n\t\tlsys := cidlink.DefaultLinkSystem()\n\t\tlsys.SetReadStorage(&store)\n\t\tvisitedCids := make([]string, 0)\n\t\tlsys.StorageReadOpener = func(lnkCtx ipld.LinkContext, lnk ipld.Link) (io.Reader, error) {\n\t\t\tvisitedCids = append(visitedCids, lnk.(cidlink.Link).Cid.String())\n\t\t\treturn store.GetStream(lnkCtx.Ctx, lnk.(cidlink.Link).Cid.KeyString())\n\t\t}\n\t\terr = traversal.Progress{\n\t\t\tCfg: &traversal.Config{\n\t\t\t\tLinkSystem:                     lsys,\n\t\t\t\tLinkTargetNodePrototypeChooser: basicnode.Chooser,\n\t\t\t\tStartAtPath:                    datamodel.ParsePath(\"linkedMap/nested/nonlink\"),\n\t\t\t},\n\t\t}.WalkMatching(rootNode, s, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\tswitch order {\n\t\t\tcase 0:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"zoo\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"linkedMap/nested/nonlink\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Path.String(), qt.Equals, \"linkedMap\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Link.String(), qt.Equals, middleMapNodeLnk.String())\n\t\t\tcase 1:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"alpha\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"linkedMap/nested/alink\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Path.String(), qt.Equals, \"linkedMap/nested/alink\")\n\t\t\t\tqt.Check(t, prog.LastBlock.Link.String(), qt.Equals, leafAlphaLnk.String())\n\t\t\t}\n\t\t\torder++\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, order, qt.Equals, 2)\n\t\t// linkedMap=baguqeeyezhlahvq, alink=baguqeeyexkjwnfy\n\t\tqt.Check(t, visitedCids, qt.DeepEquals, []string{\"baguqeeyezhlahvq\", \"baguqeeyexkjwnfy\"})\n\t})\n\n\tt.Run(\"no loading of unnecessary nodes before start path\", func(t *testing.T) {\n\t\tss := ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {\n\t\t\tefsb.Insert(\"linkedList\", ssb.ExploreRecursive(selector.RecursionLimitNone(), ssb.ExploreAll(ssb.ExploreRecursiveEdge())))\n\t\t\tefsb.Insert(\"plain\", ssb.ExploreRecursive(selector.RecursionLimitNone(), ssb.ExploreAll(ssb.ExploreRecursiveEdge())))\n\t\t\tefsb.Insert(\"linkedString\", ssb.ExploreRecursive(selector.RecursionLimitNone(), ssb.ExploreAll(ssb.ExploreRecursiveEdge())))\n\t\t\tefsb.Insert(\"linkedMap\",\n\t\t\t\tssb.ExploreRecursive(selector.RecursionLimitDepth(3), ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {\n\t\t\t\t\tefsb.Insert(\"foo\", ssb.ExploreRecursive(selector.RecursionLimitNone(), ssb.ExploreAll(ssb.ExploreRecursiveEdge())))\n\t\t\t\t\tefsb.Insert(\"nonlink\", ssb.ExploreRecursive(selector.RecursionLimitNone(), ssb.ExploreAll(ssb.ExploreRecursiveEdge())))\n\t\t\t\t\tefsb.Insert(\"alink\", ssb.ExploreRecursive(selector.RecursionLimitNone(), ssb.ExploreAll(ssb.ExploreRecursiveEdge())))\n\t\t\t\t\tefsb.Insert(\"nested\", ssb.ExploreRecursiveEdge())\n\t\t\t\t})))\n\t\t})\n\t\ts, err := ss.Selector()\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tlsys := cidlink.DefaultLinkSystem()\n\t\tlsys.SetReadStorage(&store)\n\t\tvisitedCids := make([]string, 0)\n\t\tlsys.StorageReadOpener = func(lnkCtx ipld.LinkContext, lnk ipld.Link) (io.Reader, error) {\n\t\t\tvisitedCids = append(visitedCids, lnk.(cidlink.Link).Cid.String())\n\t\t\treturn store.GetStream(lnkCtx.Ctx, lnk.(cidlink.Link).Cid.KeyString())\n\t\t}\n\t\terr = traversal.Progress{\n\t\t\tCfg: &traversal.Config{\n\t\t\t\tLinkSystem:                     lsys,\n\t\t\t\tLinkTargetNodePrototypeChooser: basicnode.Chooser,\n\t\t\t\tStartAtPath:                    datamodel.ParsePath(\"linkedMap/nested/nonlink\"),\n\t\t\t},\n\t\t}.WalkMatching(rootNode, s, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\t// linkedMap=baguqeeyezhlahvq, alink=baguqeeyexkjwnfy\n\t\tqt.Check(t, visitedCids, qt.DeepEquals, []string{\"baguqeeyezhlahvq\", \"baguqeeyexkjwnfy\"})\n\t})\n}\n\nfunc TestWalkBudgets(t *testing.T) {\n\tfor _, preloader := range []bool{false, true} {\n\t\tt.Run(fmt.Sprintf(\"preloader=%v\", preloader), func(t *testing.T) {\n\t\t\tt.Run(\"node-budget-halts\", func(t *testing.T) {\n\t\t\t\tssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any)\n\t\t\t\tss := ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {\n\t\t\t\t\tefsb.Insert(\"foo\", ssb.Matcher())\n\t\t\t\t\tefsb.Insert(\"bar\", ssb.Matcher())\n\t\t\t\t})\n\t\t\t\ts, err := ss.Selector()\n\t\t\t\tqt.Assert(t, err, qt.Equals, nil)\n\t\t\t\tvar order int\n\t\t\t\tprog := traversal.Progress{}\n\t\t\t\tprog.Budget = &traversal.Budget{\n\t\t\t\t\tNodeBudget: 2, // should reach root, then \"foo\", then stop.\n\t\t\t\t}\n\t\t\t\tpreloadLinks := make([]preload.Link, 0)\n\t\t\t\tif preloader {\n\t\t\t\t\t// having a preloader shouldn't change budgeting\n\t\t\t\t\tprog.Cfg = &traversal.Config{\n\t\t\t\t\t\tPreloader: func(_ preload.PreloadContext, link preload.Link) {\n\t\t\t\t\t\t\tpreloadLinks = append(preloadLinks, link)\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\terr = prog.WalkMatching(middleMapNode, s, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\t\t\tswitch order {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tqt.Assert(t, n, nodetests.NodeContentEquals, basicnode.NewBool(true))\n\t\t\t\t\t\tqt.Assert(t, prog.Path.String(), qt.Equals, \"foo\")\n\t\t\t\t\t}\n\t\t\t\t\torder++\n\t\t\t\t\treturn nil\n\t\t\t\t})\n\t\t\t\tif preloader {\n\t\t\t\t\tqt.Assert(t, preloadLinks, qt.HasLen, 0)\n\t\t\t\t}\n\t\t\t\tqt.Check(t, order, qt.Equals, 1) // because it should've stopped early\n\t\t\t\tqt.Assert(t, err, qt.Not(qt.Equals), nil)\n\t\t\t\tqt.Check(t, err.Error(), qt.Equals, `traversal budget exceeded: budget for nodes reached zero while on path \"bar\"`)\n\t\t\t})\n\n\t\t\tt.Run(\"link-budget-halts\", func(t *testing.T) {\n\t\t\t\tssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any)\n\t\t\t\tss := ssb.ExploreAll(ssb.Matcher())\n\t\t\t\ts, err := ss.Selector()\n\t\t\t\tqt.Assert(t, err, qt.Equals, nil)\n\t\t\t\tvar order int\n\t\t\t\tlsys := cidlink.DefaultLinkSystem()\n\t\t\t\tlsys.SetReadStorage(&store)\n\t\t\t\tprog := traversal.Progress{\n\t\t\t\t\tCfg: &traversal.Config{\n\t\t\t\t\t\tLinkSystem:                     lsys,\n\t\t\t\t\t\tLinkTargetNodePrototypeChooser: basicnode.Chooser,\n\t\t\t\t\t},\n\t\t\t\t\tBudget: &traversal.Budget{\n\t\t\t\t\t\tNodeBudget: 9000,\n\t\t\t\t\t\tLinkBudget: 3,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tpreloadLinks := make([]preload.Link, 0)\n\t\t\t\tif preloader {\n\t\t\t\t\t// having a preloader shouldn't change budgeting\n\t\t\t\t\tprog.Cfg.Preloader = func(_ preload.PreloadContext, link preload.Link) {\n\t\t\t\t\t\tpreloadLinks = append(preloadLinks, link)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\terr = prog.WalkMatching(middleListNode, s, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\t\t\tswitch order {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tqt.Assert(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"alpha\"))\n\t\t\t\t\t\tqt.Assert(t, prog.Path.String(), qt.Equals, \"0\")\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\tqt.Assert(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"alpha\"))\n\t\t\t\t\t\tqt.Assert(t, prog.Path.String(), qt.Equals, \"1\")\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\tqt.Assert(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"beta\"))\n\t\t\t\t\t\tqt.Assert(t, prog.Path.String(), qt.Equals, \"2\")\n\t\t\t\t\t}\n\t\t\t\t\torder++\n\t\t\t\t\treturn nil\n\t\t\t\t})\n\t\t\t\tqt.Check(t, order, qt.Equals, 3)\n\t\t\t\tqt.Assert(t, err, qt.Not(qt.Equals), nil)\n\t\t\t\tqt.Check(t, err.Error(), qt.Equals, `traversal budget exceeded: budget for links reached zero while on path \"3\" (link: \"baguqeeyexkjwnfy\")`)\n\t\t\t\tif preloader {\n\t\t\t\t\tqt.Assert(t, preloadLinks, qt.HasLen, 3)\n\t\t\t\t\tqt.Check(t, preloadLinks[0].Link, qt.Equals, leafAlphaLnk)\n\t\t\t\t\tqt.Check(t, preloadLinks[1].Link, qt.Equals, leafAlphaLnk)\n\t\t\t\t\tqt.Check(t, preloadLinks[2].Link, qt.Equals, leafBetaLnk)\n\t\t\t\t}\n\t\t\t})\n\t\t})\n\t}\n}\n\nfunc TestWalkBlockLoadOrder(t *testing.T) {\n\t// a more nested root that we can use to test SkipMe as well\n\t// note that in using `rootNodeLnk` here rather than `rootNode` we're using the\n\t// dag-json round-trip version which will have different field ordering\n\tnewRootNode, newRootLink := encode(fluent.MustBuildList(basicnode.Prototype.List, 6, func(na fluent.ListAssembler) {\n\t\tna.AssembleValue().AssignLink(rootNodeLnk)\n\t\tna.AssembleValue().AssignLink(middleListNodeLnk)\n\t\tna.AssembleValue().AssignLink(rootNodeLnk)\n\t\tna.AssembleValue().AssignLink(middleListNodeLnk)\n\t\tna.AssembleValue().AssignLink(rootNodeLnk)\n\t\tna.AssembleValue().AssignLink(middleListNodeLnk)\n\t}))\n\n\tlinkNames := make(map[datamodel.Link]string)\n\tlinkNames[newRootLink] = \"newRootLink\"\n\tlinkNames[rootNodeLnk] = \"rootNodeLnk\"\n\tlinkNames[leafAlphaLnk] = \"leafAlphaLnk\"\n\tlinkNames[middleMapNodeLnk] = \"middleMapNodeLnk\"\n\tlinkNames[leafAlphaLnk] = \"leafAlphaLnk\"\n\tlinkNames[middleListNodeLnk] = \"middleListNodeLnk\"\n\tlinkNames[leafAlphaLnk] = \"leafAlphaLnk\"\n\tlinkNames[leafBetaLnk] = \"leafBetaLnk\"\n\t/* useful to know CIDs for these when debugging\n\tfor v, n := range linkNames {\n\t\tt.Logf(\"n:%v:%v\\n\", n, v)\n\t}\n\t*/\n\t// the links that we expect from the root node, starting _at_ the root node itself\n\trootNodeExpectedLinks := []datamodel.Link{\n\t\trootNodeLnk,\n\t\tmiddleListNodeLnk,\n\t\tleafAlphaLnk,\n\t\tleafAlphaLnk,\n\t\tleafBetaLnk,\n\t\tleafAlphaLnk,\n\t\tmiddleMapNodeLnk,\n\t\tleafAlphaLnk,\n\t\tleafAlphaLnk,\n\t}\n\t// same thing but just for middleListNode\n\tmiddleListNodeLinks := []datamodel.Link{\n\t\tmiddleListNodeLnk,\n\t\tleafAlphaLnk,\n\t\tleafAlphaLnk,\n\t\tleafBetaLnk,\n\t\tleafAlphaLnk,\n\t}\n\t// our newRootNode is a list that contains 3 consecutive links to rootNode\n\texpectedAllBlocks := make([]datamodel.Link, 3*(len(rootNodeExpectedLinks)+len(middleListNodeLinks)))\n\tfor i := 0; i < 3; i++ {\n\t\tcopy(expectedAllBlocks[i*len(rootNodeExpectedLinks)+i*len(middleListNodeLinks):], rootNodeExpectedLinks[:])\n\t\tcopy(expectedAllBlocks[(i+1)*len(rootNodeExpectedLinks)+i*len(middleListNodeLinks):], middleListNodeLinks[:])\n\t}\n\n\tverifySelectorLoads := func(\n\t\tt *testing.T,\n\t\trootNode datamodel.Node,\n\t\texpected []datamodel.Link,\n\t\ts datamodel.Node,\n\t\tlinkVisitOnce bool,\n\t\tstartAtPath datamodel.Path,\n\t\tpreloader preload.Loader,\n\t\treadFn func(lc linking.LinkContext, l datamodel.Link) (io.Reader, error)) {\n\n\t\tvar count int\n\t\tlsys := cidlink.DefaultLinkSystem()\n\t\tlsys.StorageReadOpener = func(lc linking.LinkContext, l datamodel.Link) (io.Reader, error) {\n\t\t\t// t.Logf(\"load %d: %v (%s) <> %v (%s) - %s\", count, expected[count].String(), linkNames[expected[count]], l.String(), linkNames[l], lc.LinkPath)\n\t\t\t// t.Logf(\"%v (%v) %s<> %v (%v)\\n\", l, linkNames[l], strings.Repeat(\" \", 17-len(linkNames[l])), expected[count], linkNames[expected[count]])\n\t\t\tqt.Check(t, l.String(), qt.Equals, expected[count].String())\n\t\t\tcount++\n\t\t\treturn readFn(lc, l)\n\t\t}\n\t\tsel, err := selector.CompileSelector(s)\n\t\tqt.Check(t, err, qt.IsNil)\n\t\terr = traversal.Progress{\n\t\t\tCfg: &traversal.Config{\n\t\t\t\tLinkSystem:                     lsys,\n\t\t\t\tLinkTargetNodePrototypeChooser: basicnode.Chooser,\n\t\t\t\tLinkVisitOnlyOnce:              linkVisitOnce,\n\t\t\t\tStartAtPath:                    startAtPath,\n\t\t\t\tPreloader:                      preloader,\n\t\t\t},\n\t\t}.WalkMatching(rootNode, sel, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, count, qt.Equals, len(expected))\n\t}\n\n\tt.Run(\"CommonSelector_MatchAllRecursively\", func(t *testing.T) {\n\t\ts := selectorparse.CommonSelector_MatchAllRecursively\n\t\tverifySelectorLoads(t, newRootNode, expectedAllBlocks, s, false, datamodel.NewPath(nil), nil, func(lctx linking.LinkContext, lnk datamodel.Link) (io.Reader, error) {\n\t\t\treturn storage.GetStream(lctx.Ctx, &store, lnk.Binary())\n\t\t})\n\t})\n\n\tt.Run(\"CommonSelector_ExploreAllRecursively\", func(t *testing.T) {\n\t\ts := selectorparse.CommonSelector_ExploreAllRecursively\n\t\tverifySelectorLoads(t, newRootNode, expectedAllBlocks, s, false, datamodel.NewPath(nil), nil, func(lctx linking.LinkContext, lnk datamodel.Link) (io.Reader, error) {\n\t\t\treturn storage.GetStream(lctx.Ctx, &store, lnk.Binary())\n\t\t})\n\t})\n\n\tt.Run(\"explore all with preload\", func(t *testing.T) {\n\t\ts := selectorparse.CommonSelector_ExploreAllRecursively\n\n\t\tnewNestedRootNode, _ := encode(fluent.MustBuildList(basicnode.Prototype.List, 2, func(na fluent.ListAssembler) {\n\t\t\tna.AssembleValue().CreateMap(3, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"a\").AssignLink(rootNodeLnk)\n\t\t\t\tma.AssembleEntry(\"b\").AssignLink(middleListNodeLnk)\n\t\t\t\tma.AssembleEntry(\"c\").AssignLink(rootNodeLnk)\n\t\t\t})\n\t\t\tna.AssembleValue().CreateMap(3, func(ma fluent.MapAssembler) {\n\t\t\t\tma.AssembleEntry(\"d\").AssignLink(middleListNodeLnk)\n\t\t\t\tma.AssembleEntry(\"e\").AssignLink(rootNodeLnk)\n\t\t\t\tma.AssembleEntry(\"f\").AssignLink(middleListNodeLnk)\n\t\t\t})\n\t\t}))\n\n\t\trootNodePreloads := []datamodel.Link{middleListNodeLnk, middleMapNodeLnk, leafAlphaLnk}\n\t\tmiddleListNodePreloads := []datamodel.Link{leafAlphaLnk, leafAlphaLnk, leafBetaLnk, leafAlphaLnk}\n\t\tmiddleMapNodePreloads := []datamodel.Link{leafAlphaLnk}\n\t\trootNodePreloadsRecursive := [][]datamodel.Link{rootNodePreloads, middleListNodePreloads, middleMapNodePreloads}\n\t\tel := [][]datamodel.Link{\n\t\t\t{rootNodeLnk, middleListNodeLnk, rootNodeLnk, middleListNodeLnk, rootNodeLnk, middleListNodeLnk},\n\t\t}\n\t\tfor i := 0; i < 3; i++ {\n\t\t\tel = append(el, rootNodePreloadsRecursive...)\n\t\t\tel = append(el, middleListNodePreloads)\n\t\t}\n\t\texpectedLinks := make([]datamodel.Link, 0)\n\t\tfor _, l := range el {\n\t\t\texpectedLinks = append(expectedLinks, l...)\n\t\t}\n\t\tpreloadIndex := 0\n\t\tpreloader := func(_ preload.PreloadContext, link preload.Link) {\n\t\t\tif preloadIndex >= len(expectedLinks) {\n\t\t\t\tt.Fatal(\"too many preloads\")\n\t\t\t}\n\t\t\tqt.Check(t, link.Link, qt.Equals, expectedLinks[preloadIndex])\n\t\t\tpreloadIndex++\n\t\t}\n\n\t\tverifySelectorLoads(t, newNestedRootNode, expectedAllBlocks, s, false, datamodel.NewPath(nil), preloader, func(lctx linking.LinkContext, lnk datamodel.Link) (io.Reader, error) {\n\t\t\treturn storage.GetStream(lctx.Ctx, &store, lnk.Binary())\n\t\t})\n\t\tqt.Check(t, preloadIndex, qt.Equals, len(expectedLinks))\n\t})\n\n\tt.Run(\"constructed explore-all selector\", func(t *testing.T) {\n\t\t// used commonly in Filecoin and other places to \"visit all blocks in stable order\"\n\t\tssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any)\n\t\ts := ssb.ExploreRecursive(selector.RecursionLimitNone(),\n\t\t\tssb.ExploreAll(ssb.ExploreRecursiveEdge())).\n\t\t\tNode()\n\t\tverifySelectorLoads(t, newRootNode, expectedAllBlocks, s, false, datamodel.NewPath(nil), nil, func(lctx linking.LinkContext, lnk datamodel.Link) (io.Reader, error) {\n\t\t\treturn storage.GetStream(lctx.Ctx, &store, lnk.Binary())\n\t\t})\n\t})\n\n\tt.Run(\"explore-all with duplicate load skips via SkipMe\", func(t *testing.T) {\n\t\t// when we use SkipMe to skip loading of already visited blocks we expect to\n\t\t// see the links show up in Loads but the lack of the links inside rootNode\n\t\t// and middleListNode in this list beyond the first set of loads show that\n\t\t// the block is not traversed when the SkipMe is received\n\t\texpectedSkipMeBlocks := []datamodel.Link{\n\t\t\trootNodeLnk,\n\t\t\tmiddleListNodeLnk,\n\t\t\tleafAlphaLnk,\n\t\t\tleafAlphaLnk,\n\t\t\tleafBetaLnk,\n\t\t\tleafAlphaLnk,\n\t\t\tmiddleMapNodeLnk,\n\t\t\tleafAlphaLnk,\n\t\t\tleafAlphaLnk,\n\t\t\tmiddleListNodeLnk,\n\t\t\trootNodeLnk,\n\t\t\tmiddleListNodeLnk,\n\t\t\trootNodeLnk,\n\t\t\tmiddleListNodeLnk,\n\t\t}\n\n\t\ts := selectorparse.CommonSelector_ExploreAllRecursively\n\t\tvisited := make(map[datamodel.Link]bool)\n\t\tverifySelectorLoads(t, newRootNode, expectedSkipMeBlocks, s, false, datamodel.NewPath(nil), nil, func(lc linking.LinkContext, l datamodel.Link) (io.Reader, error) {\n\t\t\t// t.Logf(\"load %v [%v]\\n\", l, visited[l])\n\t\t\tif visited[l] {\n\t\t\t\treturn nil, traversal.SkipMe{}\n\t\t\t}\n\t\t\tvisited[l] = true\n\t\t\treturn storage.GetStream(lc.Ctx, &store, l.Binary())\n\t\t})\n\t})\n\n\tt.Run(\"explore-all with duplicate load skips via LinkVisitOnlyOnce:true\", func(t *testing.T) {\n\t\t// when using LinkRevisit:false to skip duplicate block loads, our loader\n\t\t// doesn't even get to see the load attempts (unlike SkipMe, where the\n\t\t// loader signals the skips)\n\t\texpectedLinkRevisitBlocks := []datamodel.Link{\n\t\t\trootNodeLnk,\n\t\t\tmiddleListNodeLnk,\n\t\t\tleafAlphaLnk,\n\t\t\tleafBetaLnk,\n\t\t\tmiddleMapNodeLnk,\n\t\t}\n\t\ts := selectorparse.CommonSelector_ExploreAllRecursively\n\t\tverifySelectorLoads(t, newRootNode, expectedLinkRevisitBlocks, s, true, datamodel.NewPath(nil), nil, func(lctx linking.LinkContext, lnk datamodel.Link) (io.Reader, error) {\n\t\t\treturn storage.GetStream(lctx.Ctx, &store, lnk.Binary())\n\t\t})\n\t})\n\n\tt.Run(\"explore-all with duplicate load and preloader skips via LinkVisitOnlyOnce:true\", func(t *testing.T) {\n\t\t// same as above but make sure the preloader doesn't get in the way\n\t\texpectedLinkRevisitBlocks := []datamodel.Link{\n\t\t\trootNodeLnk,\n\t\t\tmiddleListNodeLnk,\n\t\t\tleafAlphaLnk,\n\t\t\tleafBetaLnk,\n\t\t\tmiddleMapNodeLnk,\n\t\t}\n\t\ts := selectorparse.CommonSelector_ExploreAllRecursively\n\t\tpreloadLinks := make(map[datamodel.Link]struct{})\n\t\tpreloader := func(_ preload.PreloadContext, link preload.Link) {\n\t\t\tpreloadLinks[link.Link] = struct{}{}\n\t\t}\n\t\tverifySelectorLoads(t, newRootNode, expectedLinkRevisitBlocks, s, true, datamodel.NewPath(nil), preloader, func(lctx linking.LinkContext, lnk datamodel.Link) (io.Reader, error) {\n\t\t\treturn storage.GetStream(lctx.Ctx, &store, lnk.Binary())\n\t\t})\n\t\tfor _, l := range expectedLinkRevisitBlocks {\n\t\t\tqt.Check(t, preloadLinks[l], qt.IsNotNil)\n\t\t}\n\t})\n\n\tt.Run(\"explore-all with duplicate traversal skip via load at path\", func(t *testing.T) {\n\t\t// when using LinkRevisit:false to skip duplicate block loads, our loader\n\t\t// doesn't even get to see the load attempts (unlike SkipMe, where the\n\t\t// loader signals the skips)\n\t\ttestPathsToBlocksSkipped := []struct {\n\t\t\tpath               string\n\t\t\texpectedLinkVisits []datamodel.Link\n\t\t}{\n\t\t\t// 5th node in load sequence for rootNode\n\t\t\t{\"0/linkedList/2\", append([]datamodel.Link{rootNodeLnk, middleListNodeLnk}, expectedAllBlocks[4:]...)},\n\t\t\t// LinkedMap is 7th no, foo doesn't affect loading\n\t\t\t{\"0/linkedMap/foo\", append([]datamodel.Link{rootNodeLnk}, expectedAllBlocks[6:]...)},\n\t\t\t// 8th node in load sequence for rootNode\n\t\t\t{\"0/linkedMap/nested/alink\", append([]datamodel.Link{rootNodeLnk, middleMapNodeLnk}, expectedAllBlocks[7:]...)},\n\t\t\t{\"0/linkedString\", append([]datamodel.Link{rootNodeLnk}, expectedAllBlocks[8:]...)},\n\t\t\t// pash through all nodes first root block, then go load middle list block\n\t\t\t{\"1/2\", append([]datamodel.Link{middleListNodeLnk}, expectedAllBlocks[len(rootNodeExpectedLinks)+3:]...)},\n\t\t\t{\"3/1\", append([]datamodel.Link{middleListNodeLnk}, expectedAllBlocks[2*len(rootNodeExpectedLinks)+len(middleListNodeLinks)+2:]...)},\n\t\t}\n\t\tfor _, testCase := range testPathsToBlocksSkipped {\n\t\t\tt.Run(testCase.path, func(t *testing.T) {\n\t\t\t\tstartAtPath := datamodel.ParsePath(testCase.path)\n\t\t\t\ts := selectorparse.CommonSelector_ExploreAllRecursively\n\t\t\t\tverifySelectorLoads(t, newRootNode, testCase.expectedLinkVisits, s, false, startAtPath, nil, func(lctx linking.LinkContext, lnk datamodel.Link) (io.Reader, error) {\n\t\t\t\t\treturn storage.GetStream(lctx.Ctx, &store, lnk.Binary())\n\t\t\t\t})\n\t\t\t})\n\t\t}\n\t})\n}\n\nfunc TestWalk_ADLs(t *testing.T) {\n\t// we'll make a reifier that when it sees a list returns a custom element instead.\n\tcustomReifier := func(_ linking.LinkContext, n datamodel.Node, _ *linking.LinkSystem) (datamodel.Node, error) {\n\t\tif n.Kind() == datamodel.Kind_List {\n\t\t\treturn leafAlpha, nil\n\t\t}\n\t\treturn n, nil\n\t}\n\n\tssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any)\n\tss := ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {\n\t\tefsb.Insert(\"linkedList\", ssb.ExploreInterpretAs(\"linkJumper\", ssb.Matcher()))\n\t})\n\ts, err := ss.Selector()\n\tqt.Check(t, err, qt.IsNil)\n\tlsys := cidlink.DefaultLinkSystem()\n\tlsys.KnownReifiers = map[string]linking.NodeReifier{\"linkJumper\": customReifier}\n\tlsys.SetReadStorage(&store)\n\tvar order int\n\terr = traversal.Progress{\n\t\tCfg: &traversal.Config{\n\t\t\tLinkSystem:                     lsys,\n\t\t\tLinkTargetNodePrototypeChooser: basicnode.Chooser,\n\t\t},\n\t}.WalkMatching(rootNode, s, func(prog traversal.Progress, n datamodel.Node) error {\n\t\tswitch order {\n\t\tcase 0:\n\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"alpha\"))\n\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"linkedList\")\n\t\t}\n\t\torder++\n\t\treturn nil\n\t})\n\tqt.Check(t, err, qt.IsNil)\n\tqt.Check(t, order, qt.Equals, 1)\n}\n\nfunc TestWalkTransforming(t *testing.T) {\n\tssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any)\n\tt.Run(\"transform selecting true should transform the root\", func(t *testing.T) {\n\t\tn, err := traversal.WalkTransforming(basicnode.NewString(\"x\"), selector.Matcher{}, func(prog traversal.Progress, n datamodel.Node) (datamodel.Node, error) {\n\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"x\"))\n\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, datamodel.Path{}.String())\n\t\t\treturn basicnode.NewString(\"replaced\"), nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"replaced\"))\n\t})\n\tt.Run(\"transforming selecting fields recursively should work\", func(t *testing.T) {\n\t\tss := ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {\n\t\t\tefsb.Insert(\"foo\", ssb.Matcher())\n\t\t\tefsb.Insert(\"nested\", ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {\n\t\t\t\tefsb.Insert(\"nonlink\", ssb.Matcher())\n\t\t\t}))\n\t\t})\n\t\ts, err := ss.Selector()\n\t\tqt.Assert(t, err, qt.IsNil)\n\t\tvar order int\n\t\tn, err := traversal.WalkTransforming(middleMapNode, s, func(prog traversal.Progress, n datamodel.Node) (datamodel.Node, error) {\n\t\t\tswitch order {\n\t\t\tcase 0:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewBool(true))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"foo\")\n\t\t\tcase 1:\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"zoo\"))\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"nested/nonlink\")\n\t\t\t}\n\t\t\torder++\n\t\t\treturn basicnode.NewString(\"replaced\"), nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, order, qt.Equals, 2)\n\t\tqt.Check(t, n, nodetests.NodeContentEquals, fluent.MustBuildMap(basicnode.Prototype.Map, 3, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(\"foo\").AssignString(\"replaced\")\n\t\t\tna.AssembleEntry(\"bar\").AssignBool(false)\n\t\t\tna.AssembleEntry(\"nested\").CreateMap(2, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(\"alink\").AssignLink(leafAlphaLnk)\n\t\t\t\tna.AssembleEntry(\"nonlink\").AssignString(\"replaced\")\n\t\t\t})\n\t\t}))\n\t})\n}\n"
  },
  {
    "path": "traversal/walk_with_stop_test.go",
    "content": "package traversal_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\tqt \"github.com/frankban/quicktest\"\n\n\t_ \"github.com/ipld/go-ipld-prime/codec/dagjson\"\n\t\"github.com/ipld/go-ipld-prime/datamodel\"\n\t\"github.com/ipld/go-ipld-prime/fluent\"\n\tcidlink \"github.com/ipld/go-ipld-prime/linking/cid\"\n\t\"github.com/ipld/go-ipld-prime/node/basicnode\"\n\tnodetests \"github.com/ipld/go-ipld-prime/node/tests\"\n\t\"github.com/ipld/go-ipld-prime/traversal\"\n\t\"github.com/ipld/go-ipld-prime/traversal/selector\"\n\t\"github.com/ipld/go-ipld-prime/traversal/selector/builder\"\n)\n\n/* Remember, we've got the following fixtures in scope:\nvar (\n\tleafAlpha, leafAlphaLnk         = encode(basicnode.NewString(\"alpha\"))\n\tleafBeta, leafBetaLnk           = encode(basicnode.NewString(\"beta\"))\n\tmiddleMapNode, middleMapNodeLnk = encode(fluent.MustBuildMap(basicnode.Prototype__Map{}, 3, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"foo\").AssignBool(true)\n\t\tna.AssembleEntry(\"bar\").AssignBool(false)\n\t\tna.AssembleEntry(\"nested\").CreateMap(2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(\"alink\").AssignLink(leafAlphaLnk)\n\t\t\tna.AssembleEntry(\"nonlink\").AssignString(\"zoo\")\n\t\t})\n\t}))\n\tmiddleListNode, middleListNodeLnk = encode(fluent.MustBuildList(basicnode.Prototype__List{}, 4, func(na fluent.ListAssembler) {\n\t\tna.AssembleValue().AssignLink(leafAlphaLnk)\n\t\tna.AssembleValue().AssignLink(leafAlphaLnk)\n\t\tna.AssembleValue().AssignLink(leafBetaLnk)\n\t\tna.AssembleValue().AssignLink(leafAlphaLnk)\n\t}))\n\trootNode, rootNodeLnk = encode(fluent.MustBuildMap(basicnode.Prototype__Map{}, 4, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"plain\").AssignString(\"olde string\")\n\t\tna.AssembleEntry(\"linkedString\").AssignLink(leafAlphaLnk)\n\t\tna.AssembleEntry(\"linkedMap\").AssignLink(middleMapNodeLnk)\n\t\tna.AssembleEntry(\"linkedList\").AssignLink(middleListNodeLnk)\n\t}))\n)\n*/\n\n// ExploreRecursiveWithStop builds a recursive selector node with a stop condition\nfunc ExploreRecursiveWithStop(limit selector.RecursionLimit, sequence builder.SelectorSpec, stopLnk datamodel.Link) datamodel.Node {\n\tnp := basicnode.Prototype__Map{}\n\treturn fluent.MustBuildMap(np, 1, func(na fluent.MapAssembler) {\n\t\t// RecursionLimit\n\t\tna.AssembleEntry(selector.SelectorKey_ExploreRecursive).CreateMap(3, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(selector.SelectorKey_Limit).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tswitch limit.Mode() {\n\t\t\t\tcase selector.RecursionLimit_Depth:\n\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_LimitDepth).AssignInt(limit.Depth())\n\t\t\t\tcase selector.RecursionLimit_None:\n\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_LimitNone).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\tdefault:\n\t\t\t\t\tpanic(\"Unsupported recursion limit type\")\n\t\t\t\t}\n\t\t\t})\n\t\t\t// Sequence\n\t\t\tna.AssembleEntry(selector.SelectorKey_Sequence).CreateMap(1, func(na fluent.MapAssembler) {\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_ExploreUnion).CreateList(2, func(na fluent.ListAssembler) {\n\t\t\t\t\tna.AssembleValue().AssignNode(fluent.MustBuildMap(np, 1, func(na fluent.MapAssembler) {\n\t\t\t\t\t\tna.AssembleEntry(selector.SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {})\n\t\t\t\t\t}))\n\t\t\t\t\tna.AssembleValue().AssignNode(sequence.Node())\n\t\t\t\t})\n\t\t\t})\n\n\t\t\t// Stop condition\n\t\t\tif stopLnk != nil {\n\t\t\t\tcond := fluent.MustBuildMap(basicnode.Prototype__Map{}, 1, func(na fluent.MapAssembler) {\n\t\t\t\t\tna.AssembleEntry(string(selector.ConditionMode_Link)).AssignLink(stopLnk)\n\t\t\t\t})\n\t\t\t\tna.AssembleEntry(selector.SelectorKey_StopAt).AssignNode(cond)\n\t\t\t}\n\t\t})\n\t})\n\n}\n\nfunc TestStopAtLink(t *testing.T) {\n\tssb := builder.NewSelectorSpecBuilder(basicnode.Prototype__Any{})\n\tt.Run(\"test ExploreRecursive stopAt with simple node\", func(t *testing.T) {\n\t\t// Selector that passes through the map\n\t\ts, err := selector.CompileSelector(ExploreRecursiveWithStop(\n\t\t\tselector.RecursionLimitNone(), ssb.ExploreAll(ssb.ExploreRecursiveEdge()),\n\t\t\tmiddleMapNodeLnk))\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tvar order int\n\t\tlsys := cidlink.DefaultLinkSystem()\n\t\tlsys.SetReadStorage(&store)\n\t\terr = traversal.Progress{\n\t\t\tCfg: &traversal.Config{\n\t\t\t\tLinkSystem:                     lsys,\n\t\t\t\tLinkTargetNodePrototypeChooser: basicnode.Chooser,\n\t\t\t},\n\t\t}.WalkMatching(rootNode, s, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\t// fmt.Println(\"Order\", order, prog.Path.String())\n\t\t\tswitch order {\n\t\t\tcase 0:\n\t\t\t\t// Root\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"\")\n\t\t\tcase 1:\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"plain\")\n\t\t\t\tqt.Check(t, n, nodetests.NodeContentEquals, basicnode.NewString(\"olde string\"))\n\t\t\tcase 2:\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"linkedString\")\n\t\t\tcase 3:\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"linkedList\")\n\t\t\t// We are starting to traverse the linkedList, we passed through the map already\n\t\t\tcase 4:\n\t\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, \"linkedList/0\")\n\t\t\t}\n\t\t\torder++\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, order, qt.Equals, 8)\n\t})\n}\n\n// mkChain creates a DAG that represent a chain of subDAGs.\n// The stopAt condition is extremely appealing for these use cases, as we can\n// partially sync a chain using ExploreRecursive without having to sync the\n// chain from scratch if we are already partially synced\nfunc mkChain() (datamodel.Node, []datamodel.Link) {\n\tleafAlpha, leafAlphaLnk = encode(basicnode.NewString(\"alpha\"))\n\tleafBeta, leafBetaLnk = encode(basicnode.NewString(\"beta\"))\n\tmiddleMapNode, middleMapNodeLnk = encode(fluent.MustBuildMap(basicnode.Prototype__Map{}, 3, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"foo\").AssignBool(true)\n\t\tna.AssembleEntry(\"bar\").AssignBool(false)\n\t\tna.AssembleEntry(\"nested\").CreateMap(2, func(na fluent.MapAssembler) {\n\t\t\tna.AssembleEntry(\"alink\").AssignLink(leafAlphaLnk)\n\t\t\tna.AssembleEntry(\"nonlink\").AssignString(\"zoo\")\n\t\t})\n\t}))\n\tmiddleListNode, middleListNodeLnk = encode(fluent.MustBuildList(basicnode.Prototype__List{}, 4, func(na fluent.ListAssembler) {\n\t\tna.AssembleValue().AssignLink(leafAlphaLnk)\n\t\tna.AssembleValue().AssignLink(leafAlphaLnk)\n\t\tna.AssembleValue().AssignLink(leafBetaLnk)\n\t\tna.AssembleValue().AssignLink(leafAlphaLnk)\n\t}))\n\n\t_, ch1Lnk := encode(fluent.MustBuildMap(basicnode.Prototype__Map{}, 4, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"linkedList\").AssignLink(middleListNodeLnk)\n\t}))\n\t_, ch2Lnk := encode(fluent.MustBuildMap(basicnode.Prototype__Map{}, 4, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"linkedMap\").AssignLink(middleMapNodeLnk)\n\t\tna.AssembleEntry(\"ch1\").AssignLink(ch1Lnk)\n\t}))\n\t_, ch3Lnk := encode(fluent.MustBuildMap(basicnode.Prototype__Map{}, 4, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"linkedString\").AssignLink(leafAlphaLnk)\n\t\tna.AssembleEntry(\"ch2\").AssignLink(ch2Lnk)\n\t}))\n\n\theadNode, headLnk := encode(fluent.MustBuildMap(basicnode.Prototype__Map{}, 4, func(na fluent.MapAssembler) {\n\t\tna.AssembleEntry(\"plain\").AssignString(\"olde string\")\n\t\tna.AssembleEntry(\"ch3\").AssignLink(ch3Lnk)\n\t}))\n\treturn headNode, []datamodel.Link{headLnk, ch3Lnk, ch2Lnk, ch1Lnk}\n}\n\nfunc TestStopInChain(t *testing.T) {\n\tchainNode, chainLnks := mkChain()\n\t// Stay in head\n\tstopAtInChainTest(t, chainNode, chainLnks[1], []string{\"\", \"plain\"})\n\t// Get head and following block\n\tstopAtInChainTest(t, chainNode, chainLnks[2], []string{\"\", \"plain\", \"ch3\", \"ch3/linkedString\"})\n\t// One more\n\tstopAtInChainTest(t, chainNode, chainLnks[3], []string{\n\t\t\"\",\n\t\t\"plain\",\n\t\t\"ch3\",\n\t\t\"ch3/ch2\",\n\t\t\"ch3/ch2/linkedMap\",\n\t\t\"ch3/ch2/linkedMap/bar\",\n\t\t\"ch3/ch2/linkedMap/foo\",\n\t\t\"ch3/ch2/linkedMap/nested\",\n\t\t\"ch3/ch2/linkedMap/nested/alink\",\n\t\t\"ch3/ch2/linkedMap/nested/nonlink\",\n\t\t\"ch3/linkedString\",\n\t})\n\t// Get the full chain\n\tstopAtInChainTest(t, chainNode, nil, []string{\n\t\t\"\",\n\t\t\"plain\",\n\t\t\"ch3\",\n\t\t\"ch3/ch2\",\n\t\t\"ch3/ch2/ch1\",\n\t\t\"ch3/ch2/ch1/linkedList\",\n\t\t\"ch3/ch2/ch1/linkedList/0\",\n\t\t\"ch3/ch2/ch1/linkedList/1\",\n\t\t\"ch3/ch2/ch1/linkedList/2\",\n\t\t\"ch3/ch2/ch1/linkedList/3\",\n\t\t\"ch3/ch2/linkedMap\",\n\t\t\"ch3/ch2/linkedMap/bar\",\n\t\t\"ch3/ch2/linkedMap/foo\",\n\t\t\"ch3/ch2/linkedMap/nested\",\n\t\t\"ch3/ch2/linkedMap/nested/alink\",\n\t\t\"ch3/ch2/linkedMap/nested/nonlink\",\n\t\t\"ch3/linkedString\",\n\t})\n}\n\nfunc stopAtInChainTest(t *testing.T, chainNode datamodel.Node, stopLnk datamodel.Link, expectedPaths []string) {\n\tssb := builder.NewSelectorSpecBuilder(basicnode.Prototype__Any{})\n\tt.Run(fmt.Sprintf(\"test ExploreRecursive stopAt in chain with stoplink: %s\", stopLnk), func(t *testing.T) {\n\t\ts, err := selector.CompileSelector(ExploreRecursiveWithStop(\n\t\t\tselector.RecursionLimitNone(), ssb.ExploreAll(ssb.ExploreRecursiveEdge()),\n\t\t\tstopLnk))\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tvar order int\n\t\tlsys := cidlink.DefaultLinkSystem()\n\t\tlsys.SetReadStorage(&store)\n\t\terr = traversal.Progress{\n\t\t\tCfg: &traversal.Config{\n\t\t\t\tLinkSystem:                     lsys,\n\t\t\t\tLinkTargetNodePrototypeChooser: basicnode.Chooser,\n\t\t\t},\n\t\t}.WalkMatching(chainNode, s, func(prog traversal.Progress, n datamodel.Node) error {\n\t\t\t//fmt.Println(\"Order\", order, prog.Path.String())\n\t\t\tqt.Check(t, order < len(expectedPaths), qt.IsTrue)\n\t\t\tqt.Check(t, prog.Path.String(), qt.Equals, expectedPaths[order])\n\t\t\torder++\n\t\t\treturn nil\n\t\t})\n\t\tqt.Check(t, err, qt.IsNil)\n\t\tqt.Check(t, order, qt.Equals, len(expectedPaths))\n\t})\n}\n"
  },
  {
    "path": "version.json",
    "content": "{\n  \"version\": \"v0.23.0\"\n}\n"
  }
]