[
  {
    "path": ".cargo/config.toml",
    "content": "[alias]\nxtask = \"run --package xtask --\"\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches: [\"main\"]\n  pull_request:\n    branches: [\"main\"]\n\nenv:\n  CARGO_TERM_COLOR: always\n\njobs:\n  build-mac:\n    runs-on: macos-14\n    strategy:\n      fail-fast: false\n    steps:\n      - uses: actions/checkout@v3\n      - uses: jdx/mise-action@v3\n      - name: Install Rust stable\n        run: |\n          rustup toolchain install stable\n          rustup target add wasm32-wasip1\n          rustup component add rustfmt\n      - name: Install Clang 19\n        run: brew install llvm@19\n      - name: Run `cargo xtask ci`\n        run: CC=$(brew --prefix llvm@19)/bin/clang CXX=$(brew --prefix llvm@19)/bin/clang++ cargo xtask ci\n\n  build:\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        cpp_compiler:\n          - clang++\n          - g++\n    env:\n      CXX: ${{ matrix.cpp_compiler }}\n    steps:\n      - uses: actions/checkout@v3\n      - uses: jdx/mise-action@v3\n      - name: Install Rust stable\n        run: |\n          rustup toolchain install stable\n          rustup target add wasm32-wasip1\n          rustup component add rustfmt\n      - name: Install LLD for clang++\n        if: matrix.cpp_compiler == 'clang++'\n        run: sudo apt-get update && sudo apt-get install -y lld\n      - name: Run CI (clang++)\n        if: matrix.cpp_compiler == 'clang++'\n        run: CC=clang cargo xtask ci\n      - name: Run CI (g++)\n        if: matrix.cpp_compiler == 'g++'\n        run: cargo xtask ci\n\n  build-nightly:\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n    env:\n      CXX: g++\n    steps:\n      - uses: actions/checkout@v3\n      - uses: jdx/mise-action@v3\n      - name: Install Rust nightly\n        run: |\n          rustup toolchain install nightly\n          rustup default nightly\n          rustup target add wasm32-wasip1\n          rustup component add rustfmt\n      - name: Run CI (g++ nightly)\n        run: cargo xtask ci\n\n  build-win:\n    runs-on: windows-2022\n    steps:\n      - name: Turn off autocrlf\n        run: |\n          git config --global core.autocrlf false\n      - uses: actions/checkout@v3\n      - name: Enter VS Developer shell\n        uses: ilammy/msvc-dev-cmd@v1\n        with:\n          arch: amd64\n          vsversion: 2022\n      - uses: jdx/mise-action@v3\n      - name: Install Rust stable\n        run: |\n          rustup toolchain install stable\n          rustup target add wasm32-wasip1\n          rustup component add rustfmt\n      - name: Run `cargo xtask ci`\n        run: cargo xtask ci\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Publish\non:\n  workflow_dispatch:\njobs:\n  publish:\n    name: Publish\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v2\n        with:\n          token: ${{ secrets.PAT }}\n          fetch-depth: 0\n\n      - name: Install Rust toolchain\n        uses: actions-rs/toolchain@v1\n        with:\n          toolchain: stable\n          profile: minimal\n          override: true\n\n      - name: Install cargo-workspaces\n        uses: actions-rs/install@v0.1\n        with:\n          crate: cargo-workspaces\n          version: 0.2.44\n\n      - name: Release\n        env:\n          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}\n        shell: bash\n        run: |\n          # Check if we can skip releasing a new version\n          # (there are no changes and the job was not manually triggered)\n          export CHANGED=$(cargo workspaces changed --include-merged-tags --ignore-changes \"**/Cargo.toml\")\n          if [[ -z \"$CHANGED\" && \"$GITHUB_EVENT_NAME\" != \"workflow_dispatch\" ]]; then\n            # Nothing has changed, so don't publish a new version\n            echo \"No changes detected, skipping publish.\"\n            exit 0\n          fi\n\n          # Update version\n          git config --global user.email \"runner@gha.local\"\n          git config --global user.name \"Github Action\"\n          cargo workspaces -v version -ay --force '*' --include-merged-tags --no-git-commit --exact minor\n          export VERSION=$(cd zngur; cargo pkgid | sed -E 's/.*#(.*)/\\1/g')\n\n          # Commit and publish\n          git commit -am \"Release $VERSION\"\n          git tag \"v$VERSION\"\n          cargo workspaces -v publish --from-git --skip-published\n          git push --tags\n          git push\n"
  },
  {
    "path": ".github/workflows/site.yml",
    "content": "name: Deploy\n\non:\n  push:\n    branches:\n      - main\n    paths:\n      - book/**\n      - .github/workflows/site.yml\n  workflow_dispatch:\n\njobs:\n  deploy:\n    name: Deploy\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n    timeout-minutes: 30\n    steps:\n      - uses: actions/checkout@v3\n      - uses: dtolnay/install@mdbook\n      - run: mdbook --version\n\n      - name: Build\n        run: |\n          cd book\n          mdbook build\n      - uses: crazy-max/ghaction-github-pages@v3.1.0\n        with:\n          build_dir: book/book\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "/target\na.out\na.out.dSYM\n*.exe\n*.obj\n*.bat\n*.a\n*.o\n.vscode\ncompile_commands.json\nzngur-autozng/doc.json\nperf.data\nperf.data.old\nactual_output.txt\nflamegraph.svg\ngenerated*.*\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nmembers = [\n    \"zngur\",\n    \"zngur-cli\",\n    \"zngur-def\",\n    \"zngur-generator\",\n    \"zngur-parser\",\n    \"zngur-autozng\",\n    \"examples/*\",\n    \"xtask\",\n    \"benchmark\",\n]\n# Exclude tutorial-wasm32 from default workspace builds since it requires extra dependencies\nexclude = [\n    \"examples/tutorial-wasm32\",\n]\nresolver = \"2\"\n\n[workspace.package]\nedition = \"2024\"\nrust-version = \"1.85\"\nlicense = \"MIT OR Apache-2.0\"\n\n[profile.dev]\nopt-level = 3\n\n[profile.release]\nlto = true\n"
  },
  {
    "path": "LICENSE-APACHE",
    "content": "                              Apache License\n                        Version 2.0, January 2004\n                     http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n   \"License\" shall mean the terms and conditions for use, reproduction,\n   and distribution as defined by Sections 1 through 9 of this document.\n\n   \"Licensor\" shall mean the copyright owner or entity authorized by\n   the copyright owner that is granting the License.\n\n   \"Legal Entity\" shall mean the union of the acting entity and all\n   other entities that control, are controlled by, or are under common\n   control with that entity. For the purposes of this definition,\n   \"control\" means (i) the power, direct or indirect, to cause the\n   direction or management of such entity, whether by contract or\n   otherwise, or (ii) ownership of fifty percent (50%) or more of the\n   outstanding shares, or (iii) beneficial ownership of such entity.\n\n   \"You\" (or \"Your\") shall mean an individual or Legal Entity\n   exercising permissions granted by this License.\n\n   \"Source\" form shall mean the preferred form for making modifications,\n   including but not limited to software source code, documentation\n   source, and configuration files.\n\n   \"Object\" form shall mean any form resulting from mechanical\n   transformation or translation of a Source form, including but\n   not limited to compiled object code, generated documentation,\n   and conversions to other media types.\n\n   \"Work\" shall mean the work of authorship, whether in Source or\n   Object form, made available under the License, as indicated by a\n   copyright notice that is included in or attached to the work\n   (an example is provided in the Appendix below).\n\n   \"Derivative Works\" shall mean any work, whether in Source or Object\n   form, that is based on (or derived from) the Work and for which the\n   editorial revisions, annotations, elaborations, or other modifications\n   represent, as a whole, an original work of authorship. For the purposes\n   of this License, Derivative Works shall not include works that remain\n   separable from, or merely link (or bind by name) to the interfaces of,\n   the Work and Derivative Works thereof.\n\n   \"Contribution\" shall mean any work of authorship, including\n   the original version of the Work and any modifications or additions\n   to that Work or Derivative Works thereof, that is intentionally\n   submitted to Licensor for inclusion in the Work by the copyright owner\n   or by an individual or Legal Entity authorized to submit on behalf of\n   the copyright owner. For the purposes of this definition, \"submitted\"\n   means any form of electronic, verbal, or written communication sent\n   to the Licensor or its representatives, including but not limited to\n   communication on electronic mailing lists, source code control systems,\n   and issue tracking systems that are managed by, or on behalf of, the\n   Licensor for the purpose of discussing and improving the Work, but\n   excluding communication that is conspicuously marked or otherwise\n   designated in writing by the copyright owner as \"Not a Contribution.\"\n\n   \"Contributor\" shall mean Licensor and any individual or Legal Entity\n   on behalf of whom a Contribution has been received by Licensor and\n   subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n   this License, each Contributor hereby grants to You a perpetual,\n   worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n   copyright license to reproduce, prepare Derivative Works of,\n   publicly display, publicly perform, sublicense, and distribute the\n   Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n   this License, each Contributor hereby grants to You a perpetual,\n   worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n   (except as stated in this section) patent license to make, have made,\n   use, offer to sell, sell, import, and otherwise transfer the Work,\n   where such license applies only to those patent claims licensable\n   by such Contributor that are necessarily infringed by their\n   Contribution(s) alone or by combination of their Contribution(s)\n   with the Work to which such Contribution(s) was submitted. If You\n   institute patent litigation against any entity (including a\n   cross-claim or counterclaim in a lawsuit) alleging that the Work\n   or a Contribution incorporated within the Work constitutes direct\n   or contributory patent infringement, then any patent licenses\n   granted to You under this License for that Work shall terminate\n   as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n   Work or Derivative Works thereof in any medium, with or without\n   modifications, and in Source or Object form, provided that You\n   meet the following conditions:\n\n   (a) You must give any other recipients of the Work or\n   Derivative Works a copy of this License; and\n\n   (b) You must cause any modified files to carry prominent notices\n   stating that You changed the files; and\n\n   (c) You must retain, in the Source form of any Derivative Works\n   that You distribute, all copyright, patent, trademark, and\n   attribution notices from the Source form of the Work,\n   excluding those notices that do not pertain to any part of\n   the Derivative Works; and\n\n   (d) If the Work includes a \"NOTICE\" text file as part of its\n   distribution, then any Derivative Works that You distribute must\n   include a readable copy of the attribution notices contained\n   within such NOTICE file, excluding those notices that do not\n   pertain to any part of the Derivative Works, in at least one\n   of the following places: within a NOTICE text file distributed\n   as part of the Derivative Works; within the Source form or\n   documentation, if provided along with the Derivative Works; or,\n   within a display generated by the Derivative Works, if and\n   wherever such third-party notices normally appear. The contents\n   of the NOTICE file are for informational purposes only and\n   do not modify the License. You may add Your own attribution\n   notices within Derivative Works that You distribute, alongside\n   or as an addendum to the NOTICE text from the Work, provided\n   that such additional attribution notices cannot be construed\n   as modifying the License.\n\n   You may add Your own copyright statement to Your modifications and\n   may provide additional or different license terms and conditions\n   for use, reproduction, or distribution of Your modifications, or\n   for any such Derivative Works as a whole, provided Your use,\n   reproduction, and distribution of the Work otherwise complies with\n   the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n   any Contribution intentionally submitted for inclusion in the Work\n   by You to the Licensor shall be under the terms and conditions of\n   this License, without any additional terms or conditions.\n   Notwithstanding the above, nothing herein shall supersede or modify\n   the terms of any separate license agreement you may have executed\n   with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n   names, trademarks, service marks, or product names of the Licensor,\n   except as required for reasonable and customary use in describing the\n   origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n   agreed to in writing, Licensor provides the Work (and each\n   Contributor provides its Contributions) on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n   implied, including, without limitation, any warranties or conditions\n   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n   PARTICULAR PURPOSE. You are solely responsible for determining the\n   appropriateness of using or redistributing the Work and assume any\n   risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n   whether in tort (including negligence), contract, or otherwise,\n   unless required by applicable law (such as deliberate and grossly\n   negligent acts) or agreed to in writing, shall any Contributor be\n   liable to You for damages, including any direct, indirect, special,\n   incidental, or consequential damages of any character arising as a\n   result of this License or out of the use or inability to use the\n   Work (including but not limited to damages for loss of goodwill,\n   work stoppage, computer failure or malfunction, or any and all\n   other commercial damages or losses), even if such Contributor\n   has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n   the Work or Derivative Works thereof, You may choose to offer,\n   and charge a fee for, acceptance of support, warranty, indemnity,\n   or other liability obligations and/or rights consistent with this\n   License. However, in accepting such obligations, You may act only\n   on Your own behalf and on Your sole responsibility, not on behalf\n   of any other Contributor, and only if You agree to indemnify,\n   defend, and hold each Contributor harmless for any liability\n   incurred by, or claims asserted against, such Contributor by reason\n   of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n"
  },
  {
    "path": "LICENSE-MIT",
    "content": "Permission is hereby granted, free of charge, to any\nperson obtaining a copy of this software and associated\ndocumentation files (the \"Software\"), to deal in the\nSoftware without restriction, including without\nlimitation the rights to use, copy, modify, merge,\npublish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software\nis furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice\nshall be included in all copies or substantial portions\nof the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF\nANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\nTO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\nSHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\nIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Zngur\n\n[<img alt=\"github\" src=\"https://img.shields.io/badge/github-hkalbasi/zngur-8da0cb?style=for-the-badge&labelColor=555555&logo=github\" height=\"20\">](https://github.com/hkalbasi/zngur)\n[<img alt=\"crates.io\" src=\"https://img.shields.io/crates/v/zngur.svg?style=for-the-badge&color=fc8d62&logo=rust\" height=\"20\">](https://crates.io/crates/zngur)\n[<img alt=\"docs.rs\" src=\"https://img.shields.io/badge/docs.rs-zngur-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs\" height=\"20\">](https://docs.rs/zngur)\n[<img alt=\"build status\" src=\"https://img.shields.io/github/actions/workflow/status/hkalbasi/zngur/ci.yml?branch=main&style=for-the-badge\" height=\"20\">](https://github.com/hkalbasi/zngur/actions?query=branch%3Amain)\n\nZngur (/zængɑr/) is a C++/Rust interop tool. It tries to expose arbitrary Rust types, methods and functions, while preserving its\nsemantics and ergonomics as much as possible. Using Zngur, you can use arbitrary Rust crates in your C++ code as easily as using it in\nnormal Rust code, and you can write idiomatic Rusty APIs for your C++ library inside C++. See [the documentation](https://hkalbasi.github.io/zngur/)\nfor more info.\n\n## Demo\n\n```C++\n#include <iostream>\n#include <vector>\n\n#include \"./generated.h\"\n\n// Rust values are available in the `::rust` namespace from their absolute path\n// in Rust\ntemplate <typename T> using Vec = rust::std::vec::Vec<T>;\ntemplate <typename T> using Option = rust::std::option::Option<T>;\ntemplate <typename T> using BoxDyn = rust::Box<rust::Dyn<T>>;\n\n// You can implement Rust traits for your classes\ntemplate <typename T>\nclass VectorIterator : public rust::std::iter::Iterator<T> {\n  std::vector<T> vec;\n  size_t pos;\n\npublic:\n  VectorIterator(std::vector<T> &&v) : vec(v), pos(0) {}\n  ~VectorIterator() {\n    std::cout << \"vector iterator has been destructed\" << std::endl;\n  }\n\n  Option<T> next() override {\n    if (pos >= vec.size()) {\n      return Option<T>::None();\n    }\n    T value = vec[pos++];\n    // You can construct Rust enum with fields in C++\n    return Option<T>::Some(value);\n  }\n};\n\nint main() {\n  // You can call Rust functions that return things by value, and store that\n  // value in your stack.\n  auto s = Vec<int32_t>::new_();\n  s.push(2);\n  Vec<int32_t>::push(s, 5);\n  s.push(7);\n  Vec<int32_t>::push(s, 3);\n  // You can call Rust functions just like normal Rust.\n  std::cout << s.clone().into_iter().sum() << std::endl;\n  // You can catch Rust panics as C++ exceptions\n  try {\n    std::cout << \"s[2] = \" << *s.get(2).unwrap() << std::endl;\n    std::cout << \"s[4] = \" << *s.get(4).unwrap() << std::endl;\n  } catch (rust::Panic e) {\n    std::cout << \"Rust panic happened\" << std::endl;\n  }\n  int state = 0;\n  // You can convert a C++ lambda into a `Box<dyn Fn>` and friends.\n  auto f = BoxDyn<rust::Fn<int32_t, int32_t>>::make_box([&](int32_t x) {\n    state += x;\n    std::cout << \"hello \" << x << \" \" << state << \"\\n\";\n    return x * 2;\n  });\n  // And pass it to Rust functions that accept closures.\n  auto x = s.into_iter().map(std::move(f)).sum();\n  std::cout << x << \" \" << state << \"\\n\";\n  std::vector<int32_t> vec{10, 20, 60};\n  // You can convert a C++ type that implements `Trait` to a `Box<dyn Trait>`.\n  // `make_box` is similar to the `make_unique`, it takes constructor arguments\n  // and construct it inside the `Box` (instead of `unique_ptr`).\n  auto vec_as_iter = BoxDyn<rust::std::iter::Iterator<int32_t>>::make_box<\n      VectorIterator<int32_t>>(std::move(vec));\n  // Then use it like a normal Rust value.\n  auto t = vec_as_iter.collect();\n  // Some utilities are also provided. For example, `zngur_dbg` is the\n  // equivalent of `dbg!` macro.\n  zngur_dbg(t);\n}\n```\n\nOutput:\n\n```\n17\ns[2] = 7\nthread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', examples/simple/src/generated.rs:186:39\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\ns[4] = Rust panic happened\nhello 2 2\nhello 5 7\nhello 7 14\nhello 3 17\n34 17\nvector iterator has been destructed\n[main.cpp:71] t = [\n    10,\n    20,\n    60,\n]\n```\n\nSee the [`examples/simple`](https://github.com/HKalbasi/zngur/blob/main/examples/simple) if you want to build and run it.\n\n## Installation\n\nThe `zngur` CLI tool can be installed with cargo:\n\n```\ncargo install zngur-cli\n```\n\n<br>\n\n## Contributing\n\nBecause our examples require invoking a built `zngur` binary, we use `xtask` to orchestrate the build process and validate correctness across all examples.\n\n1. **Install mise**: This project uses `mise` for tool management. Install it from [mise.jdx.dev](https://mise.jdx.dev/) or via your package manager.\n\n2. **Install dependencies**: Run `mise install` to install the required tools. See [`mise.toml`](/mise.toml) for the list of installed tools.\n\n3. **Run the CI locally**: The official command to run our CI is:\n   ```bash\n   CXX=clang++ cargo xtask ci\n   ```\n   You can use any of the C++ compilers mentioned in our CI workflow: `clang++` or `g++`.\n   Other compilers may work, but are not guaranteed to by our CI testing.\n\n### Formatting\n\nYou may run `cargo xtask format-book` to run `mdformat` on the `/book` directory.\n\n#### License\n\n<sup>\nLicensed under either of <a href=\"LICENSE-APACHE\">Apache License, Version\n2.0</a> or <a href=\"LICENSE-MIT\">MIT license</a> at your option.\n</sup>\n\n<br>\n\n<sub>\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in this project by you, as defined in the Apache-2.0 license,\nshall be dual licensed as above, without any additional terms or conditions.\n</sub>\n"
  },
  {
    "path": "benchmark/.gitignore",
    "content": "/target\n"
  },
  {
    "path": "benchmark/Cargo.toml",
    "content": "[package]\nname = \"benchmark\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[dependencies]\n\n[dev-dependencies]\ncriterion = { version = \"0.5\", features = [\"html_reports\"] }\n\n[build-dependencies]\ncc = \"1.0\"\nbuild-rs = \"0.1.2\"\nzngur = { path = \"../zngur\" }\n\n[[bench]]\nname = \"simple\"\nharness = false\n"
  },
  {
    "path": "benchmark/benches/simple.rs",
    "content": "use criterion::{Criterion, criterion_group, criterion_main};\nuse std::hint::black_box;\n\nfn criterion_benchmark(c: &mut Criterion) {\n    c.bench_function(\"build_vec_by_push 10_000 rust\", |b| {\n        b.iter(|| benchmark::build_vec_by_push_rust(black_box(10_000)))\n    });\n    c.bench_function(\"build_vec_by_push 10_000 cpp\", |b| {\n        b.iter(|| benchmark::build_vec_by_push_cpp(black_box(10_000)))\n    });\n}\n\ncriterion_group!(benches, criterion_benchmark);\ncriterion_main!(benches);\n"
  },
  {
    "path": "benchmark/build.rs",
    "content": "use zngur::Zngur;\n\nfn main() {\n    build::rerun_if_changed(\"main.zng\");\n    build::rerun_if_changed(\"impls.cpp\");\n\n    #[cfg(not(target_os = \"windows\"))]\n    let cxx = std::env::var(\"CXX\").unwrap_or(\"c++\".to_owned());\n\n    #[cfg(not(target_os = \"windows\"))]\n    let lto_enabled = cxx.ends_with(\"clang++\") && cfg!(target_os = \"linux\");\n\n    #[cfg(not(target_os = \"windows\"))]\n    if lto_enabled {\n        build::rustc_env(\"RUSTC_FLAGS\", \"-C linker-plugin-lto -C linker=clang\");\n        build::rustc_link_arg(\"-fuse-ld=lld\");\n    }\n\n    let crate_dir = build::cargo_manifest_dir();\n    let out_dir = build::out_dir();\n\n    Zngur::from_zng_file(crate_dir.join(\"main.zng\"))\n        .with_cpp_file(out_dir.join(\"generated.cpp\"))\n        .with_h_file(out_dir.join(\"generated.h\"))\n        .with_rs_file(out_dir.join(\"generated.rs\"))\n        .with_zng_header_in_place_as(true)\n        .generate();\n\n    let my_build = &mut cc::Build::new();\n    let my_build = my_build.cpp(true).std(\"c++17\");\n\n    #[cfg(not(target_os = \"windows\"))]\n    my_build.compiler(cxx);\n\n    my_build.include(&crate_dir).include(&out_dir);\n\n    #[cfg(not(target_os = \"windows\"))]\n    if lto_enabled {\n        my_build.flag(\"-flto\");\n    }\n\n    let my_build = || my_build.clone();\n\n    my_build()\n        .file(out_dir.join(\"generated.cpp\"))\n        .compile(\"zngur_generated\");\n    my_build().file(\"impls.cpp\").compile(\"impls\");\n}\n"
  },
  {
    "path": "benchmark/impls.cpp",
    "content": "#include <generated.h>\n\ntemplate <typename T>\nusing Vec = rust::std::vec::Vec<T>;\nusing u64 = uint64_t;\n\nnamespace rust::exported_functions {\n    auto build_vec_by_push_cpp(u64 n) -> Vec<u64> {\n        auto v = Vec<u64>::new_();\n        for (u64 i = 0; i < n; ++i) {\n            v.push(i);\n        }\n        return v;\n    }\n}"
  },
  {
    "path": "benchmark/main.zng",
    "content": "type ::std::vec::Vec<u64> {\n    #layout(size = 24, align = 8);\n    wellknown_traits(Debug);\n\n    fn new() -> ::std::vec::Vec<u64>;\n    fn push(&mut self, u64);\n}\n\nextern \"C++\" {\n    fn build_vec_by_push_cpp(u64) -> ::std::vec::Vec<u64>;\n}\n"
  },
  {
    "path": "benchmark/src/lib.rs",
    "content": "mod generated {\n    include!(concat!(env!(\"OUT_DIR\"), \"/generated.rs\"));\n}\n\npub fn build_vec_by_push_rust(n: u64) -> Vec<u64> {\n    let mut v = Vec::new();\n    for i in 0..n {\n        v.push(i);\n    }\n    v\n}\n\npub fn build_vec_by_push_cpp(n: u64) -> Vec<u64> {\n    generated::build_vec_by_push_cpp(n)\n}\n"
  },
  {
    "path": "cspell-words.txt",
    "content": "alignas\nalignof\nassocs\nautozng\nbarbaz\nbarbazxxx\nblobstore\ncerr\nchumsky\ncloneable\nConds\nconstexpr\ncout\ncplusplus\nCPTE\nCrubit\ncsignal\ncstddef\ncstdint\ncstring\nCXXFLAGS\ndecltype\ndelem\ndeinit\ndepfile\ndigset\ndiscontiguous\nemsdk\nendl\nfastlink\nflto\nfoldl\nfoldr\nfuncs\nfvec\nGNUC\nhkalbasi\nilog\nimpls\nindexmap\ninplace\nitertools\nlibexample\nLIBPATH\nlibyourcrate\nlwasi\nmdformat\nmemcpy\nmoveit\nmsvc\nnewtype\nnoexcept\nnmake\nntdll\npmut\nprimitve\nprintln\nptrdiff\nrefmut\nrelpath\nrepr\nrespecify\nrlib\nrustc\nRUSTC\nRUSTFLAGS\nRUSTLIB\nRustup\nrustup\nrustyline\nRustyline\nscrutinee\nscrutinees\nserde\nSIGSEGV\nsptl\nsref\nssize\nstaticlib\nstrvec\nstmnt\nunimportability\nUninit\nuninit\nusize\nuserenv\nWASI\nWINLIBS\nwasi\nWASIFLAGS\nwasip\nwasmtime\nxshell\nxtask\nzngur\nZngur\nZngur's\nzngur's\nzængɑr\nzigza\nzoop\nifndef\nendif\nifdef\nselectany\ndeclspec\nelif\naskama\nendfor\n"
  },
  {
    "path": "cspell.json",
    "content": "{\n    \"$schema\": \"https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json\",\n    \"version\": \"0.2\",\n    \"dictionaryDefinitions\": [\n        {\n            \"name\": \"project-words\",\n            \"path\": \"./cspell-words.txt\",\n            \"addWords\": true\n        }\n    ],\n    \"dictionaries\": [\n        \"project-words\"\n    ],\n    \"ignorePaths\": [\n        \"target\",\n        \"*generated*.*\",\n        \"/cspell-words.txt\",\n        \"*.zng.h\",\n        \"*.svg\",\n        \"examples/**/Makefile\",\n        \"examples/**/NMakefile\",\n        \"actual_output.txt\"\n    ]\n}\n"
  },
  {
    "path": "dprint.json",
    "content": "{\n  \"markdown\": {\n    \"lineWidth\": 100,\n    \"emphasisKind\": \"asterisks\",\n    \"strongKind\": \"asterisks\",\n    \"textWrap\": \"maintain\",\n    \"ignoreDirective\": \"dprint-ignore\",\n    \"ignoreFileDirective\": \"dprint-ignore-file\",\n    \"ignoreStartDirective\": \"dprint-ignore-start\",\n    \"ignoreEndDirective\": \"dprint-ignore-end\",\n    \"newLineKind\": \"lf\"\n  },\n  \"includes\": [\"book/src/**/*.md\", \"*.md\"],\n  \"excludes\": [],\n  \"plugins\": [\"https://plugins.dprint.dev/markdown-0.17.8.wasm\"]\n}\n"
  },
  {
    "path": "examples/.gitignore",
    "content": "zngur.h\n*.zng.*\n"
  },
  {
    "path": "examples/char/.gitignore",
    "content": "generated.h\ngenerated.rs"
  },
  {
    "path": "examples/char/Cargo.toml",
    "content": "[package]\nname = \"example-char\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"staticlib\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "examples/char/Makefile",
    "content": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_char.a\n\t${CXX} -std=c++11 -Werror -I. main.cpp -g -L ../../target/release/ -l example_char\n\n../../target/release/libexample_char.a:\n\tcargo build --release\n\ngenerated.h ./src/generated.rs: main.zng\n\tcd ../../zngur-cli && cargo run g -i ../examples/char/main.zng --crate-name \"crate\"\n\n.PHONY: ../../target/release/libexample_char.a generated.h clean\n\nclean:\n\trm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt\n"
  },
  {
    "path": "examples/char/NMakefile",
    "content": "CXX = cl.exe\r\n# MSVC doesn't support earlier that c++14\r\nCXXFLAGS = /W4 /DEBUG /EHsc /std:c++14 \r\nWINLIBS = ntdll.lib\r\n\r\nEXAMPLE_NAME = char\r\n\r\nGENERATED = generated.h src/generated.rs\r\n\r\nRUSTLIB_PATH = ../../target/release/\r\n\r\nRUSTLIB = example_$(EXAMPLE_NAME).lib\r\n\r\na.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)\r\n\t$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)\r\n\r\n$(RUSTLIB_PATH)/$(RUSTLIB) :\r\n\tcargo build --release\r\n\r\n$(GENERATED) : main.zng\r\n\tcd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name \"crate\"\r\n\r\nclean :\r\n\t- del /f /q generated.h generated.cpp src\\generated.rs a.exe main.obj actual_output.txt 2>nul\r\n"
  },
  {
    "path": "examples/char/expected_output.txt",
    "content": "Rust received char: 'A' (U+0041)\nRust received char: 'é' (U+00E9)\nRust received char: 'Z' (U+005A)\nRust received char: '�' (U+FFFD)\n"
  },
  {
    "path": "examples/char/main.cpp",
    "content": "#include \"./generated.h\"\n\nusing ::operator\"\"_rs;\n\nint main() {\n    // Pass a char literal directly using the _rs suffix\n    rust::crate::CharPrinter::print(U'A'_rs);\n\n    // Pass a char from a char32_t variable\n    char32_t c = U'\\u00E9'; // é\n    rust::crate::CharPrinter::print(operator\"\"_rs(c));\n\n    // Use a char in a predicate\n    if (rust::crate::CharPrinter::is_alphabetic(U'z'_rs)) {\n        rust::crate::CharPrinter::print(rust::crate::CharPrinter::to_uppercase(U'z'_rs));\n    }\n\n    // Invalid chars are replaced with U+FFFD\n    char32_t invalid = 0xD800; // Surrogate code point\n    rust::crate::CharPrinter::print(operator\"\"_rs(invalid));\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/char/main.zng",
    "content": "type char {\n  #layout(size = 4, align = 4);\n  wellknown_traits(Copy);\n}\n\ntype bool {\n  #layout(size = 1, align = 1);\n  wellknown_traits(Copy);\n}\n\ntype crate::CharPrinter {\n  #layout(size = 0, align = 1);\n  fn print(char);\n  fn is_alphabetic(char) -> bool;\n  fn to_uppercase(char) -> char;\n}\n\n"
  },
  {
    "path": "examples/char/src/lib.rs",
    "content": "#[rustfmt::skip]\nmod generated;\n\nstruct CharPrinter;\n\nimpl CharPrinter {\n    fn print(c: char) {\n        println!(\"Rust received char: '{}' (U+{:04X})\", c, c as u32);\n    }\n\n    fn is_alphabetic(c: char) -> bool {\n        c.is_alphabetic()\n    }\n\n    fn to_uppercase(c: char) -> char {\n        c.to_uppercase().next().unwrap_or(c)\n    }\n}\n"
  },
  {
    "path": "examples/conditional/.gitignore",
    "content": "generated.h\r\ngenerated.rs\r\ngenerated*.rs\r\ngenerated.cpp\r\nhistory.txt\r\nb.out\r\n"
  },
  {
    "path": "examples/conditional/Cargo.toml",
    "content": "[package]\r\nname = \"example-conditional\"\r\nversion = \"0.9.0\"\r\nedition.workspace = true\r\nrust-version.workspace = true\r\nlicense.workspace = true\r\npublish = false\r\n\r\n[lib]\r\ncrate-type = [\"staticlib\"]\r\n\r\n[features]\r\ndefault = []\r\nfloat-values = []\r\n\r\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\r\n\r\n[dependencies]\n"
  },
  {
    "path": "examples/conditional/Makefile",
    "content": "both:: a.out b.out\r\n\r\na.out: main.cpp include/float/generated.h src/lib.rs ../../target/release/libexample_conditional.a\r\n\t${CXX} -std=c++20 -Werror main.cpp -g -I include/float -o a.out -L../../target/release -l example_conditional\r\n\r\nb.out: main.cpp include/int/generated.h src/lib.rs ../../target/debug/libexample_conditional.a\r\n\t${CXX} -std=c++20 -Werror main.cpp -g -I include/int -o b.out -L../../target/debug -l example_conditional\r\n\r\n../../target/release/libexample_conditional.a: ./src/generated_float.rs\r\n\tcargo build --release -F \"float-values\"\r\n\r\n../../target/debug/libexample_conditional.a: ./src/generated_int.rs\r\n\tcargo build\r\n\r\ninclude/float/generated.h ./src/generated_float.rs: main.zng\r\n\tmkdir -p include/float\r\n\tcd ../../zngur-cli && cargo run g -i ../examples/conditional/main.zng --h-file ../examples/conditional/include/float/generated.h --rs-file ../examples/conditional/src/generated_float.rs -F \"float-values\" --load-cfg-from-rustc --use-cargo-rustc --profile=release --package example-conditional --crate-name \"crate\"\r\n\r\ninclude/int/generated.h ./src/generated_int.rs: main.zng\r\n\tmkdir -p include/int\r\n\tcd ../../zngur-cli && cargo run g -i ../examples/conditional/main.zng --h-file ../examples/conditional/include/int/generated.h --rs-file ../examples/conditional/src/generated_int.rs --load-cfg-from-rustc --crate-name \"crate\"\r\n\r\n.PHONY: ../../target/release/libexample_conditional.a ../../target/debug/libexample_conditional.a include/float/generated.h include/int/generated.h clean\r\n\r\nclean:\r\n\trm -f include/float/generated.h include/int/generated.h generated.cpp src/generated_float.rs src/generated_int.rs a.out b.out actual_output.txt\r\n"
  },
  {
    "path": "examples/conditional/NMakefile",
    "content": "CXX = cl.exe\r\nCXXFLAGS = /W4 /DEBUG /EHsc /std:c++20 \r\nWINLIBS = ntdll.lib Userenv.lib Ws2_32.lib\r\n\r\nEXAMPLE_NAME = conditional\r\n\r\nGENERATED_A = include/float/generated.h ./src/generated_float.rs\r\nGENERATED_B = include/int/generated.h ./src/generated_int.rs\r\n\r\nRUSTLIB_PATH_A = ../../target/release/\r\nRUSTLIB_PATH_B = ../../target/debug/\r\n\r\nRUSTLIB = example_$(EXAMPLE_NAME).lib\r\n\r\nall : a.exe b.exe\r\n\r\na.exe : main.cpp  src/lib.rs $(GENERATED_A) $(RUSTLIB_PATH_A)/$(RUSTLIB)\r\n\t$(CXX) $(CXXFLAGS) /c main.cpp /I include/float /Fo: \"a\"\r\n\t$(CXX) $(CXXFLAGS) a.obj /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH_A)\r\n\r\nb.exe : main.cpp  src/lib.rs $(GENERATED_B) $(RUSTLIB_PATH_B)/$(RUSTLIB)\r\n\t$(CXX) $(CXXFLAGS) /c main.cpp /I include/int /Fo: \"b\"\r\n\t$(CXX) $(CXXFLAGS) b.obj /Fe:b.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH_B)\r\n\r\n$(RUSTLIB_PATH_A)/$(RUSTLIB) :\r\n\tcargo build --release -F \"float-values\"\r\n\r\n$(RUSTLIB_PATH_B)/$(RUSTLIB) :\r\n\tcargo build\r\n\r\n$(GENERATED_A) : main.zng\r\n\tIF NOT EXIST \"include\" mkdir include\r\n\tIF NOT EXIST \"include\\float\" mkdir \"include\\float\"\r\n\tcd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --h-file ../examples/$(EXAMPLE_NAME)/include/float/generated.h --rs-file ../examples/$(EXAMPLE_NAME)/src/generated_float.rs -F \"float-values\" --load-cfg-from-rustc --use-cargo-rustc --profile=release --package example-conditional --crate-name \"crate\"\r\n\r\n$(GENERATED_B) : main.zng\r\n\tIF NOT EXIST \"include\" mkdir include\r\n\tIF NOT EXIST \"include\\int\" mkdir \"include\\int\"\r\n\tcd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --h-file ../examples/$(EXAMPLE_NAME)/include/int/generated.h --rs-file ../examples/$(EXAMPLE_NAME)/src/generated_int.rs --load-cfg-from-rustc --crate-name \"crate\"\r\n\r\nclean :\r\n\t- del /f /q include\\float\\generated.h include\\int\\generated.h generated.cpp src\\generated_float.rs src\\generated_int.rs a.exe b.exe a.obj b.obj actual_output.txt 2>nul\r\n"
  },
  {
    "path": "examples/conditional/README.md",
    "content": "# Example: Conditional\n\nA example, used to demonstrate conditional compilation\n\nTo run this example:\n\n```\nmake\n./a.out\n```\n"
  },
  {
    "path": "examples/conditional/expected_output.txt",
    "content": "KVPair(size = 32, align = 8){foo : 1.000000}\n[main.cpp:44] pair = KeyValuePair[f64] { key: \"foo\", value: 1.0, }\nKVPair(size = 32, align = 8){bar : 2.000000}\n[main.cpp:44] pair = KeyValuePair[f64] { key: \"bar\", value: 2.0, }\nKVPair(size = 32, align = 8){baz : 3.000000}\n[main.cpp:44] pair = KeyValuePair[f64] { key: \"baz\", value: 3.0, }\nKVPair(size = 32, align = 8){abc : 4.000000}\n[main.cpp:44] pair = KeyValuePair[f64] { key: \"abc\", value: 4.0, }\nKVPair(size = 32, align = 8){foo : 1}\n[main.cpp:44] pair = KeyValuePair[i32] { key: \"foo\", value: 1, }(with debug_assertions)\nKVPair(size = 32, align = 8){bar : 2}\n[main.cpp:44] pair = KeyValuePair[i32] { key: \"bar\", value: 2, }(with debug_assertions)\nKVPair(size = 32, align = 8){baz : 3}\n[main.cpp:44] pair = KeyValuePair[i32] { key: \"baz\", value: 3, }(with debug_assertions)\nKVPair(size = 32, align = 8){abc : 4}\n[main.cpp:44] pair = KeyValuePair[i32] { key: \"abc\", value: 4, }(with debug_assertions)\n"
  },
  {
    "path": "examples/conditional/main.cpp",
    "content": "\r\n#include <cmath>\r\n#include <iostream>\r\n#include <string>\r\n#include <string_view>\r\n#include <utility>\r\n#include <vector>\r\n\r\n#include \"generated.h\"\r\n\r\n// Rust values are available in the `::rust` namespace from their absolute path\r\n// in Rust\r\ntemplate <typename T> using Vec = rust::std::vec::Vec<T>;\r\ntemplate <typename T> using Option = rust::std::option::Option<T>;\r\n\r\nusing KVPair = rust::crate::KeyValuePair;\r\n\r\n#ifdef ZNGUR_CFG_FEATURE_FLOAT_VALUES\r\nusing KVPairValue_T = ::std::double_t;\r\n#else\r\nusing KVPairValue_T = ::std::int32_t;\r\n#endif\r\n\r\nint main() {\r\n  auto s = Vec<KVPair>::new_();\r\n\r\n  std::vector<std::pair<rust::Ref<rust::Str>, int>> pairs = {\r\n      {\"foo\"_rs, 1}, {\"bar\"_rs, 2}, {\"baz\"_rs, 3}, {\"abc\"_rs, 4}};\r\n\r\n  for (const auto &[key, value] : pairs) {\r\n    s.push(KVPair{key.to_owned(), static_cast<KVPairValue_T>(value)});\r\n  }\r\n  auto it = s.iter();\r\n  for (auto next = it.next(); next.matches_Some(); next = it.next()) {\r\n    auto pair = next.unwrap();\r\n    rust::Ref<rust::std::string::String> key = pair.key;\r\n    KVPairValue_T value = pair.value;\r\n    std::cout << \"KVPair(size = \" << KVPair::self_size()\r\n              << \", align = \" << KVPair::self_align() << \"){\"\r\n              << std::string_view(\r\n                     reinterpret_cast<const char *>(key.as_str().as_ptr()),\r\n                     key.len())\r\n              << \" : \" << std::to_string(value) << \"}\\n\";\r\n    zngur_dbg(pair);\r\n  }\r\n}\r\n"
  },
  {
    "path": "examples/conditional/main.zng",
    "content": "#convert_panic_to_exception\r\n#unstable(cfg_if)\r\n\r\ntype str {\r\n    wellknown_traits(?Sized, Debug);\r\n\r\n    fn as_ptr(&self) -> *const u8;\r\n    fn len(&self) -> usize;\r\n    fn to_owned(&self) -> ::std::string::String;\r\n}\r\n\r\ntype ::std::string::String {\r\n    #layout(size = 24, align = 8);\r\n    wellknown_traits(Debug);\r\n\r\n    fn clone(&self) -> ::std::string::String;\r\n    fn push_str(&mut self, &str);\r\n    fn len(&self) -> usize;\r\n    fn as_str(&self) -> &str;\r\n}\r\n\r\nmod crate {\r\n\r\n    type KeyValuePair {\r\n        #layout(size = 32, align = 8);\r\n\r\n        wellknown_traits(Debug);\r\n\r\n        #if cfg!(feature.\"float-values\") {\r\n            constructor { key: ::std::string::String, value: f64 };\r\n        } #else {\r\n            constructor { key: ::std::string::String, value: i32 };\r\n        }\r\n\r\n        fn self_size() -> usize;\r\n        fn self_align() -> usize;\r\n\r\n        field key (offset = 0, type = ::std::string::String );\r\n\r\n        #if cfg!(feature.\"float-values\") {\r\n            field value (offset = 24, type = f64 );\r\n        } #else {\r\n            field value (offset = 24, type = i32 );\r\n        }\r\n    }\r\n\r\n}\r\n\r\nmod ::std {\r\n\r\n    type option::Option<usize> {\r\n        #layout(size = 16, align = 8);\r\n\r\n        constructor None;\r\n        constructor Some(usize);\r\n\r\n        fn unwrap(self) -> usize;\r\n    }\r\n\r\n    type option::Option<crate::KeyValuePair> {\r\n        #layout(size = 32, align = 8);\r\n\r\n        constructor None;\r\n        constructor Some(crate::KeyValuePair);\r\n\r\n        fn unwrap(self) -> crate::KeyValuePair;\r\n    }\r\n\r\n    type option::Option<&crate::KeyValuePair> {\r\n        #layout(size = 8, align = 8);\r\n        wellknown_traits(Copy);\r\n\r\n        constructor None;\r\n        constructor Some(&crate::KeyValuePair);\r\n\r\n        fn unwrap(self) -> &crate::KeyValuePair;\r\n    }\r\n\r\n\r\n    mod vec {\r\n        type Vec<crate::KeyValuePair> {\r\n            #layout(size = 24, align = 8);\r\n            \r\n            wellknown_traits(Debug);\r\n\r\n            fn new() -> Vec<crate::KeyValuePair>;\r\n            fn push(&mut self, crate::KeyValuePair);\r\n            fn get(&self, usize) -> ::std::option::Option<&crate::KeyValuePair> deref [crate::KeyValuePair];\r\n            fn iter(&self) -> ::std::slice::Iter<crate::KeyValuePair> deref [crate::KeyValuePair];\r\n        }\r\n    }\r\n\r\n    mod slice {\r\n        type Iter<crate::KeyValuePair> {\r\n            #layout(size = 16, align = 8);\r\n\r\n            fn len(&self) -> usize;\r\n            fn size_hint(&self) -> (usize, ::std::option::Option<usize>);\r\n            fn count(self) -> usize;\r\n            fn next(&mut self) -> ::std::option::Option<&crate::KeyValuePair>;\r\n        }\r\n    }\r\n\r\n}\r\n\r\ntype (usize, ::std::option::Option<usize>) {\r\n    #layout(size = 24, align = 8);\r\n    wellknown_traits(Debug);\r\n\r\n    field 0 (offset = 0, type = usize);\r\n    field 1 (offset = 8, type = ::std::option::Option<usize> );\r\n}\r\n"
  },
  {
    "path": "examples/conditional/src/lib.rs",
    "content": "/// only in place to allow both build to build sid by side in CI\r\n#[rustfmt::skip]\r\n#[cfg(feature = \"float-values\")]\r\nmod generated_float;\r\n\r\n#[rustfmt::skip]\r\n#[cfg(not(feature = \"float-values\"))]\r\nmod generated_int;\r\n\r\nstruct KeyValuePair {\r\n    pub key: String,\r\n    #[cfg(feature = \"float-values\")]\r\n    pub value: f64,\r\n    #[cfg(not(feature = \"float-values\"))]\r\n    pub value: i32,\r\n}\r\n\r\nimpl KeyValuePair {\r\n    fn self_size() -> usize {\r\n        std::mem::size_of::<Self>()\r\n    }\r\n    fn self_align() -> usize {\r\n        std::mem::align_of::<Self>()\r\n    }\r\n}\r\n\r\n#[cfg(debug_assertions)]\r\nimpl std::fmt::Debug for KeyValuePair {\r\n    #[cfg(feature = \"float-values\")]\r\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\r\n        write!(\r\n            f,\r\n            \"KeyValuePair[f64] {{ key: {:?}, value: {:?}, }}(with debug_assertions)\",\r\n            &self.key, &self.value\r\n        )\r\n    }\r\n    #[cfg(not(feature = \"float-values\"))]\r\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\r\n        write!(\r\n            f,\r\n            \"KeyValuePair[i32] {{ key: {:?}, value: {:?}, }}(with debug_assertions)\",\r\n            &self.key, &self.value\r\n        )\r\n    }\r\n}\r\n\r\n#[cfg(not(debug_assertions))]\r\nimpl std::fmt::Debug for KeyValuePair {\r\n    #[cfg(feature = \"float-values\")]\r\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\r\n        write!(\r\n            f,\r\n            \"KeyValuePair[f64] {{ key: {:?}, value: {:?}, }}\",\r\n            &self.key, &self.value\r\n        )\r\n    }\r\n    #[cfg(not(feature = \"float-values\"))]\r\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\r\n        write!(\r\n            f,\r\n            \"KeyValuePair[i32] {{ key: {:?}, value: {:?}, }}\",\r\n            &self.key, &self.value\r\n        )\r\n    }\r\n}\r\n"
  },
  {
    "path": "examples/cxx_demo/.gitignore",
    "content": "generated.h\ngenerated.rs\ngenerated.cpp\nhistory.txt\n"
  },
  {
    "path": "examples/cxx_demo/Cargo.toml",
    "content": "[package]\nname = \"example-cxx_demo\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n\n[build-dependencies]\ncc = \"1.0\"\nbuild-rs = \"0.1.2\"\nzngur = { path = \"../../zngur\" }\n"
  },
  {
    "path": "examples/cxx_demo/README.md",
    "content": "# Example: CXX demo\n\nThis example tries to replicate [the CXX demo](https://github.com/dtolnay/cxx/tree/master/demo) using Zngur. It tries to keep it as close\nas possible to the original CXX example, so it doesn't use Zngur features that may make the code easier, more readable, and more\nperformant. To see an example that uses all Zngur features in C++ to Rust codes, go to the osmium example.\n\nTo run this example:\n\n```\ncargo run\n```\n"
  },
  {
    "path": "examples/cxx_demo/blobstore.cpp",
    "content": "#include <algorithm>\n#include <cstdint>\n#include <set>\n#include <unordered_map>\n\n#include \"./generated.h\"\n\nclass BlobStore : public rust::crate::BlobStoreTrait {\n  class Impl {\n    friend BlobStore;\n\n    using Blob = struct {\n      std::string data;\n      std::set<std::string> tags;\n    };\n    std::unordered_map<uint64_t, Blob> blobs;\n  };\n\npublic:\n  uint64_t put(rust::RefMut<rust::crate::MultiBuf> buf) override {\n    std::string contents;\n\n    // Traverse the caller's chunk iterator.\n    //\n    // In reality there might be sophisticated batching of chunks and/or\n    // parallel upload implemented by the blob_store's C++ client.\n    while (true) {\n      auto chunk = buf.next_chunk();\n      if (chunk.len() == 0) {\n        break;\n      }\n      contents.append(reinterpret_cast<const char *>(chunk.as_ptr()),\n                      chunk.len());\n    }\n\n    // Insert into map and provide caller the handle.\n    auto blob_id = std::hash<std::string>{}(contents);\n    impl.blobs[blob_id] = {std::move(contents), {}};\n    return blob_id;\n  }\n\n  rust::Unit tag(::uint64_t blob_id,\n                 rust::Ref<rust::Str> tag) override {\n    impl.blobs[blob_id].tags.emplace((char *)tag.as_ptr(), tag.len());\n    return rust::Unit{};\n  }\n\n  rust::crate::BlobMetadata metadata(::uint64_t blob_id) override {\n    rust::crate::BlobMetadata r = rust::crate::BlobMetadata::default_();\n    auto blob = impl.blobs.find(blob_id);\n    if (blob != impl.blobs.end()) {\n      r.set_size(blob->second.data.size());\n      std::for_each(blob->second.tags.cbegin(), blob->second.tags.cend(),\n                    [&](auto &t) {\n                      r.push_tag(reinterpret_cast<const int8_t *>(t.c_str()));\n                    });\n    }\n    return r;\n  }\n\nprivate:\n  Impl impl;\n};\n\nrust::Box<rust::Dyn<rust::crate::BlobStoreTrait>>\nrust::exported_functions::new_blob_store_client() {\n  return rust::Box<rust::Dyn<rust::crate::BlobStoreTrait>>::make_box<\n      BlobStore>();\n}\n"
  },
  {
    "path": "examples/cxx_demo/build.rs",
    "content": "#[cfg(not(target_os = \"windows\"))]\nuse std::env;\n\nuse zngur::Zngur;\n\nfn main() {\n    build::rerun_if_changed(\"main.zng\");\n    build::rerun_if_changed(\"blobstore.cpp\");\n    build::rerun_if_changed(\"src/\");\n    build::rerun_if_env_changed(\"CXX\");\n\n    #[cfg(not(target_os = \"windows\"))]\n    let cxx = env::var(\"CXX\").unwrap_or(\"c++\".to_owned());\n\n    let crate_dir = build::cargo_manifest_dir();\n\n    Zngur::from_zng_file(crate_dir.join(\"main.zng\"))\n        .with_cpp_file(crate_dir.join(\"generated.cpp\"))\n        .with_h_file(crate_dir.join(\"generated.h\"))\n        .with_rs_file(crate_dir.join(\"./src/generated.rs\"))\n        .with_crate_name(\"crate\")\n        .with_zng_header_in_place()\n        .generate();\n\n    let my_build = &mut cc::Build::new();\n    let my_build = my_build.cpp(true).std(\"c++17\");\n\n    #[cfg(not(target_os = \"windows\"))]\n    my_build.compiler(&cxx);\n\n    let my_build = || my_build.clone();\n\n    my_build().file(\"generated.cpp\").compile(\"zngur_generated\");\n    my_build().file(\"blobstore.cpp\").compile(\"blobstore\");\n}\n"
  },
  {
    "path": "examples/cxx_demo/expected_output.txt",
    "content": "metadata = BlobMetadata { size: 19, tags: [\"rust\"] }\n"
  },
  {
    "path": "examples/cxx_demo/main.zng",
    "content": "type [u8] {\n    wellknown_traits(?Sized);\n\n    fn as_ptr(&self) -> *const u8;\n    fn len(&self) -> usize;\n}\n\ntype str {\n    wellknown_traits(?Sized);\n\n    fn as_ptr(&self) -> *const u8;\n    fn len(&self) -> usize;\n}\n\nmod crate {\n    type MultiBuf {\n        #layout(size = 32, align = 8);\n\n        fn next_chunk(&mut self) -> &[u8];\n    }\n\n    type BlobMetadata {\n        #layout(size = 32, align = 8);\n\n        fn default() -> BlobMetadata;  \n        fn set_size(&mut self, usize);\n        fn push_tag(&mut self, *const i8);\n    }\n\n    trait BlobStoreTrait {\n        fn put(&self, &mut MultiBuf) -> u64;\n        fn tag(&self, u64, &str);\n        fn metadata(&self, u64) -> BlobMetadata;\n    }\n\n    type Box<dyn BlobStoreTrait> {\n        #layout(size = 16, align = 8);\n        fn put(&self, &mut MultiBuf) -> u64 deref dyn BlobStoreTrait;\n        fn tag(&self, u64, &str) deref dyn BlobStoreTrait;\n        fn metadata(&self, u64) -> BlobMetadata deref dyn BlobStoreTrait;\n    }\n}\n\nextern \"C++\" {\n    fn new_blob_store_client() -> Box<dyn crate::BlobStoreTrait>;\n}\n"
  },
  {
    "path": "examples/cxx_demo/src/main.rs",
    "content": "#[rustfmt::skip]\nmod generated;\n\nuse generated::new_blob_store_client;\n\n// An iterator over contiguous chunks of a discontiguous file object. Toy\n// implementation uses a Vec<Vec<u8>> but in reality this might be iterating\n// over some more complex Rust data structure like a rope, or maybe loading\n// chunks lazily from somewhere.\npub struct MultiBuf {\n    chunks: Vec<Vec<u8>>,\n    pos: usize,\n}\n\nimpl MultiBuf {\n    pub fn next_chunk(&mut self) -> &[u8] {\n        let next = self.chunks.get(self.pos);\n        self.pos += 1;\n        next.map_or(&[], Vec::as_slice)\n    }\n}\n\n#[derive(Debug, Default)]\nstruct BlobMetadata {\n    size: usize,\n    tags: Vec<String>,\n}\n\nimpl BlobMetadata {\n    fn set_size(&mut self, size: usize) {\n        self.size = size;\n    }\n\n    fn push_tag(&mut self, c: *const i8) {\n        self.tags.push(\n            String::from_utf8_lossy(unsafe { std::ffi::CStr::from_ptr(c).to_bytes() }).to_string(),\n        );\n    }\n}\n\ntrait BlobStoreTrait {\n    fn put(&self, buf: &mut MultiBuf) -> u64;\n    fn tag(&self, blob_id: u64, tag: &str);\n    fn metadata(&self, blob_id: u64) -> BlobMetadata;\n}\n\nfn main() {\n    let client = new_blob_store_client();\n\n    // Upload a blob_.\n    let chunks = vec![b\"fearless\".to_vec(), b\"concurrency\".to_vec()];\n    let mut buf = MultiBuf { chunks, pos: 0 };\n    let blob_id = client.put(&mut buf);\n\n    // Add a tag.\n    client.tag(blob_id, \"rust\");\n\n    // Read back the tags.\n    let metadata = client.metadata(blob_id);\n    println!(\"metadata = {:?}\", metadata);\n}\n"
  },
  {
    "path": "examples/cxx_demo_split/.gitignore",
    "content": "generated.h\ngenerated.rs\ngenerated.cpp\nhistory.txt\n"
  },
  {
    "path": "examples/cxx_demo_split/Cargo.toml",
    "content": "[package]\nname = \"example-cxx_demo_split\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n\n[build-dependencies]\ncc = \"1.0\"\nbuild-rs = \"0.1.2\"\nzngur = { path = \"../../zngur\" }\n"
  },
  {
    "path": "examples/cxx_demo_split/README.md",
    "content": "# Example: CXX demo\n\nThis example tries to replicate [the CXX demo](https://github.com/dtolnay/cxx/tree/master/demo) using Zngur. It tries to keep it as close\nas possible to the original CXX example, so it doesn't use Zngur features that may make the code easier, more readable, and more\nperformant. To see an example that uses all Zngur features in C++ to Rust codes, go to the osmium example.\n\nTo run this example:\n\n```\ncargo run\n```\n"
  },
  {
    "path": "examples/cxx_demo_split/blobstore.cpp",
    "content": "#include <algorithm>\n#include <cstdint>\n#include <set>\n#include <unordered_map>\n\n#include \"./generated.h\"\n\nclass BlobStore : public rust::crate::BlobStoreTrait {\n  class Impl {\n    friend BlobStore;\n\n    using Blob = struct {\n      std::string data;\n      std::set<std::string> tags;\n    };\n    std::unordered_map<uint64_t, Blob> blobs;\n  };\n\npublic:\n  uint64_t put(rust::RefMut<rust::crate::MultiBuf> buf) override {\n    std::string contents;\n\n    // Traverse the caller's chunk iterator.\n    //\n    // In reality there might be sophisticated batching of chunks and/or\n    // parallel upload implemented by the blob_store's C++ client.\n    while (true) {\n      auto chunk = buf.next_chunk();\n      if (chunk.len() == 0) {\n        break;\n      }\n      contents.append(reinterpret_cast<const char *>(chunk.as_ptr()),\n                      chunk.len());\n    }\n\n    // Insert into map and provide caller the handle.\n    auto blob_id = std::hash<std::string>{}(contents);\n    impl.blobs[blob_id] = {std::move(contents), {}};\n    return blob_id;\n  }\n\n  rust::Unit tag(::uint64_t blob_id,\n                 rust::Ref<rust::Str> tag) override {\n    impl.blobs[blob_id].tags.emplace((char *)tag.as_ptr(), tag.len());\n    return rust::Unit{};\n  }\n\n  rust::crate::BlobMetadata metadata(::uint64_t blob_id) override {\n    rust::crate::BlobMetadata r = rust::crate::BlobMetadata::default_();\n    auto blob = impl.blobs.find(blob_id);\n    if (blob != impl.blobs.end()) {\n      r.set_size(blob->second.data.size());\n      std::for_each(blob->second.tags.cbegin(), blob->second.tags.cend(),\n                    [&](auto &t) {\n                      r.push_tag(reinterpret_cast<const int8_t *>(t.c_str()));\n                    });\n    }\n    return r;\n  }\n\nprivate:\n  Impl impl;\n};\n\nrust::Box<rust::Dyn<rust::crate::BlobStoreTrait>>\nrust::exported_functions::new_blob_store_client() {\n  return rust::Box<rust::Dyn<rust::crate::BlobStoreTrait>>::make_box<\n      BlobStore>();\n}\n"
  },
  {
    "path": "examples/cxx_demo_split/build.rs",
    "content": "#[cfg(not(target_os = \"windows\"))]\nuse std::env;\n\nuse zngur::Zngur;\n\nfn main() {\n    build::rerun_if_changed(\"main.zng\");\n    build::rerun_if_changed(\"blobstore.cpp\");\n    build::rerun_if_changed(\"src/\");\n    build::rerun_if_changed(\"zngur.h\");\n    build::rerun_if_env_changed(\"CXX\");\n\n    #[cfg(not(target_os = \"windows\"))]\n    let cxx = env::var(\"CXX\").unwrap_or(\"c++\".to_owned());\n\n    let crate_dir = build::cargo_manifest_dir();\n\n    Zngur::from_zng_file(crate_dir.join(\"main.zng\"))\n        .with_cpp_file(crate_dir.join(\"generated.cpp\"))\n        .with_h_file(crate_dir.join(\"generated.h\"))\n        .with_rs_file(crate_dir.join(\"./src/generated.rs\"))\n        .with_crate_name(\"crate\")\n        .with_zng_header(\"zngur.h\")\n        .generate();\n\n    let my_build = &mut cc::Build::new();\n    let my_build = my_build.cpp(true).std(\"c++17\").include(\".\");\n\n    #[cfg(not(target_os = \"windows\"))]\n    my_build.compiler(&cxx);\n\n    let my_build = || my_build.clone();\n\n    my_build().file(\"generated.cpp\").compile(\"zngur_generated\");\n    my_build().file(\"blobstore.cpp\").compile(\"blobstore\");\n}\n"
  },
  {
    "path": "examples/cxx_demo_split/expected_output.txt",
    "content": "metadata = BlobMetadata { size: 19, tags: [\"rust\"] }\n"
  },
  {
    "path": "examples/cxx_demo_split/main.zng",
    "content": "type [u8] {\n    wellknown_traits(?Sized);\n\n    fn as_ptr(&self) -> *const u8;\n    fn len(&self) -> usize;\n}\n\ntype str {\n    wellknown_traits(?Sized);\n\n    fn as_ptr(&self) -> *const u8;\n    fn len(&self) -> usize;\n}\n\nmod crate {\n    type MultiBuf {\n        #layout(size = 32, align = 8);\n\n        fn next_chunk(&mut self) -> &[u8];\n    }\n\n    type BlobMetadata {\n        #layout(size = 32, align = 8);\n\n        fn default() -> BlobMetadata;  \n        fn set_size(&mut self, usize);\n        fn push_tag(&mut self, *const i8);\n    }\n\n    trait BlobStoreTrait {\n        fn put(&self, &mut MultiBuf) -> u64;\n        fn tag(&self, u64, &str);\n        fn metadata(&self, u64) -> BlobMetadata;\n    }\n\n    type Box<dyn BlobStoreTrait> {\n        #layout(size = 16, align = 8);\n        fn put(&self, &mut MultiBuf) -> u64 deref dyn BlobStoreTrait;\n        fn tag(&self, u64, &str) deref dyn BlobStoreTrait;\n        fn metadata(&self, u64) -> BlobMetadata deref dyn BlobStoreTrait;\n    }\n}\n\nextern \"C++\" {\n    fn new_blob_store_client() -> Box<dyn crate::BlobStoreTrait>;\n}\n"
  },
  {
    "path": "examples/cxx_demo_split/src/main.rs",
    "content": "#[rustfmt::skip]\nmod generated;\n\nuse generated::new_blob_store_client;\n\n// An iterator over contiguous chunks of a discontiguous file object. Toy\n// implementation uses a Vec<Vec<u8>> but in reality this might be iterating\n// over some more complex Rust data structure like a rope, or maybe loading\n// chunks lazily from somewhere.\npub struct MultiBuf {\n    chunks: Vec<Vec<u8>>,\n    pos: usize,\n}\n\nimpl MultiBuf {\n    pub fn next_chunk(&mut self) -> &[u8] {\n        let next = self.chunks.get(self.pos);\n        self.pos += 1;\n        next.map_or(&[], Vec::as_slice)\n    }\n}\n\n#[derive(Debug, Default)]\nstruct BlobMetadata {\n    size: usize,\n    tags: Vec<String>,\n}\n\nimpl BlobMetadata {\n    fn set_size(&mut self, size: usize) {\n        self.size = size;\n    }\n\n    fn push_tag(&mut self, c: *const i8) {\n        self.tags.push(\n            String::from_utf8_lossy(unsafe { std::ffi::CStr::from_ptr(c).to_bytes() }).to_string(),\n        );\n    }\n}\n\ntrait BlobStoreTrait {\n    fn put(&self, buf: &mut MultiBuf) -> u64;\n    fn tag(&self, blob_id: u64, tag: &str);\n    fn metadata(&self, blob_id: u64) -> BlobMetadata;\n}\n\nfn main() {\n    let client = new_blob_store_client();\n\n    // Upload a blob_.\n    let chunks = vec![b\"fearless\".to_vec(), b\"concurrency\".to_vec()];\n    let mut buf = MultiBuf { chunks, pos: 0 };\n    let blob_id = client.put(&mut buf);\n\n    // Add a tag.\n    client.tag(blob_id, \"rust\");\n\n    // Read back the tags.\n    let metadata = client.metadata(blob_id);\n    println!(\"metadata = {:?}\", metadata);\n}\n"
  },
  {
    "path": "examples/impl_trait/.gitignore",
    "content": "generated.h\ngenerated.rs\ngenerated.cpp\n"
  },
  {
    "path": "examples/impl_trait/Cargo.toml",
    "content": "[package]\nname = \"example-impl-trait\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"staticlib\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "examples/impl_trait/Makefile",
    "content": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_impl_trait.a\n\t${CXX} -std=c++20 -Werror main.cpp -g -L ../../target/release/ -l example_impl_trait\n\n../../target/release/libexample_impl_trait.a:\n\tcargo build --release\n\ngenerated.h ./src/generated.rs: main.zng\n\tcd ../../zngur-cli && cargo run g -i ../examples/impl_trait/main.zng --crate-name \"crate\"\n\n.PHONY: ../../target/release/libexample_impl_trait.a generated.h clean\n\nclean:\n\trm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt\n"
  },
  {
    "path": "examples/impl_trait/NMakefile",
    "content": "CXX = cl.exe\r\nCXXFLAGS = /W4 /DEBUG /EHsc /std:c++20 \r\nWINLIBS = ntdll.lib\r\n\r\nEXAMPLE_NAME = impl_trait\r\n\r\nGENERATED = generated.h src/generated.rs\r\n\r\nRUSTLIB_PATH = ../../target/release/\r\n\r\nRUSTLIB = example_$(EXAMPLE_NAME).lib\r\n\r\na.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)\r\n\t$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)\r\n\r\n$(RUSTLIB_PATH)/$(RUSTLIB) :\r\n\tcargo build --release\r\n\r\n$(GENERATED) : main.zng\r\n\tcd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name \"crate\"\r\n\r\nclean :\r\n\t- del /f /q generated.h generated.cpp src\\generated.rs a.exe main.obj actual_output.txt 2>nul\r\n"
  },
  {
    "path": "examples/impl_trait/README.md",
    "content": "# Example: Regression test 1\n\nA example, used to check previous Zngur problems in CI.\n\nTo run this example:\n\n```\nmake\n./a.out\n```\n"
  },
  {
    "path": "examples/impl_trait/expected_output.txt",
    "content": "Print debug -- 5\nPrint debug -- \"hello\"\nPrint debug -- 4\nPrint debug -- \"foo\"\nPrint debug -- \"foo\"\nPrint debug -- \"Rust futures are lazy\"\nAsync func 1\nFuture done with result 43\nAsync func 2\nFuture done with result 44\nPrint debug -- \"Before calling impl_future\"\nBefore async block\nPrint debug -- \"Before polling impl_future\"\nInside async block\nFuture done with result 45\n"
  },
  {
    "path": "examples/impl_trait/main.cpp",
    "content": "#include <iostream>\n#include <vector>\n\n#include \"./generated.h\"\n\nusing DynDebug = rust::Dyn<rust::std::fmt::Debug>;\n\nint main() {\n  rust::crate::argument_position_impl_trait(5);\n  rust::crate::argument_position_impl_trait(\"hello\"_rs.to_owned());\n  rust::crate::argument_position_impl_trait(\n      rust::crate::return_position_impl_trait());\n  rust::Box<DynDebug> elem = rust::crate::both_impl_trait(\"foo\"_rs);\n  rust::crate::argument_position_impl_trait(elem.deref());\n  rust::crate::argument_position_impl_trait(std::move(elem));\n\n  auto future = rust::crate::async_func1();\n  rust::crate::argument_position_impl_trait(\n      \"Rust futures are lazy\"_rs.to_owned());\n  rust::crate::busy_wait_future(std::move(future));\n  rust::crate::busy_wait_future(rust::crate::async_func2());\n\n  rust::crate::argument_position_impl_trait(\n      \"Before calling impl_future\"_rs.to_owned());\n  future = rust::crate::impl_future();\n  rust::crate::argument_position_impl_trait(\n      \"Before polling impl_future\"_rs.to_owned());\n  rust::crate::busy_wait_future(std::move(future));\n}\n"
  },
  {
    "path": "examples/impl_trait/main.zng",
    "content": "#convert_panic_to_exception\n\ntype str {\n    wellknown_traits(?Sized, Debug);\n\n    fn as_ptr(&self) -> *const u8;\n    fn len(&self) -> usize;\n    fn to_owned(&self) -> ::std::string::String;\n}\n\ntype dyn ::std::fmt::Debug {\n    wellknown_traits(?Sized, Debug);\n}\n\ntype Box<dyn ::std::fmt::Debug> {\n    #layout(size = 16, align = 8);\n\n    fn deref(&self) -> &dyn ::std::fmt::Debug use ::std::ops::Deref;\n}\n\ntype Box<dyn ::std::future::Future<Output = i32>> {\n    #layout(size = 16, align = 8);\n}\n\ntype ::std::string::String {\n    #layout(size = 24, align = 8);\n    wellknown_traits(Debug);\n\n    fn clone(&self) -> ::std::string::String;\n    fn push_str(&mut self, &str);\n    fn len(&self) -> usize;\n}\n\nmod crate {\n    fn argument_position_impl_trait(i32);\n    fn argument_position_impl_trait(::std::string::String);\n    fn argument_position_impl_trait(Box<dyn ::std::fmt::Debug>);\n    fn argument_position_impl_trait(&dyn ::std::fmt::Debug);\n    fn return_position_impl_trait() -> impl ::std::fmt::Debug;\n    fn both_impl_trait(&str) -> impl ::std::fmt::Debug;\n\n    fn async_func1() -> impl ::std::future::Future<Output = i32>;\n    async fn async_func2() -> i32;\n    async fn impl_future() -> i32;\n    fn busy_wait_future(Box<dyn ::std::future::Future<Output = i32>>) -> i32;\n}\n"
  },
  {
    "path": "examples/impl_trait/src/lib.rs",
    "content": "use std::{\n    fmt::Debug,\n    task::{Context, Waker},\n};\n\n#[rustfmt::skip]\nmod generated;\n\nfn argument_position_impl_trait(arg: impl Debug) {\n    println!(\"Print debug -- {arg:?}\");\n}\n\nfn return_position_impl_trait() -> impl Debug {\n    4\n}\n\nfn both_impl_trait(input: impl Debug) -> impl Debug {\n    input\n}\n\nasync fn async_func1() -> i32 {\n    println!(\"Async func 1\");\n    43\n}\n\nasync fn async_func2() -> i32 {\n    println!(\"Async func 2\");\n    44\n}\n\nfn impl_future() -> impl Future<Output = i32> {\n    println!(\"Before async block\");\n    async {\n        println!(\"Inside async block\");\n        45\n    }\n}\n\nfn busy_wait_future<T: Debug>(fut: Box<dyn Future<Output = T>>) -> T {\n    let mut fut = Box::into_pin(fut);\n    let waker = Waker::noop();\n    let mut cx = Context::from_waker(waker);\n    loop {\n        match fut.as_mut().poll(&mut cx) {\n            std::task::Poll::Ready(r) => {\n                println!(\"Future done with result {r:?}\");\n                return r;\n            }\n            std::task::Poll::Pending => (),\n        }\n    }\n}\n"
  },
  {
    "path": "examples/memory_management/.gitignore",
    "content": "generated.h\ngenerated.rs\ngenerated.cpp\n"
  },
  {
    "path": "examples/memory_management/Cargo.toml",
    "content": "[package]\nname = \"example-memory_management\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"staticlib\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "examples/memory_management/Makefile",
    "content": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_memory_management.a\n\t${CXX} -std=c++17 -Werror main.cpp generated.cpp -g -L ../../target/release/ -l example_memory_management\n\n../../target/release/libexample_memory_management.a:\n\tcargo build --release\n\ngenerated.h generated.cpp ./src/generated.rs: main.zng\n\tcd ../../zngur-cli && cargo run g -i ../examples/memory_management/main.zng --crate-name \"crate\"\n\n.PHONY: ../../target/release/libexample_memory_management.a generated.h clean\n\nclean:\n\trm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt\n"
  },
  {
    "path": "examples/memory_management/NMakefile",
    "content": "CXX = cl.exe\r\nCXXFLAGS = /W4 /DEBUG /EHsc /std:c++20 \r\nWINLIBS = ntdll.lib\r\n\r\nEXAMPLE_NAME = memory_management\r\n\r\nGENERATED = generated.h src/generated.rs\r\n\r\nRUSTLIB_PATH = ../../target/release/\r\n\r\nRUSTLIB = example_$(EXAMPLE_NAME).lib\r\n\r\na.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)\r\n\t$(CXX) $(CXXFLAGS) main.cpp generated.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)\r\n\r\n$(RUSTLIB_PATH)/$(RUSTLIB) :\r\n\tcargo build --release\r\n\r\n$(GENERATED) : main.zng\r\n\tcd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name \"crate\"\r\n\r\nclean :\r\n\t- del /f /q generated.h generated.cpp src\\generated.rs a.exe main.obj generated.obj actual_output.txt 2>nul\r\n"
  },
  {
    "path": "examples/memory_management/README.md",
    "content": "# Example: Memory management\n\nExplains the corner cases of memory management by code.\n\nTo run this example:\n\n```\nmake\n./a.out\n```\n"
  },
  {
    "path": "examples/memory_management/expected_output.txt",
    "content": "Checkpoint 1\nPrintOnDrop(B) has been dropped\nCheckpoint 2\nCheckpoint 3\nCheckpoint 4\nPrintOnDrop(A) has been dropped\nCheckpoint 5\nPrintOnDrop(cpp_V3) has been dropped\nPrintOnDrop(cpp_V2) has been dropped\nCheckpoint 6\nPrintOnDrop(cpp_V1) has been dropped\nCheckpoint 7\nCheckpoint 8\nPrintOnDrop(rust_V1) has been dropped\nPrintOnDrop(rust_V2) has been dropped\nCheckpoint 9\nPrintOnDrop(rust_V1) has been dropped\nPrintOnDrop(rust_V2) has been dropped\nCheckpoint 10\nCheckpoint 11\nPrintOnDrop(P) has been dropped\nPrintOnDrop(P) has been dropped\nCheckpoint 12\nPrintOnDrop(P) has been dropped\nPrintOnDrop(Q) has been dropped\nCheckpoint 13\nPrintOnDrop(Q) has been dropped\nCheckpoint 14\nCheckpoint 15\nCheckpoint 16\nPrintOnDrop(P2) has been dropped\nPrintOnDrop(P2) has been dropped\nCheckpoint 17\nPrintOnDrop(P2) has been dropped\nPrintOnDrop(Q2) has been dropped\nCheckpoint 18\nCheckpoint 19\nPrintOnDrop(Q2) has been dropped\nCheckpoint 20\nCheckpoint 21\nPrintOnDrop(A) has been dropped\nCheckpoint 22\n\nthread panicked at examples/memory_management/src/lib.rs:30:9:\nconsume_and_panic executed with value B\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\nPrintOnDrop(B) has been dropped\nPrintOnDrop(A) has been dropped\nCheckpoint 24\nCheckpoint 25\nCheckpoint 26\nPrintOnDrop(first) has been dropped\nPrintOnDrop(second) has been dropped\nCheckpoint 27\nCheckpoint 28\nPrintOnDrop(elem1) has been dropped\nCheckpoint 29\nPrintOnDrop(elem1) has been dropped\nCheckpoint 30\nPrintOnDrop(elem1) has been dropped\nPrintOnDrop(elem2) has been dropped\nCheckpoint 31\n[main.cpp:113] PrintOnDrop(\"dbg_A\"_rs) = PrintOnDrop(\n    \"dbg_A\",\n)\nCheckpoint 32\n[main.cpp:115] std::move(p1) = PrintOnDrop(\n    \"dbg_A\",\n)\nCheckpoint 33\n[main.cpp:117] p2 = PrintOnDrop(\n    \"dbg_A\",\n)\nCheckpoint 34\nPrintOnDrop(dbg_A) has been dropped\nCheckpoint 35\nCheckpoint 36\nCheckpoint 37\nPrintOnDrop(option_B) has been dropped\nCheckpoint 38\nCheckpoint 39\nPrintOnDrop(option_A) has been dropped\nCheckpoint 40\nCheckpoint 41\nCheckpoint 42\nPrintOnDrop(elem1) has been dropped\nCheckpoint 42\nPrintOnDrop(elem2) has been dropped\nCheckpoint 42\nPrintOnDrop(elem3) has been dropped\nCheckpoint 43\nCheckpoint 44\nPrintOnDrop(field_0) has been dropped\nPrintOnDrop(field_2) has been dropped\nCheckpoint 45\nPrintOnDrop(C) has been dropped\n"
  },
  {
    "path": "examples/memory_management/main.cpp",
    "content": "#include <cstdint>\n#include <iostream>\n#include <vector>\n\n#include \"./generated.h\"\n\ntemplate <typename T> using Vec = rust::std::vec::Vec<T>;\ntemplate <typename T> using Option = rust::std::option::Option<T>;\ntemplate <typename T> using BoxDyn = rust::Box<rust::Dyn<T>>;\ntemplate <typename T> using RmDyn = rust::RefMut<rust::Dyn<T>>;\nusing namespace rust::crate;\n\nclass CppPrintOnDropHolder : public PrintOnDropConsumer {\n  rust::Unit consume(PrintOnDrop p) override {\n    item = std::move(p);\n    return {};\n  }\n\n  PrintOnDrop item;\n};\n\nint main() {\n  auto p1 = PrintOnDrop(\"A\"_rs);\n  auto p2 = PrintOnDrop(\"B\"_rs);\n  auto p3 = PrintOnDrop(\"C\"_rs);\n  std::cout << \"Checkpoint 1\" << std::endl;\n  p2 = std::move(p1);\n  std::cout << \"Checkpoint 2\" << std::endl;\n  {\n    std::cout << \"Checkpoint 3\" << std::endl;\n    PrintOnDrop p{std::move(p2)};\n    std::cout << \"Checkpoint 4\" << std::endl;\n  }\n  {\n    std::vector<PrintOnDrop> vec1;\n    vec1.emplace_back(\"cpp_V1\"_rs);\n    vec1.emplace_back(\"cpp_V2\"_rs);\n    vec1.emplace_back(\"cpp_V3\"_rs);\n    std::cout << \"Checkpoint 5\" << std::endl;\n    vec1.pop_back();\n    vec1.pop_back();\n    std::cout << \"Checkpoint 6\" << std::endl;\n  }\n  {\n    std::cout << \"Checkpoint 7\" << std::endl;\n    Vec<PrintOnDrop> vec2 = Vec<PrintOnDrop>::new_();\n    vec2.push(PrintOnDrop(\"rust_V1\"_rs));\n    vec2.push(PrintOnDrop(\"rust_V2\"_rs));\n    std::cout << \"Checkpoint 8\" << std::endl;\n    vec2.clone(); // Clone and drop immediately\n    std::cout << \"Checkpoint 9\" << std::endl;\n  }\n  {\n    CppPrintOnDropHolder c;\n    {\n      std::cout << \"Checkpoint 10\" << std::endl;\n      auto holder = BoxDyn<PrintOnDropConsumer>::make_box<CppPrintOnDropHolder>(\n          std::move(c));\n      std::cout << \"Checkpoint 11\" << std::endl;\n      consume_n_times(holder.deref_mut(), \"P\"_rs, 3);\n      std::cout << \"Checkpoint 12\" << std::endl;\n      consume_n_times(holder.deref_mut(), \"Q\"_rs, 2);\n      std::cout << \"Checkpoint 13\" << std::endl;\n    }\n    std::cout << \"Checkpoint 14\" << std::endl;\n  }\n  {\n    CppPrintOnDropHolder c;\n    {\n      std::cout << \"Checkpoint 15\" << std::endl;\n      auto holder = RmDyn<PrintOnDropConsumer>(c);\n      std::cout << \"Checkpoint 16\" << std::endl;\n      consume_n_times(holder, \"P2\"_rs, 3);\n      std::cout << \"Checkpoint 17\" << std::endl;\n      consume_n_times(holder, \"Q2\"_rs, 2);\n      std::cout << \"Checkpoint 18\" << std::endl;\n    }\n    std::cout << \"Checkpoint 19\" << std::endl;\n  }\n  std::cout << \"Checkpoint 20\" << std::endl;\n  try {\n    PrintOnDrop a{\"A\"_rs};\n    std::cout << \"Checkpoint 21\" << std::endl;\n    consume_and_panic(a.clone(), false);\n    std::cout << \"Checkpoint 22\" << std::endl;\n    consume_and_panic(\"B\"_rs, true);\n    std::cout << \"Checkpoint 23\" << std::endl;\n  } catch (rust::Panic e) {\n    std::cout << \"Checkpoint 24\" << std::endl;\n  }\n  {\n    std::cout << \"Checkpoint 25\" << std::endl;\n    PrintOnDropPair p{\"first\"_rs,\n                      \"second\"_rs};\n    std::cout << \"Checkpoint 26\" << std::endl;\n  }\n  {\n    std::cout << \"Checkpoint 27\" << std::endl;\n    Vec<PrintOnDrop> vec2 = Vec<PrintOnDrop>::new_();\n    vec2.push(PrintOnDrop(\"elem1\"_rs));\n    vec2.push(PrintOnDrop(\"elem2\"_rs));\n    std::cout << \"Checkpoint 28\" << std::endl;\n    vec2.get(0).unwrap().clone();\n    {\n      auto vec_slice = vec2.deref();\n      auto tmp = vec_slice.get(0).unwrap().clone();\n      std::cout << \"Checkpoint 29\" << std::endl;\n    }\n    std::cout << \"Checkpoint 30\" << std::endl;\n  }\n  std::cout << \"Checkpoint 31\" << std::endl;\n  {\n    auto p1 = zngur_dbg(PrintOnDrop(\"dbg_A\"_rs));\n    std::cout << \"Checkpoint 32\" << std::endl;\n    auto p2 = zngur_dbg(std::move(p1));\n    std::cout << \"Checkpoint 33\" << std::endl;\n    zngur_dbg(p2);\n    std::cout << \"Checkpoint 34\" << std::endl;\n  }\n  std::cout << \"Checkpoint 35\" << std::endl;\n  {\n    auto p1 = Option<PrintOnDrop>::Some(\n        PrintOnDrop(\"option_A\"_rs));\n    std::cout << \"Checkpoint 36\" << std::endl;\n    auto p2 = Option<PrintOnDrop>::Some(\n        PrintOnDrop(\"option_B\"_rs));\n    std::cout << \"Checkpoint 37\" << std::endl;\n    p2.take();\n    std::cout << \"Checkpoint 38\" << std::endl;\n    p2.take();\n    std::cout << \"Checkpoint 39\" << std::endl;\n  }\n  std::cout << \"Checkpoint 40\" << std::endl;\n  {\n    rust::Ref<rust::Str> elems[3] = {\"elem1\"_rs, \"elem2\"_rs, \"elem3\"_rs};\n    int i = 0;\n    auto iter = rust::std::iter::from_fn(\n        rust::Box<rust::Dyn<rust::Fn<Option<PrintOnDrop>>>>::make_box([&] {\n          if (i == 3) {\n            return Option<PrintOnDrop>::None();\n          }\n          return Option<PrintOnDrop>::Some(\n              PrintOnDrop(elems[i++]));\n        }));\n    std::cout << \"Checkpoint 41\" << std::endl;\n    iter.for_each(\n        rust::Box<rust::Dyn<rust::Fn<PrintOnDrop, rust::Unit>>>::make_box(\n            [](PrintOnDrop p) -> rust::Unit {\n              std::cout << \"Checkpoint 42\" << std::endl;\n              return {};\n            }));\n  }\n  std::cout << \"Checkpoint 43\" << std::endl;\n  {\n    auto tuple = rust::Tuple<PrintOnDrop, int32_t, PrintOnDrop>(\n        PrintOnDrop(\"field_0\"_rs), 5,\n        PrintOnDrop(\"field_2\"_rs));\n    std::cout << \"Checkpoint 44\" << std::endl;\n  }\n  std::cout << \"Checkpoint 45\" << std::endl;\n}\n"
  },
  {
    "path": "examples/memory_management/main.zng",
    "content": "#convert_panic_to_exception\n\ntype (crate::PrintOnDrop, i32, crate::PrintOnDrop) {\n    #layout(size = 40, align = 8);\n}\n\ntype bool {\n    #layout(size = 1, align = 1);\n    wellknown_traits(Copy);\n}\n\ntype str {\n    wellknown_traits(?Sized);\n}\n\ntype Box<dyn Fn() -> ::std::option::Option<crate::PrintOnDrop>> {\n    #layout(size = 16, align = 8);\n}\n\ntype Box<dyn Fn(crate::PrintOnDrop)> {\n    #layout(size = 16, align = 8);\n}\n\nmod crate {\n    type PrintOnDropPair {\n        #layout(size = 32, align = 8);\n\n        constructor { first: PrintOnDrop, second: PrintOnDrop };\n    }\n\n    type PrintOnDrop {\n        #layout(size = 16, align = 8);\n        wellknown_traits(Debug);\n        constructor(&str);\n\n        fn clone(&self) -> PrintOnDrop;\n    }\n\n    type [PrintOnDrop] {\n        wellknown_traits(?Sized);\n\n        fn get(&self, usize) -> ::std::option::Option<&crate::PrintOnDrop>;    \n    }\n\n    trait PrintOnDropConsumer {\n        fn consume(&mut self, PrintOnDrop);\n    }\n\n    type Box<dyn PrintOnDropConsumer> {\n        #layout(size = 16, align = 8);\n    \n        fn deref_mut(&mut self) -> &mut dyn PrintOnDropConsumer use ::std::ops::DerefMut;\n    }\n\n    type dyn PrintOnDropConsumer {\n        wellknown_traits(?Sized);\n    }\n\n    fn consume_n_times(&mut dyn PrintOnDropConsumer, &str, usize);\n    fn consume_and_panic(PrintOnDrop, bool) -> PrintOnDrop;\n}\n\nmod ::std {\n    mod option {\n        type Option<&crate::PrintOnDrop> {\n            #layout(size = 8, align = 8);\n\n            fn unwrap(self) -> &crate::PrintOnDrop;\n        }\n\n        type Option<crate::PrintOnDrop> {\n            #layout(size = 16, align = 8);\n\n            constructor Some(crate::PrintOnDrop);\n            constructor None;\n\n            fn take(&mut self) -> Option<crate::PrintOnDrop>;\n        }\n    }\n\n    mod iter {\n        type FromFn<Box<dyn Fn() -> ::std::option::Option<crate::PrintOnDrop>>> {\n            #layout(size = 16, align = 8);\n        \n            fn for_each<Box<dyn Fn(crate::PrintOnDrop)>>(self, Box<dyn Fn(crate::PrintOnDrop)>);\n        }\n\n        fn from_fn<crate::PrintOnDrop, Box<dyn Fn() -> ::std::option::Option<crate::PrintOnDrop>>>(\n            Box<dyn Fn() -> ::std::option::Option<crate::PrintOnDrop>>\n        ) -> FromFn<Box<dyn Fn() -> ::std::option::Option<crate::PrintOnDrop>>>;\n    }\n\n    mod vec {\n        type Vec<crate::PrintOnDrop> {\n            #layout(size = 24, align = 8);\n\n            fn new() -> Vec<crate::PrintOnDrop>;\n            fn push(&mut self, crate::PrintOnDrop);\n            fn clone(&self) -> Vec<crate::PrintOnDrop>;\n            fn get(&self, usize) -> ::std::option::Option<&crate::PrintOnDrop> deref [crate::PrintOnDrop];\n            fn deref(&self) -> &[crate::PrintOnDrop] use ::std::ops::Deref;\n        }\n    }\n}\n\n"
  },
  {
    "path": "examples/memory_management/src/lib.rs",
    "content": "#[rustfmt::skip]\nmod generated;\n\n#[derive(Debug, Clone)]\npub struct PrintOnDrop(&'static str);\n\npub struct PrintOnDropPair {\n    pub first: PrintOnDrop,\n    pub second: PrintOnDrop,\n}\n\nimpl Drop for PrintOnDrop {\n    fn drop(&mut self) {\n        println!(\"PrintOnDrop({}) has been dropped\", self.0);\n    }\n}\n\ntrait PrintOnDropConsumer {\n    fn consume(&mut self, p: PrintOnDrop);\n}\n\nfn consume_n_times(consumer: &mut dyn PrintOnDropConsumer, name: &'static str, times: usize) {\n    for _ in 0..times {\n        consumer.consume(PrintOnDrop(name));\n    }\n}\n\nfn consume_and_panic(p: PrintOnDrop, do_panic: bool) -> PrintOnDrop {\n    if do_panic {\n        panic!(\"consume_and_panic executed with value {}\", p.0);\n    }\n    p\n}\n"
  },
  {
    "path": "examples/multiple_modules/Cargo.toml",
    "content": "[package]\nname = \"example-multiple-modules\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"staticlib\"]\n\n[dependencies]\npacket = { path = \"packet\" }\nreceiver = { path = \"receiver\" }\naggregation = { path = \"aggregation\" }\nprocessor = { path = \"processor\" }\n"
  },
  {
    "path": "examples/multiple_modules/Makefile",
    "content": "ZNGUR_CLI = cd ../../zngur-cli && cargo run\n\na.out: main.cpp aggregation.a packet.zng.h receiver.zng.h aggregation.zng.h processor.zng.h zngur.h ../../target/release/libexample_multiple_modules.a\n\t${CXX} -std=c++11 -Werror -I. -Iaggregation main.cpp aggregation.a -g -L ../../target/release/ -l example_multiple_modules\n\n../../target/release/libexample_multiple_modules.a:\n\tcargo build --release\n\naggregation.a: aggregation/impls.cpp aggregation/generated.cpp aggregation.zng.h zngur.h\n\t${CXX} -c -std=c++11 -Werror -I. -Iaggregation -o aggregation/generated.o aggregation/generated.cpp\n\t${CXX} -c -std=c++11 -Werror -I. -Iaggregation -o aggregation/impls.o aggregation/impls.cpp\n\tld -r -o aggregation.a aggregation/impls.o aggregation/generated.o\n\t\n\npacket.zng.h packet/src/packet.zng.rs: packet/packet.zng\n\t${ZNGUR_CLI} g ../examples/multiple_modules/packet/packet.zng \\\n\t\t--h-file=../examples/multiple_modules/packet.zng.h \\\n\t\t--rs-file=../examples/multiple_modules/packet/src/packet.zng.rs \\\n\t\t--crate-name \"packet\"\n\nreceiver.zng.h receiver/src/receiver.zng.rs: receiver/receiver.zng packet.zng.h\n\t${ZNGUR_CLI} g ../examples/multiple_modules/receiver/receiver.zng \\\n\t\t--h-file=../examples/multiple_modules/receiver.zng.h \\\n\t\t--rs-file=../examples/multiple_modules/receiver/src/receiver.zng.rs \\\n\t\t--crate-name \"receiver\"\n\naggregation.zng.h aggregation/src/aggregation.zng.rs aggregation/generated.cpp: aggregation/aggregation.zng packet.zng.h\n\t${ZNGUR_CLI} g ../examples/multiple_modules/aggregation/aggregation.zng \\\n\t\t--h-file=../examples/multiple_modules/aggregation.zng.h \\\n\t\t--rs-file=../examples/multiple_modules/aggregation/src/aggregation.zng.rs \\\n\t\t--crate-name \"aggregation\"\n\nprocessor.zng.h processor/src/processor.zng.rs: processor/processor.zng receiver.zng.h aggregation.zng.h\n\t${ZNGUR_CLI} g ../examples/multiple_modules/processor/processor.zng \\\n\t\t--h-file=../examples/multiple_modules/processor.zng.h \\\n\t\t--rs-file=../examples/multiple_modules/processor/src/processor.zng.rs \\\n\t\t--crate-name \"processor\"\n\nzngur.h:\n\t${ZNGUR_CLI} -- make-zng-header ../examples/multiple_modules/zngur.h\n\n.PHONY: ../../target/release/libexample_multiple_modules.a clean run\n\nrun: a.out\n\t./a.out\n\nclean:\n\trm -f *.zng.h packet/src/*.zng.rs receiver/src/*.zng.rs aggregation/generated.cpp aggregation/src/*.zng.rs aggregation/*.o processor/src/*.zng.rs zngur.h a.out *.o *.a\n"
  },
  {
    "path": "examples/multiple_modules/aggregation/Cargo.toml",
    "content": "[package]\nname = \"aggregation\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"rlib\"]\n\n[dependencies]\npacket = { path = \"../packet\" }\n"
  },
  {
    "path": "examples/multiple_modules/aggregation/aggregation.zng",
    "content": "import \"packet.zng\";\n\n#cpp_additional_includes \"\n#include <stats.h>\n\"\n\ntype crate::StatsAccumulator {\n    #layout(size = 16, align = 8);\n    constructor(ZngurCppOpaqueOwnedObject);\n    #cpp_value \"0\" \"::cpp_stats::StatsAccumulator\";\n}\n\nextern \"C++\" {\n    impl crate::StatsAccumulator {\n        fn create() -> crate::StatsAccumulator;\n        fn add_packet(&mut self, packet::Packet);\n        fn print_report(&self);\n    }\n}\n"
  },
  {
    "path": "examples/multiple_modules/aggregation/impls.cpp",
    "content": "#include <aggregation.zng.h>\n#include <packet.zng.h>\n#include <stats.h>\n\nusing rust::aggregation::StatsAccumulator;\nusing rust::packet::Packet;\n\n// We need to implement the methods declared in aggregation.zng\nStatsAccumulator rust::Impl<StatsAccumulator>::create() {\n  return StatsAccumulator(\n      rust::ZngurCppOpaqueOwnedObject::build<cpp_stats::StatsAccumulator>());\n}\n\nrust::Unit\nrust::Impl<StatsAccumulator>::add_packet(rust::RefMut<StatsAccumulator> self,\n                                         Packet p) {\n  self.cpp().add_packet(p);\n  return {};\n}\n\nrust::Unit\nrust::Impl<StatsAccumulator>::print_report(rust::Ref<StatsAccumulator> self) {\n  self.cpp().print_report();\n  return {};\n}\n"
  },
  {
    "path": "examples/multiple_modules/aggregation/src/lib.rs",
    "content": "#[rustfmt::skip]\n#[path = \"aggregation.zng.rs\"]\nmod generated;\n\npub use packet::Packet;\n\npub struct StatsAccumulator(pub generated::ZngurCppOpaqueOwnedObject);\n"
  },
  {
    "path": "examples/multiple_modules/aggregation/stats.h",
    "content": "#pragma once\n#include <iostream>\n#include <numeric>\n#include <vector>\n\n// We include packet.zng.h to use Packet methods\n#include <packet.zng.h>\n\nnamespace cpp_stats {\n\nclass StatsAccumulator {\n  std::vector<uint64_t> timestamps;\n  std::vector<uint32_t> sizes;\n\npublic:\n  StatsAccumulator() = default;\n\n  void add_packet(const rust::packet::Packet &p) {\n    timestamps.push_back(p.timestamp());\n    sizes.push_back(p.size());\n  }\n\n  void print_report() const {\n    uint64_t total_size = std::accumulate(sizes.begin(), sizes.end(), 0ULL);\n    double latency_avg = 0;\n    for (int i = 1; i < timestamps.size(); ++i) {\n      latency_avg += static_cast<double>(timestamps[i] - timestamps[i - 1]) /\n                     (timestamps.size() - 1);\n    }\n\n    std::cout << \"LatencyAnalysis Report:\" << std::endl;\n    std::cout << \"Total Packets: \" << timestamps.size() << std::endl;\n    std::cout << \"Total Bytes: \" << total_size << std::endl;\n    if (!timestamps.empty()) {\n      std::cout << \"Average Latency: \" << latency_avg << std::endl;\n    }\n  }\n};\n\n} // namespace cpp_stats\n"
  },
  {
    "path": "examples/multiple_modules/expected_output.txt",
    "content": "Starting LatencyAnalysis simulation...\nLatencyAnalysis Report:\nTotal Packets: 5\nTotal Bytes: 150\nAverage Latency: 100\n"
  },
  {
    "path": "examples/multiple_modules/main.cpp",
    "content": "#include <iostream>\n\n#include <aggregation.zng.h>\n#include <packet.zng.h>\n#include <processor.zng.h>\n#include <receiver.zng.h>\n\nint main() {\n  auto processor = rust::std::option::Option<rust::processor::Processor>::Some(\n      rust::processor::Processor::new_());\n  auto receiver = rust::std::option::Option<rust::receiver::Receiver>::Some(\n      rust::receiver::Receiver::new_());\n  auto stats =\n      rust::Impl<rust::aggregation::StatsAccumulator, rust::Inherent>::create();\n\n  std::cout << \"Starting LatencyAnalysis simulation...\" << std::endl;\n\n  processor.unwrap().run(receiver.unwrap(), stats, 5);\n\n  rust::Impl<rust::aggregation::StatsAccumulator, rust::Inherent>::print_report(\n      stats);\n\n  return 0;\n}\n"
  },
  {
    "path": "examples/multiple_modules/packet/Cargo.toml",
    "content": "[package]\nname = \"packet\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"rlib\"]\n\n[dependencies]\n"
  },
  {
    "path": "examples/multiple_modules/packet/packet.zng",
    "content": "type crate::Packet {\n    #layout(size = 16, align = 8); // u64 timestamp, u32 size\n    fn new(u64, u32) -> crate::Packet;\n    fn timestamp(&self) -> u64;\n    fn size(&self) -> u32;\n}\n"
  },
  {
    "path": "examples/multiple_modules/packet/src/lib.rs",
    "content": "pub struct Packet(pub u64, pub u32);\n\nimpl Packet {\n    pub fn new(timestamp: u64, size: u32) -> Self {\n        Packet(timestamp, size)\n    }\n\n    pub fn timestamp(&self) -> u64 {\n        self.0\n    }\n\n    pub fn size(&self) -> u32 {\n        self.1\n    }\n}\n\n#[rustfmt::skip]\n#[path = \"packet.zng.rs\"]\nmod generated;\n"
  },
  {
    "path": "examples/multiple_modules/processor/Cargo.toml",
    "content": "[package]\nname = \"processor\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"rlib\"]\n\n[dependencies]\nreceiver = { path = \"../receiver\" }\naggregation = { path = \"../aggregation\" }\n"
  },
  {
    "path": "examples/multiple_modules/processor/processor.zng",
    "content": "import \"receiver.zng\";\nimport \"aggregation.zng\";\n\ntype crate::Processor {\n    #layout(size = 0, align = 1);\n    fn new() -> crate::Processor;\n    fn run(&self, &mut receiver::Receiver, &mut aggregation::StatsAccumulator, u32);\n}\n\n// This isn't necessary for the example but we want to test that specialization\n// of the same type across modules works properly (See receiver.zng)\ntype ::std::option::Option<crate::Processor> {\n    #layout(size = 1, align = 1);\n\n    constructor None;\n    constructor Some(crate::Processor);\n    fn unwrap(self) -> crate::Processor;   \n}\n"
  },
  {
    "path": "examples/multiple_modules/processor/src/lib.rs",
    "content": "pub use aggregation::StatsAccumulator;\npub use receiver::Receiver;\n\npub struct Processor;\n\nimpl Processor {\n    pub fn new() -> Self {\n        Processor\n    }\n\n    pub fn run(\n        &self,\n        receiver: &mut receiver::Receiver,\n        stats: &mut aggregation::StatsAccumulator,\n        count: u32,\n    ) {\n        for _ in 0..count {\n            let packet = receiver.next_packet();\n            stats.add_packet(packet);\n        }\n    }\n}\n\n#[rustfmt::skip]\n#[path = \"processor.zng.rs\"]\nmod generated;\n"
  },
  {
    "path": "examples/multiple_modules/receiver/Cargo.toml",
    "content": "[package]\nname = \"receiver\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"rlib\"]\n\n[dependencies]\npacket = { path = \"../packet\" }\n"
  },
  {
    "path": "examples/multiple_modules/receiver/receiver.zng",
    "content": "import \"packet.zng\";\n\ntype crate::Receiver {\n    #layout(size = 8, align = 8); // count: u64\n    fn new() -> crate::Receiver;\n    fn next_packet(&mut self) -> packet::Packet;\n}\n\n// This isn't necessary for the example but we want to test that specialization\n// of the same type across modules works properly (See processor.zng)\ntype ::std::option::Option<crate::Receiver> {\n    #layout(size = 16, align = 8);\n\n    constructor None;\n    constructor Some(crate::Receiver);\n    fn unwrap(self) -> crate::Receiver;   \n}\n"
  },
  {
    "path": "examples/multiple_modules/receiver/src/lib.rs",
    "content": "pub use packet::Packet;\n\npub struct Receiver {\n    count: u64,\n}\n\nimpl Receiver {\n    pub fn new() -> Self {\n        Receiver { count: 0 }\n    }\n\n    pub fn next_packet(&mut self) -> Packet {\n        self.count += 1;\n        // Simulate packet: timestamp = count * 100, size = count * 10\n        Packet::new(self.count * 100, (self.count * 10) as u32)\n    }\n}\n\n#[rustfmt::skip]\n#[path = \"receiver.zng.rs\"]\nmod generated;\n"
  },
  {
    "path": "examples/multiple_modules/src/lib.rs",
    "content": "// Re-export everything from child crates to ensure symbols are included in the staticlib\n#![allow(unused)]\npub use aggregation::*;\npub use packet::*;\npub use processor::*;\npub use receiver::*;\n"
  },
  {
    "path": "examples/raw_pointer/.gitignore",
    "content": "generated.h\ngenerated.rs\ngenerated.cpp\n"
  },
  {
    "path": "examples/raw_pointer/Cargo.toml",
    "content": "[package]\nname = \"example-raw-pointer\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"staticlib\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "examples/raw_pointer/Makefile",
    "content": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_raw_pointer.a\n\t${CXX} --std=c++17 -Werror main.cpp -g -L ../../target/release/ -l example_raw_pointer\n\n../../target/release/libexample_raw_pointer.a:\n\tcargo build --release\n\ngenerated.h ./src/generated.rs: main.zng\n\tcd ../../zngur-cli && cargo run g -i ../examples/raw_pointer/main.zng --crate-name \"crate\"\n\n.PHONY: ../../target/release/libexample_raw_pointer.a generated.h clean\n\nclean:\n\trm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt\n"
  },
  {
    "path": "examples/raw_pointer/NMakefile",
    "content": "CXX = cl.exe\r\nCXXFLAGS = /W4 /DEBUG /EHsc /std:c++17 # c++17 is needed for panic to exceptions\r\nWINLIBS = ntdll.lib\r\n\r\nEXAMPLE_NAME = raw_pointer\r\n\r\nGENERATED = generated.h src/generated.rs\r\n\r\nRUSTLIB_PATH = ../../target/release/\r\n\r\nRUSTLIB = example_$(EXAMPLE_NAME).lib\r\n\r\na.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)\r\n\t$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)\r\n\r\n$(RUSTLIB_PATH)/$(RUSTLIB) :\r\n\tcargo build --release\r\n\r\n$(GENERATED) : main.zng\r\n\tcd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name \"crate\"\r\n\r\nclean :\r\n\t- del /f /q generated.h generated.cpp src\\generated.rs a.exe main.obj actual_output.txt 2>nul\r\n"
  },
  {
    "path": "examples/raw_pointer/README.md",
    "content": "# Example: Simple\n\nA simple example, used as a demo in the main README file.\n\nTo run this example:\n\n```\nmake\n./a.out\n```\n"
  },
  {
    "path": "examples/raw_pointer/expected_output.txt",
    "content": "[main.cpp:13] s = [\n    2,\n    7,\n]\n[main.cpp:20] s = [\n    2,\n    7,\n    3,\n    10,\n    2,\n]\n[main.cpp:25] ss = [\n    [\n        2,\n        7,\n        3,\n        10,\n        2,\n    ],\n    [],\n]\n[main.cpp:32] ss = [\n    [\n        2,\n        7,\n        3,\n        10,\n        2,\n    ],\n    [],\n    [],\n    [\n        2,\n        7,\n        3,\n        10,\n        2,\n    ],\n    [\n        2,\n        7,\n        3,\n        10,\n        2,\n    ],\n]\n[main.cpp:38] s2 = [\n    2,\n    7,\n    3,\n    10,\n    2,\n    4,\n]\n[main.cpp:40] ss_ptr.read_ref() = [\n    2,\n    7,\n    3,\n    10,\n    2,\n]\n[main.cpp:43] s3_ref_mut = [\n    2000,\n]\n[main.cpp:44] ss = [\n    [\n        2,\n        7,\n        3,\n        10,\n        2,\n    ],\n    [],\n    [\n        2000,\n    ],\n    [\n        2,\n        7,\n        3,\n        10,\n        2,\n    ],\n]\n[main.cpp:48] s4_raw_mut.read_ref() = [\n    2000,\n    5,\n]\n[main.cpp:49] ss = [\n    [\n        2,\n        7,\n        3,\n        10,\n        2,\n    ],\n    [],\n    [\n        2000,\n        5,\n    ],\n    [\n        2,\n        7,\n        3,\n        10,\n        2,\n    ],\n]\n[main.cpp:52] s4_raw.read_ref() = [\n    2000,\n    5,\n]\n[main.cpp:55] ss_ptr2.offset(2).read_ref() = [\n    2000,\n    5,\n]\n[main.cpp:56] ss_ptr2.offset(4).offset(-2).read_ref() = [\n    2000,\n    5,\n]\n[main.cpp:60] s5_raw_mut.read_ref().to_vec() = [\n    10,\n    20,\n    3,\n]\n"
  },
  {
    "path": "examples/raw_pointer/main.cpp",
    "content": "#include <vector>\n\n#include \"./generated.h\"\n\ntemplate <typename T>\nusing Vec = rust::std::vec::Vec<T>;\n\nint main()\n{\n    Vec<int32_t> s = Vec<int32_t>::new_();\n    s.push(2);\n    s.push(7);\n    zngur_dbg(s);\n    s.reserve(3);\n    int32_t* s_ptr = s.as_mut_ptr();\n    s_ptr[2] = 3;\n    s_ptr[3] = 10;\n    s_ptr[4] = 2;\n    s.set_len(5);\n    zngur_dbg(s);\n\n    Vec<Vec<int32_t>> ss = Vec<Vec<int32_t>>::new_();\n    ss.push(s.clone());\n    ss.push(Vec<int32_t>::new_());\n    zngur_dbg(ss);\n    ss.reserve(3);\n    rust::RawMut<Vec<int32_t>> ss_ptr = ss.as_mut_ptr();\n    ss_ptr.offset(2).write(Vec<int32_t>::new_());\n    ss_ptr.offset(3).write(s.clone());\n    ss_ptr.offset(4).write(s.clone());\n    ss.set_len(5);\n    zngur_dbg(ss);\n\n    Vec<int32_t> s2 = ss_ptr.offset(4).read();\n    ss.set_len(4);\n\n    s2.push(4);\n    zngur_dbg(s2);\n\n    zngur_dbg(ss_ptr.read_ref());\n    auto s3_ref_mut = ss_ptr.offset(2).read_mut();\n    s3_ref_mut.push(2000);\n    zngur_dbg(s3_ref_mut);\n    zngur_dbg(ss);\n\n    rust::RawMut<Vec<int32_t>> s4_raw_mut = ss.get_mut(2).unwrap();\n    s4_raw_mut.read_mut().push(5);\n    zngur_dbg(s4_raw_mut.read_ref());\n    zngur_dbg(ss);\n\n    rust::Raw<Vec<int32_t>> s4_raw = ss.get_mut(2).unwrap();\n    zngur_dbg(s4_raw.read_ref());\n\n    rust::Raw<Vec<int32_t>> ss_ptr2 = ss.as_ptr();\n    zngur_dbg(ss_ptr2.offset(2).read_ref());\n    zngur_dbg(ss_ptr2.offset(4).offset(-2).read_ref());\n\n    std::vector<int32_t> v { 10, 20, 3, 15 };\n    rust::RawMut<rust::Slice<int32_t>> s5_raw_mut { { reinterpret_cast<uint8_t*>(v.data()), 3 } };\n    zngur_dbg(s5_raw_mut.read_ref().to_vec());\n}\n"
  },
  {
    "path": "examples/raw_pointer/main.zng",
    "content": "#convert_panic_to_exception\n\ntype str {\n    wellknown_traits(?Sized);\n\n    fn to_owned(&self) -> ::std::string::String;\n}\n\ntype ::std::string::String {\n    #heap_allocated;\n}\n\ntype [i32] {\n    wellknown_traits(?Sized);\n\n    fn as_ptr(&self) -> *const i32;\n    fn len(&self) -> usize;\n    fn to_vec(&self) -> ::std::vec::Vec<i32>;\n}\n\nmod ::std {\n    mod option {\n        type Option<&mut ::std::vec::Vec<i32>> {\n            #layout(size = 8, align = 8);\n            \n            fn unwrap(self) -> &mut ::std::vec::Vec<i32>;\n        }\n    }\n\n    mod vec {\n        type Vec<i32> {\n            #layout(size = 24, align = 8);\n            wellknown_traits(Debug);\n\n            fn new() -> Vec<i32>;\n            fn push(&mut self, i32);\n            fn clone(&self) -> Vec<i32>;\n            fn reserve(&mut self, usize);\n            fn set_len(&mut self, usize);\n            fn as_mut_ptr(&mut self) -> *mut i32;\n        }\n\n        type Vec<Vec<i32>> {\n            #layout(size = 24, align = 8);\n            wellknown_traits(Debug);\n\n            fn new() -> Vec<Vec<i32>>;\n            fn push(&mut self, Vec<i32>);\n            fn clone(&self) -> Vec<Vec<i32>>;\n            fn get_mut(&mut self, usize) -> ::std::option::Option<&mut Vec<i32>> deref [Vec<i32>];\n            fn reserve(&mut self, usize);\n            fn set_len(&mut self, usize);\n            fn as_mut_ptr(&mut self) -> *mut Vec<i32>;\n            fn as_ptr(&self) -> *const Vec<i32>;\n        }\n    }\n}\n"
  },
  {
    "path": "examples/raw_pointer/src/lib.rs",
    "content": "#[rustfmt::skip]\nmod generated;\n"
  },
  {
    "path": "examples/rayon/.gitignore",
    "content": "generated.h\ngenerated.rs\ngenerated.cpp\nhistory.txt\n"
  },
  {
    "path": "examples/rayon/Cargo.toml",
    "content": "[package]\nname = \"example-rayon\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"staticlib\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrayon = \"1.7.0\"\n"
  },
  {
    "path": "examples/rayon/Makefile",
    "content": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_rayon.a\n\t${CXX} -std=c++11 -Werror main.cpp -g -L ../../target/release/ -l example_rayon\n\n../../target/release/libexample_rayon.a:\n\tcargo build --release\n\ngenerated.h ./src/generated.rs: main.zng\n\tcd ../../zngur-cli && cargo run g -i ../examples/rayon/main.zng --crate-name \"crate\"\n\n.PHONY: ../../target/release/libexample_rayon.a generated.h clean\n\nclean:\n\trm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt\n"
  },
  {
    "path": "examples/rayon/NMakefile",
    "content": "CXX = cl.exe\r\nCXXFLAGS = /W4 /DEBUG /EHsc /std:c++14 # c++14 is as low as msvc goes\r\nWINLIBS = ntdll.lib\r\n\r\nEXAMPLE_NAME = rayon\r\n\r\nGENERATED = generated.h src/generated.rs\r\n\r\nRUSTLIB_PATH = ../../target/release/\r\n\r\nRUSTLIB = example_$(EXAMPLE_NAME).lib\r\n\r\na.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)\r\n\t$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)\r\n\r\n$(RUSTLIB_PATH)/$(RUSTLIB) :\r\n\tcargo build --release\r\n\r\n$(GENERATED) : main.zng\r\n\tcd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name \"crate\"\r\n\r\nclean :\r\n\t- del /f /q generated.h generated.cpp src\\generated.rs a.exe main.obj actual_output.txt 2>nul\r\n"
  },
  {
    "path": "examples/rayon/README.md",
    "content": "# Example: Rayon\n\nCalculates the sum and the number of prime numbers in `1..10000000` with multiple cores using [rayon](https://github.com/rayon-rs/rayon).\n\nTo run this example:\n\n```\nmake\n./a.out\n```\n"
  },
  {
    "path": "examples/rayon/expected_output.txt",
    "content": "Sum = 50000005000000\nCount of primes = 664579\n"
  },
  {
    "path": "examples/rayon/main.cpp",
    "content": "#include <cstddef>\n#include <cstdint>\n#include <iostream>\n#include <numeric>\n#include <vector>\n\n#include \"./generated.h\"\n\ntemplate <typename T> using Box = rust::Box<T>;\ntemplate <typename T> using Ref = rust::Ref<T>;\ntemplate <typename... T> using Dyn = rust::Dyn<T...>;\ntemplate <typename... T> using Fn = rust::Fn<T...>;\nusing rust::Bool;\nusing rust::Send;\nusing rust::Sync;\n\nbool is_prime(uint64_t v) {\n  if (v < 2)\n    return 0;\n  for (int i = 2; i * i <= v; i += 1) {\n    if (v % i == 0) {\n      return 0;\n    }\n  }\n  return 1;\n}\n\nint main() {\n  std::vector<uint64_t> v(10000000);\n  std::iota(v.begin(), v.end(), 1);\n  auto slice = rust::std::slice::from_raw_parts(v.data(), v.size());\n  auto f = Box<Dyn<Fn<Ref<uint64_t>, Bool>, Sync, Send>>::make_box(\n      [&](Ref<uint64_t> x) { return is_prime(*x); });\n  std::cout << \"Sum = \" << slice.par_iter().sum() << std::endl;\n  std::cout << \"Count of primes = \"\n            << slice.par_iter().copied().filter(std::move(f)).count()\n            << std::endl;\n}\n"
  },
  {
    "path": "examples/rayon/main.zng",
    "content": "type bool {\n    #layout(size = 1, align = 1);\n    wellknown_traits(Copy);\n}\n\ntype ::std::option::Option<&u64> {\n    #layout(size = 8, align = 8);\n    wellknown_traits(Debug, Copy);\n    \n    fn unwrap(self) -> &u64;\n}\n\ntype Box<dyn Fn(&u64) -> bool + Sync + Send> {\n    #layout(size = 16, align = 8);\n}\n\ntype ::rayon::iter::Filter<::rayon::iter::Copied<::rayon::slice::Iter<u64>>, Box<dyn Fn(&u64) -> bool + Sync + Send>> {\n    #layout(size = 32, align = 8);\n\n    fn count(self) -> usize use ::rayon::iter::ParallelIterator;\n}\n\ntype ::rayon::slice::Iter<u64> {\n    #layout(size = 16, align = 8);\n\n    fn sum<u64>(self) -> u64 use ::rayon::iter::ParallelIterator;\n    fn copied<u64>(self) -> ::rayon::iter::Copied<::rayon::slice::Iter<u64>> use ::rayon::iter::ParallelIterator;\n}\n\ntype ::rayon::iter::Copied<::rayon::slice::Iter<u64>> {\n    #layout(size = 16, align = 8);\n\n    fn filter<Box<dyn Fn(&u64) -> bool + Sync + Send>>(self, Box<dyn Fn(&u64) -> bool + Sync + Send>)\n                -> ::rayon::iter::Filter<::rayon::iter::Copied<::rayon::slice::Iter<u64>>, Box<dyn Fn(&u64) -> bool + Sync + Send>>\n                use ::rayon::iter::ParallelIterator;\n}\n\ntype [u64] {\n    wellknown_traits(?Sized);\n\n    fn get(&self, usize) -> ::std::option::Option<&u64>;\n    fn par_iter(&self) -> ::rayon::slice::Iter<u64> use ::rayon::iter::IntoParallelRefIterator;\n}\n\nmod ::std::slice {\n    fn from_raw_parts(*const u64, usize) -> &[u64];\n}\n"
  },
  {
    "path": "examples/rayon/src/lib.rs",
    "content": "#[rustfmt::skip]\nmod generated;\n"
  },
  {
    "path": "examples/rayon_split/.gitignore",
    "content": "generated.h\ngenerated.rs\ngenerated.cpp\nhistory.txt\n"
  },
  {
    "path": "examples/rayon_split/Cargo.toml",
    "content": "[package]\nname = \"example-rayon_split\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"staticlib\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrayon = \"1.7.0\"\n"
  },
  {
    "path": "examples/rayon_split/Makefile",
    "content": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_rayon_split.a\n\t${CXX} -std=c++11 -Werror main.cpp -g -L ../../target/release/ -l example_rayon_split -I .\n\n../../target/release/libexample_rayon_split.a:\n\tcargo build --release\n\ngenerated.h ./src/generated.rs: main.zng zngur.h\n\tcd ../../zngur-cli && cargo run g ../examples/rayon_split/main.zng --crate-name \"crate\"\n\nzngur.h:\n\tcd ../../zngur-cli && cargo run h ../examples/rayon_split/zngur.h\n\t\n.PHONY: ../../target/release/libexample_rayon_split.a generated.h clean\n\nclean:\n\trm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt zngur.h\n"
  },
  {
    "path": "examples/rayon_split/NMakefile",
    "content": "CXX = cl.exe\r\nCXXFLAGS = /W4 /DEBUG /EHsc /external:I . /external:W0 /std:c++14 # c++14 is as low as msvc goes\r\nWINLIBS = ntdll.lib\r\n\r\nEXAMPLE_NAME = rayon_split\r\n\r\nGENERATED = generated.h src/generated.rs\r\n\r\nRUSTLIB_PATH = ../../target/release/\r\n\r\nRUSTLIB = example_$(EXAMPLE_NAME).lib\r\n\r\na.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)\r\n\t$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH) \r\n\r\n$(RUSTLIB_PATH)/$(RUSTLIB) :\r\n\tcargo build --release\r\n\r\n$(GENERATED) : main.zng zngur.h\r\n\tcd ../../zngur-cli && cargo run g ../examples/$(EXAMPLE_NAME)/main.zng --crate-name \"crate\"\r\n\r\nzngur.h:\r\n\tcd ../../zngur-cli && cargo run h ../examples/$(EXAMPLE_NAME)/zngur.h\r\n\r\nclean :\r\n\t- del /f /q generated.h generated.cpp src\\generated.rs a.exe main.obj actual_output.txt 2>nul\r\n"
  },
  {
    "path": "examples/rayon_split/README.md",
    "content": "# Example: Rayon\n\nCalculates the sum and the number of prime numbers in `1..10000000` with multiple cores using [rayon](https://github.com/rayon-rs/rayon).\n\nTo run this example:\n\n```\nmake\n./a.out\n```\n"
  },
  {
    "path": "examples/rayon_split/expected_output.txt",
    "content": "Sum = 50000005000000\nCount of primes = 664579\n"
  },
  {
    "path": "examples/rayon_split/main.cpp",
    "content": "#include <cstddef>\n#include <cstdint>\n#include <iostream>\n#include <numeric>\n#include <vector>\n\n#include \"./generated.h\"\n\ntemplate <typename T> using Box = rust::Box<T>;\ntemplate <typename T> using Ref = rust::Ref<T>;\ntemplate <typename... T> using Dyn = rust::Dyn<T...>;\ntemplate <typename... T> using Fn = rust::Fn<T...>;\nusing rust::Bool;\nusing rust::Send;\nusing rust::Sync;\n\nbool is_prime(uint64_t v) {\n  if (v < 2)\n    return 0;\n  for (int i = 2; i * i <= v; i += 1) {\n    if (v % i == 0) {\n      return 0;\n    }\n  }\n  return 1;\n}\n\nint main() {\n  std::vector<uint64_t> v(10000000);\n  std::iota(v.begin(), v.end(), 1);\n  auto slice = rust::std::slice::from_raw_parts(v.data(), v.size());\n  auto f = Box<Dyn<Fn<Ref<uint64_t>, Bool>, Sync, Send>>::make_box(\n      [&](Ref<uint64_t> x) { return is_prime(*x); });\n  std::cout << \"Sum = \" << slice.par_iter().sum() << std::endl;\n  std::cout << \"Count of primes = \"\n            << slice.par_iter().copied().filter(std::move(f)).count()\n            << std::endl;\n}\n"
  },
  {
    "path": "examples/rayon_split/main.zng",
    "content": "type bool {\n    #layout(size = 1, align = 1);\n    wellknown_traits(Copy);\n}\n\ntype ::std::option::Option<&u64> {\n    #layout(size = 8, align = 8);\n    wellknown_traits(Debug, Copy);\n    \n    fn unwrap(self) -> &u64;\n}\n\ntype Box<dyn Fn(&u64) -> bool + Sync + Send> {\n    #layout(size = 16, align = 8);\n}\n\ntype ::rayon::iter::Filter<::rayon::iter::Copied<::rayon::slice::Iter<u64>>, Box<dyn Fn(&u64) -> bool + Sync + Send>> {\n    #layout(size = 32, align = 8);\n\n    fn count(self) -> usize use ::rayon::iter::ParallelIterator;\n}\n\ntype ::rayon::slice::Iter<u64> {\n    #layout(size = 16, align = 8);\n\n    fn sum<u64>(self) -> u64 use ::rayon::iter::ParallelIterator;\n    fn copied<u64>(self) -> ::rayon::iter::Copied<::rayon::slice::Iter<u64>> use ::rayon::iter::ParallelIterator;\n}\n\ntype ::rayon::iter::Copied<::rayon::slice::Iter<u64>> {\n    #layout(size = 16, align = 8);\n\n    fn filter<Box<dyn Fn(&u64) -> bool + Sync + Send>>(self, Box<dyn Fn(&u64) -> bool + Sync + Send>)\n                -> ::rayon::iter::Filter<::rayon::iter::Copied<::rayon::slice::Iter<u64>>, Box<dyn Fn(&u64) -> bool + Sync + Send>>\n                use ::rayon::iter::ParallelIterator;\n}\n\ntype [u64] {\n    wellknown_traits(?Sized);\n\n    fn get(&self, usize) -> ::std::option::Option<&u64>;\n    fn par_iter(&self) -> ::rayon::slice::Iter<u64> use ::rayon::iter::IntoParallelRefIterator;\n}\n\nmod ::std::slice {\n    fn from_raw_parts(*const u64, usize) -> &[u64];\n}\n"
  },
  {
    "path": "examples/rayon_split/src/lib.rs",
    "content": "#[rustfmt::skip]\nmod generated;\n"
  },
  {
    "path": "examples/regression_test1/.gitignore",
    "content": "generated.h\ngenerated.rs\ngenerated.cpp\n"
  },
  {
    "path": "examples/regression_test1/Cargo.toml",
    "content": "[package]\nname = \"example-regression-test1\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"staticlib\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "examples/regression_test1/Makefile",
    "content": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_regression_test1.a\n\t${CXX} -std=c++20 -Werror main.cpp -g -L ../../target/release/ -l example_regression_test1\n\n../../target/release/libexample_regression_test1.a:\n\tcargo build --release\n\ngenerated.h ./src/generated.rs: main.zng\n\tcd ../../zngur-cli && cargo run g -i ../examples/regression_test1/main.zng --crate-name \"crate\"\n\n.PHONY: ../../target/release/libexample_regression_test1.a generated.h clean\n\nclean:\n\trm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt\n"
  },
  {
    "path": "examples/regression_test1/NMakefile",
    "content": "CXX = cl.exe\r\nCXXFLAGS = /W4 /DEBUG /EHsc /std:c++20 \r\nWINLIBS = ntdll.lib\r\n\r\nEXAMPLE_NAME = regression_test1\r\n\r\nGENERATED = generated.h src/generated.rs\r\n\r\nRUSTLIB_PATH = ../../target/release/\r\n\r\nRUSTLIB = example_$(EXAMPLE_NAME).lib\r\n\r\na.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)\r\n\t$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)\r\n\r\n$(RUSTLIB_PATH)/$(RUSTLIB) :\r\n\tcargo build --release\r\n\r\n$(GENERATED) : main.zng\r\n\tcd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name \"crate\"\r\n\r\nclean :\r\n\t- del /f /q generated.h generated.cpp src\\generated.rs a.exe main.obj actual_output.txt 2>nul\r\n"
  },
  {
    "path": "examples/regression_test1/README.md",
    "content": "# Example: Regression test 1\n\nA example, used to check previous Zngur problems in CI.\n\nTo run this example:\n\n```\nmake\n./a.out\n```\n"
  },
  {
    "path": "examples/regression_test1/expected_output.txt",
    "content": "Test dbg works for Ref and RefMut -- started\n[main.cpp:11] v1 = \"foo\"\n[main.cpp:13] v2 = \"foo\"\n[main.cpp:15] v3 = \"foo\"\n[main.cpp:16] v2 = \"foo\"\n[main.cpp:17] v4 = \"foo\"\n[main.cpp:19] v5 = \"foo\"\n[main.cpp:20] \"bar\"_rs = \"bar\"\n[main.cpp:21] v4 = \"foobar\"\nTest dbg works for Ref and RefMut -- finished\n\nTest fields and constructor work -- started\n[main.cpp:31] v1 = Foo {\n    field1: 1,\n    field2: \"bar\",\n}\n[main.cpp:32] v1.field2 = \"bar\"\n[main.cpp:33] v1.field2.len() = 3\n[main.cpp:35] v1 = Foo {\n    field1: 1,\n    field2: \"barbaz\",\n}\n[main.cpp:39] v2 = (\n    \"kkk\",\n    Foo {\n        field1: 1,\n        field2: \"barbaz\",\n    },\n)\n[main.cpp:40] v2.f0 = \"kkk\"\n[main.cpp:41] v2.f1 = Foo {\n    field1: 1,\n    field2: \"barbaz\",\n}\n[main.cpp:42] v2.f1.field2 = \"barbaz\"\n[main.cpp:46] v3.f0 = \"kkk\"\n[main.cpp:47] v3.f1 = Foo {\n    field1: 1,\n    field2: \"barbazxxx\",\n}\n[main.cpp:48] v3.f1.field2 = \"barbazxxx\"\n[main.cpp:51] v3.f1.field2.len() = 9\n[main.cpp:55] v4.f0 = \"kkk\"\n[main.cpp:56] v4.f1 = Foo {\n    field1: 1,\n    field2: \"barbazxxx\",\n}\n[main.cpp:57] v4.f1.field2 = \"barbazxxx\"\n[main.cpp:59] v4.f1.field2.len() = 12\nTest fields and constructor work -- finished\n\nTest Field* underlying conversions -- started\n[main.cpp:71] v0 = 42\n[main.cpp:75] v1 = \"hi\"\n[main.cpp:79] sref.len() = 2\n[main.cpp:82] int32_t(pref.f0) = 42\n[main.cpp:83] pref.f1.len() = 2\n[main.cpp:86] int32_t(pmut.f0) = 42\n[main.cpp:88] pmut.f1.len() = 3\nTest Field* underlying conversions -- finished\n\nTest floats -- started\n[main.cpp:98] *r1 = 12.3\n[main.cpp:100] v1 = 12.3\n[main.cpp:105] fvec = [\n    42.24,\n    147.0,\n]\n[main.cpp:106] fvec.get(0) = Some(\n    42.24,\n)\n[main.cpp:107] fvec.get(2) = None\n[main.cpp:108] *fvec.get(1).unwrap() = 147\n[main.cpp:110] fvec = [\n    42.24,\n    5.43,\n]\nTest floats -- finished\n\nTest dyn Fn() with multiple arguments -- started\nscope passed to dyn Fn -- started\nInner function called\nscope passed to dyn Fn -- finished\n\nEnd of call_dyn_fn_multi_args\nTest dyn Fn() with multiple arguments -- finished\n\nTest Ref<Ref<T>> -- started\n[main.cpp:131] strvec = [\n    \"a str\",\n    \"foobar\",\n    \"a third str\",\n]\n[main.cpp:132] strvec.get(0) = Some(\n    \"a str\",\n)\n[main.cpp:133] strvec.get(2) = Some(\n    \"a third str\",\n)\n[main.cpp:134] *strvec.get(1).unwrap() = \"foobar\"\n[main.cpp:136] strvec = [\n    \"a str\",\n    \"flip flop\",\n    \"a third str\",\n]\nTest Ref<Ref<T>> -- finished\n\nTest zero-sized type -- started\nMethod call on ZST\n[main.cpp:143] zst = ZeroSizedType\nTest zero-sized type -- finished\n\nTest nested Ref<T> where T is #heap_allocated and auto field offsets -- started\n[main.cpp:158] a = TypeA {\n    foo: 10,\n    bar: FieldTypeA {\n        fizz: FieldTypeC {\n            buzz_1: 20,\n            buzz_2: 30,\n            buzz_3: 40,\n        },\n    },\n    baz: FieldTypeB {\n        fizz: FieldTypeC {\n            buzz_1: 50,\n            buzz_2: 60,\n            buzz_3: 70,\n        },\n    },\n}\n[main.cpp:159] ::rust::Ref<int32_t>(a.foo) = 10\n[main.cpp:160] ::rust::Ref<int32_t>(a.bar.fizz.buzz_2) = 30\n[main.cpp:161] ::rust::RefMut<int32_t>(a.baz.fizz.buzz_3) = 70\n[main.cpp:164] ::rust::Ref<int32_t>(a_fa_fizz.buzz_1) = 20\n[main.cpp:166] ::rust::Ref<int32_t>(a_fb_fizz.buzz_2) = 60\n[main.cpp:177] b = TypeB {\n    foo: 100,\n    bar: FieldTypeA {\n        fizz: FieldTypeC {\n            buzz_1: 200,\n            buzz_2: 300,\n            buzz_3: 400,\n        },\n    },\n    baz: FieldTypeB {\n        fizz: FieldTypeC {\n            buzz_1: 500,\n            buzz_2: 600,\n            buzz_3: 700,\n        },\n    },\n}\n[main.cpp:178] ::rust::Ref<int32_t>(b.foo) = 100\n[main.cpp:179] ::rust::Ref<int32_t>(b.bar.fizz.buzz_2) = 300\n[main.cpp:180] ::rust::RefMut<int32_t>(b.baz.fizz.buzz_3) = 700\n[main.cpp:183] ::rust::Ref<int32_t>(b_fa_fizz.buzz_1) = 200\n[main.cpp:185] ::rust::Ref<int32_t>(b_fb_fizz.buzz_2) = 600\n[main.cpp:190] fa = FieldTypeA {\n    fizz: FieldTypeC {\n        buzz_1: 21,\n        buzz_2: 31,\n        buzz_3: 41,\n    },\n}\n[main.cpp:191] ::rust::Ref<int32_t>(fa.fizz.buzz_1) = 21\n[main.cpp:192] ::rust::Ref<int32_t>(fa.fizz.buzz_3) = 41\n[main.cpp:197] fa = FieldTypeA {\n    fizz: FieldTypeC {\n        buzz_1: 21,\n        buzz_2: 31,\n        buzz_3: 41,\n    },\n}\n[main.cpp:198] ::rust::Ref<int32_t>(fb.fizz.buzz_2) = 61\n[main.cpp:199] ::rust::Ref<int32_t>(fb.fizz.buzz_3) = 71\nTest nested Ref<T> where T is #heap_allocated and auto field offsets -- finished\n\nTest #layout_conservative -- started\n[main.cpp:208] c_layout = ConservativeLayoutType {\n    field1: 3.14159,\n    field2: 42,\n    field3: \"A string at some unknown offset\",\n}\nRust( size = 32 , align = 8 )\nc++( size = 48 , align = 8 )\n[main.cpp:220] layouts = [\n    ConservativeLayoutType {\n        field1: 3.14159,\n        field2: 42,\n        field3: \"A string at some unknown offset\",\n    },\n    ConservativeLayoutType {\n        field1: 2.71828,\n        field2: 1000,\n        field3: \"Another test string\",\n    },\n]\n[main.cpp:221] layouts.get(0) = Some(\n    ConservativeLayoutType {\n        field1: 3.14159,\n        field2: 42,\n        field3: \"A string at some unknown offset\",\n    },\n)\n[main.cpp:222] layouts.get(1) = Some(\n    ConservativeLayoutType {\n        field1: 2.71828,\n        field2: 1000,\n        field3: \"Another test string\",\n    },\n)\n[main.cpp:223] layouts.get(1).unwrap() = ConservativeLayoutType {\n    field1: 2.71828,\n    field2: 1000,\n    field3: \"Another test string\",\n}\n[main.cpp:225] layouts = [\n    ConservativeLayoutType {\n        field1: 3.14159,\n        field2: 42,\n        field3: \"A string at some unknown offset\",\n    },\n    ConservativeLayoutType {\n        field1: 2.71828,\n        field2: 10,\n        field3: \"Another test string\",\n    },\n]\nTest #layout_conservative -- finished\n\n"
  },
  {
    "path": "examples/regression_test1/main.cpp",
    "content": "#include <iostream>\n#include <vector>\n\n#include \"./generated.h\"\n\nvoid test_dbg_works_for_ref_and_refmut() {\n  auto scope =\n      rust::crate::Scoped::new_(\"Test dbg works for Ref and RefMut\"_rs);\n\n  rust::Ref<rust::Str> v1 = \"foo\"_rs;\n  zngur_dbg(v1);\n  rust::std::string::String v2 = v1.to_owned();\n  zngur_dbg(v2);\n  rust::Ref<rust::std::string::String> v3 = v2;\n  zngur_dbg(v3);\n  rust::std::string::String v4 = std::move(zngur_dbg(v2));\n  zngur_dbg(v4);\n  rust::RefMut<rust::std::string::String> v5 = v4;\n  zngur_dbg(v5);\n  v5.push_str(zngur_dbg(\"bar\"_rs));\n  zngur_dbg(v4);\n}\n\ntemplate <typename T>\nconcept has_push_str = requires(T v, rust::Ref<rust::Str> s) { v.push_str(s); };\n\nvoid test_fields_and_constructor() {\n  auto scope = rust::crate::Scoped::new_(\"Test fields and constructor work\"_rs);\n\n  rust::crate::Foo v1 = rust::crate::Foo{1, \"bar\"_rs.to_owned()};\n  zngur_dbg(v1);\n  zngur_dbg(v1.field2);\n  zngur_dbg(v1.field2.len());\n  v1.field2.push_str(\"baz\"_rs);\n  zngur_dbg(v1);\n\n  rust::Tuple<rust::std::string::String, rust::crate::Foo> v2{\n      \"kkk\"_rs.to_owned(), std::move(v1)};\n  zngur_dbg(v2);\n  zngur_dbg(v2.f0);\n  zngur_dbg(v2.f1);\n  zngur_dbg(v2.f1.field2);\n  v2.f1.field2.push_str(\"xxx\"_rs);\n\n  rust::Ref<rust::Tuple<rust::std::string::String, rust::crate::Foo>> v3 = v2;\n  zngur_dbg(v3.f0);\n  zngur_dbg(v3.f1);\n  zngur_dbg(v3.f1.field2);\n  static_assert(has_push_str<decltype(v2.f1.field2)>);\n  static_assert(!has_push_str<decltype(v3.f1.field2)>);\n  zngur_dbg(v3.f1.field2.len());\n\n  rust::RefMut<rust::Tuple<rust::std::string::String, rust::crate::Foo>> v4 =\n      v2;\n  zngur_dbg(v4.f0);\n  zngur_dbg(v4.f1);\n  zngur_dbg(v4.f1.field2);\n  v4.f1.field2.push_str(\"yyy\"_rs);\n  zngur_dbg(v4.f1.field2.len());\n}\n\nvoid test_field_underlying_conversions() {\n  auto scope =\n      rust::crate::Scoped::new_(\"Test Field* underlying conversions\"_rs);\n\n  rust::Tuple<int32_t, rust::std::string::String> pair{42, \"hi\"_rs.to_owned()};\n\n  // FieldOwned conversion to Ref and value\n  rust::Ref<int32_t> r0 = pair.f0;\n  int32_t v0 = pair.f0;\n  zngur_dbg(v0);\n  // Types which are not `Copy` cannot support implicit conversion to T.\n  // We must use `.clone()` or similar methods to get a copy.\n  rust::std::string::String v1 = pair.f1.clone();\n  zngur_dbg(v1);\n\n  // FieldOwned<String> to Ref<String> and call a method\n  rust::Ref<rust::std::string::String> sref = pair.f1;\n  zngur_dbg(sref.len());\n\n  rust::Ref<rust::Tuple<int32_t, rust::std::string::String>> pref = pair;\n  zngur_dbg(int32_t(pref.f0));\n  zngur_dbg(pref.f1.len());\n\n  rust::RefMut<rust::Tuple<int32_t, rust::std::string::String>> pmut = pair;\n  zngur_dbg(int32_t(pmut.f0));\n  pmut.f1.push_str(\"!\"_rs);\n  zngur_dbg(pmut.f1.len());\n}\n\nvoid test_floats() {\n  auto scope = rust::crate::Scoped::new_(\"Test floats\"_rs);\n\n  rust::Tuple<float, double> pair{42.24, 12.3};\n\n  // FieldOwned conversion to Ref and value\n  rust::Ref<double> r1 = pair.f1;\n  zngur_dbg(*r1);\n  double v1 = pair.f1;\n  zngur_dbg(v1);\n\n  rust::std::vec::Vec<float> fvec = rust::std::vec::Vec<float>::new_();\n  fvec.push(pair.f0);\n  fvec.push(147);\n  zngur_dbg(fvec);\n  zngur_dbg(fvec.get(0));\n  zngur_dbg(fvec.get(2));\n  zngur_dbg(*fvec.get(1).unwrap());\n  *fvec.get_mut(1).unwrap() = 5.43;\n  zngur_dbg(fvec);\n}\n\nvoid test_dyn_fn_with_multiple_arguments() {\n  auto scope = rust::crate::Scoped::new_(\"Test dyn Fn() with multiple arguments\"_rs);\n  rust::crate::call_dyn_fn_multi_args(rust::Box<rust::Dyn<rust::Fn<int32_t, rust::crate::Scoped, rust::Ref<rust::Str>, rust::Unit>>>::make_box(\n      [](int32_t arg0, rust::crate::Scoped arg1, rust::Ref<rust::Str> arg2) {\n        std::cout << \"Inner function called\" << std::endl;\n        return rust::Unit{};\n      }\n  ));\n}\n\nvoid test_refref() {\n  auto scope = rust::crate::Scoped::new_(\"Test Ref<Ref<T>>\"_rs);\n\n  rust::std::vec::Vec<rust::Ref<rust::Str>> strvec = rust::std::vec::Vec<rust::Ref<rust::Str>>::new_();\n\n  strvec.push(\"a str\"_rs);\n  strvec.push(\"foobar\"_rs);\n  strvec.push(\"a third str\"_rs);\n  zngur_dbg(strvec);\n  zngur_dbg(strvec.get(0));\n  zngur_dbg(strvec.get(2));\n  zngur_dbg(*strvec.get(1).unwrap());\n  *strvec.get_mut(1).unwrap() = \"flip flop\"_rs;\n  zngur_dbg(strvec);\n}\n\nvoid test_zero_sized_type() {\n  auto scope = rust::crate::Scoped::new_(\"Test zero-sized type\"_rs);\n  auto zst = rust::crate::ZeroSizedType::new_();\n  zst.method();\n  zngur_dbg(zst);\n}\n\nvoid test_nested_heap_refs_and_auto_field_offset() {\n  auto scope = rust::crate::Scoped::new_(\"Test nested Ref<T> where T is #heap_allocated and auto field offsets\"_rs);\n\n  auto a = ::rust::crate::TypeA { \n    10,\n    ::rust::crate::FieldTypeA {\n      ::rust::crate::FieldTypeC { 20, 30, 40 }\n    },\n    ::rust::crate::FieldTypeB {\n      ::rust::crate::FieldTypeC { 50, 60, 70 }\n    },\n  };\n  zngur_dbg(a);\n  zngur_dbg(::rust::Ref<int32_t>(a.foo));\n  zngur_dbg(::rust::Ref<int32_t>(a.bar.fizz.buzz_2));\n  zngur_dbg(::rust::RefMut<int32_t>(a.baz.fizz.buzz_3));\n\n  auto a_fa_fizz = ::rust::Ref<::rust::crate::FieldTypeC>(a.bar.fizz);\n  zngur_dbg(::rust::Ref<int32_t>(a_fa_fizz.buzz_1));\n  auto a_fb_fizz = ::rust::Ref<::rust::crate::FieldTypeC>(a.baz.fizz);\n  zngur_dbg(::rust::Ref<int32_t>(a_fb_fizz.buzz_2));\n\n  auto b = ::rust::crate::TypeB { \n    100,\n    ::rust::crate::FieldTypeA {\n      ::rust::crate::FieldTypeC { 200, 300, 400 }\n    },\n    ::rust::crate::FieldTypeB {\n      ::rust::crate::FieldTypeC { 500, 600, 700 }\n    },\n  };\n  zngur_dbg(b);\n  zngur_dbg(::rust::Ref<int32_t>(b.foo));\n  zngur_dbg(::rust::Ref<int32_t>(b.bar.fizz.buzz_2));\n  zngur_dbg(::rust::RefMut<int32_t>(b.baz.fizz.buzz_3));\n\n  auto b_fa_fizz = ::rust::Ref<::rust::crate::FieldTypeC>(b.bar.fizz);\n  zngur_dbg(::rust::Ref<int32_t>(b_fa_fizz.buzz_1));\n  auto b_fb_fizz = ::rust::Ref<::rust::crate::FieldTypeC>(b.baz.fizz);\n  zngur_dbg(::rust::Ref<int32_t>(b_fb_fizz.buzz_2));\n\n  auto fa = ::rust::crate::FieldTypeA {\n      ::rust::crate::FieldTypeC { 21, 31, 41 }\n  };\n  zngur_dbg(fa);\n  zngur_dbg(::rust::Ref<int32_t>(fa.fizz.buzz_1));\n  zngur_dbg(::rust::Ref<int32_t>(fa.fizz.buzz_3));\n\n  auto fb = ::rust::crate::FieldTypeB {\n      ::rust::crate::FieldTypeC { 51, 61, 71 }\n  };\n  zngur_dbg(fa);\n  zngur_dbg(::rust::Ref<int32_t>(fb.fizz.buzz_2));\n  zngur_dbg(::rust::Ref<int32_t>(fb.fizz.buzz_3));\n}\n\nvoid test_conservative_layout() {\n  auto scope = rust::crate::Scoped::new_(\"Test #layout_conservative\"_rs);\n\n  auto c_layout = ::rust::crate::ConservativeLayoutType {\n      3.14159, 42, \"A string at some unknown offset\"_rs.to_owned() \n  };\n  zngur_dbg(c_layout);\n\n  std::cout << \"Rust( size = \" << c_layout.mem_size() << \" , align = \" << c_layout.mem_align() << \" )\\n\";\n  std::cout << \"c++( size = \" << sizeof(c_layout.__zngur_data) << \" , align = \" << alignof(decltype(c_layout)) << \" )\\n\";\n\n  rust::std::vec::Vec<::rust::crate::ConservativeLayoutType> layouts = rust::std::vec::Vec<::rust::crate::ConservativeLayoutType>::new_();\n  layouts.push(std::move(c_layout));\n  layouts.push(\n    ::rust::crate::ConservativeLayoutType {\n        2.71828, 1000, \"Another test string\"_rs.to_owned() \n    }\n  );\n  zngur_dbg(layouts);\n  zngur_dbg(layouts.get(0));\n  zngur_dbg(layouts.get(1));\n  zngur_dbg(layouts.get(1).unwrap());\n  *::rust::RefMut<int32_t>(layouts.get_mut(1).unwrap().field2) = 10;\n  zngur_dbg(layouts);\n\n}\n\nint main() {\n  test_dbg_works_for_ref_and_refmut();\n  test_fields_and_constructor();\n  test_field_underlying_conversions();\n  test_floats();\n  test_dyn_fn_with_multiple_arguments();\n  test_refref();\n  test_zero_sized_type();\n  test_nested_heap_refs_and_auto_field_offset();\n  test_conservative_layout();\n}\n"
  },
  {
    "path": "examples/regression_test1/main.zng",
    "content": "#convert_panic_to_exception\n\ntype bool {\n\t#layout(size = 1, align = 1);\n\twellknown_traits(Copy);\n}\n\ntype str {\n    wellknown_traits(?Sized, Debug);\n\n    fn as_ptr(&self) -> *const u8;\n    fn len(&self) -> usize;\n    fn to_owned(&self) -> ::std::string::String;\n}\n\ntype ::std::string::String {\n    #layout(size = 24, align = 8);\n    wellknown_traits(Debug);\n\n    fn clone(&self) -> ::std::string::String;\n    fn push_str(&mut self, &str);\n    fn len(&self) -> usize;\n}\n\ntype crate::Foo {\n    #layout(size = 32, align = 8);\n    wellknown_traits(Debug);\n\n    constructor { field1: i32, field2: ::std::string::String };\n    field field2 (offset = 0, type = ::std::string::String);\n}\n\ntype (::std::string::String, crate::Foo) {\n    #layout(size = 56, align = 8);\n    wellknown_traits(Debug);\n\n    field 0 (offset = 0, type = ::std::string::String);\n    field 1 (offset = 24, type = crate::Foo);\n}\n\ntype (i32, ::std::string::String) {\n    #layout(size = 32, align = 8);\n    wellknown_traits(Debug);\n\n    field 0 (offset = 0, type = i32);\n    field 1 (offset = 8, type = ::std::string::String);\n}\n\ntype (f32, f64) {\n    #layout(size = 16, align = 8);\n    wellknown_traits(Debug);\n\n    field 0 (offset = 0, type = f32);\n    field 1 (offset = 8, type = f64);\n}\n\nmod ::std::option {\n    type Option<&f32> {\n        #layout(size = 8, align = 8);\n        wellknown_traits(Debug, Copy);\n\n        fn is_some(&self) -> bool;\n        fn unwrap(self) -> &f32;\n    }\n\n    type Option<&mut f32> {\n        #layout(size = 8, align = 8);\n        wellknown_traits(Debug);\n\n        fn is_some(&self) -> bool;\n        fn unwrap(self) -> &f32;\n    }\n\n    type Option<&&str> {\n        #layout(size = 8, align = 8);\n        wellknown_traits(Debug, Copy);\n\n        fn is_some(&self) -> bool;\n        fn unwrap(self) -> &&str;\n    }\n\n    type Option<&mut &str> {\n        #layout(size = 8, align = 8);\n        wellknown_traits(Debug);\n\n        fn is_some(&self) -> bool;\n        fn unwrap(self) -> &mut &str;\n    }\n\n    type Option<&crate::ConservativeLayoutType> {\n        #layout(size = 8, align = 8);\n        wellknown_traits(Debug, Copy);\n\n        fn is_some(&self) -> bool;\n        fn unwrap(self) -> &crate::ConservativeLayoutType;\n    }\n\n    type Option<&mut crate::ConservativeLayoutType> {\n        #layout(size = 8, align = 8);\n        wellknown_traits(Debug);\n\n        fn is_some(&self) -> bool;\n        fn unwrap(self) -> &mut crate::ConservativeLayoutType;\n    }\n}\n\nmod ::std::vec {\n    type Vec<f32> {\n        #layout(size = 24, align = 8);\n        wellknown_traits(Debug);\n\n        fn new() -> Vec<f32>;\n        fn get(&self, usize) -> ::std::option::Option<&f32> deref [f32];\n        fn get_mut(&mut self, usize) -> ::std::option::Option<&mut f32> deref [f32];\n        fn push(&mut self, f32);\n    }\n\n    type Vec<&str> {\n        #layout(size = 24, align = 8);\n        wellknown_traits(Debug);\n\n        fn new() -> Vec<&str>;\n        fn get(&self, usize) -> ::std::option::Option<&&str> deref [&str];\n        fn get_mut(&mut self, usize) -> ::std::option::Option<&mut &str> deref [&str];\n        fn push(&mut self, &str);\n    }\n\n    type Vec<crate::ConservativeLayoutType> {\n        #layout(size = 24, align = 8);\n        wellknown_traits(Debug);\n\n        fn new() -> Vec<crate::ConservativeLayoutType>;\n        fn get(&self, usize) -> ::std::option::Option<&crate::ConservativeLayoutType> deref [crate::ConservativeLayoutType];\n        fn get_mut(&mut self, usize) -> ::std::option::Option<&mut crate::ConservativeLayoutType> deref [crate::ConservativeLayoutType];\n        fn push(&mut self, crate::ConservativeLayoutType);\n    }\n}\n\ntype crate::Scoped {\n    #layout(size = 16, align = 8);\n\n    fn new(&str) -> crate::Scoped;\n}\n\ntype Box<dyn Fn(i32, crate::Scoped, &str)> {\n    #layout(size = 16, align = 8);\n}\n\ntype crate::ZeroSizedType {\n    #layout(size = 0, align = 1);\n    wellknown_traits(Debug);\n    fn new() -> crate::ZeroSizedType;\n    fn method(&self);\n}\n\nmod crate {\n    fn call_dyn_fn_multi_args(Box<dyn Fn(i32, crate::Scoped, &str)>);\n}\n\ntype crate::FieldTypeA {\n    #layout(size = 12, align = 4);\n    wellknown_traits(Debug, Copy);\n    constructor { fizz: crate::FieldTypeC };\n\n    field fizz (offset = 0, type = crate::FieldTypeC );\n}\n\ntype crate::FieldTypeB {\n    #heap_allocated;\n    wellknown_traits(Debug, Copy);\n    constructor { fizz: crate::FieldTypeC };\n\n    field fizz (offset = 0, type = crate::FieldTypeC );\n}\n\ntype crate::FieldTypeC {\n    #layout(size = 12, align = 4);\n    wellknown_traits(Debug, Copy);\n    constructor { buzz_1: i32, buzz_2: i32, buzz_3: i32 };\n\n    field buzz_1 (offset = auto, type = i32 );\n    field buzz_2 (offset = auto, type = i32 );\n    field buzz_3 (offset = auto, type = i32 );\n}\n\ntype crate::TypeA {\n    #layout(size = 28, align = 4);\n    wellknown_traits(Debug, Copy);\n    constructor { foo: i32, bar: crate::FieldTypeA, baz: crate::FieldTypeB };\n\n    field foo (offset = 0, type = i32 );\n    field bar (offset = 4, type = crate::FieldTypeA );\n    field baz (offset = 16, type = crate::FieldTypeB );\n}\n\ntype crate::TypeB {\n    #heap_allocated;\n    wellknown_traits(Debug, Copy);\n    constructor { foo: i32, bar: crate::FieldTypeA, baz: crate::FieldTypeB };\n\n    field foo (offset = 0, type = i32 );\n    field bar (offset = 4, type = crate::FieldTypeA );\n    field baz (offset = 16, type = crate::FieldTypeB );\n}\n\ntype crate::ConservativeLayoutType {\n    // bigger than the real size of 32\n    #layout_conservative(size = 48, align = 8 );\n    wellknown_traits(Debug);\n    constructor { field1: f32, field2: i32, field3: ::std::string::String };\n\n    field field1 (offset = auto, type = f32 );\n    field field2 (offset = auto, type = i32 );\n    field field3 (offset = auto, type = ::std::string::String );\n\n    fn mem_size(&self) -> usize;\n    fn mem_align(&self) -> usize;\n}\n"
  },
  {
    "path": "examples/regression_test1/src/lib.rs",
    "content": "#[rustfmt::skip]\nmod generated;\n\n#[allow(unused)]\n#[derive(Debug)]\nstruct Foo {\n    field1: i32,\n    field2: String,\n}\n\n#[allow(unused)]\n#[derive(Debug, Copy, Clone)]\nstruct FieldTypeA {\n    pub fizz: FieldTypeC,\n}\n\n#[allow(unused)]\n#[derive(Debug, Copy, Clone)]\n// heap allocated\nstruct FieldTypeB {\n    pub fizz: FieldTypeC,\n}\n\n#[allow(unused)]\n#[derive(Debug, Copy, Clone)]\n// auto field offset\nstruct FieldTypeC {\n    pub buzz_1: i32,\n    pub buzz_2: i32,\n    pub buzz_3: i32,\n}\n\n#[allow(unused)]\n#[derive(Debug, Copy, Clone)]\nstruct TypeA {\n    pub foo: i32,\n    pub bar: FieldTypeA,\n    pub baz: FieldTypeB,\n}\n\n#[allow(unused)]\n#[derive(Debug, Copy, Clone)]\n// heap allocated\nstruct TypeB {\n    pub foo: i32,\n    pub bar: FieldTypeA,\n    pub baz: FieldTypeB,\n}\n\n#[allow(unused)]\n#[derive(Debug)]\n/// auto field offset + layout_conservative\nstruct ConservativeLayoutType {\n    pub field1: f32,\n    pub field2: i32,\n    pub field3: String,\n}\n\n#[allow(unused)]\nimpl ConservativeLayoutType {\n    pub fn mem_size(&self) -> usize {\n        std::mem::size_of::<Self>()\n    }\n    pub fn mem_align(&self) -> usize {\n        std::mem::align_of::<Self>()\n    }\n}\n\nstruct Scoped(&'static str);\n\nimpl Scoped {\n    fn new(message: &'static str) -> Self {\n        println!(\"{message} -- started\");\n        Self(message)\n    }\n}\n\nimpl Drop for Scoped {\n    fn drop(&mut self) {\n        println!(\"{} -- finished\", self.0);\n        println!();\n    }\n}\n\nfn call_dyn_fn_multi_args(func: Box<dyn Fn(i32, crate::Scoped, &str)>) {\n    let scope = Scoped::new(\"scope passed to dyn Fn\");\n    func(2, scope, \"hello\");\n    println!(\"End of call_dyn_fn_multi_args\");\n}\n\n#[derive(Debug)]\nstruct ZeroSizedType;\n\nimpl ZeroSizedType {\n    fn new() -> Self {\n        Self\n    }\n\n    fn method(&self) {\n        println!(\"Method call on ZST\");\n    }\n}\n"
  },
  {
    "path": "examples/rustyline/.gitignore",
    "content": "generated.h\ngenerated.rs\nhistory.txt\n"
  },
  {
    "path": "examples/rustyline/Cargo.toml",
    "content": "[package]\nname = \"example-rustyline\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"staticlib\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrustyline = \"12.0.0\"\n"
  },
  {
    "path": "examples/rustyline/Makefile",
    "content": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_rustyline.a\n\t${CXX} -std=c++11 -Werror main.cpp -g -L ../../target/release/ -l example_rustyline\n\n../../target/release/libexample_rustyline.a:\n\tcargo build --release\n\ngenerated.h ./src/generated.rs: main.zng\n\tcd ../../zngur-cli && cargo run g -i ../examples/rustyline/main.zng --crate-name \"crate\"\n\n.PHONY: ../../target/release/libexample_rustyline.a generated.h clean\n\nclean:\n\trm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt\n"
  },
  {
    "path": "examples/rustyline/NMakefile",
    "content": "CXX = cl.exe\r\nCXXFLAGS = /W4 /DEBUG /EHsc /std:c++20 \r\nWINLIBS = ntdll.lib User32.lib\r\n\r\nEXAMPLE_NAME = rustyline\r\n\r\nGENERATED = generated.h src/generated.rs\r\n\r\nRUSTLIB_PATH = ../../target/release/\r\n\r\nRUSTLIB = example_$(EXAMPLE_NAME).lib\r\n\r\na.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)\r\n\t$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)\r\n\r\n$(RUSTLIB_PATH)/$(RUSTLIB) :\r\n\tcargo build --release\r\n\r\n$(GENERATED) : main.zng\r\n\tcd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name \"crate\"\r\n\r\nclean :\r\n\t- del /f /q generated.h generated.cpp src\\generated.rs a.exe main.obj actual_output.txt 2>nul\r\n"
  },
  {
    "path": "examples/rustyline/README.md",
    "content": "# Example: Rustyline\n\nLine by line port of the [`rustyline` example](https://github.com/kkawakam/rustyline#example) in C++:\n\n```Rust\nuse rustyline::error::ReadlineError;\nuse rustyline::{DefaultEditor, Result};\n\nfn main() -> Result<()> {\n    // `()` can be used when no completer is required\n    let mut rl = DefaultEditor::new()?;\n    #[cfg(feature = \"with-file-history\")]\n    if rl.load_history(\"history.txt\").is_err() {\n        println!(\"No previous history.\");\n    }\n    loop {\n        let readline = rl.readline(\">> \");\n        match readline {\n            Ok(line) => {\n                rl.add_history_entry(line.as_str());\n                println!(\"Line: {}\", line);\n            },\n            Err(ReadlineError::Interrupted) => {\n                println!(\"CTRL-C\");\n                break\n            },\n            Err(ReadlineError::Eof) => {\n                println!(\"CTRL-D\");\n                break\n            },\n            Err(err) => {\n                println!(\"Error: {:?}\", err);\n                break\n            }\n        }\n    }\n    #[cfg(feature = \"with-file-history\")]\n    rl.save_history(\"history.txt\");\n    Ok(())\n}\n```\n\nTo run this example:\n\n```\nmake\n./a.out\n```\n"
  },
  {
    "path": "examples/rustyline/expected_output.txt",
    "content": "No previous history.\nCTRL-D\n"
  },
  {
    "path": "examples/rustyline/main.cpp",
    "content": "#include <cstddef>\n#include <cstdint>\n#include <iostream>\n#include <vector>\n\n#include \"./generated.h\"\n\nint main() {\n  auto editor = rust::rustyline::DefaultEditor::new_().unwrap();\n  if (editor.load_history(\"history.txt\"_rs).is_err()) {\n    std::cout << \"No previous history.\" << std::endl;\n  }\n  while (true) {\n    auto r = editor.readline(\">>> \"_rs);\n    if (r.is_err()) {\n      auto e = r.unwrap_err();\n      if (e.matches_Eof()) {\n        std::cout << \"CTRL-D\" << std::endl;\n      }\n      if (e.matches_Interrupted()) {\n        std::cout << \"CTRL-C\" << std::endl;\n      }\n      break;\n    } else {\n      auto s = r.as_ref().unwrap().as_str();\n      std::string cpp_s((char *)s.as_ptr(), s.len());\n      std::cout << \"Line: \" << cpp_s << std::endl;\n      editor.add_history_entry(s);\n    }\n  }\n  editor.save_history(\"history.txt\"_rs);\n}\n"
  },
  {
    "path": "examples/rustyline/main.zng",
    "content": "// This example uses various layout policies to demonstrate them. See https://hkalbasi.github.io/zngur/call_rust_from_cpp/layout_policy.html\ntype str {\n    wellknown_traits(?Sized); // Unsized types don't need layout policy\n\n    fn as_ptr(&self) -> *const u8;\n    fn len(&self) -> usize;\n}\n\ntype bool {\n    #layout(size = 1, align = 1); // primitives like bool have stable layout\n    wellknown_traits(Copy);\n}\n\nmod ::std {\n    type string::String {\n        #only_by_ref; // String has stable layout, but we don't use it by value, so we can use this policy.\n        fn as_str(&self) -> &str;\n    }\n}\n\nmod ::rustyline {\n    type DefaultEditor {\n        // DefaultEditor is a complex type defined by rustyline crate, so its layout may break\n        // when upgrading the compiler or the rustyline itself. We can easily manage this kind\n        // of breakage when we control the final binary build process, but when we don't control, it\n        // can break. Using `#heap_allocate` we don't need to know the layout information at compile time.\n        #heap_allocated;\n    \n        fn new() -> Result<DefaultEditor>;\n        fn readline(&mut self, &str) -> Result<::std::string::String>;\n        fn load_history<str>(&mut self, &str) -> Result<()>;\n        fn add_history_entry<&str>(&mut self, &str) -> Result<bool>;\n        fn save_history<str>(&mut self, &str) -> Result<()>;\n    }\n\n    type error::ReadlineError {\n        #heap_allocated;\n\n        constructor Interrupted;\n        constructor Eof;\n    }\n\n    type Result<DefaultEditor> {\n        #heap_allocated;\n\n        fn unwrap(self) -> DefaultEditor;\n    }\n\n    type ::std::result::Result<&::std::string::String, &error::ReadlineError> {\n        #heap_allocated;\n\n        fn unwrap(self) -> &::std::string::String;\n    }\n\n    type Result<::std::string::String> {\n        #heap_allocated;\n    \n        fn is_err(&self) -> bool;\n        fn as_ref(&self) -> ::std::result::Result<&::std::string::String, &error::ReadlineError>;\n        fn unwrap_err(self) -> error::ReadlineError;\n    }\n\n    type Result<()> {\n        #heap_allocated;\n    \n        fn is_err(&self) -> bool;\n    }\n\n    type Result<bool> {\n        #heap_allocated;\n    \n        fn is_err(&self) -> bool;\n    }\n}\n"
  },
  {
    "path": "examples/rustyline/src/lib.rs",
    "content": "#[rustfmt::skip]\nmod generated;\n"
  },
  {
    "path": "examples/simple/.gitignore",
    "content": "generated.h\ngenerated.rs\ngenerated.cpp\n"
  },
  {
    "path": "examples/simple/Cargo.toml",
    "content": "[package]\nname = \"example-simple\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"staticlib\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "examples/simple/Makefile",
    "content": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_simple.a\n\t${CXX} -std=c++17 -Werror main.cpp generated.cpp -g -L ../../target/release/ -l example_simple\n\n../../target/release/libexample_simple.a:\n\tcargo build --release\n\ngenerated.h generated.cpp ./src/generated.rs: main.zng\n\tcd ../../zngur-cli && cargo run g -i ../examples/simple/main.zng --crate-name \"crate\"\n\n.PHONY: ../../target/release/libexample_simple.a generated.h clean\n\nclean:\n\trm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt\n"
  },
  {
    "path": "examples/simple/NMakefile",
    "content": "CXX = cl.exe\r\nCXXFLAGS = /W4 /DEBUG /EHsc /std:c++20 \r\nWINLIBS = ntdll.lib\r\n\r\nEXAMPLE_NAME = simple\r\n\r\nGENERATED = generated.h src/generated.rs\r\n\r\nRUSTLIB_PATH = ../../target/release/\r\n\r\nRUSTLIB = example_$(EXAMPLE_NAME).lib\r\n\r\na.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)\r\n\t$(CXX) $(CXXFLAGS) main.cpp generated.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)\r\n\r\n$(RUSTLIB_PATH)/$(RUSTLIB) :\r\n\tcargo build --release\r\n\r\n$(GENERATED) : main.zng\r\n\tcd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name \"crate\"\r\n\r\nclean :\r\n\t- del /f /q generated.h generated.cpp src\\generated.rs a.exe main.obj generated.obj actual_output.txt 2>nul\r\n"
  },
  {
    "path": "examples/simple/README.md",
    "content": "# Example: Simple\n\nA simple example, used as a demo in the main README file.\n\nTo run this example:\n\n```\nmake\n./a.out\n```\n"
  },
  {
    "path": "examples/simple/expected_output.txt",
    "content": "17\ns[2] = 7\n\nthread panicked at examples/simple/src/generated.rs:370:40:\ncalled `Option::unwrap()` on a `None` value\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\ns[4] = Rust panic happened\nhello 2 2\nhello 5 7\nhello 7 14\nhello 3 17\n34 17\nvector iterator has been destructed\n[main.cpp:71] t = [\n    10,\n    20,\n    60,\n]\n"
  },
  {
    "path": "examples/simple/main.cpp",
    "content": "#include <iostream>\n#include <vector>\n\n#include \"./generated.h\"\n\n// Rust values are available in the `::rust` namespace from their absolute path\n// in Rust\ntemplate <typename T> using Vec = rust::std::vec::Vec<T>;\ntemplate <typename T> using Option = rust::std::option::Option<T>;\ntemplate <typename T> using BoxDyn = rust::Box<rust::Dyn<T>>;\n\n// You can implement Rust traits for your classes\ntemplate <typename T>\nclass VectorIterator : public rust::std::iter::Iterator<T> {\n  std::vector<T> vec;\n  size_t pos;\n\npublic:\n  VectorIterator(std::vector<T> &&v) : vec(v), pos(0) {}\n  ~VectorIterator() {\n    std::cout << \"vector iterator has been destructed\" << std::endl;\n  }\n\n  Option<T> next() override {\n    if (pos >= vec.size()) {\n      return Option<T>::None();\n    }\n    T value = vec[pos++];\n    // You can construct Rust enum with fields in C++\n    return Option<T>::Some(value);\n  }\n};\n\nint main() {\n  // You can call Rust functions that return things by value, and store that\n  // value in your stack.\n  auto s = Vec<int32_t>::new_();\n  s.push(2);\n  Vec<int32_t>::push(s, 5);\n  s.push(7);\n  Vec<int32_t>::push(s, 3);\n  // You can call Rust functions just like normal Rust.\n  std::cout << s.clone().into_iter().sum() << std::endl;\n  // You can catch Rust panics as C++ exceptions\n  try {\n    std::cout << \"s[2] = \" << *s.get(2).unwrap() << std::endl;\n    std::cout << \"s[4] = \" << *s.get(4).unwrap() << std::endl;\n  } catch (rust::Panic e) {\n    std::cout << \"Rust panic happened\" << std::endl;\n  }\n  int state = 0;\n  // You can convert a C++ lambda into a `Box<dyn Fn>` and friends.\n  auto f = BoxDyn<rust::Fn<int32_t, int32_t>>::make_box([&](int32_t x) {\n    state += x;\n    std::cout << \"hello \" << x << \" \" << state << \"\\n\";\n    return x * 2;\n  });\n  // And pass it to Rust functions that accept closures.\n  auto x = s.into_iter().map(std::move(f)).sum();\n  std::cout << x << \" \" << state << \"\\n\";\n  std::vector<int32_t> vec{10, 20, 60};\n  // You can convert a C++ type that implements `Trait` to a `Box<dyn Trait>`.\n  // `make_box` is similar to the `make_unique`, it takes constructor arguments\n  // and construct it inside the `Box` (instead of `unique_ptr`).\n  auto vec_as_iter = BoxDyn<rust::std::iter::Iterator<int32_t>>::make_box<\n      VectorIterator<int32_t>>(std::move(vec));\n  // Then use it like a normal Rust value.\n  auto t = vec_as_iter.collect();\n  // Some utilities are also provided. For example, `zngur_dbg` is the\n  // equivalent of `dbg!` macro.\n  zngur_dbg(t);\n}\n"
  },
  {
    "path": "examples/simple/main.zng",
    "content": "#convert_panic_to_exception\n\ntype Box<dyn Fn(i32) -> i32> {\n    #layout(size = 16, align = 8);\n}\n\nmod ::std {\n    type option::Option<i32> {\n        #layout(size = 8, align = 4);\n        wellknown_traits(Copy);\n\n        constructor None;\n        constructor Some(i32);\n\n        fn unwrap(self) -> i32;\n    }\n\n    type option::Option<&i32> {\n        #layout(size = 8, align = 8);\n        wellknown_traits(Copy);\n\n        fn unwrap(self) -> &i32;\n    }\n\n    type iter::Map<::std::vec::IntoIter<i32>, Box<dyn Fn(i32) -> i32>> {\n        #layout(size = 48, align = 8);\n\n        fn sum<i32>(self) -> i32;\n    }\n    \n    mod vec {\n        type IntoIter<i32> {\n            #layout(size = 32, align = 8);\n\n            fn sum<i32>(self) -> i32;\n            fn map<i32, Box<dyn Fn(i32) -> i32>>(self, Box<dyn Fn(i32) -> i32>)\n                -> ::std::iter::Map<::std::vec::IntoIter<i32>, Box<dyn Fn(i32) -> i32>>;\n        }\n\n        type Vec<i32> {\n            #layout(size = 24, align = 8);\n            wellknown_traits(Debug);\n\n            fn new() -> Vec<i32>;\n            fn push(&mut self, i32);\n            fn clone(&self) -> Vec<i32>;\n            fn get(&self, usize) -> ::std::option::Option<&i32> deref [i32];\n            fn into_iter(self) -> ::std::vec::IntoIter<i32>;\n        }\n    }\n\n    trait iter::Iterator::<Item = i32> {\n        fn next(&mut self) -> ::std::option::Option<i32>;\n    }\n}\n\ntype Box<dyn ::std::iter::Iterator<Item = i32>> {\n    #layout(size = 16, align = 8);\n\n    fn collect<::std::vec::Vec<i32>>(self) -> ::std::vec::Vec<i32>;\n}\n"
  },
  {
    "path": "examples/simple/src/lib.rs",
    "content": "#[rustfmt::skip]\nmod generated;\n"
  },
  {
    "path": "examples/simple_import/.gitignore",
    "content": "generated.h\ngenerated.rs\ngenerated.cpp\n"
  },
  {
    "path": "examples/simple_import/Cargo.toml",
    "content": "[package]\nname = \"example-simple-import\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"staticlib\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "examples/simple_import/Makefile",
    "content": ".PHONY: ../../target/release/libexample_simple_import.a\n\na.out: main.cpp foo.cpp bar.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_simple_import.a\n\t${CXX} -std=c++11 main.cpp foo.cpp bar.cpp -g -L ../../target/release/ -l example_simple_import\n\n../../target/release/libexample_simple_import.a:\n\tcargo build --release\n\ngenerated.h ./src/generated.rs: main.zng primitives.zng foo.zng bar.zng\n\tcd ../../zngur-cli && cargo run g -i ../examples/simple_import/main.zng --crate-name \"crate\"\n\nclean:\n\trm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt\n"
  },
  {
    "path": "examples/simple_import/NMakefile",
    "content": "CXX = cl.exe\r\nCXXFLAGS = /W4 /DEBUG /EHsc /std:c++20 \r\nWINLIBS = ntdll.lib\r\n\r\nEXAMPLE_NAME = simple_import\r\n\r\nGENERATED = generated.h src/generated.rs\r\n\r\nRUSTLIB_PATH = ../../target/release/\r\n\r\nRUSTLIB = example_$(EXAMPLE_NAME).lib\r\n\r\na.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)\r\n\t$(CXX) $(CXXFLAGS) main.cpp foo.cpp bar.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)\r\n\r\n$(RUSTLIB_PATH)/$(RUSTLIB) :\r\n\tcargo build --release\r\n\r\n$(GENERATED) : main.zng\r\n\tcd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name \"crate\"\r\n\r\nclean :\r\n\t- del /f /q generated.h generated.cpp src\\generated.rs a.exe main.obj foo.obj bar.obj actual_output.txt 2>nul\r\n"
  },
  {
    "path": "examples/simple_import/README.md",
    "content": "# Example: Import and Merge\n\nA demonstration of Zngur's `import` and `merge` functionality using four focused modules.\n\n## Structure\n\n- **`primitives.zng`** - Defines basic primitive types (`bool`)\n- **`foo.{zng,cpp}`** - Imports primitives, defines `Vec<i32>` APIs and returns a populated Vec\n- **`bar.{zng,cpp}`** - Imports primitives, defines `Option<String>` APIs and returns an Option\n- **`main.{zng,cpp}`** - Imports foo and bar (transitively gets primitives), extends both types with additional APIs, and demonstrates everything\n\n## API Extensions in main.zng\n\nThe main module doesn't just import - it extends the imported types:\n\n- **Vec<i32>**: Adds `is_empty()` and `clear()` methods beyond `foo.zng`'s `new()` and `push()`\n- **Option<String>**: Adds `unwrap()` method beyond `bar.zng`'s constructors and `is_some()`/`is_none()`\n\n## Running\n\n```bash\nmake\n./a.out\n```\n"
  },
  {
    "path": "examples/simple_import/bar.cpp",
    "content": "#include \"generated.h\"\n\n// Creates and returns a Rust Option<String> with Some(String)\nrust::std::option::Option<rust::std::string::String> bar() {\n    // Create Some(String)\n    return rust::std::option::Option<rust::std::string::String>::Some(\n        rust::std::string::String::new_()\n    );\n}\n"
  },
  {
    "path": "examples/simple_import/bar.zng",
    "content": "// Bar module - exports Option<String> APIs for C++ usage\n\nmerge \"./primitives.zng\";\n\nmod ::std {\n    mod string {\n        type String {\n            #layout(size = 24, align = 8);\n            wellknown_traits(Debug);\n\n            fn new() -> String;\n        }\n    }\n\n    type option::Option<::std::string::String> {\n        #layout(size = 24, align = 8);\n\n        constructor None;\n        constructor Some(::std::string::String);\n\n        fn is_some(&self) -> bool;\n        fn is_none(&self) -> bool;\n    }\n}\n"
  },
  {
    "path": "examples/simple_import/expected_output.txt",
    "content": "foo(): Creating a Rust Vec<i32>\n  Vec contents: [main.cpp:13] numbers = [\n    10,\n    20,\n    30,\n]\n  Vec is_empty(): 0\n  After clear(), is_empty(): 1\n\nbar(): Creating Rust Option<String>\n  some_value.is_some(): 1\n  none_value.is_none(): 1\n  Unwrapped string: [main.cpp:33] unwrapped_string = \"\"\n"
  },
  {
    "path": "examples/simple_import/foo.cpp",
    "content": "#include \"generated.h\"\n\n// Creates and returns a Rust Vec<i32> with sample data\nrust::std::vec::Vec<int32_t> foo() {\n    // Create a new Rust Vec<i32>\n    auto numbers = rust::std::vec::Vec<int32_t>::new_();\n\n    // Add some numbers\n    numbers.push(10);\n    numbers.push(20);\n    numbers.push(30);\n\n    return numbers;\n}\n"
  },
  {
    "path": "examples/simple_import/foo.zng",
    "content": "// Foo module - exports Vec<i32> APIs for C++ usage\n\nmerge \"./primitives.zng\";\n\nmod ::std {\n    mod vec {\n        type Vec<i32> {\n            #layout(size = 24, align = 8);\n            wellknown_traits(Debug);\n\n            fn new() -> Vec<i32>;\n            fn push(&mut self, i32);\n        }\n    }\n}\n"
  },
  {
    "path": "examples/simple_import/main.cpp",
    "content": "#include <iostream>\n#include \"generated.h\"\n\n// External function declarations from foo.cpp and bar.cpp\nextern rust::std::vec::Vec<int32_t> foo();\nextern rust::std::option::Option<rust::std::string::String> bar();\n\nint main() {\n    // Get Vec<i32> from foo() and demonstrate both imported and extended APIs\n    std::cout << \"foo(): Creating a Rust Vec<i32>\" << std::endl;\n    auto numbers = foo();\n    std::cout << \"  Vec contents: \";\n    zngur_dbg(numbers);\n\n    // Use extended APIs defined in main.zng\n    std::cout << \"  Vec is_empty(): \" << numbers.is_empty() << std::endl;\n    numbers.clear();  // Clear the vector using main.zng API\n    std::cout << \"  After clear(), is_empty(): \" << numbers.is_empty() << std::endl;\n    std::cout << std::endl;\n\n    // Get Option<String> from bar() and demonstrate both imported and extended APIs\n    std::cout << \"bar(): Creating Rust Option<String>\" << std::endl;\n    auto some_value = bar();\n    auto none_value = rust::std::option::Option<rust::std::string::String>::None();\n\n    // Use imported APIs from bar.zng\n    std::cout << \"  some_value.is_some(): \" << some_value.is_some() << std::endl;\n    std::cout << \"  none_value.is_none(): \" << none_value.is_none() << std::endl;\n\n    // Use extended API defined in main.zng\n    auto unwrapped_string = some_value.unwrap();  // Use main.zng API\n    std::cout << \"  Unwrapped string: \";\n    zngur_dbg(unwrapped_string);\n    return 0;\n}\n"
  },
  {
    "path": "examples/simple_import/main.zng",
    "content": "// Main module - imports foo and bar modules to demonstrate import/merge\n\nmerge \"./foo.zng\";\nmerge \"./bar.zng\";\n\n// Note: All APIs from foo.zng and bar.zng are now available\n// Primitives from primitives.zng are also available transitively\n// The std module definitions are automatically merged\n\n// Main module extensions - adding additional APIs to imported types\nmod ::std {\n    mod vec {\n        type Vec<i32> {\n            #layout(size = 24, align = 8);\n            wellknown_traits(Debug);\n\n            // Inherited methods from foo.zng (automatically merged)\n            fn new() -> Vec<i32>;\n            fn push(&mut self, i32);\n\n            // Additional methods beyond what foo.zng provides\n            fn is_empty(&self) -> bool;\n            fn clear(&mut self);\n        }\n    }\n\n    type option::Option<::std::string::String> {\n        #layout(size = 24, align = 8);\n\n        // Inherited constructors and methods from bar.zng (automatically merged)\n        constructor None;\n        constructor Some(::std::string::String);\n        fn is_some(&self) -> bool;\n        fn is_none(&self) -> bool;\n\n        // Additional methods beyond what bar.zng provides\n        fn unwrap(self) -> ::std::string::String;\n    }\n}\n"
  },
  {
    "path": "examples/simple_import/primitives.zng",
    "content": "// Primitive types used across the import/merge example\n\ntype bool {\n    #layout(size = 1, align = 1);\n    wellknown_traits(Copy);\n}\n"
  },
  {
    "path": "examples/simple_import/src/lib.rs",
    "content": "// Minimal lib.rs - just includes the generated Zngur bindings\n\n#[rustfmt::skip]\nmod generated;\n"
  },
  {
    "path": "examples/tutorial/.gitignore",
    "content": "generated.h\ngenerated.rs\n"
  },
  {
    "path": "examples/tutorial/Cargo.toml",
    "content": "[package]\nname = \"example-tutorial\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"staticlib\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "examples/tutorial/Makefile",
    "content": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_tutorial.a\n\t${CXX} -std=c++11 -Werror main.cpp -g -L ../../target/release/ -l example_tutorial\n\n../../target/release/libexample_tutorial.a:\n\tcargo build --release\n\ngenerated.h ./src/generated.rs: main.zng\n\tcd ../../zngur-cli && cargo run g -i ../examples/tutorial/main.zng --crate-name \"crate\"\n\n.PHONY: ../../target/release/libexample_tutorial.a generated.h clean\n\nclean:\n\trm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt\n"
  },
  {
    "path": "examples/tutorial/NMakefile",
    "content": "CXX = cl.exe\r\nCXXFLAGS = /W4 /DEBUG /EHsc /std:c++20 \r\nWINLIBS = ntdll.lib\r\n\r\nEXAMPLE_NAME = tutorial\r\n\r\nGENERATED = generated.h src/generated.rs\r\n\r\nRUSTLIB_PATH = ../../target/release/\r\n\r\nRUSTLIB = example_$(EXAMPLE_NAME).lib\r\n\r\na.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)\r\n\t$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)\r\n\r\n$(RUSTLIB_PATH)/$(RUSTLIB) :\r\n\tcargo build --release\r\n\r\n$(GENERATED) : main.zng\r\n\tcd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name \"crate\"\r\n\r\nclean :\r\n\t- del /f /q generated.h generated.cpp src\\generated.rs a.exe main.obj actual_output.txt 2>nul\r\n"
  },
  {
    "path": "examples/tutorial/README.md",
    "content": "# Example: Tutorial\n\nFull code of the [Tutorial](https://hkalbasi.github.io/zngur/tutorial.html) part 1 (Calling Rust from C++) in the Zngur book.\n\nTo run this example:\n\n```\nmake\n./a.out\n```\n"
  },
  {
    "path": "examples/tutorial/expected_output.txt",
    "content": "[main.cpp:7] inventory = Inventory {\n    items: [\n        Item {\n            name: \"banana\",\n            size: 7,\n        },\n        Item {\n            name: \"banana\",\n            size: 7,\n        },\n        Item {\n            name: \"banana\",\n            size: 7,\n        },\n        Item {\n            name: \"apple\",\n            size: 5,\n        },\n    ],\n    remaining_space: 974,\n}\n[main.cpp:10] v = [\n    Item {\n        name: \"banana\",\n        size: 7,\n    },\n    Item {\n        name: \"banana\",\n        size: 7,\n    },\n    Item {\n        name: \"banana\",\n        size: 7,\n    },\n    Item {\n        name: \"apple\",\n        size: 5,\n    },\n]\n"
  },
  {
    "path": "examples/tutorial/main.cpp",
    "content": "#include \"./generated.h\"\n\nint main() {\n  auto inventory = rust::crate::Inventory::new_empty(1000);\n  inventory.add_banana(3);\n  inventory.add_item(rust::crate::Item(\"apple\"_rs.to_owned(), 5));\n  zngur_dbg(inventory);\n\n  rust::std::vec::Vec<rust::crate::Item> v = inventory.into_items();\n  zngur_dbg(v);\n}\n"
  },
  {
    "path": "examples/tutorial/main.zng",
    "content": "type ::std::vec::Vec<crate::Item> {\n    #layout(size = 24, align = 8);\n    wellknown_traits(Debug);\n}\n\ntype str {\n    wellknown_traits(?Sized);\n\n    fn to_owned(&self) -> ::std::string::String;\n}\n\ntype ::std::string::String {\n    #layout(size = 24, align = 8);\n}\n\ntype crate::Item {\n    #layout(size = 32, align = 8);\n\n    constructor { name: ::std::string::String, size: u32 };\n}\n\ntype crate::Inventory {\n    #layout(size = 32, align = 8);\n    wellknown_traits(Debug);\n\n    fn new_empty(u32) -> crate::Inventory;\n    fn add_banana(&mut self, u32);\n    fn add_item(&mut self, crate::Item);\n    fn into_items(self) -> ::std::vec::Vec<crate::Item>;\n}\n"
  },
  {
    "path": "examples/tutorial/src/lib.rs",
    "content": "#![allow(dead_code)]\n\n#[rustfmt::skip]\nmod generated;\n\n#[derive(Debug)]\nstruct Item {\n    name: String,\n    size: u32,\n}\n\n#[derive(Debug)]\nstruct Inventory {\n    items: Vec<Item>,\n    remaining_space: u32,\n}\n\nimpl Inventory {\n    fn new_empty(space: u32) -> Self {\n        Self {\n            items: vec![],\n            remaining_space: space,\n        }\n    }\n\n    fn add_item(&mut self, item: Item) {\n        self.remaining_space -= item.size;\n        self.items.push(item);\n    }\n\n    fn add_banana(&mut self, count: u32) {\n        for _ in 0..count {\n            self.add_item(Item {\n                name: \"banana\".to_owned(),\n                size: 7,\n            });\n        }\n    }\n\n    fn into_items(self) -> Vec<Item> {\n        self.items\n    }\n}\n"
  },
  {
    "path": "examples/tutorial-wasm32/.gitignore",
    "content": "generated.h\ngenerated.rs\ngenerated.cpp\ngenerated.o\nmain.js\ntarget/\na.out\nexample_tutorial_wasm32.wasm\n\n# WASI SDK and dependencies\nwasi-sdk-*\nwasi-sdk-latest.tar.gz\nwasi-sdk-installed\nwasm32-wasip1-target\n\n# Build artifacts\nactual_output.txt\n*.wasm\n"
  },
  {
    "path": "examples/tutorial-wasm32/Cargo.toml",
    "content": "[package]\nname = \"example-tutorial-wasm32\"\nversion = \"0.6.0\"\nedition = \"2024\"\nrust-version = \"1.85\"\nlicense = \"MIT OR Apache-2.0\"\npublish = false\n\n[lib]\ncrate-type = [\"staticlib\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "examples/tutorial-wasm32/Makefile",
    "content": "# WASI build flags for C++ compilation with wasmtime\nWASIFLAGS = -std=c++14 \\\n           --target=wasm32-wasi \\\n           --sysroot=$(WASI_SDK_PATH)/share/wasi-sysroot \\\n           -D_WASI_EMULATED_SIGNAL \\\n           -lwasi-emulated-signal \\\n           -fno-exceptions\n\n# Use the mise-installed WASI SDK C++ compiler\n# Load mise environment if WASI_SDK_PATH is not set\nifeq ($(WASI_SDK_PATH),)\n    $(eval $(shell mise env))\nendif\nCXX = $(WASI_SDK_PATH)/bin/clang++\n\n# Default target\nall: run a.out\n\n# Run the example with wasmtime (installs all deps automatically)\nrun: main.wasm\n\twasmtime run --allow-precompiled main.wasm\n\n# CI expects a.out; we create it as a bash script that simply execs wasmtime\na.out: main.wasm\n\t@printf '%s\\n' '#!/usr/bin/env bash' 'exec wasmtime run --allow-precompiled \"$$(dirname \"$$0\")/main.wasm\" \"$$@\"' > $@\n\t@chmod +x $@\n\nmain.wasm: main.cpp generated.h generated.cpp \\\n           ./target/wasm32-wasip1/release/libexample_tutorial_wasm32.a\n\t$(CXX) $(WASIFLAGS) \\\n\t    main.cpp generated.cpp \\\n\t    ./target/wasm32-wasip1/release/libexample_tutorial_wasm32.a \\\n\t    -o $@\n\n./target/wasm32-wasip1/release/libexample_tutorial_wasm32.a: wasm32-wasip1-target generated.h ./src/generated.rs ./src/lib.rs\n\tcargo build --target=wasm32-wasip1 --release\n\ngenerated.h ./src/generated.rs generated.cpp: main32.zng\n\tcargo run --release --manifest-path ../../zngur-cli/Cargo.toml g -i main32.zng\n\n# Ensure wasm32-wasip1 target is installed\nwasm32-wasip1-target:\n\t@rustup target list --installed | grep -q wasm32-wasip1 || { \\\n\t\techo \"Installing wasm32-wasip1 Rust target...\"; \\\n\t\trustup target add wasm32-wasip1; \\\n\t}\n\t@touch wasm32-wasip1-target\n\nclean:\n\tcargo clean\n\trm -f generated.h ./src/generated.rs generated.cpp generated.o\n\trm -f main.wasm example_tutorial_wasm32.wasm a.out\n\trm -f wasm32-wasip1-target\n\nFORCE: ;\n"
  },
  {
    "path": "examples/tutorial-wasm32/NMakefile",
    "content": "# can not eval mise after the fact in nmake, must preeval\r\nWASIFLAGS = -std=c++17 \\\r\n           --target=wasm32-wasi \\\r\n           --sysroot=$(WASI_SDK_PATH)/share/wasi-sysroot \\\r\n           -D_WASI_EMULATED_SIGNAL \\\r\n           -lwasi-emulated-signal \\\r\n           -fno-exceptions\r\n\r\nCXX = $(WASI_SDK_PATH)\\bin\\clang++\r\n\r\n# Default target\r\nall: run a.bat\r\n\r\n# Run the example with wasmtime (installs all deps automatically)\r\nrun: main.wasm\r\n\twasmtime run --allow-precompiled main.wasm\r\n\r\n# CI expects a.bat; we create it as a batch script that simply execs wasmtime\r\na.bat: main.wasm\r\n\techo @echo off > $@\r\n\techo wasmtime run --allow-precompiled \"%0\\..\\main.wasm\" \"$$@\" >> $@\r\n\r\nmain.wasm: main.cpp generated.h generated.cpp \\\r\n           ./target/wasm32-wasip1/release/libexample_tutorial_wasm32.a\r\n\t$(CXX) $(WASIFLAGS) \\\r\n\t    main.cpp generated.cpp \\\r\n\t    ./target/wasm32-wasip1/release/libexample_tutorial_wasm32.a \\\r\n\t    -o $@\r\n\r\n\r\n./target/wasm32-wasip1/release/libexample_tutorial_wasm32.a:  generated.h ./src/generated.rs ./src/lib.rs\r\n\tcargo build --target=wasm32-wasip1 --release\r\n\r\ngenerated.h ./src/generated.rs generated.cpp: main32.zng\r\n\tcargo run --release --manifest-path ../../zngur-cli/Cargo.toml g -i main32.zng\r\n\r\nclean:\r\n\tcargo clean\r\n\t- del /f generated.h .\\src\\generated.rs generated.cpp generated.o 2>nul\r\n  - del /f main.wasm example_tutorial_wasm32.wasm a.bat 2>nul\r\n"
  },
  {
    "path": "examples/tutorial-wasm32/README.md",
    "content": "# Wasm32 Example\n\nThis example builds a sample application for wasmtime to test zngur's support for basic WASM applications.\n\n## To build and run\n\n```\n$ make run\n```\n\nThis automatically installs all dependencies (wasmtime, WASI SDK, Rust targets) and runs the example.\n\n## Alternative targets\n\n```\n$ make            # Same as 'make run'\n$ make main.wasm  # Build without running\n$ make a.out      # Create executable wrapper script\n$ make clean      # Clean all build artifacts\n```\n"
  },
  {
    "path": "examples/tutorial-wasm32/expected_output.txt",
    "content": "17\ns[2] = 7\nRust panic would happen if we accessed invalid index, but we avoid it\nhello 2 2\nhello 5 7\nhello 7 14\nhello 3 17\n34 17\nvector iterator has been destructed\n[main.cpp:70] t = [\n    10,\n    20,\n    60,\n]\n"
  },
  {
    "path": "examples/tutorial-wasm32/main.cpp",
    "content": "#include <iostream>\n#include <vector>\n\n#include \"./generated.h\"\n\n// Rust values are available in the `::rust` namespace from their absolute path\n// in Rust\ntemplate <typename T> using Vec = rust::std::vec::Vec<T>;\ntemplate <typename T> using Option = rust::std::option::Option<T>;\ntemplate <typename T> using BoxDyn = rust::Box<rust::Dyn<T>>;\n\n// You can implement Rust traits for your classes\ntemplate <typename T>\nclass VectorIterator : public rust::std::iter::Iterator<T> {\n  std::vector<T> vec;\n  size_t pos;\n\npublic:\n  VectorIterator(std::vector<T> &&v) : vec(v), pos(0) {}\n  ~VectorIterator() {\n    std::cout << \"vector iterator has been destructed\" << std::endl;\n  }\n\n  Option<T> next() override {\n    if (pos >= vec.size()) {\n      return Option<T>::None();\n    }\n    T value = vec[pos++];\n    // You can construct Rust enum with fields in C++\n    return Option<T>::Some(value);\n  }\n};\n\nint main() {\n  // You can call Rust functions that return things by value, and store that\n  // value in your stack.\n  auto s = Vec<int32_t>::new_();\n  s.push(2);\n  Vec<int32_t>::push(s, 5);\n  s.push(7);\n  Vec<int32_t>::push(s, 3);\n  // You can call Rust functions just like normal Rust.\n  std::cout << s.clone().into_iter().sum() << std::endl;\n  // Access valid indices\n  std::cout << \"s[2] = \" << *s.get(2).unwrap() << std::endl;\n  // TODO: Uncomment this line after enabling wasmtime exceptions.\n  // std::cout << \"s[4] = \" << *s.get(4).unwrap() << std::endl;\n  std::cout << \"Rust panic would happen if we accessed invalid index, but we avoid it\" << std::endl;\n\n  int state = 0;\n  // You can convert a C++ lambda into a `Box<dyn Fn>` and friends.\n  auto f = BoxDyn<rust::Fn<int32_t, int32_t>>::make_box([&](int32_t x) {\n    state += x;\n    std::cout << \"hello \" << x << \" \" << state << \"\\n\";\n    return x * 2;\n  });\n  // And pass it to Rust functions that accept closures.\n  auto x = s.into_iter().map(std::move(f)).sum();\n  std::cout << x << \" \" << state << \"\\n\";\n  std::vector<int32_t> vec{10, 20, 60};\n  // You can convert a C++ type that implements `Trait` to a `Box<dyn Trait>`.\n  // `make_box` is similar to the `make_unique`, it takes constructor arguments\n  // and construct it inside the `Box` (instead of `unique_ptr`).\n  auto vec_as_iter = BoxDyn<rust::std::iter::Iterator<int32_t>>::make_box<\n      VectorIterator<int32_t>>(std::move(vec));\n  // Then use it like a normal Rust value.\n  auto t = vec_as_iter.collect();\n  // Some utilities are also provided. For example, `zngur_dbg` is the\n  // equivalent of `dbg!` macro.\n  zngur_dbg(t);\n  return 0;\n}\n"
  },
  {
    "path": "examples/tutorial-wasm32/main32.zng",
    "content": "type Box<dyn Fn(i32) -> i32> {\n    #layout(size = 8, align = 4);\n}\n\nmod ::std {\n    type option::Option<i32> {\n        #layout(size = 8, align = 4);\n        wellknown_traits(Copy);\n\n        constructor None;\n        constructor Some(i32);\n\n        fn unwrap(self) -> i32;\n    }\n\n    type option::Option<&i32> {\n        #layout(size = 4, align = 4);\n        wellknown_traits(Copy);\n\n        fn unwrap(self) -> &i32;\n    }\n\n    type iter::Map<::std::vec::IntoIter<i32>, Box<dyn Fn(i32) -> i32>> {\n        #layout(size = 24, align = 4);\n\n        fn sum<i32>(self) -> i32;\n    }\n\n    mod vec {\n        type IntoIter<i32> {\n            #layout(size = 16, align = 4);\n\n            fn sum<i32>(self) -> i32;\n            fn map<i32, Box<dyn Fn(i32) -> i32>>(self, Box<dyn Fn(i32) -> i32>)\n                -> ::std::iter::Map<::std::vec::IntoIter<i32>, Box<dyn Fn(i32) -> i32>>;\n        }\n\n        type Vec<i32> {\n            #layout(size = 12, align = 4);\n            wellknown_traits(Debug);\n\n            fn new() -> Vec<i32>;\n            fn push(&mut self, i32);\n            fn clone(&self) -> Vec<i32>;\n            fn get(&self, usize) -> ::std::option::Option<&i32> deref [i32];\n            fn into_iter(self) -> ::std::vec::IntoIter<i32>;\n        }\n    }\n\n    trait iter::Iterator::<Item = i32> {\n        fn next(&mut self) -> ::std::option::Option<i32>;\n    }\n}\n\ntype Box<dyn ::std::iter::Iterator<Item = i32>> {\n    #layout(size = 8, align = 4);\n\n    fn collect<::std::vec::Vec<i32>>(self) -> ::std::vec::Vec<i32>;\n}\n"
  },
  {
    "path": "examples/tutorial-wasm32/src/lib.rs",
    "content": "#![allow(dead_code)]\n\n#[rustfmt::skip]\nmod generated;\n\npub fn add_one(x: usize) -> usize {\n    x + 1\n}\n\n#[derive(Debug)]\nstruct Item {\n    name: String,\n    size: u32,\n}\n\n#[derive(Debug)]\nstruct Inventory {\n    items: Vec<Item>,\n    remaining_space: u32,\n}\n\nimpl Inventory {\n    fn new_empty(space: u32) -> Self {\n        Self {\n            items: vec![],\n            remaining_space: space,\n        }\n    }\n\n    fn add_item(&mut self, item: Item) {\n        self.remaining_space -= item.size;\n        self.items.push(item);\n    }\n\n    fn add_banana(&mut self, count: u32) {\n        for _ in 0..count {\n            self.add_item(Item {\n                name: \"banana\".to_owned(),\n                size: 7,\n            });\n        }\n    }\n\n    fn into_items(self) -> Vec<Item> {\n        self.items\n    }\n}\n"
  },
  {
    "path": "examples/tutorial_cpp/Cargo.toml",
    "content": "[package]\nname = \"example-tutorial_cpp\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n\n[build-dependencies]\ncc = \"1.0\"\nbuild-rs = \"0.1.2\"\nzngur = { path = \"../../zngur\" }\n"
  },
  {
    "path": "examples/tutorial_cpp/README.md",
    "content": "# Example: Tutorial Cpp\n\nFull code of the [Tutorial](https://hkalbasi.github.io/zngur/tutorial.html) part 2 (Calling C++ from Rust) in the Zngur book.\n\nTo run this example:\n\n```\ncargo run\n```\n"
  },
  {
    "path": "examples/tutorial_cpp/build.rs",
    "content": "#[cfg(not(target_os = \"windows\"))]\nuse std::env;\n\nuse zngur::Zngur;\n\nfn main() {\n    build::rerun_if_changed(\"main.zng\");\n    build::rerun_if_changed(\"impls.cpp\");\n    build::rerun_if_env_changed(\"CXX\");\n\n    #[cfg(not(target_os = \"windows\"))]\n    let cxx = env::var(\"CXX\").unwrap_or(\"c++\".to_owned());\n\n    let crate_dir = build::cargo_manifest_dir();\n    let out_dir = build::out_dir();\n\n    // Force rerun if generated files don't exist\n    let generated_files = [\n        out_dir.join(\"generated.cpp\"),\n        out_dir.join(\"generated.h\"),\n        out_dir.join(\"generated.rs\"),\n    ];\n    for file in &generated_files {\n        if !file.exists() {\n            println!(\"cargo:rerun-if-changed=nonexistent_trigger_file\");\n            break;\n        }\n    }\n\n    Zngur::from_zng_file(crate_dir.join(\"main.zng\"))\n        .with_cpp_file(out_dir.join(\"generated.cpp\"))\n        .with_h_file(out_dir.join(\"generated.h\"))\n        .with_rs_file(out_dir.join(\"generated.rs\"))\n        .with_crate_name(\"crate\")\n        .with_zng_header_in_place()\n        .generate();\n\n    let my_build = &mut cc::Build::new();\n    let my_build = my_build.cpp(true).std(\"c++20\");\n\n    #[cfg(not(target_os = \"windows\"))]\n    my_build.compiler(&cxx);\n\n    my_build.include(&crate_dir).include(&out_dir);\n\n    let my_build = || my_build.clone();\n\n    my_build()\n        .file(out_dir.join(\"generated.cpp\"))\n        .compile(\"zngur_generated\");\n    my_build().file(\"impls.cpp\").compile(\"impls\");\n}\n"
  },
  {
    "path": "examples/tutorial_cpp/expected_output.txt",
    "content": "[examples/tutorial_cpp/src/main.rs:12:5] inventory = Inventory { remaining_space: 974, items: [Item { name: \"banana\", size: 7 }, Item { name: \"banana\", size: 7 }, Item { name: \"banana\", size: 7 }, Item { name: \"apple\", size: 5 }] }\n"
  },
  {
    "path": "examples/tutorial_cpp/impls.cpp",
    "content": "#include \"generated.h\"\n#include <string>\n\nusing namespace rust::crate;\n\ntemplate <typename T> using Ref = rust::Ref<T>;\ntemplate <typename T> using RefMut = rust::RefMut<T>;\n\nrust::Ref<rust::Str> rust_str_from_c_str(const char* input) {\n  return rust::std::ffi::CStr::from_ptr(reinterpret_cast<const int8_t*>(input)).to_str().expect(\"invalid_utf8\"_rs);\n}\n\nInventory rust::Impl<Inventory>::new_empty(uint32_t space) {\n  return Inventory(\n      rust::ZngurCppOpaqueOwnedObject::build<cpp_inventory::Inventory>(space));\n}\n\nrust::Unit rust::Impl<Inventory>::add_banana(RefMut<Inventory> self,\n                                             uint32_t count) {\n  self.cpp().add_banana(count);\n  return {};\n}\n\nrust::Unit rust::Impl<Inventory>::add_item(RefMut<Inventory> self, Item item) {\n  self.cpp().add_item(item.cpp());\n  return {};\n}\n\nItem rust::Impl<Item>::new_(Ref<rust::Str> name, uint32_t size) {\n  return Item(rust::ZngurCppOpaqueOwnedObject::build<cpp_inventory::Item>(\n      cpp_inventory::Item{\n          .name = ::std::string(reinterpret_cast<const char *>(name.as_ptr()),\n                                name.len()),\n          .size = size}));\n}\n\nrust::std::fmt::Result rust::Impl<Inventory, rust::std::fmt::Debug>::fmt(\n    Ref<Inventory> self, RefMut<rust::std::fmt::Formatter> f) {\n  ::std::string result = \"Inventory { remaining_space: \";\n  result += ::std::to_string(self.cpp().remaining_space);\n  result += \", items: [\";\n  bool is_first = true;\n  for (const auto &item : self.cpp().items) {\n    if (!is_first) {\n      result += \", \";\n    } else {\n      is_first = false;\n    }\n    result += \"Item { name: \\\"\";\n    result += item.name;\n    result += \"\\\", size: \";\n    result += ::std::to_string(item.size);\n    result += \" }\";\n  }\n  result += \"] }\";\n  return f.write_str(rust_str_from_c_str(result.c_str()));\n}\n"
  },
  {
    "path": "examples/tutorial_cpp/inventory.h",
    "content": "#include <cstdint>\n#include <string>\n#include <vector>\n\nnamespace cpp_inventory {\nstruct Item {\n  std::string name;\n  uint32_t size;\n};\n\nstruct Inventory {\n  std::vector<Item> items;\n  uint32_t remaining_space;\n  Inventory(uint32_t space) : items(), remaining_space(space) {}\n\n  void add_item(Item item) {\n    remaining_space -= item.size;\n    items.push_back(std::move(item));\n  }\n\n  void add_banana(uint32_t count) {\n    for (uint32_t i = 0; i < count; i += 1) {\n      add_item(Item{\n          .name = \"banana\",\n          .size = 7,\n      });\n    }\n  }\n};\n\n} // namespace cpp_inventory\n"
  },
  {
    "path": "examples/tutorial_cpp/main.zng",
    "content": "#cpp_additional_includes \"\n    #include <inventory.h>\n\"\n\ntype str {\n    wellknown_traits(?Sized);\n\n    fn as_ptr(&self) -> *const u8;\n    fn len(&self) -> usize;\n}\n\ntype ::std::ffi::CStr {\n    wellknown_traits(?Sized);\n\n    fn from_ptr(*const i8) -> &::std::ffi::CStr;\n    fn to_str(&self) -> ::std::result::Result<&str, ::std::str::Utf8Error>;\n}\n\ntype ::std::result::Result<&str, ::std::str::Utf8Error> {\n    #layout(size = 24, align = 8);\n\n    fn expect(self, &str) -> &str;\n}\n\ntype crate::Inventory {\n    #layout(size = 16, align = 8);\n\n    constructor(ZngurCppOpaqueOwnedObject);\n\n    #cpp_value \"0\" \"::cpp_inventory::Inventory\";\n}\n\ntype crate::Item {\n    #layout(size = 16, align = 8);\n\n    constructor(ZngurCppOpaqueOwnedObject);\n\n    #cpp_value \"0\" \"::cpp_inventory::Item\";\n}\n\ntype ::std::fmt::Result {\n    #layout(size = 1, align = 1);\n\n    constructor Ok(());\n}\n\ntype ::std::fmt::Formatter {\n    #only_by_ref;\n\n    fn write_str(&mut self, &str) -> ::std::fmt::Result;\n}\n\nextern \"C++\" {\n    impl crate::Inventory {\n        fn new_empty(u32) -> crate::Inventory;\n        fn add_banana(&mut self, u32);\n        fn add_item(&mut self, crate::Item);\n    }\n\n    impl crate::Item {\n        fn new(&str, u32) -> crate::Item;\n    }\n\n    impl std::fmt::Debug for crate::Inventory {\n        fn fmt(&self, &mut ::std::fmt::Formatter) -> ::std::fmt::Result;\n    }\n}\n"
  },
  {
    "path": "examples/tutorial_cpp/src/main.rs",
    "content": "mod generated {\n    include!(concat!(env!(\"OUT_DIR\"), \"/generated.rs\"));\n}\n\nstruct Inventory(generated::ZngurCppOpaqueOwnedObject);\nstruct Item(generated::ZngurCppOpaqueOwnedObject);\n\nfn main() {\n    let mut inventory = Inventory::new_empty(1000);\n    inventory.add_banana(3);\n    inventory.add_item(Item::new(\"apple\", 5));\n    dbg!(inventory);\n}\n"
  },
  {
    "path": "mise.toml",
    "content": "[tools]\ncspell = \"9.4.0\"\ndprint = \"0.50.2\"\nwasmtime = \"36.0.2\"\n\n[tools.\"github:WebAssembly/wasi-sdk\"]\nversion = \"30\"\nversion_prefix = \"wasi-sdk-\"\n# don't export clang binaries\nfilter_bins = \"\"\n\n[tools.\"http:emsdk\"]\nversion = \"5.0.2\"\nurl = \"https://github.com/emscripten-core/emsdk/archive/refs/tags/{{version}}.tar.gz\"\n\n[env]\nWASI_SDK_PATH = { value = '{{ tools[\"github:WebAssembly/wasi-sdk\"].path }}', tools = true }\nEMSDK_PATH = { value = '{{ [tools[\"http:emsdk\"].path] | concat(with= [\"emsdk-\", tools[\"http:emsdk\"].version] | join ) | join_path }}', tools = true }\nRUST_BACKTRACE = { value = \"0\" }\n"
  },
  {
    "path": "xtask/Cargo.toml",
    "content": "[package]\nname = \"xtask\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\npublish = false\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nxshell = \"0.2.7\"\nanyhow = \"1.0\"\nclap = { version = \"4.3.12\", features = [\"derive\"] }\n"
  },
  {
    "path": "xtask/src/ci.rs",
    "content": "use crate::format_book;\nuse anyhow::{Context, Result};\nuse xshell::{Shell, cmd};\n\nfn check_crate(sh: &Shell) -> Result<()> {\n    cmd!(sh, \"cargo check\").run()?;\n    cmd!(sh, \"cargo fmt --check\")\n        .run()\n        .with_context(|| \"Crate is not formatted. Run `cargo fmt`\")?;\n    Ok(())\n}\n\nfn check_book_formatting() -> Result<()> {\n    format_book::main(false /* don't fix */)\n        .with_context(|| \"Book markdown files are not formatted. Run `cargo xtask format-book`\")\n}\n\nfn check_examples(sh: &Shell, fix: bool) -> Result<()> {\n    const CARGO_PROJECTS: &[&str] = &[\"cxx_demo\", \"tutorial_cpp\"];\n    let examples_dir = sh.current_dir().join(\"examples\");\n    sh.change_dir(\"examples\");\n    let examples = sh.read_dir(\".\")?;\n    for example in examples {\n        let mut skip = false;\n        let example = example\n            .file_name()\n            .unwrap_or_default()\n            .to_str()\n            .ok_or(anyhow::anyhow!(\"Non utf8 example name?\"))?;\n        println!(\"Building and testing {example}\");\n        sh.change_dir(example);\n        println!(\"Working in {}\", sh.current_dir().display());\n        if CARGO_PROJECTS.contains(&example) {\n            #[cfg(not(target_os = \"windows\"))]\n            {\n                // Clean generated files for Cargo projects\n                let _ = cmd!(\n                    sh,\n                    \"rm -f generated.h generated.cpp src/generated.rs actual_output.txt\"\n                )\n                .run();\n                cmd!(sh, \"cargo build\")\n                    .run()\n                    .with_context(|| format!(\"Building example `{example}` failed\"))?;\n\n                let bash_cmd = format!(\n                    \"../../target/debug/example-{example} 2>&1 | sed -e s/thread.*\\\\(.*\\\\)/thread/g > actual_output.txt\"\n                );\n                cmd!(sh, \"bash -c {bash_cmd}\")\n                    .run()\n                    .with_context(|| format!(\"Running example `{example}` failed\"))?;\n            }\n            #[cfg(target_os = \"windows\")]\n            {\n                // Clean generated files for Cargo projects\n                let _ = cmd!(\n                    sh,\n                    \"cmd /c 'del /f /q generated.h generated.cpp src\\\\generated.rs actual_output.txt 2>nul'\"\n                )\n                .run();\n                cmd!(sh, \"cmd /c 'cargo build'\")\n                    .run()\n                    .with_context(|| format!(\"Building example `{example}` failed\"))?;\n                let batch_cmd =\n                    format!(\"..\\\\..\\\\target\\\\debug\\\\example-{example} > actual_output.txt 2>&1\");\n                cmd!(sh, \"cmd /c {batch_cmd}\")\n                    .run()\n                    .with_context(|| format!(\"Running example `{example}` failed\"))?;\n                cmd!(sh, \"pwsh -Command '(Get-Content actual_output.txt) -replace \\\"thread.*\\\\(.*\\\\)\\\", \\\"thread\\\" -replace \\\"\\\\\\\\\\\", \\\"/\\\"| Out-File actual_output.txt'\")\n                        .run()\n                        .with_context(|| format!(\"Filtering example `{example}` thread output failed\"))?;\n            }\n        } else {\n            #[cfg(not(target_os = \"windows\"))]\n            if sh.path_exists(\"Makefile\") {\n                // Clean generated files for Make projects\n                cmd!(sh, \"make clean\")\n                    .run()\n                    .with_context(|| format!(\"Cleaning example `{example}` failed\"))?;\n                cmd!(sh, \"make\")\n                    .run()\n                    .with_context(|| format!(\"Building example `{example}` failed\"))?;\n                cmd!(\n                    sh,\n                    \"bash -c './a.out 2>&1 | sed -e s/thread.*\\\\(.*\\\\)/thread/g > actual_output.txt'\"\n                )\n                .run()\n                .with_context(|| format!(\"Running example `{example}` failed\"))?;\n                if sh.path_exists(\"b.out\") {\n                    cmd!(\n                        sh,\n                        \"bash -c './b.out 2>&1 | sed -r s/thread.*\\\\(.*\\\\)/thread/g >> actual_output.txt'\"\n                    )\n                    .run()\n                    .with_context(|| format!(\"Running example `{example}` b.out failed\"))?;\n                }\n            } else {\n                skip = true;\n                println!(\"Skipping {example}, no Makefile for this example\");\n            }\n\n            #[cfg(target_os = \"windows\")]\n            if sh.path_exists(\"NMakefile\") {\n                // Clean generated files for NMake projects\n                cmd!(sh, \"nmake /f NMakefile clean\")\n                    .run()\n                    .with_context(|| format!(\"Cleaning example `{example}` failed\"))?;\n                cmd!(sh, \"nmake /f NMakefile\")\n                    .run()\n                    .with_context(|| format!(\"Building example `{example}` failed\"))?;\n                if sh.path_exists(\"a.bat\") {\n                    cmd!(sh, \"cmd /c '.\\\\a.bat > actual_output.txt 2>&1'\")\n                        .run()\n                        .with_context(|| format!(\"Running example `{example}` failed\"))?;\n                } else {\n                    cmd!(sh, \"cmd /c '.\\\\a.exe > actual_output.txt 2>&1'\")\n                        .run()\n                        .with_context(|| format!(\"Running example `{example}` failed\"))?;\n                }\n                if sh.path_exists(\"b.exe\") {\n                    cmd!(sh, \"cmd /c '.\\\\b.exe >> actual_output.txt 2>&1'\")\n                        .run()\n                        .with_context(|| format!(\"Running example `{example}` b.exe failed\"))?;\n                }\n                cmd!(sh, \"pwsh -Command '(Get-Content actual_output.txt) -replace \\\"thread.*\\\\(.*\\\\)\\\", \\\"thread\\\" -replace \\\"\\\\\\\\\\\", \\\"/\\\"| Out-File actual_output.txt'\")\n                        .run()\n                        .with_context(|| format!(\"Filtering example `{example}` thread output failed\"))?;\n            } else {\n                skip = true;\n                println!(\"Skipping {example}, no NMakefile for this example\");\n            }\n        }\n        if fix {\n            sh.copy_file(\"./actual_output.txt\", \"./expected_output.txt\")?;\n        }\n\n        if !skip {\n            #[cfg(not(target_os = \"windows\"))]\n            cmd!(sh, \"diff actual_output.txt expected_output.txt\")\n                .run()\n                .with_context(|| format!(\"Example `{example}` output differs from expected.\"))?;\n            #[cfg(target_os = \"windows\")]\n            cmd!(sh, \"cmd /c 'fc actual_output.txt expected_output.txt'\")\n                .run()\n                .with_context(|| format!(\"Example `{example}` output differs from expected.\"))?;\n\n            cmd!(sh, \"cargo fmt --check\").run().with_context(|| {\n                format!(\"Example `{example}` is not formatted. Run `cargo fmt`\")\n            })?;\n        }\n\n        sh.change_dir(&examples_dir);\n    }\n    Ok(())\n}\n\npub fn main(fix: bool) -> Result<()> {\n    let sh = &Shell::new()?;\n    println!(\"Cargo version = {}\", cmd!(sh, \"cargo --version\").read()?);\n\n    #[cfg(not(target_os = \"windows\"))]\n    {\n        let cxx = sh.var(\"CXX\")?;\n        println!(\"CXX version = {}\", cmd!(sh, \"{cxx} --version\").read()?);\n    }\n    #[cfg(target_os = \"windows\")]\n    let msvc_ver: u32 = {\n        let msvc = String::from_utf8(cmd!(sh, \"cl.exe /help\").output()?.stderr)?;\n        let msvc = msvc\n            .lines()\n            .next()\n            .and_then(|line| line.split(\"Version \").nth(1))\n            .unwrap_or_default();\n\n        let mut parts = msvc.split(\".\");\n        let major = parts.next().unwrap_or(\"0\");\n        let minor = parts.next().unwrap_or(\"0\");\n        let msvc_ver: u32 = format!(\"{major}{minor}\").parse()?;\n\n        println!(\"MSVC version = {msvc} ({msvc_ver})\",);\n        msvc_ver\n    };\n\n    #[cfg(not(target_os = \"windows\"))]\n    sh.set_var(\"RUSTFLAGS\", \"-D warnings\");\n\n    #[cfg(target_os = \"windows\")]\n    {\n        // Prevent link.exe error:1318\n        let link_debug = if msvc_ver > 1944 {\n            // sorry, msvc 2026 removed FASTLINK support so it can't prevent pdb\n            // corruption. best we can do is disable debug symbols\n            \"/DEBUG:NONE\"\n        } else {\n            \"/DEBUG:FASTLINK\"\n        };\n        sh.set_var(\n            \"RUSTFLAGS\",\n            format!(\"-D warnings -C link-arg={link_debug} -C link-arg=/INCREMENTAL:NO\"),\n        );\n    }\n\n    if fix {\n        cmd!(sh, \"cargo fmt --all\").run()?;\n        if let Err(e) = format_book::main(true /* fix */) {\n            eprintln!(\"Warning: Failed to format book: {}\", e);\n        }\n    }\n\n    #[cfg(not(target_os = \"windows\"))]\n    cmd!(sh, \"cspell .\")\n        .run()\n        .with_context(|| \"Failed to check word spellings\")?;\n    #[cfg(target_os = \"windows\")]\n    cmd!(sh, \"cspell.cmd .\")\n        .run()\n        .with_context(|| \"Failed to check word spellings\")?;\n\n    // Check book formatting\n    check_book_formatting().with_context(|| \"Book formatting check failed\")?;\n\n    for dir in sh.read_dir(\".\")? {\n        if sh.path_exists(dir.join(\"Cargo.toml\")) {\n            let _crate_dir = sh.push_dir(dir.file_name().unwrap_or_default());\n            check_crate(sh).with_context(|| format!(\"Checking crate {dir:?} failed\"))?;\n        }\n    }\n\n    check_examples(sh, fix).with_context(|| \"Checking examples failed\")?;\n\n    // it's nigh impossible to get this to run under MSVC\n    #[cfg(not(target_os = \"windows\"))]\n    cmd!(sh, \"cargo test --all-features\").run()?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "xtask/src/format_book.rs",
    "content": "use anyhow::{Context, Result, bail};\nuse xshell::{Shell, cmd};\n\npub fn main(fix: bool) -> Result<()> {\n    let sh = Shell::new()?;\n\n    // Check if dprint config exists\n    if !sh.path_exists(\"dprint.json\") {\n        bail!(\"dprint.json config file not found. Please create it first.\");\n    }\n\n    // Check if book source directory exists\n    if !sh.path_exists(\"book/src\") {\n        bail!(\"Book source directory 'book/src' not found\");\n    }\n\n    if fix {\n        println!(\"Formatting markdown files...\");\n        cmd!(sh, \"dprint fmt\")\n            .run()\n            .with_context(|| \"Failed to format markdown files\")?;\n        println!(\"✓ Book formatting complete!\");\n        Ok(())\n    } else {\n        println!(\"Checking markdown formatting...\");\n        match cmd!(sh, \"dprint check\").run() {\n            Ok(_) => {\n                println!(\"✓ All markdown files are correctly formatted!\");\n                Ok(())\n            }\n            Err(_) => {\n                eprintln!(\"✗ Some markdown files need formatting.\");\n                eprintln!(\"Run `cargo xtask format-book --fix` to fix them.\");\n                bail!(\"Book formatting check failed\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "xtask/src/format_templates.rs",
    "content": "use anyhow::{Context, Result, bail};\nuse xshell::{Shell, cmd};\n\nfn convert_sailfish_tags_to_comment(mut template: &str) -> Result<(String, Vec<&str>)> {\n    let mut result_text = String::with_capacity(template.len());\n    let mut result_dicts = vec![];\n    while let Some((before_start, rest)) = template.split_once(\"<%\") {\n        result_text.push_str(before_start);\n        let comment = format!(\"/* SAILFISH_TEMPLATE{} */\", result_dicts.len());\n        let (tag, rest) = rest\n            .split_once(\"%>\")\n            .context(\"A <% without %> found in template\")?;\n        result_dicts.push(tag);\n        template = rest;\n        result_text.push_str(&comment);\n    }\n    result_text.push_str(template);\n    Ok((result_text, result_dicts))\n}\n\nfn convert_comments_to_sailfish_tag(mut template: String, tags: Vec<&str>) -> String {\n    for (i, tag) in tags.into_iter().enumerate() {\n        let comment = format!(\"/* SAILFISH_TEMPLATE{i} */\");\n        let tag_fixed = format!(\"<%{tag}%>\");\n        template = template.replace(&comment, &tag_fixed);\n    }\n    template\n}\n\npub fn main(fix: bool) -> Result<()> {\n    let sh = Shell::new()?;\n\n    let temp_dir = sh.create_temp_dir()?;\n\n    for cpp_template in [\n        \"./zngur-generator/templates/cpp_header.sptl\",\n        \"./zngur-generator/templates/cpp_source.sptl\",\n    ] {\n        let text = std::fs::read_to_string(cpp_template).context(\"failed to open template file\")?;\n\n        let (commented_text, tags) = convert_sailfish_tags_to_comment(&text)?;\n\n        let temp_file_path = temp_dir.path().join(\"template.cpp\");\n        std::fs::write(&temp_file_path, commented_text)?;\n\n        cmd!(sh, \"clang-format --style=webkit -i {temp_file_path}\").run()?;\n\n        let fixed_text = std::fs::read_to_string(&temp_file_path)?;\n        let fixed_text = convert_comments_to_sailfish_tag(fixed_text, tags);\n\n        if fix {\n            std::fs::write(&cpp_template, fixed_text)?;\n        } else {\n            if fixed_text != text {\n                bail!(\"Diff detected in file {cpp_template}\");\n            }\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "xtask/src/main.rs",
    "content": "use clap::Parser;\n\nmod ci;\nmod format_book;\nmod format_templates;\n\n#[derive(Parser)]\nenum Command {\n    CI {\n        #[arg(long)]\n        fix: bool,\n    },\n    FormatBook {\n        #[arg(long)]\n        fix: bool,\n    },\n    FormatTemplates {\n        #[arg(long)]\n        fix: bool,\n    },\n}\n\nfn main() -> anyhow::Result<()> {\n    let cmd = Command::parse();\n    match cmd {\n        Command::CI { fix } => ci::main(fix),\n        Command::FormatBook { fix } => format_book::main(fix),\n        Command::FormatTemplates { fix } => format_templates::main(fix),\n    }\n}\n"
  },
  {
    "path": "zngur/Cargo.toml",
    "content": "[package]\nname = \"zngur\"\ndescription = \"A Rust/C++ interoperability tool\"\nreadme = \"../README.md\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nzngur-generator = { version = \"=0.9.0\", path = \"../zngur-generator\" }\n"
  },
  {
    "path": "zngur/src/lib.rs",
    "content": "//! This crate contains an API for using the Zngur code generator inside build scripts. For more information\n//! about the Zngur itself, see [the documentation](https://hkalbasi.github.io/zngur).\n\nuse std::{\n    fs::File,\n    io::Write,\n    path::{Path, PathBuf},\n};\n\nuse zngur_generator::{\n    ParsedZngFile, ZngHeaderGenerator, ZngurGenerator,\n    cfg::{InMemoryRustCfgProvider, NullCfg, RustCfgProvider},\n};\n\n#[must_use]\n/// Builder for the Zngur generator.\n///\n/// Usage:\n/// ```ignore\n/// let crate_dir = PathBuf::from(env::var(\"CARGO_MANIFEST_DIR\").unwrap());\n/// let out_dir = PathBuf::from(env::var(\"OUT_DIR\").unwrap());\n/// Zngur::from_zng_file(crate_dir.join(\"main.zng\"))\n///     .with_cpp_file(out_dir.join(\"generated.cpp\"))\n///     .with_h_file(out_dir.join(\"generated.h\"))\n///     .with_rs_file(out_dir.join(\"generated.rs\"))\n///     .with_depfile(out_dir.join(\"zngur.d\"))\n///     .generate();\n/// ```\npub struct Zngur {\n    zng_file: PathBuf,\n    h_file_path: Option<PathBuf>,\n    cpp_file_path: Option<PathBuf>,\n    rs_file_path: Option<PathBuf>,\n    depfile_path: Option<PathBuf>,\n    mangling_base: Option<String>,\n    cpp_namespace: Option<String>,\n    rust_cfg: Option<Box<dyn RustCfgProvider>>,\n    zng_header_in_place: bool,\n    zng_h_file_path: Option<PathBuf>,\n    crate_name: Option<String>,\n}\n\nimpl Zngur {\n    pub fn from_zng_file(zng_file_path: impl AsRef<Path>) -> Self {\n        Zngur {\n            zng_file: zng_file_path.as_ref().to_owned(),\n            h_file_path: None,\n            cpp_file_path: None,\n            rs_file_path: None,\n            depfile_path: None,\n            mangling_base: None,\n            cpp_namespace: None,\n            rust_cfg: None,\n            zng_header_in_place: false,\n            zng_h_file_path: None,\n            crate_name: None,\n        }\n    }\n\n    pub fn with_zng_header(mut self, zng_header: impl AsRef<Path>) -> Self {\n        self.zng_h_file_path.replace(zng_header.as_ref().to_owned());\n        self\n    }\n\n    pub fn with_h_file(mut self, path: impl AsRef<Path>) -> Self {\n        self.h_file_path = Some(path.as_ref().to_owned());\n        self\n    }\n\n    pub fn with_cpp_file(mut self, path: impl AsRef<Path>) -> Self {\n        self.cpp_file_path = Some(path.as_ref().to_owned());\n        self\n    }\n\n    pub fn with_rs_file(mut self, path: impl AsRef<Path>) -> Self {\n        self.rs_file_path = Some(path.as_ref().to_owned());\n        self\n    }\n\n    /// Set the path for the dependency file (.d file) output.\n    ///\n    /// The dependency file lists all .zng files that were processed (main file + imports).\n    /// This can be used by build systems to detect when regeneration is needed.\n    pub fn with_depfile(mut self, path: impl AsRef<Path>) -> Self {\n        self.depfile_path = Some(path.as_ref().to_owned());\n        self\n    }\n\n    pub fn with_mangling_base(mut self, mangling_base: &str) -> Self {\n        self.mangling_base = Some(mangling_base.to_owned());\n        self\n    }\n\n    pub fn with_cpp_namespace(mut self, cpp_namespace: &str) -> Self {\n        self.cpp_namespace = Some(cpp_namespace.to_owned());\n        self\n    }\n\n    pub fn with_crate_name(mut self, crate_name: &str) -> Self {\n        self.crate_name = Some(crate_name.to_owned());\n        self\n    }\n\n    pub fn with_rust_cargo_cfg(mut self) -> Self {\n        self.rust_cfg = Some(Box::new(\n            InMemoryRustCfgProvider::default().load_from_cargo_env(),\n        ));\n        self\n    }\n\n    pub fn with_zng_header_in_place_as(mut self, value: bool) -> Self {\n        self.zng_header_in_place = value;\n        self\n    }\n\n    pub fn with_zng_header_in_place(self) -> Self {\n        self.with_zng_header_in_place_as(true)\n    }\n\n    pub fn with_rust_in_memory_cfg<'a, CfgPairs, CfgKey, CfgValues>(\n        mut self,\n        cfg_values: CfgPairs,\n    ) -> Self\n    where\n        CfgPairs: IntoIterator<Item = (CfgKey, CfgValues)>,\n        CfgKey: AsRef<str> + 'a,\n        CfgValues: Clone + IntoIterator + 'a,\n        <CfgValues as IntoIterator>::Item: AsRef<str>,\n    {\n        self.rust_cfg = Some(Box::new(\n            InMemoryRustCfgProvider::default().with_values(cfg_values),\n        ));\n        self\n    }\n\n    pub fn generate(self) {\n        let rust_cfg = self.rust_cfg.unwrap_or_else(|| Box::new(NullCfg));\n        let parse_result = ParsedZngFile::parse(self.zng_file, rust_cfg);\n        let crate_name = self\n            .crate_name\n            .or_else(|| std::env::var(\"CARGO_PKG_NAME\").ok())\n            .unwrap_or_else(|| \"crate\".to_owned());\n        // We will pass crate_name to ZngurGenerator instead of mutating spec.\n        let panic_to_exception = parse_result.spec.convert_panic_to_exception.0;\n        let mut file = ZngurGenerator::build_from_zng(parse_result.spec, crate_name);\n\n        let rs_file_path = self.rs_file_path.expect(\"No rs file path provided\");\n        let h_file_path = self.h_file_path.expect(\"No h file path provided\");\n\n        file.0.cpp_include_header_name = h_file_path\n            .file_name()\n            .unwrap()\n            .to_string_lossy()\n            .into_owned();\n\n        if let Some(cpp_namespace) = &self.cpp_namespace {\n            file.0.mangling_base = cpp_namespace.clone();\n            file.0.cpp_namespace = Some(cpp_namespace.clone());\n        }\n\n        if let Some(mangling_base) = self.mangling_base.or_else(|| file.0.cpp_namespace.clone()) {\n            // println!(\"Mangling: {mangling_base}\");\n            file.0.mangling_base = mangling_base;\n        }\n        let (rust, h, cpp) = file.render(self.zng_header_in_place);\n\n        File::create(&rs_file_path)\n            .unwrap()\n            .write_all(rust.as_bytes())\n            .unwrap();\n        File::create(&h_file_path)\n            .unwrap()\n            .write_all(h.as_bytes())\n            .unwrap();\n        if let Some(cpp) = &cpp {\n            let cpp_file_path = self\n                .cpp_file_path\n                .as_ref()\n                .expect(\"No cpp file path provided\");\n            File::create(cpp_file_path)\n                .unwrap()\n                .write_all(cpp.as_bytes())\n                .unwrap();\n        }\n\n        // Write dependency file if requested\n        if let Some(depfile_path) = self.depfile_path {\n            let mut targets = vec![\n                h_file_path.display().to_string(),\n                rs_file_path.display().to_string(),\n            ];\n            if let Some(cpp_path) = self.cpp_file_path {\n                if cpp.is_some() {\n                    targets.push(cpp_path.display().to_string());\n                }\n            }\n\n            // Format: \"target1 target2: dep1 dep2 dep3\"\n            let deps: Vec<String> = parse_result\n                .processed_files\n                .iter()\n                .map(|p| p.display().to_string())\n                .collect();\n\n            let depfile_content = format!(\"{}: {}\\n\", targets.join(\" \"), deps.join(\" \"));\n\n            File::create(depfile_path)\n                .unwrap()\n                .write_all(depfile_content.as_bytes())\n                .unwrap();\n        }\n        if let Some(zng_h) = self.zng_h_file_path {\n            let mut zng = ZngurHdr::new()\n                .with_panic_to_exception_as(panic_to_exception)\n                .with_zng_header(zng_h);\n            if let Some(cpp_namespace) = &self.cpp_namespace {\n                zng = zng.with_cpp_namespace(&cpp_namespace);\n            }\n            zng.generate();\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct ZngurHdr {\n    panic_to_exception: bool,\n    zng_header_file: Option<PathBuf>,\n    cpp_namespace: Option<String>,\n}\n\nimpl ZngurHdr {\n    pub const fn new() -> Self {\n        Self {\n            panic_to_exception: false,\n            zng_header_file: None,\n            cpp_namespace: None,\n        }\n    }\n\n    pub fn with_panic_to_exception(self) -> Self {\n        self.with_panic_to_exception_as(true)\n    }\n\n    pub fn without_panic_to_exception(self) -> Self {\n        self.with_panic_to_exception_as(false)\n    }\n\n    pub fn with_panic_to_exception_as(mut self, panic_to_exception: bool) -> Self {\n        self.panic_to_exception = panic_to_exception;\n        self\n    }\n\n    pub fn with_zng_header(mut self, zng_header: impl Into<PathBuf>) -> Self {\n        self.zng_header_file.replace(zng_header.into());\n        self\n    }\n\n    pub fn with_cpp_namespace(mut self, cpp_namespace: &str) -> Self {\n        self.cpp_namespace = Some(cpp_namespace.to_owned());\n        self\n    }\n\n    pub fn generate(self) {\n        let generator = ZngHeaderGenerator {\n            panic_to_exception: self.panic_to_exception,\n            cpp_namespace: self.cpp_namespace.unwrap_or_else(|| \"rust\".to_owned()),\n        };\n\n        let out_h = self\n            .zng_header_file\n            .expect(\"Missing zng header output file\");\n        let rendered = generator.render();\n        std::fs::write(&out_h, rendered)\n            .unwrap_or_else(|_| panic!(\"Couldn't write contents to {}\", out_h.display()));\n    }\n}\n"
  },
  {
    "path": "zngur-autozng/Cargo.toml",
    "content": "[package]\nname = \"zngur-autozng\"\ndescription = \"Generating Zngur zng files automatically for a Rust crate\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\n\n[dependencies]\nserde = { version = \"1.0.204\", features = [\"derive\"] }\nserde_json = \"1.0.122\"\n"
  },
  {
    "path": "zngur-autozng/src/main.rs",
    "content": "use std::collections::HashMap;\n\nuse serde::{Deserialize, Serialize};\nuse serde_json::Value;\n\n#[derive(Debug, Serialize, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\nenum RustdocRustType {\n    BorrowedRef {\n        mutable: bool,\n        #[serde(rename = \"type\")]\n        inner: Box<RustdocRustType>,\n    },\n    RawPointer {\n        mutable: bool,\n        #[serde(rename = \"type\")]\n        inner: Box<RustdocRustType>,\n    },\n    Primitive(String),\n    Generic(String),\n    Tuple(Vec<RustdocRustType>),\n    Slice(Box<RustdocRustType>),\n    ResolvedPath {\n        name: String,\n    },\n    QualifiedPath {},\n}\n\nimpl RustdocRustType {\n    fn render(&self) -> String {\n        match self {\n            RustdocRustType::BorrowedRef {\n                mutable: false,\n                inner,\n            } => format!(\"&{}\", inner.render()),\n            RustdocRustType::BorrowedRef {\n                mutable: true,\n                inner,\n            } => format!(\"&mut {}\", inner.render()),\n            RustdocRustType::RawPointer { .. } => todo!(),\n            RustdocRustType::Primitive(n) => n.clone(),\n            RustdocRustType::Generic(n) => n.clone(),\n            RustdocRustType::Tuple(_) => todo!(),\n            RustdocRustType::Slice(_) => todo!(),\n            RustdocRustType::ResolvedPath { name } => name.clone(),\n            RustdocRustType::QualifiedPath {} => todo!(),\n        }\n    }\n}\n\n#[derive(Debug, Serialize, Deserialize)]\nstruct RustdocFunctionDecl {\n    inputs: Vec<(String, RustdocRustType)>,\n    output: Option<RustdocRustType>,\n    #[serde(flatten)]\n    other_fields: Value,\n}\n\n#[derive(Debug, Serialize, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\nenum RustdocItemInner {\n    Function {\n        decl: RustdocFunctionDecl,\n        #[serde(flatten)]\n        other_fields: Value,\n    },\n    Struct {\n        impls: Vec<String>,\n        #[serde(flatten)]\n        other_fields: Value,\n    },\n    Impl {\n        items: Vec<String>,\n        #[serde(rename = \"trait\")]\n        for_trait: Option<serde_json::Value>,\n        #[serde(flatten)]\n        other_fields: Value,\n    },\n    Module {\n        #[serde(flatten)]\n        other_fields: Value,\n    },\n    StructField {\n        #[serde(flatten)]\n        other_fields: Value,\n    },\n    Import {\n        #[serde(flatten)]\n        other_fields: Value,\n    },\n    AssocType {\n        #[serde(flatten)]\n        other_fields: Value,\n    },\n    Variant {\n        #[serde(flatten)]\n        other_fields: Value,\n    },\n    TypeAlias {\n        #[serde(flatten)]\n        other_fields: Value,\n    },\n    Enum {\n        impls: Vec<String>,\n        #[serde(flatten)]\n        other_fields: Value,\n    },\n}\n\n#[derive(Debug, Serialize, Deserialize)]\nstruct RustdocItem {\n    name: Option<String>,\n    inner: RustdocItemInner,\n    #[serde(flatten)]\n    other_fields: Value,\n}\n\n#[derive(Serialize, Deserialize)]\nstruct RustdocOutput {\n    index: HashMap<String, RustdocItem>,\n}\n\nfn main() {\n    let s = std::fs::read_to_string(\"./doc.json\").unwrap();\n    let d: RustdocOutput = serde_json::from_str(&s).unwrap();\n    for x in &d.index {\n        if let RustdocItemInner::Struct { impls, .. } | RustdocItemInner::Enum { impls, .. } =\n            &x.1.inner\n        {\n            println!(\"type crate::{} {{\", x.1.name.as_ref().unwrap());\n            println!(\"    #heap_allocated;\");\n            for imp in impls {\n                let imp = &d.index[imp];\n                // dbg!(imp);\n\n                if let RustdocItemInner::Impl {\n                    items, for_trait, ..\n                } = &imp.inner\n                {\n                    if for_trait.is_some() {\n                        continue;\n                    }\n                    for item in items {\n                        let item = &d.index[item];\n                        if let RustdocItemInner::Function {\n                            decl: RustdocFunctionDecl { inputs, output, .. },\n                            ..\n                        } = &item.inner\n                        {\n                            print!(\"    fn {}(\", item.name.as_deref().unwrap());\n                            let mut first = true;\n                            for (name, ty) in inputs {\n                                if !first {\n                                    print!(\", \");\n                                }\n                                first = false;\n                                if name == \"self\" {\n                                    print!(\"self\");\n                                    continue;\n                                }\n                                print!(\"{}\", ty.render());\n                            }\n                            print!(\")\");\n                            if let Some(output) = output {\n                                print!(\" -> {}\", output.render());\n                            }\n                            println!(\";\");\n                        }\n                    }\n                }\n            }\n            println!(\"}}\");\n        }\n    }\n}\n"
  },
  {
    "path": "zngur-cli/Cargo.toml",
    "content": "[package]\nname = \"zngur-cli\"\ndescription = \"CLI of the Zngur, a Rust/C++ interoperability tool\"\nreadme = \"../README.md\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\n\n[[bin]]\nname = \"zngur\"\npath = \"src/main.rs\"\nbench = false\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nzngur = { version = \"=0.9.0\", path = \"../zngur\" }\nclap = { version = \"4.3.12\", features = [\"derive\"] }\n"
  },
  {
    "path": "zngur-cli/src/cfg_extractor.rs",
    "content": "use clap::Args;\nuse std::collections::HashMap;\n\n#[derive(Args)]\npub struct CfgFromRustc {\n    /// Load rust cfg values using `rustc --print cfg`\n    ///\n    /// values loaded are in addition to any values provided with `--cfg` or `--feature`\n    /// respects the `RUSTFLAGS` environment variable\n    #[arg(long, group = \"rustc\")]\n    pub load_cfg_from_rustc: bool,\n\n    /// Use `cargo rustc -- --print cfg` which allows automatically collecting profile flags and\n    /// features\n    ///\n    /// WARNING: because `cargo rustc --print` is unstable this uses `cargo rustc -- --print` which\n    /// may invoke side effects like downloading all crate dependencies\n    ///\n    /// (requires --load-cfg-from-rustc)\n    #[arg(long, group = \"cargo_rustc\", requires = \"rustc\")]\n    use_cargo_rustc: bool,\n\n    /// flags to pass to rustc when loading cfg values\n    ///\n    /// (requires --load-cfg-from-rustc)\n    #[arg(long, requires = \"rustc\")]\n    rustc_flags: Option<String>,\n\n    /// A target to provide to `rustc` when loading config values\n    ///\n    /// (requires --load-cfg-from-rustc)\n    #[arg(long = \"target\", requires = \"rustc\")]\n    rustc_target: Option<String>,\n\n    /// cargo profile to use when loading cfg values\n    ///\n    /// (requires --use-cargo-rustc)\n    #[arg(long = \"profile\", requires = \"cargo_rustc\")]\n    cargo_profile: Option<String>,\n\n    /// cargo package to use when loading cfg values\n    ///\n    /// (requires --use-cargo-rustc)\n    #[arg(long = \"package\", requires = \"cargo_rustc\")]\n    cargo_package: Option<String>,\n\n    /// passes --no-default-features to cargo\n    ///\n    /// (requires --use-cargo-rustc)\n    #[arg(long, requires = \"cargo_rustc\")]\n    no_default_features: bool,\n\n    /// passes --all_features to cargo\n    ///\n    /// (requires --use-cargo-rustc)\n    #[arg(long, requires = \"cargo_rustc\")]\n    all_features: bool,\n}\n\npub fn cfg_from_rustc(\n    args: CfgFromRustc,\n    rust_features: &[String],\n) -> HashMap<String, Vec<String>> {\n    let mut cfg: HashMap<String, Vec<String>> = HashMap::new();\n    let mut rustflags = parse_rustflags_env();\n    if let Some(flags) = &args.rustc_flags {\n        rustflags.extend(parse_rustflags(flags))\n    }\n\n    let mut cmd = if args.use_cargo_rustc {\n        let mut cmd = std::process::Command::new(\"cargo\");\n        cmd.arg(\"rustc\");\n        if let Some(package) = &args.cargo_package {\n            cmd.args([\"--package\", package]);\n        }\n        if let Some(profile) = &args.cargo_profile {\n            cmd.args([\"--profile\", profile]);\n        }\n        if !rust_features.is_empty() && !args.all_features {\n            cmd.args([\"--features\", &rust_features.join(\",\")]);\n        }\n        if args.all_features {\n            cmd.arg(\"--all-features\");\n        }\n        if args.no_default_features {\n            cmd.arg(\"--no-default-features\");\n        }\n        cmd\n    } else {\n        std::process::Command::new(\"rustc\")\n    };\n\n    if let Some(target) = &args.rustc_target {\n        cmd.args([\"--target\", target]);\n    }\n\n    if args.use_cargo_rustc {\n        cmd.arg(\"--\");\n    }\n\n    cmd.args(rustflags);\n\n    cmd.args([\"--print\", \"cfg\"]);\n\n    let out = cmd.output().expect(\"failed to print cfg with rustc\");\n\n    if !out.status.success() {\n        eprintln!(\"{}\", String::from_utf8_lossy(&out.stderr));\n        std::process::exit(1);\n    }\n\n    let out = String::from_utf8(out.stdout).expect(\"failed to parse rustc output as utf8\");\n\n    let lines = out.split('\\n').collect::<Vec<_>>();\n    for line in lines {\n        if line.trim().is_empty() {\n            continue;\n        }\n        let (key, value) = line.trim().split_once('=').unwrap_or((line, \"\"));\n        let value = if value.len() >= 2 && value.starts_with('\"') && value.ends_with('\"') {\n            &value[1..value.len() - 1]\n        } else {\n            value\n        };\n        let entry = cfg.entry(key.to_owned()).or_default();\n        entry.push(value.to_owned())\n    }\n\n    cfg\n}\n\nfn parse_rustflags_env() -> Vec<String> {\n    let flags_str = std::env::var(\"RUSTFLAGS\").unwrap_or_default();\n    parse_rustflags(&flags_str)\n}\n\nfn parse_rustflags(flags_str: &str) -> Vec<String> {\n    let mut word: String = String::new();\n    let mut flags: Vec<String> = Vec::new();\n\n    #[derive(Copy, Clone)]\n    enum State {\n        Delem,\n        Unquoted,\n        Escape(&'static State),\n        Single,\n        Double,\n    }\n    use State::*;\n\n    let mut state = Delem;\n\n    let mut chars = flags_str.chars();\n\n    loop {\n        let Some(c) = chars.next() else {\n            match state {\n                Delem => break,\n                Unquoted | Single | Double => {\n                    flags.push(std::mem::take(&mut word));\n                    break;\n                }\n                Escape(_) => {\n                    word.push('\\\\');\n                    flags.push(std::mem::take(&mut word));\n                    break;\n                }\n            }\n        };\n        state = match state {\n            Delem => match c {\n                '\\'' => Single,\n                '\"' => Double,\n                '\\\\' => Escape(&Delem),\n                '\\t' | ' ' | '\\n' => Delem,\n                c => {\n                    word.push(c);\n                    Unquoted\n                }\n            },\n            Unquoted => match c {\n                '\\'' => Single,\n                '\"' => Double,\n                '\\\\' => Escape(&Unquoted),\n                '\\t' | ' ' | '\\n' => {\n                    flags.push(std::mem::take(&mut word));\n                    Delem\n                }\n                c => {\n                    word.push(c);\n                    Unquoted\n                }\n            },\n            Escape(next_state) => match c {\n                c @ '\"' | c @ '\\\\' if matches!(next_state, Double) => {\n                    word.push(c);\n                    Double\n                }\n                '\\n' => *next_state,\n                c => {\n                    word.push('\\\\');\n                    word.push(c);\n                    *next_state\n                }\n            },\n            Single => match c {\n                '\\'' => Unquoted,\n                c => {\n                    word.push(c);\n                    Single\n                }\n            },\n            Double => match c {\n                '\"' => Unquoted,\n                '\\\\' => Escape(&Double),\n                c => {\n                    word.push(c);\n                    Double\n                }\n            },\n        }\n    }\n\n    flags\n}\n"
  },
  {
    "path": "zngur-cli/src/main.rs",
    "content": "use std::{collections::HashMap, path::PathBuf};\n\nuse clap::Parser;\nuse zngur::{Zngur, ZngurHdr};\n\nuse crate::cfg_extractor::{CfgFromRustc, cfg_from_rustc};\n\nmod cfg_extractor;\n\n#[derive(Clone)]\nstruct CfgKey {\n    pub key: String,\n    pub values: Vec<String>,\n}\n\nimpl CfgKey {\n    fn into_tuple(self) -> (String, Vec<String>) {\n        (self.key, self.values)\n    }\n}\n\nimpl<'a> From<&'a str> for CfgKey {\n    fn from(s: &'a str) -> Self {\n        let (key, values_s) = s.split_once('=').unwrap_or((s, \"\"));\n        let values: Vec<String> = values_s\n            .split(',')\n            .map(|s| {\n                (if s.len() >= 2 && s.starts_with('\"') && s.ends_with('\"') {\n                    &s[1..s.len() - 1]\n                } else {\n                    s\n                })\n                .to_owned()\n            })\n            .collect();\n        CfgKey {\n            key: key.to_owned(),\n            values,\n        }\n    }\n}\n\n#[derive(Parser)]\n#[command(version)]\nenum Command {\n    #[command(alias = \"g\")]\n    Generate {\n        /// Path to the zng file\n        path: PathBuf,\n\n        /// Path of the generated C++ file, if it is needed\n        ///\n        /// Default is {ZNG_FILE_PARENT}/generated.cpp\n        #[arg(long)]\n        cpp_file: Option<PathBuf>,\n\n        /// Path of the generated header file\n        ///\n        /// Default is {ZNG_FILE_PARENT}/generated.h\n        #[arg(long)]\n        h_file: Option<PathBuf>,\n\n        /// Path of the generated Rust file\n        ///\n        /// Default is {ZNG_FILE_PARENT}/src/generated.rs\n        #[arg(long)]\n        rs_file: Option<PathBuf>,\n\n        /// Path of the dependency file (.d file) to generate\n        ///\n        /// The dependency file lists all .zng files that were processed.\n        /// This can be used by build systems to detect when regeneration is needed.\n        #[arg(long)]\n        depfile: Option<PathBuf>,\n\n        /// A unique string which is included in zngur symbols to prevent duplicate\n        /// symbols in linker\n        ///\n        /// Default is \"rust\"\n        #[arg(long)]\n        mangling_base: Option<String>,\n\n        /// A rust config value of the form key(=value1(,value2 ...)) to use when\n        /// generating the zngur spec.\n        /// i.e.  -C target_os=linux -C target_feature=sse,sse2 -C debug_assertions\n        ///\n        /// see https://doc.rust-lang.org/reference/conditional-compilation.html\n        /// for possible values\n        ///\n        /// combined with any values loaded from rustc (if enabled)\n        ///\n        /// Default is an empty configuration\n        #[arg(long = \"cfg\", short = 'C')]\n        rust_cfg: Vec<CfgKey>,\n\n        /// A feature name to enable when generating the zngur spec\n        ///\n        /// combined with any values loaded from rustc (if enabled)\n        ///\n        /// Default is no features\n        #[arg(long = \"feature\", short = 'F')]\n        rust_features: Vec<String>,\n\n        #[command(flatten)]\n        load_rustc_cfg: CfgFromRustc,\n\n        /// When set, the generator will embed the common Zngur types into the generated header.\n        ///\n        /// The recommended workflow is to generate a `zngur.h` header with `make-zng-header` which should\n        /// be shared between all of your generated modules and leave this flag unset.\n        #[arg(long = \"in-place\", short = 'i')]\n        zng_header_in_place: bool,\n\n        /// Set the namespace of the generated C++ types. If not provided it defaults to `rust`\n        ///\n        /// You may use this to customize overarching namespace for all the\n        /// generated types in C++, but if your project spans multiple .zng modules, you\n        /// must use a shared namespace\n        #[arg(long)]\n        cpp_namespace: Option<String>,\n\n        /// Set the crate name to be used in the generated code where `crate` appears.\n        ///\n        /// If not provided, it tries to read `CARGO_PKG_NAME` and defaults to `crate` if unset.\n        #[arg(long)]\n        crate_name: Option<String>,\n    },\n    #[command(alias = \"h\")]\n    /// Generates the zngur.h file that contains shared interop definitions used by all generated zngur bridges.\n    MakeZngHeader {\n        /// Path to the generated header file\n        path: PathBuf,\n\n        /// If set, it will generate the \"panic to exceptions\" mechanism in the generated header.\n        ///\n        /// Note that each `zng` module will need to use `#convert_panic_to_exception` in order to fully enable it.\n        #[arg(long = \"panic-to-exception\")]\n        convert_panic_to_exception: bool,\n\n        /// Set the namespace of the generated C++ types. If not provided it defaults to `rust`\n        ///\n        /// You may use this to customize overarching namespace for all the\n        /// generated types in C++, but if your project spans multiple .zng modules, you\n        /// must use a shared namespace\n        #[arg(long)]\n        cpp_namespace: Option<String>,\n    },\n}\n\nfn main() {\n    let cmd = Command::parse();\n    match cmd {\n        Command::Generate {\n            path,\n            cpp_file,\n            h_file,\n            rs_file,\n            depfile,\n            mangling_base,\n            rust_cfg,\n            rust_features,\n            load_rustc_cfg,\n            zng_header_in_place,\n            cpp_namespace,\n            crate_name,\n        } => {\n            let pp = path.parent().unwrap();\n            let cpp_file = cpp_file.unwrap_or_else(|| pp.join(\"generated.cpp\"));\n            let h_file = h_file.unwrap_or_else(|| pp.join(\"generated.h\"));\n            let rs_file = rs_file.unwrap_or_else(|| pp.join(\"src/generated.rs\"));\n            let mut zng = Zngur::from_zng_file(&path)\n                .with_cpp_file(cpp_file)\n                .with_h_file(h_file)\n                .with_rs_file(rs_file)\n                .with_zng_header_in_place_as(zng_header_in_place);\n            if let Some(cpp_namespace) = cpp_namespace {\n                zng = zng.with_cpp_namespace(&cpp_namespace);\n            }\n            if let Some(crate_name) = crate_name {\n                zng = zng.with_crate_name(&crate_name);\n            }\n\n            let mut cfg: HashMap<String, Vec<String>> = HashMap::new();\n            if load_rustc_cfg.load_cfg_from_rustc {\n                cfg.extend(cfg_from_rustc(load_rustc_cfg, &rust_features));\n            }\n            if !rust_cfg.is_empty() {\n                cfg.extend(rust_cfg.into_iter().map(CfgKey::into_tuple));\n            }\n            if !rust_features.is_empty() {\n                cfg.insert(\"feature\".to_owned(), rust_features);\n            }\n            if !cfg.is_empty() {\n                zng = zng.with_rust_in_memory_cfg(cfg);\n            }\n            if let Some(depfile) = depfile {\n                zng = zng.with_depfile(depfile);\n            }\n            if let Some(mangling_base) = mangling_base {\n                zng = zng.with_mangling_base(&mangling_base);\n            }\n            zng.generate();\n        }\n        Command::MakeZngHeader {\n            path,\n            convert_panic_to_exception,\n            cpp_namespace,\n        } => {\n            let mut hdr = ZngurHdr::new()\n                .with_panic_to_exception_as(convert_panic_to_exception)\n                .with_zng_header(path);\n            if let Some(cpp_namespace) = cpp_namespace {\n                hdr = hdr.with_cpp_namespace(&cpp_namespace);\n            }\n            hdr.generate();\n        }\n    }\n}\n"
  },
  {
    "path": "zngur-def/Cargo.toml",
    "content": "[package]\nname = \"zngur-def\"\ndescription = \"Data types that define the structure of a zng file\"\nreadme = \"../README.md\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nindexmap = \"2.13.0\"\nitertools = \"0.11\"\n"
  },
  {
    "path": "zngur-def/src/lib.rs",
    "content": "use std::fmt::Display;\n\nuse indexmap::IndexMap;\nuse itertools::Itertools;\n\nmod merge;\npub use merge::{Merge, MergeFailure, MergeResult};\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub enum Mutability {\n    Mut,\n    Not,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub enum ZngurMethodReceiver {\n    Static,\n    Ref(Mutability),\n    Move,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub struct ZngurMethod {\n    pub name: String,\n    pub generics: Vec<RustType>,\n    pub receiver: ZngurMethodReceiver,\n    pub inputs: Vec<RustType>,\n    pub output: RustType,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub struct ZngurFn {\n    pub path: RustPathAndGenerics,\n    pub inputs: Vec<RustType>,\n    pub output: RustType,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub struct ZngurExternCppFn {\n    pub name: String,\n    pub inputs: Vec<RustType>,\n    pub output: RustType,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub struct ZngurExternCppImpl {\n    pub tr: Option<RustTrait>,\n    pub ty: RustType,\n    pub methods: Vec<ZngurMethod>,\n}\n\n#[derive(Debug, PartialEq, Eq)]\npub struct ZngurConstructor {\n    pub name: Option<String>,\n    pub inputs: Vec<(String, RustType)>,\n}\n\n#[derive(Debug, PartialEq, Eq)]\npub struct ZngurField {\n    pub name: String,\n    pub ty: RustType,\n    pub offset: Option<usize>,\n}\n\n#[derive(Debug, PartialEq, Eq)]\npub struct ZngurFieldData {\n    pub name: String,\n    pub ty: RustType,\n    pub offset: ZngurFieldDataOffset,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub enum ZngurFieldDataOffset {\n    Offset(usize),\n    Auto(String),\n}\n\nimpl ZngurFieldDataOffset {\n    pub fn is_offset(&self) -> bool {\n        matches!(self, ZngurFieldDataOffset::Offset(_))\n    }\n\n    pub fn as_offset(&self) -> Option<usize> {\n        match self {\n            ZngurFieldDataOffset::Offset(o) => Some(*o),\n            _ => None,\n        }\n    }\n\n    pub fn as_auto(&self) -> Option<&str> {\n        match self {\n            ZngurFieldDataOffset::Auto(s) => Some(s),\n            _ => None,\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub enum ZngurWellknownTrait {\n    Debug,\n    Drop,\n    Unsized,\n    Copy,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub enum ZngurWellknownTraitData {\n    Debug {\n        pretty_print: String,\n        debug_print: String,\n    },\n    Drop {\n        drop_in_place: String,\n    },\n    Unsized,\n    Copy,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum LayoutPolicy {\n    StackAllocated { size: usize, align: usize },\n    Conservative { size: usize, align: usize },\n    HeapAllocated,\n    OnlyByRef,\n}\n\nimpl LayoutPolicy {\n    pub const ZERO_SIZED_TYPE: Self = LayoutPolicy::StackAllocated { size: 0, align: 1 };\n}\n\n#[derive(Debug, PartialEq, Eq)]\npub struct ZngurMethodDetails {\n    pub data: ZngurMethod,\n    pub use_path: Option<Vec<String>>,\n    pub deref: Option<(RustType, Mutability)>,\n}\n\n#[derive(Debug, PartialEq, Eq)]\npub struct CppValue(pub String, pub String);\n\n#[derive(Debug, PartialEq, Eq)]\npub struct CppRef(pub String);\n\nimpl Display for CppRef {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}\", self.0)\n    }\n}\n\n#[derive(Debug)]\npub struct ZngurType {\n    pub ty: RustType,\n    pub layout: LayoutPolicy,\n    pub wellknown_traits: Vec<ZngurWellknownTrait>,\n    pub methods: Vec<ZngurMethodDetails>,\n    pub constructors: Vec<ZngurConstructor>,\n    pub fields: Vec<ZngurField>,\n    pub cpp_value: Option<CppValue>,\n    pub cpp_ref: Option<CppRef>,\n}\n\n#[derive(Debug)]\npub struct ZngurTrait {\n    pub tr: RustTrait,\n    pub methods: Vec<ZngurMethod>,\n}\n\n#[derive(Debug, Default)]\npub struct AdditionalIncludes(pub String);\n\n#[derive(Debug, Default)]\npub struct ConvertPanicToException(pub bool);\n\n#[derive(Clone, Debug, Default)]\npub struct Import(pub std::path::PathBuf);\n\n#[derive(Debug, Clone)]\npub struct ModuleImport {\n    pub path: std::path::PathBuf,\n}\n\n#[derive(Debug, Default)]\npub struct ZngurSpec {\n    pub imports: Vec<Import>,\n    pub imported_modules: Vec<ModuleImport>,\n    pub types: Vec<ZngurType>,\n    pub traits: IndexMap<RustTrait, ZngurTrait>,\n    pub funcs: Vec<ZngurFn>,\n    pub extern_cpp_funcs: Vec<ZngurExternCppFn>,\n    pub extern_cpp_impls: Vec<ZngurExternCppImpl>,\n    pub additional_includes: AdditionalIncludes,\n    pub convert_panic_to_exception: ConvertPanicToException,\n    pub cpp_include_header_name: String,\n    pub mangling_base: String,\n    pub cpp_namespace: Option<String>,\n    pub rust_cfg: Vec<(String, Option<String>)>,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub enum RustTrait {\n    Normal(RustPathAndGenerics),\n    Fn {\n        name: String,\n        inputs: Vec<RustType>,\n        output: Box<RustType>,\n    },\n}\n\nimpl RustTrait {\n    pub fn take_assocs(mut self) -> (Self, Vec<(String, RustType)>) {\n        let assocs = match &mut self {\n            RustTrait::Normal(p) => std::mem::take(&mut p.named_generics),\n            RustTrait::Fn { .. } => vec![],\n        };\n        (self, assocs)\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub enum PrimitiveRustType {\n    Uint(u32),\n    Int(u32),\n    Float(u32),\n    Usize,\n    Bool,\n    Char,\n    Str,\n    ZngurCppOpaqueOwnedObject,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub struct RustPathAndGenerics {\n    pub path: Vec<String>,\n    pub generics: Vec<RustType>,\n    pub named_generics: Vec<(String, RustType)>,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub enum RustType {\n    Primitive(PrimitiveRustType),\n    Ref(Mutability, Box<RustType>),\n    Raw(Mutability, Box<RustType>),\n    Boxed(Box<RustType>),\n    Slice(Box<RustType>),\n    Dyn(RustTrait, Vec<String>),\n    Impl(RustTrait, Vec<String>),\n    Tuple(Vec<RustType>),\n    Adt(RustPathAndGenerics),\n}\n\nimpl RustType {\n    pub const UNIT: Self = RustType::Tuple(Vec::new());\n}\n\nimpl Display for RustPathAndGenerics {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        let RustPathAndGenerics {\n            path,\n            generics,\n            named_generics,\n        } = self;\n        for p in path {\n            if p != \"crate\" {\n                write!(f, \"::\")?;\n            }\n            write!(f, \"{p}\")?;\n        }\n        if !generics.is_empty() || !named_generics.is_empty() {\n            write!(\n                f,\n                \"::<{}>\",\n                generics\n                    .iter()\n                    .map(|x| format!(\"{x}\"))\n                    .chain(named_generics.iter().map(|x| format!(\"{} = {}\", x.0, x.1)))\n                    .join(\", \")\n            )?;\n        }\n        Ok(())\n    }\n}\n\nimpl Display for RustTrait {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            RustTrait::Normal(tr) => write!(f, \"{tr}\"),\n            RustTrait::Fn {\n                name,\n                inputs,\n                output,\n            } => {\n                write!(f, \"{name}({})\", inputs.iter().join(\", \"))?;\n                if **output != RustType::UNIT {\n                    write!(f, \" -> {output}\")?;\n                }\n                Ok(())\n            }\n        }\n    }\n}\n\nimpl Display for RustType {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            RustType::Primitive(s) => match s {\n                PrimitiveRustType::Uint(s) => write!(f, \"u{s}\"),\n                PrimitiveRustType::Int(s) => write!(f, \"i{s}\"),\n                PrimitiveRustType::Float(s) => write!(f, \"f{s}\"),\n                PrimitiveRustType::Usize => write!(f, \"usize\"),\n                PrimitiveRustType::Bool => write!(f, \"bool\"),\n                PrimitiveRustType::Char => write!(f, \"char\"),\n                PrimitiveRustType::Str => write!(f, \"str\"),\n                PrimitiveRustType::ZngurCppOpaqueOwnedObject => {\n                    write!(f, \"ZngurCppOpaqueOwnedObject\")\n                }\n            },\n            RustType::Ref(Mutability::Not, ty) => write!(f, \"&{ty}\"),\n            RustType::Ref(Mutability::Mut, ty) => write!(f, \"&mut {ty}\"),\n            RustType::Raw(Mutability::Not, ty) => write!(f, \"*const {ty}\"),\n            RustType::Raw(Mutability::Mut, ty) => write!(f, \"*mut {ty}\"),\n            RustType::Boxed(ty) => write!(f, \"Box<{ty}>\"),\n            RustType::Tuple(v) => write!(f, \"({})\", v.iter().join(\", \")),\n            RustType::Adt(pg) => write!(f, \"{pg}\"),\n            RustType::Dyn(tr, marker_bounds) => {\n                write!(f, \"dyn {tr}\")?;\n                for mb in marker_bounds {\n                    write!(f, \"+ {mb}\")?;\n                }\n                Ok(())\n            }\n            RustType::Impl(tr, marker_bounds) => {\n                write!(f, \"impl {tr}\")?;\n                for mb in marker_bounds {\n                    write!(f, \"+ {mb}\")?;\n                }\n                Ok(())\n            }\n            RustType::Slice(s) => write!(f, \"[{s}]\"),\n        }\n    }\n}\n"
  },
  {
    "path": "zngur-def/src/merge.rs",
    "content": "use crate::{\n    AdditionalIncludes, ConvertPanicToException, CppRef, CppValue, LayoutPolicy, ZngurConstructor,\n    ZngurExternCppFn, ZngurExternCppImpl, ZngurField, ZngurFn, ZngurMethodDetails, ZngurSpec,\n    ZngurTrait, ZngurType,\n};\n\n/// Trait for types with a partial union operation.\n///\n/// If a type T is Merge, it provides a partial union operation `merge`: T x T -> T.\n///\n/// Partial unions do not need to be homogenous. If a type U is Merge<T>,\n/// it provides a partial union operation `merge`: T X U -> U.\n/// For example, T: usize, U: Set<usize>; the partial union is the result of\n/// adding the lhs usize to the rhs Set.\n///\n/// \"Partial\" means the result is not necessarily defined for all inputs; the union may fail.\n/// This is often because the instances are contradictory (as defined by the type).\n///\n/// There are no guarantees about the state of the mutable argument, `into`, in the case\n/// of a failed merge. `merge` is not required to leave `into` in a valid state, or restore\n/// it to its original state.\npub trait Merge<T = Self> {\n    /// Writes the partial union of `self` and `into` to the latter.\n    ///\n    /// # Errors\n    ///\n    /// If the instances are contradictory, a `MergeFailure` is returned.\n    fn merge(self, into: &mut T) -> MergeResult;\n}\n\n/// The result of a merge operation.\npub type MergeResult = Result<(), MergeFailure>;\n\n/// An unsuccessful merge operation.\npub enum MergeFailure {\n    /// The merge was not successful because of a conflict.\n    Conflict(String),\n}\n\n/// Push an item onto a vector if it is not already present, in linear time.\nfn push_unique<T: Eq>(item: T, smallvec: &mut std::vec::Vec<T>) {\n    if !smallvec.contains(&item) {\n        smallvec.push(item);\n    }\n}\n\n/// Writes the union of `other` and `smallvec` to the latter in O(N * M) time.\nfn inplace_union<T: Eq>(other: Vec<T>, smallvec: &mut std::vec::Vec<T>) {\n    for item in other {\n        push_unique(item, smallvec);\n    }\n}\n\n/// Writes the union of `other` and `smallvec` to the latter in O(N * M) time.\n/// If an element in `other` has the same identity as an element in `smallvec`,\n/// the elements are merged. Otherwise, the element is added to `smallvec`.\nfn merge_by_identity<T: Merge>(\n    other: Vec<T>,\n    smallvec: &mut std::vec::Vec<T>,\n    identity: impl Fn(&T, &T) -> bool,\n) -> MergeResult {\n    for item in other {\n        if let Some(existing) = smallvec.iter_mut().find(|e| identity(e, &item)) {\n            item.merge(existing)?;\n        } else {\n            smallvec.push(item);\n        }\n    }\n    Ok(())\n}\n\nimpl<T: Merge> Merge for Option<T> {\n    /// Writes the partial union of `self` and `into` to the latter.\n    ///\n    /// If both `self` and `into` are Some, the underlying values are merged.\n    /// Otherwise, the result is whichever value is Some, or None if neither is.\n    fn merge(self, into: &mut Self) -> MergeResult {\n        match self {\n            Some(src) => match into.as_mut() {\n                Some(dst) => src.merge(dst),\n                None => {\n                    *into = Some(src);\n                    Ok(())\n                }\n            },\n            None => Ok(()),\n        }\n    }\n}\n\nimpl<K, V, I: IntoIterator<Item = (K, V)>> Merge<indexmap::IndexMap<K, V>> for I\nwhere\n    K: Eq + std::hash::Hash,\n    V: Merge,\n{\n    /// Merges a sequence of key-value pairs into a map.\n    ///\n    /// If a key is present in both `self` and `into`, the corresponding values are merged.\n    /// Otherwise, the entry from `self` is inserted into `into`.\n    ///\n    /// This implementation implies `indexmap::IndexMap<K,V>` is `Merge` for all `V: Merge`,\n    /// because IndexMap is `IntoIterator`. We use `IntoIterator` to allow literal sequences of\n    /// key-value pairs to be merged into a map.\n    fn merge(self, into: &mut indexmap::IndexMap<K, V>) -> MergeResult {\n        for (key, value) in self {\n            match into.entry(key) {\n                indexmap::map::Entry::Vacant(e) => {\n                    e.insert(value);\n                }\n                indexmap::map::Entry::Occupied(mut e) => match value.merge(e.get_mut()) {\n                    Ok(()) => {}\n                    Err(message) => {\n                        return Err(message);\n                    }\n                },\n            }\n        }\n        Ok(())\n    }\n}\n\nimpl Merge for ZngurType {\n    /// Writes the partial union of `self` and `into` to the latter.\n    ///\n    /// PRECONDITION: `self.ty == into.ty`.\n    fn merge(self, into: &mut Self) -> MergeResult {\n        if self.ty != into.ty {\n            panic!(\n                \"Attempt to merge different types: {} and {}\",\n                self.ty, into.ty\n            );\n        }\n\n        if self.layout != into.layout {\n            return Err(MergeFailure::Conflict(\n                \"Duplicate layout policy found\".to_string(),\n            ));\n        }\n\n        // TODO: We need to improve the architecture around checking parsing, semantic, and other types of errors.\n        if self.cpp_ref.is_some() && into.layout != LayoutPolicy::ZERO_SIZED_TYPE {\n            return Err(MergeFailure::Conflict(\n                \"cpp_ref implies a zero sized stack allocated type\".to_string(),\n            ));\n        }\n\n        self.cpp_value.merge(&mut into.cpp_value)?;\n        self.cpp_ref.merge(&mut into.cpp_ref)?;\n\n        inplace_union(self.wellknown_traits, &mut into.wellknown_traits);\n        merge_by_identity(self.methods, &mut into.methods, |a, b| {\n            a.data.name == b.data.name\n        })?;\n        merge_by_identity(self.constructors, &mut into.constructors, |a, b| {\n            a.name == b.name\n        })?;\n        merge_by_identity(self.fields, &mut into.fields, |a, b| a.name == b.name)?;\n\n        Ok(())\n    }\n}\n\nimpl Merge for ZngurTrait {\n    /// Writes the partial union of `self` and `into` to the latter.\n    ///\n    /// PRECONDITION: `self.tr == into.tr`.\n    fn merge(self, into: &mut Self) -> MergeResult {\n        if self.tr != into.tr {\n            panic!(\n                \"Attempt to merge different traits: {} and {}\",\n                self.tr, into.tr\n            );\n        }\n\n        inplace_union(self.methods, &mut into.methods);\n\n        Ok(())\n    }\n}\n\nimpl Merge for CppValue {\n    /// Writes the partial union of `self` and `into` to the latter.\n    ///\n    /// There is no meaningful way to merge different CppValues, but we allow\n    /// merging the same CppValue from different sources.\n    fn merge(self, into: &mut Self) -> MergeResult {\n        if self != *into {\n            return Err(MergeFailure::Conflict(\"Cpp value mismatch\".to_string()));\n        }\n        Ok(())\n    }\n}\n\nimpl Merge for CppRef {\n    /// Writes the partial union of `self` and `into` to the latter.\n    ///\n    /// There is no meaningful way to merge different CppRefs, but we allow\n    /// merging the same CppRef from different sources.\n    fn merge(self, into: &mut Self) -> MergeResult {\n        if self != *into {\n            return Err(MergeFailure::Conflict(\"Cpp ref mismatch\".to_string()));\n        }\n        Ok(())\n    }\n}\n\nimpl Merge<ZngurSpec> for ZngurType {\n    /// Merges a type into a specification's type list.\n    fn merge(self, into: &mut ZngurSpec) -> MergeResult {\n        if let Some(existing) = into.types.iter_mut().find(|t| t.ty == self.ty) {\n            self.merge(existing)?;\n        } else {\n            into.types.push(self);\n        }\n        Ok(())\n    }\n}\n\nimpl Merge for ZngurMethodDetails {\n    fn merge(self, into: &mut Self) -> MergeResult {\n        if self != *into {\n            return Err(MergeFailure::Conflict(\"Method mismatch\".to_string()));\n        }\n        Ok(())\n    }\n}\n\nimpl Merge for ZngurConstructor {\n    fn merge(self, into: &mut Self) -> MergeResult {\n        if self != *into {\n            return Err(MergeFailure::Conflict(\"Constructor mismatch\".to_string()));\n        }\n        Ok(())\n    }\n}\n\nimpl Merge for ZngurField {\n    fn merge(self, into: &mut Self) -> MergeResult {\n        if self != *into {\n            return Err(MergeFailure::Conflict(\"Field mismatch\".to_string()));\n        }\n        Ok(())\n    }\n}\n\nimpl Merge<ZngurSpec> for ZngurTrait {\n    /// Merges a trait into a specification's trait list.\n    fn merge(self, into: &mut ZngurSpec) -> MergeResult {\n        [(self.tr.clone(), self)].merge(&mut into.traits)\n    }\n}\n\nimpl Merge<ZngurSpec> for ZngurFn {\n    /// Merges a function into a specification's function list.\n    fn merge(self, into: &mut ZngurSpec) -> MergeResult {\n        push_unique(self, &mut into.funcs);\n        Ok(())\n    }\n}\n\nimpl Merge<ZngurSpec> for ZngurExternCppFn {\n    /// Merges an extern C++ function into a specification's C++ function list.\n    fn merge(self, into: &mut ZngurSpec) -> MergeResult {\n        push_unique(self, &mut into.extern_cpp_funcs);\n        Ok(())\n    }\n}\n\nimpl Merge<ZngurSpec> for ZngurExternCppImpl {\n    /// Merges an extern C++ implementation into a specification's C++ implementation list.\n    fn merge(self, into: &mut ZngurSpec) -> MergeResult {\n        push_unique(self, &mut into.extern_cpp_impls);\n        Ok(())\n    }\n}\n\nimpl Merge<ZngurSpec> for AdditionalIncludes {\n    /// Merges #include directives into a specification's additional includes string.\n    fn merge(self, into: &mut ZngurSpec) -> MergeResult {\n        into.additional_includes.0 += self.0.as_str();\n        Ok(())\n    }\n}\n\nimpl Merge<ZngurSpec> for ConvertPanicToException {\n    /// Merges a CPtE flag into a specification's CPtE flag.\n    fn merge(self, into: &mut ZngurSpec) -> MergeResult {\n        // TODO: There's an architectural decision here.\n        // I'd like to encode the \"unimportability\" of CPTE here, rather than in the parser.\n        // But checking this requires knowledge of the parse depth, which seems inappropriate\n        // to pass through here.\n        into.convert_panic_to_exception.0 |= self.0;\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "zngur-generator/Cargo.toml",
    "content": "[package]\nname = \"zngur-generator\"\ndescription = \"Generates Rust and C++ glue codes from the zng file\"\nreadme = \"../README.md\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nitertools = \"0.11\"\naskama = \"0.12\"\nzngur-parser = { version = \"=0.9.0\", path = \"../zngur-parser\" }\nzngur-def = { version = \"=0.9.0\", path = \"../zngur-def\" }\nsha2 = \"0.10.9\"\nhex = \"0.4.3\"\nindexmap = \"2.13.0\"\n"
  },
  {
    "path": "zngur-generator/src/cpp.rs",
    "content": "use std::{\n    fmt::{Display, Write},\n    iter,\n};\n\nuse indexmap::IndexMap;\nuse itertools::Itertools;\nuse zngur_def::{CppRef, CppValue, RustTrait, ZngurFieldData, ZngurMethodReceiver};\n\nuse crate::{\n    ZngurWellknownTraitData,\n    template::{CppHeaderTemplate, CppSourceTemplate},\n};\nuse askama::Template;\n\n#[derive(Debug)]\npub struct CppPath(pub Vec<String>);\n\nimpl CppPath {\n    fn namespace(&self) -> &[String] {\n        self.0.split_last().unwrap().1\n    }\n\n    pub(crate) fn open_namespace(&self) -> String {\n        self.namespace()\n            .iter()\n            .enumerate()\n            .map(|(i, x)| format!(\"{:indent$}namespace {} {{\", \"\", x, indent = i * 4))\n            .join(\"\\n\")\n    }\n\n    pub(crate) fn close_namespace(&self) -> String {\n        self.namespace()\n            .iter()\n            .enumerate()\n            .map(|(i, x)| format!(\"{:indent$}}} // namespace {}\", \"\", x, indent = i * 4))\n            .join(\"\\n\")\n    }\n\n    pub(crate) fn name(&self) -> &str {\n        match self.0.split_last().unwrap().0.as_str() {\n            // Unit is a valid type alias for Tuple<> except when defining the constructors\n            \"Unit\" => \"Tuple\",\n            s => s,\n        }\n    }\n\n    fn need_header(&self) -> bool {\n        if self.0.len() == 1 && self.0[0].ends_with(\"_t\") {\n            return false;\n        }\n        // Top level namespace and type...\n        if self.0.len() == 2 {\n            let ty = &self.0[1];\n            return ty != \"Unit\" && ty != \"Ref\" && ty != \"RefMut\";\n        }\n        true\n    }\n\n    pub(crate) fn from_rust_path(path: &[String], ns: &str, crate_name: &str) -> CppPath {\n        CppPath(\n            iter::once(ns)\n                .chain(\n                    path.iter()\n                        .map(|x| if x == \"crate\" { crate_name } else { x.as_str() }),\n                )\n                .map(cpp_handle_keyword)\n                .map(|x| x.to_owned())\n                .collect(),\n        )\n    }\n}\n\nimpl<const N: usize> From<[&str; N]> for CppPath {\n    fn from(value: [&str; N]) -> Self {\n        CppPath(value.iter().map(|x| x.to_string()).collect())\n    }\n}\n\nimpl From<&str> for CppPath {\n    fn from(value: &str) -> Self {\n        let value = value.trim();\n        CppPath(value.split(\"::\").map(|x| x.to_owned()).collect())\n    }\n}\n\nimpl Display for CppPath {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"::{}\", self.0.iter().join(\"::\"))\n    }\n}\n\n#[derive(Debug)]\npub struct CppType {\n    pub path: CppPath,\n    pub generic_args: Vec<CppType>,\n}\n\nimpl CppType {\n    pub fn into_ref(self) -> CppType {\n        CppType {\n            path: CppPath::from(&*format!(\"{}::Ref\", self.top_level_ns())),\n            generic_args: vec![self],\n        }\n    }\n\n    fn top_level_ns(&self) -> &String {\n        &self.path.namespace()[0]\n    }\n\n    pub(crate) fn specialization_decl(&self) -> String {\n        let name = self.path.name();\n        // Tuple<> is a little special because it is a template even though self.generic_args is empty\n        if self.generic_args.is_empty() && name != \"Tuple\" {\n            format!(\"struct {}\", name)\n        } else {\n            format!(\n                \"template<> struct {}< {} >\",\n                name,\n                self.generic_args.iter().join(\", \")\n            )\n        }\n    }\n\n    fn header_helper(&self, state: &mut impl Write) -> std::fmt::Result {\n        // Note: probably need to keep this out of the template because it's recursive.\n        for x in &self.generic_args {\n            x.header_helper(state)?;\n        }\n\n        if !self.path.need_header() {\n            return Ok(());\n        }\n\n        for p in self.path.namespace() {\n            writeln!(state, \"namespace {} {{\", p)?;\n        }\n\n        if !self.generic_args.is_empty() {\n            writeln!(state, \"template<typename ...T>\")?;\n        }\n\n        writeln!(state, \"struct {};\", self.path.name())?;\n\n        for _ in self.path.namespace() {\n            writeln!(state, \"}}\")?;\n        }\n\n        Ok(())\n    }\n\n    pub(crate) fn header(&self) -> String {\n        let mut state = String::new();\n\n        self.header_helper(&mut state).unwrap();\n\n        state\n    }\n}\n\nimpl Display for CppType {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}\", self.path)?;\n        if !self.generic_args.is_empty() {\n            write!(f, \"< {} >\", self.generic_args.iter().join(\", \"))?;\n        }\n        Ok(())\n    }\n}\n\nfn split_string(input: &str) -> impl Iterator<Item = String> {\n    let mut parts = Vec::new();\n    let mut current_part = String::new();\n    let mut parentheses_count = 0;\n\n    for c in input.chars() {\n        match c {\n            ',' if parentheses_count == 0 => {\n                parts.push(current_part.clone());\n                current_part.clear();\n            }\n            '<' => {\n                parentheses_count += 1;\n                current_part.push(c);\n            }\n            '>' => {\n                parentheses_count -= 1;\n                current_part.push(c);\n            }\n            _ => {\n                current_part.push(c);\n            }\n        }\n    }\n\n    if !current_part.is_empty() {\n        parts.push(current_part);\n    }\n\n    parts.into_iter()\n}\n\nimpl From<&str> for CppType {\n    fn from(value: &str) -> Self {\n        let value = value.trim();\n        match value.split_once('<') {\n            None => CppType {\n                path: CppPath::from(value),\n                generic_args: vec![],\n            },\n            Some((path, generics)) => {\n                let generics = generics.strip_suffix('>').unwrap();\n                CppType {\n                    path: CppPath::from(path),\n                    generic_args: split_string(generics).map(|x| CppType::from(&*x)).collect(),\n                }\n            }\n        }\n    }\n}\n\n// pub(crate) just for migration\npub(crate) struct State {\n    pub(crate) text: String,\n    pub(crate) panic_to_exception: bool,\n}\n\nimpl State {\n    fn remove_no_except_in_panic(&mut self) {\n        if self.panic_to_exception {\n            self.text = self.text.replace(\" noexcept \", \" \");\n        }\n    }\n}\n\nimpl Write for State {\n    fn write_str(&mut self, s: &str) -> std::fmt::Result {\n        self.text += s;\n        Ok(())\n    }\n}\n\n#[derive(Debug)]\npub struct CppTraitMethod {\n    pub name: String,\n    pub rust_link_name: String,\n    pub inputs: Vec<CppType>,\n    pub output: CppType,\n}\n\nimpl CppTraitMethod {\n    pub fn render_inputs(&self, namespace: &str) -> String {\n        self.inputs\n            .iter()\n            .enumerate()\n            .map(|(n, ty)| {\n                format!(\n                    \"::{}::__zngur_internal_move_from_rust< {ty} >(i{n})\",\n                    namespace\n                )\n            })\n            .join(\", \")\n    }\n}\n\n#[derive(Debug)]\npub struct CppFnSig {\n    pub rust_link_name: String,\n    pub inputs: Vec<CppType>,\n    pub output: CppType,\n}\n\nimpl CppFnSig {\n    pub fn render_inputs(&self, namespace: &str) -> String {\n        self.inputs\n            .iter()\n            .enumerate()\n            .map(|(n, ty)| {\n                format!(\n                    \"::{}::__zngur_internal_move_from_rust< {ty} >(i{n})\",\n                    namespace\n                )\n            })\n            .join(\", \")\n    }\n}\n\npub struct CppFnDefinition {\n    pub name: CppPath,\n    pub sig: CppFnSig,\n}\n\npub struct CppExportedFnDefinition {\n    pub name: String,\n    pub sig: CppFnSig,\n}\n\npub struct CppExportedImplDefinition {\n    pub tr: Option<CppType>,\n    pub ty: CppType,\n    pub methods: Vec<(String, CppFnSig)>,\n}\n\nimpl CppExportedImplDefinition {\n    pub fn render_tr(&self, namespace: &str) -> String {\n        match &self.tr {\n            Some(x) => format!(\"{x}\"),\n            None => format!(\"::{}::Inherent\", namespace),\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct CppMethod {\n    pub name: String,\n    pub kind: ZngurMethodReceiver,\n    pub sig: CppFnSig,\n}\n\nimpl CppMethod {\n    pub fn is_valid_field_method(&self, field_kind: &str) -> bool {\n        if let zngur_def::ZngurMethodReceiver::Ref(m) = &self.kind {\n            !(*m == zngur_def::Mutability::Mut && field_kind == \"FieldRef\")\n        } else {\n            false\n        }\n    }\n\n    pub fn is_ref_not_mut(&self) -> bool {\n        matches!(\n            self.kind,\n            zngur_def::ZngurMethodReceiver::Ref(zngur_def::Mutability::Not)\n        )\n    }\n\n    pub fn fn_name(&self, type_name: &str) -> String {\n        format!(\"{}::{}\", type_name, self.name)\n    }\n\n    pub fn render_sig_inputs_skip_one(&self) -> String {\n        use itertools::Itertools;\n        self.sig\n            .inputs\n            .iter()\n            .skip(1)\n            .enumerate()\n            .map(|(n, ty)| format!(\"{ty} i{n}\"))\n            .join(\", \")\n    }\n}\n\n#[derive(Debug)]\npub enum CppTraitDefinition {\n    Fn {\n        sig: CppFnSig,\n    },\n    Normal {\n        as_ty: CppType,\n        methods: Vec<CppTraitMethod>,\n        link_name: String,\n        link_name_ref: String,\n    },\n}\n\nimpl CppTraitDefinition {\n    pub fn is_normal(&self) -> bool {\n        matches!(self, CppTraitDefinition::Normal { .. })\n    }\n\n    pub fn as_normal(&self) -> Option<(&CppType, &[CppTraitMethod], &str, &str)> {\n        if let CppTraitDefinition::Normal {\n            as_ty,\n            methods,\n            link_name,\n            link_name_ref,\n        } = self\n        {\n            Some((as_ty, methods, link_name, link_name_ref))\n        } else {\n            None\n        }\n    }\n\n    pub fn as_fn(&self) -> Option<&CppFnSig> {\n        if let CppTraitDefinition::Fn { sig } = self {\n            Some(sig)\n        } else {\n            None\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum CppLayoutPolicy {\n    StackAllocated {\n        size: usize,\n        align: usize,\n    },\n    HeapAllocated {\n        size_fn: String,\n        alloc_fn: String,\n        free_fn: String,\n    },\n    OnlyByRef,\n}\n\nimpl CppLayoutPolicy {\n    pub fn is_only_by_ref(&self) -> bool {\n        matches!(self, CppLayoutPolicy::OnlyByRef)\n    }\n\n    pub fn is_stack_allocated(&self) -> bool {\n        matches!(self, CppLayoutPolicy::StackAllocated { .. })\n    }\n\n    pub fn stack_size(&self) -> usize {\n        if let CppLayoutPolicy::StackAllocated { size, .. } = self {\n            *size\n        } else {\n            0\n        }\n    }\n\n    pub fn stack_align(&self) -> usize {\n        if let CppLayoutPolicy::StackAllocated { align, .. } = self {\n            *align\n        } else {\n            1\n        }\n    }\n\n    pub fn alloc_heap(&self) -> String {\n        if let CppLayoutPolicy::HeapAllocated { alloc_fn, .. } = self {\n            format!(\"__zngur_data = {}();\", alloc_fn)\n        } else {\n            \"\".to_owned()\n        }\n    }\n\n    pub fn free_heap(&self) -> String {\n        if let CppLayoutPolicy::HeapAllocated { free_fn, .. } = self {\n            format!(\"{}(__zngur_data);\", free_fn)\n        } else {\n            \"\".to_owned()\n        }\n    }\n\n    pub fn copy_data(&self) -> String {\n        if let CppLayoutPolicy::HeapAllocated { size_fn, .. } = self {\n            format!(\n                \"memcpy(this->__zngur_data, other.__zngur_data, {}());\",\n                size_fn\n            )\n        } else {\n            \"this->__zngur_data = other.__zngur_data;\".to_owned()\n        }\n    }\n\n    pub fn size_fn(&self) -> String {\n        if let CppLayoutPolicy::HeapAllocated { size_fn, .. } = self {\n            size_fn.clone()\n        } else {\n            \"\".to_owned()\n        }\n    }\n\n    pub fn alloc_fn(&self) -> String {\n        if let CppLayoutPolicy::HeapAllocated { alloc_fn, .. } = self {\n            alloc_fn.clone()\n        } else {\n            \"\".to_owned()\n        }\n    }\n\n    pub fn free_fn(&self) -> String {\n        if let CppLayoutPolicy::HeapAllocated { free_fn, .. } = self {\n            free_fn.clone()\n        } else {\n            \"\".to_owned()\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct CppTypeDefinition {\n    pub ty: CppType,\n    pub layout: CppLayoutPolicy,\n    pub methods: Vec<CppMethod>,\n    pub constructors: Vec<CppFnSig>,\n    pub fields: Vec<ZngurFieldData>,\n    pub from_trait: Option<RustTrait>,\n    pub from_trait_ref: Option<RustTrait>,\n    pub wellknown_traits: Vec<ZngurWellknownTraitData>,\n    pub cpp_value: Option<CppValue>,\n    pub cpp_ref: Option<CppRef>,\n}\n\nimpl CppTypeDefinition {\n    pub fn has_unsized(&self) -> bool {\n        self.wellknown_traits\n            .iter()\n            .any(|t| matches!(t, ZngurWellknownTraitData::Unsized))\n    }\n\n    pub fn has_copy(&self) -> bool {\n        self.wellknown_traits\n            .iter()\n            .any(|t| matches!(t, ZngurWellknownTraitData::Copy))\n    }\n\n    pub fn drop_in_place(&self) -> String {\n        self.wellknown_traits\n            .iter()\n            .find_map(|t| {\n                if let ZngurWellknownTraitData::Drop { drop_in_place } = t {\n                    Some(drop_in_place.clone())\n                } else {\n                    None\n                }\n            })\n            .unwrap_or_default()\n    }\n\n    pub fn render_make_box(&self, name: &str, namespace: &str, crate_name: &str) -> String {\n        use crate::rust::IntoCpp;\n        use itertools::Itertools;\n        match &self.from_trait {\n            Some(RustTrait::Fn { inputs, output, .. }) => {\n                let out_ty = output.into_cpp(namespace, crate_name);\n                let in_tys = inputs\n                    .iter()\n                    .map(|x| x.into_cpp(namespace, crate_name))\n                    .join(\", \");\n                format!(\n                    \"static inline {} make_box(::std::function<{} ({})> f);\",\n                    name, out_ty, in_tys\n                )\n            }\n            Some(RustTrait::Normal(_)) => {\n                format!(\n                    \"template<typename T, typename... Args>\\nstatic inline {} make_box(Args&&... args);\",\n                    name\n                )\n            }\n            None => \"\".to_owned(),\n        }\n    }\n\n    pub fn render_make_box_ref(&self, name: &str, namespace: &str, crate_name: &str) -> String {\n        use crate::rust::IntoCpp;\n        use itertools::Itertools;\n        match &self.from_trait_ref {\n            Some(RustTrait::Fn { inputs, output, .. }) => {\n                let out_ty = output.into_cpp(namespace, crate_name);\n                let in_tys = inputs\n                    .iter()\n                    .map(|x| x.into_cpp(namespace, crate_name))\n                    .join(\", \");\n                format!(\n                    \"inline {}(::std::function<{} ({})> f);\",\n                    name, out_ty, in_tys\n                )\n            }\n            Some(tr @ RustTrait::Normal(_)) => {\n                format!(\n                    \"inline RefMut({}& arg);\",\n                    tr.into_cpp(namespace, crate_name)\n                )\n            }\n            None => \"\".to_owned(),\n        }\n    }\n\n    pub fn render_make_box_ref_only(\n        &self,\n        name: &str,\n        namespace: &str,\n        crate_name: &str,\n    ) -> String {\n        use crate::rust::IntoCpp;\n        use itertools::Itertools;\n        match &self.from_trait_ref {\n            Some(RustTrait::Fn { inputs, output, .. }) => {\n                let out_ty = output.into_cpp(namespace, crate_name);\n                let in_tys = inputs\n                    .iter()\n                    .map(|x| x.into_cpp(namespace, crate_name))\n                    .join(\", \");\n                format!(\n                    \"inline {}(::std::function<{} ({})> f);\",\n                    name, out_ty, in_tys\n                )\n            }\n            Some(tr @ RustTrait::Normal(_)) => {\n                format!(\"inline Ref({}& arg);\", tr.into_cpp(namespace, crate_name))\n            }\n            None => \"\".to_owned(),\n        }\n    }\n}\n\nimpl Default for CppTypeDefinition {\n    fn default() -> Self {\n        Self {\n            ty: CppType::from(\"fill::me::you::forgot::it\"),\n            layout: CppLayoutPolicy::OnlyByRef,\n            methods: vec![],\n            constructors: vec![],\n            fields: vec![],\n            wellknown_traits: vec![],\n            from_trait: None,\n            from_trait_ref: None,\n            cpp_value: None,\n            cpp_ref: None,\n        }\n    }\n}\n\n#[derive(Default)]\npub struct CppFile {\n    pub header_file_name: String,\n    pub type_defs: Vec<CppTypeDefinition>,\n    pub trait_defs: IndexMap<RustTrait, CppTraitDefinition>,\n    pub fn_defs: Vec<CppFnDefinition>,\n    pub exported_fn_defs: Vec<CppExportedFnDefinition>,\n    pub exported_impls: Vec<CppExportedImplDefinition>,\n    pub additional_includes: String,\n    pub panic_to_exception: bool,\n    pub rust_cfg_defines: Vec<String>,\n    pub zng_header_in_place: bool,\n}\n\nimpl CppFile {\n    fn emit_h_file(\n        &self,\n        state: &mut State,\n        namespace: &str,\n        crate_name: &str,\n    ) -> std::fmt::Result {\n        let template = CppHeaderTemplate {\n            panic_to_exception: self.panic_to_exception,\n            additional_includes: &self.additional_includes,\n            fn_deps: &self.fn_defs,\n            type_defs: &self.type_defs,\n            trait_defs: &self.trait_defs,\n            exported_impls: &self.exported_impls,\n            exported_fn_defs: &self.exported_fn_defs,\n            rust_cfg_defines: &self.rust_cfg_defines,\n            zng_header_in_place: self.zng_header_in_place,\n            namespace,\n            crate_name,\n        };\n        state.text += normalize_whitespace(template.render().unwrap().as_str()).as_str();\n        Ok(())\n    }\n\n    fn emit_cpp_file(\n        &self,\n        state: &mut State,\n        is_really_needed: &mut bool,\n        namespace: &str,\n    ) -> std::fmt::Result {\n        let template = CppSourceTemplate {\n            header_file_name: &self.header_file_name,\n            trait_defs: &self.trait_defs,\n            exported_fn_defs: &self.exported_fn_defs,\n            exported_impls: &self.exported_impls,\n            cpp_namespace: namespace,\n        };\n        state.text += normalize_whitespace(template.render().unwrap().as_str()).as_str();\n\n        *is_really_needed = !self.trait_defs.is_empty()\n            || !self.exported_fn_defs.is_empty()\n            || !self.exported_impls.is_empty();\n\n        Ok(())\n    }\n\n    pub fn render(self, namespace: &str, crate_name: &str) -> (String, Option<String>) {\n        let mut h_file = State {\n            text: \"\".to_owned(),\n            panic_to_exception: self.panic_to_exception,\n        };\n        let mut cpp_file = State {\n            text: \"\".to_owned(),\n            panic_to_exception: self.panic_to_exception,\n        };\n        self.emit_h_file(&mut h_file, namespace, crate_name)\n            .unwrap();\n        let mut is_cpp_needed = false;\n        self.emit_cpp_file(&mut cpp_file, &mut is_cpp_needed, namespace)\n            .unwrap();\n        h_file.remove_no_except_in_panic();\n\n        (h_file.text, is_cpp_needed.then_some(cpp_file.text))\n    }\n}\n\npub fn cpp_handle_keyword(name: &str) -> &str {\n    match name {\n        \"new\" => \"new_\",\n        \"default\" => \"default_\",\n        x => x,\n    }\n}\n\npub fn cpp_handle_field_name(name: &str) -> String {\n    if name.parse::<u32>().is_ok() {\n        return format!(\"f{name}\");\n    }\n    cpp_handle_keyword(name).to_owned()\n}\n\ntrait CountCharMatchesExt {\n    fn count_start_matches(&self, pred: impl Fn(char) -> bool) -> usize;\n    fn count_matches(&self, pred: impl Fn(char) -> bool) -> usize;\n}\n\nimpl CountCharMatchesExt for str {\n    fn count_start_matches(&self, pred: impl Fn(char) -> bool) -> usize {\n        let mut count = 0;\n        for c in self.chars() {\n            if pred(c) {\n                count += 1;\n            } else {\n                break;\n            }\n        }\n        count\n    }\n    fn count_matches(&self, pred: impl Fn(char) -> bool) -> usize {\n        let mut count = 0;\n        for c in self.chars() {\n            if pred(c) {\n                count += 1;\n            }\n        }\n        count\n    }\n}\n\n/// Normalize newlines and indents in cpp source code\n///\n/// A relatively naive algorithm intended only to correct excessive indentation and condense\n/// unneeded newlines that result from the sailfish template rendering.\npub fn normalize_whitespace(cpp: &str) -> String {\n    enum LineType {\n        PreProc,\n        NamespaceOpen,\n        ExternOpen,\n        BlockOpen,\n        BlockClose,\n        Statement,\n        Unknown,\n        Empty,\n    }\n    struct FormatState {\n        indent: usize,\n        last_indent: usize,\n        last_line: LineType,\n    }\n\n    let mut state = FormatState {\n        indent: 0,\n        last_indent: 0,\n        last_line: LineType::Empty,\n    };\n    let lines = cpp.lines();\n    // builds vec of &str then `join`s them to reduce memory footprint and copies\n    let mut out: Vec<&str> = Vec::new();\n\n    fn count_open_pairs(line: &str, pairs: &[[char; 2]]) -> isize {\n        let mut count: isize = 0;\n        for [open, close] in pairs {\n            count += line.count_matches(|c| c == *open) as isize;\n            count -= line.count_matches(|c| c == *close) as isize;\n        }\n        count\n    }\n\n    fn trim_end_c_comments(line: &str) -> &str {\n        let mut j: usize = 0;\n        let mut prev = false;\n        for (index, c) in line.char_indices() {\n            let is_slash = c == '/';\n            if is_slash && prev {\n                // consecutive `//` means rest of line is a comment\n                break;\n            }\n            prev = is_slash;\n            j = index;\n        }\n        if j + 1 >= line.len() {\n            j = line.len()\n        }\n        // SAFETY: `line.char_indices` returns valid indices\n        unsafe { line.get_unchecked(0..j) }\n    }\n\n    fn line_type(line: &str) -> LineType {\n        if line.trim().is_empty() {\n            LineType::Empty\n        } else if line.trim_start().starts_with('#') {\n            LineType::PreProc\n        } else if line.trim_start().starts_with(\"namespace\") && line.ends_with('{') {\n            LineType::NamespaceOpen\n        } else if line.trim_start().starts_with(\"extern\") && line.ends_with('{') {\n            LineType::ExternOpen\n        } else if line.ends_with('{') && count_open_pairs(line, &[['{', '}']]) > 0 {\n            LineType::BlockOpen\n        } else if (line.ends_with('}') || line.ends_with(\"};\"))\n            && count_open_pairs(line, &[['{', '}']]) < 0\n        {\n            LineType::BlockClose\n        } else if line.ends_with(';') {\n            LineType::Statement\n        } else {\n            LineType::Unknown\n        }\n    }\n\n    let mut last_indent: usize = 0;\n    let mut last_line: &str = \"\";\n    let mut last_extra_indent: usize = 0;\n    let mut indents: Vec<usize> = Vec::new();\n    for line in lines {\n        let trimmed = trim_end_c_comments(line).trim_end();\n        let ty = line_type(trimmed);\n        let indent = line.count_start_matches(char::is_whitespace);\n        let mut emit_line = false;\n        // don't indent this line\n        let mut do_not_indent = false;\n        // extra indent levels for this line\n        let mut extra_indent = 0;\n        // subtracted from indent\n        let mut special_indent = 0;\n        // when opening a indent level, don't indent this line\n        let mut use_last_indent = false;\n        match ty {\n            LineType::PreProc => {\n                do_not_indent = true;\n                emit_line = true;\n            }\n            LineType::NamespaceOpen => {\n                indents.clear();\n                state.indent = 0;\n                state.last_indent = 0;\n                emit_line = true;\n            }\n            LineType::ExternOpen => {\n                indents.clear();\n                indents.push(4);\n                state.indent = 4;\n                state.last_indent = 0;\n                emit_line = true;\n                use_last_indent = true;\n            }\n            LineType::BlockOpen => {\n                emit_line = true;\n                indents.push(4);\n                state.indent += 4;\n                use_last_indent = true;\n            }\n            LineType::BlockClose => {\n                emit_line = true;\n                if let Some(n) = indents.pop() {\n                    state.indent = state.indent.saturating_sub(n);\n                }\n            }\n            LineType::Statement | LineType::Unknown => {\n                let open_pairs =\n                    count_open_pairs(last_line, &[['[', ']'], ['{', '}'], ['<', '>'], ['(', ')']]);\n                if trimmed.ends_with(\"public:\") || trimmed.ends_with(\"private:\") {\n                    special_indent = 2;\n                } else if indent == last_indent {\n                    extra_indent = last_extra_indent;\n                } else if !matches!(\n                    state.last_line,\n                    LineType::BlockOpen | LineType::NamespaceOpen | LineType::ExternOpen\n                ) && indent > last_indent\n                    && open_pairs > 0\n                {\n                    extra_indent += 4;\n                } else if extra_indent > 0\n                    && !matches!(\n                        state.last_line,\n                        LineType::BlockOpen | LineType::NamespaceOpen | LineType::ExternOpen\n                    )\n                    && open_pairs < 0\n                {\n                    extra_indent = extra_indent.saturating_sub(4);\n                }\n                emit_line = true;\n            }\n            LineType::Empty => match &state.last_line {\n                // preserve empty line if previous line held meaning\n                LineType::Statement | LineType::Unknown | LineType::BlockClose => {\n                    do_not_indent = false;\n                    if !last_line.ends_with([',', '[', '<', '(']) {\n                        emit_line = true\n                    }\n                }\n                // eliminate all other empty lines\n                _ => {}\n            },\n        }\n\n        state.last_line = ty;\n        last_line = trimmed;\n        last_indent = indent;\n        last_extra_indent = extra_indent;\n        if emit_line {\n            // emit indent\n            // extra_indent is for *this* line and forward\n            // special_indent is for *this* line only\n            if !do_not_indent\n                && (((use_last_indent && state.last_indent > 0)\n                    || (!use_last_indent && state.indent > 0))\n                    || extra_indent > 0\n                    || special_indent > 0)\n            {\n                out.extend(\n                    iter::once(\" \").cycle().take(\n                        (if use_last_indent {\n                            state.last_indent\n                        } else {\n                            state.indent\n                        } + extra_indent)\n                            .saturating_sub(special_indent),\n                    ),\n                );\n            }\n            // emit line without it's source indent\n            out.push(line.trim());\n            out.push(\"\\n\");\n        }\n        state.last_indent = state.indent;\n    }\n    out.join(\"\")\n}\n"
  },
  {
    "path": "zngur-generator/src/lib.rs",
    "content": "use cpp::CppExportedFnDefinition;\nuse cpp::CppExportedImplDefinition;\nuse cpp::CppFile;\nuse cpp::CppFnDefinition;\nuse cpp::CppFnSig;\nuse cpp::CppMethod;\nuse cpp::CppPath;\nuse cpp::CppTraitDefinition;\nuse cpp::CppType;\nuse cpp::CppTypeDefinition;\nuse cpp::cpp_handle_keyword;\nuse indexmap::map::Entry;\nuse itertools::Itertools;\nuse rust::IntoCpp;\n\npub mod cpp;\nmod rust;\nmod template;\n\nuse askama::Template;\npub use rust::RustFile;\npub use zngur_parser::{ParseResult, ParsedZngFile, cfg};\n\npub use zngur_def::*;\n\nuse crate::template::ZngHeaderTemplate;\n\npub struct ZngurGenerator(pub ZngurSpec, pub String);\n\nimpl ZngurGenerator {\n    pub fn build_from_zng(zng: ZngurSpec, crate_name: String) -> Self {\n        ZngurGenerator(zng, crate_name)\n    }\n\n    pub fn render(self, zng_header_in_place: bool) -> (String, String, Option<String>) {\n        let zng = self.0;\n        let mut cpp_file = CppFile::default();\n        cpp_file.header_file_name = zng.cpp_include_header_name.clone();\n        cpp_file.additional_includes = zng.additional_includes.0;\n        cpp_file.zng_header_in_place = zng_header_in_place;\n        for module in &zng.imported_modules {\n            cpp_file\n                .additional_includes\n                .push_str(&format!(\"\\n#include \\\"{}.h\\\"\", module.path.display()));\n        }\n        let default_ns = zng.cpp_namespace.as_deref().unwrap_or(\"rust\");\n        let sanitized_crate_name = self.1.replace('-', \"_\");\n        let mut rust_file = RustFile::new(&zng.mangling_base);\n        rust_file.panic_to_exception = zng.convert_panic_to_exception.0;\n        cpp_file.trait_defs = zng\n            .traits\n            .iter()\n            .map(|(key, value)| {\n                (\n                    key.clone(),\n                    rust_file.add_builder_for_dyn_trait(value, default_ns, &sanitized_crate_name),\n                )\n            })\n            .collect();\n        cpp_file.panic_to_exception = zng.convert_panic_to_exception.0;\n        cpp_file\n            .rust_cfg_defines\n            .extend(zng.rust_cfg.iter().map(|(key, value)| {\n                format!(\n                    \"ZNGUR_CFG_{}{}\",\n                    key.to_uppercase(),\n                    value\n                        .as_ref()\n                        .and_then(|value| if value.trim().is_empty() {\n                            None\n                        } else {\n                            Some(format!(\n                                \"_{}\",\n                                value\n                                    .chars()\n                                    .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })\n                                    .collect::<String>()\n                                    .to_uppercase()\n                            ))\n                        })\n                        .unwrap_or_default()\n                )\n            }));\n        for ty_def in zng.types {\n            let ty = &ty_def.ty;\n            let is_copy = ty_def.wellknown_traits.contains(&ZngurWellknownTrait::Copy);\n            match ty_def.layout {\n                LayoutPolicy::StackAllocated { size, align } => {\n                    rust_file.add_static_size_assert(&ty, size);\n                    rust_file.add_static_align_assert(&ty, align);\n                }\n                LayoutPolicy::Conservative { size, align } => {\n                    rust_file.add_static_size_upper_bound_assert(&ty, size);\n                    rust_file.add_static_align_upper_bound_assert(&ty, align);\n                }\n                LayoutPolicy::HeapAllocated => (),\n                LayoutPolicy::OnlyByRef => (),\n            }\n            if is_copy {\n                rust_file.add_static_is_copy_assert(&ty);\n            }\n            let mut cpp_methods = vec![];\n            let mut constructors = vec![];\n            let mut fields = vec![];\n            let mut wellknown_traits = vec![];\n            for constructor in ty_def.constructors {\n                match constructor.name {\n                    Some(name) => {\n                        let rust_link_names = rust_file\n                            .add_constructor(&format!(\"{}::{}\", ty, name), &constructor.inputs);\n                        cpp_methods.push(CppMethod {\n                            name: cpp_handle_keyword(&name).to_owned(),\n                            kind: ZngurMethodReceiver::Static,\n                            sig: CppFnSig {\n                                rust_link_name: rust_link_names.constructor,\n                                inputs: constructor\n                                    .inputs\n                                    .iter()\n                                    .map(|x| x.1.into_cpp(default_ns, &sanitized_crate_name))\n                                    .collect(),\n                                output: ty.into_cpp(default_ns, &sanitized_crate_name),\n                            },\n                        });\n                        cpp_methods.push(CppMethod {\n                            name: format!(\"matches_{}\", name),\n                            kind: ZngurMethodReceiver::Ref(Mutability::Not),\n                            sig: CppFnSig {\n                                rust_link_name: rust_link_names.match_check,\n                                inputs: vec![\n                                    ty.into_cpp(default_ns, &sanitized_crate_name).into_ref(),\n                                ],\n                                output: CppType::from(\"uint8_t\"),\n                            },\n                        });\n                    }\n                    None => {\n                        let rust_link_name = rust_file\n                            .add_constructor(&format!(\"{}\", ty), &constructor.inputs)\n                            .constructor;\n                        constructors.push(CppFnSig {\n                            rust_link_name,\n                            inputs: constructor\n                                .inputs\n                                .iter()\n                                .map(|x| x.1.into_cpp(default_ns, &sanitized_crate_name))\n                                .collect(),\n                            output: ty.into_cpp(default_ns, &sanitized_crate_name),\n                        });\n                    }\n                }\n            }\n            for field in ty_def.fields {\n                let extern_mn = rust_file.add_field_assertions(&field, &ty_def.ty);\n                let field = ZngurFieldData {\n                    name: field.name,\n                    ty: field.ty,\n                    offset: match field.offset {\n                        Some(offset) => ZngurFieldDataOffset::Offset(offset),\n                        None => ZngurFieldDataOffset::Auto(\n                            extern_mn.expect(\"auto offset did not provide extern name\"),\n                        ),\n                    },\n                };\n                fields.push(field);\n            }\n            if let RustType::Tuple(fields) = &ty_def.ty {\n                if !fields.is_empty() {\n                    let rust_link_name = rust_file.add_tuple_constructor(&fields);\n                    constructors.push(CppFnSig {\n                        rust_link_name,\n                        inputs: fields\n                            .iter()\n                            .map(|x| x.into_cpp(default_ns, &sanitized_crate_name))\n                            .collect(),\n                        output: ty.into_cpp(default_ns, &sanitized_crate_name),\n                    });\n                }\n            }\n            let is_unsized = ty_def\n                .wellknown_traits\n                .contains(&ZngurWellknownTrait::Unsized);\n            for wellknown_trait in ty_def.wellknown_traits {\n                let data = rust_file.add_wellknown_trait(&ty, wellknown_trait, is_unsized);\n                wellknown_traits.push(data);\n            }\n            for method_details in ty_def.methods {\n                let ZngurMethodDetails {\n                    data: method,\n                    use_path,\n                    deref,\n                } = method_details;\n                let rusty_inputs = real_inputs_of_method(&method, &ty);\n\n                let sig = rust_file.add_function(\n                    &format!(\n                        \"<{}>::{}::<{}>\",\n                        deref.as_ref().map(|x| &x.0).unwrap_or(&ty),\n                        method.name,\n                        method.generics.iter().join(\", \"),\n                    ),\n                    &rusty_inputs,\n                    &method.output,\n                    use_path,\n                    deref.map(|x| x.1),\n                    default_ns,\n                    &sanitized_crate_name,\n                );\n                cpp_methods.push(CppMethod {\n                    name: cpp_handle_keyword(&method.name).to_owned(),\n                    kind: method.receiver,\n                    sig,\n                });\n            }\n            cpp_file.type_defs.push(CppTypeDefinition {\n                ty: ty.into_cpp(default_ns, &sanitized_crate_name),\n                layout: rust_file.add_layout_policy_shim(&ty, ty_def.layout),\n                constructors,\n                fields,\n                methods: cpp_methods,\n                wellknown_traits,\n                cpp_value: ty_def.cpp_value.map(|mut cpp_value| {\n                    cpp_value.0 = rust_file.add_cpp_value_bridge(&ty, &cpp_value.0);\n                    cpp_value\n                }),\n                cpp_ref: ty_def.cpp_ref,\n                from_trait: if let RustType::Boxed(b) = &ty {\n                    if let RustType::Dyn(tr, _) = b.as_ref() {\n                        if let RustTrait::Fn {\n                            name,\n                            inputs,\n                            output,\n                        } = tr\n                        {\n                            if let Entry::Vacant(e) = cpp_file.trait_defs.entry(tr.clone()) {\n                                let rust_link_name =\n                                    rust_file.add_builder_for_dyn_fn(name, inputs, output);\n                                e.insert(CppTraitDefinition::Fn {\n                                    sig: CppFnSig {\n                                        rust_link_name,\n                                        inputs: inputs\n                                            .iter()\n                                            .map(|x| x.into_cpp(default_ns, &sanitized_crate_name))\n                                            .collect(),\n                                        output: output.into_cpp(default_ns, &sanitized_crate_name),\n                                    },\n                                });\n                            }\n                        }\n                        Some(tr.clone())\n                    } else {\n                        None\n                    }\n                } else {\n                    None\n                },\n                from_trait_ref: if let RustType::Dyn(tr, _) = &ty {\n                    Some(tr.clone())\n                } else {\n                    None\n                },\n            });\n        }\n        for func in zng.funcs {\n            let sig = rust_file.add_function(\n                &func.path.to_string(),\n                &func.inputs,\n                &func.output,\n                None,\n                None,\n                default_ns,\n                &sanitized_crate_name,\n            );\n            cpp_file.fn_defs.push(CppFnDefinition {\n                name: CppPath::from_rust_path(&func.path.path, default_ns, &sanitized_crate_name),\n                sig,\n            });\n        }\n        for func in zng.extern_cpp_funcs {\n            let rust_link_name =\n                rust_file.add_extern_cpp_function(&func.name, &func.inputs, &func.output);\n            cpp_file.exported_fn_defs.push(CppExportedFnDefinition {\n                name: func.name.clone(),\n                sig: CppFnSig {\n                    rust_link_name,\n                    inputs: func\n                        .inputs\n                        .into_iter()\n                        .map(|x| x.into_cpp(default_ns, &sanitized_crate_name))\n                        .collect(),\n                    output: func.output.into_cpp(default_ns, &sanitized_crate_name),\n                },\n            });\n        }\n        for impl_block in zng.extern_cpp_impls {\n            let rust_link_names = rust_file.add_extern_cpp_impl(\n                &impl_block.ty,\n                impl_block.tr.as_ref(),\n                &impl_block.methods,\n            );\n            cpp_file.exported_impls.push(CppExportedImplDefinition {\n                tr: impl_block\n                    .tr\n                    .map(|x| x.into_cpp(default_ns, &sanitized_crate_name)),\n                ty: impl_block.ty.into_cpp(default_ns, &sanitized_crate_name),\n                methods: impl_block\n                    .methods\n                    .iter()\n                    .zip(&rust_link_names)\n                    .map(|(method, link_name)| {\n                        let inputs = real_inputs_of_method(method, &impl_block.ty);\n                        let inputs = inputs\n                            .iter()\n                            .map(|ty| ty.into_cpp(default_ns, &sanitized_crate_name))\n                            .collect();\n                        (\n                            cpp_handle_keyword(&method.name).to_owned(),\n                            CppFnSig {\n                                rust_link_name: link_name.clone(),\n                                inputs,\n                                output: method.output.into_cpp(default_ns, &sanitized_crate_name),\n                            },\n                        )\n                    })\n                    .collect(),\n            });\n        }\n        let (h, cpp) = cpp_file.render(default_ns, &sanitized_crate_name);\n        (rust_file.text, h, cpp)\n    }\n}\n\npub struct ZngHeaderGenerator {\n    pub panic_to_exception: bool,\n    pub cpp_namespace: String,\n}\n\nimpl ZngHeaderGenerator {\n    /// Renders the zngur.h header\n    pub fn render(&self) -> String {\n        let zng_h = ZngHeaderTemplate {\n            panic_to_exception: self.panic_to_exception,\n            cpp_namespace: self.cpp_namespace.clone(),\n        };\n        zng_h.render().unwrap()\n    }\n}\n\nfn real_inputs_of_method(method: &ZngurMethod, ty: &RustType) -> Vec<RustType> {\n    let receiver_type = match method.receiver {\n        ZngurMethodReceiver::Static => None,\n        ZngurMethodReceiver::Ref(m) => Some(RustType::Ref(m, Box::new(ty.clone()))),\n        ZngurMethodReceiver::Move => Some(ty.clone()),\n    };\n    let rusty_inputs = receiver_type\n        .into_iter()\n        .chain(method.inputs.clone())\n        .collect::<Vec<_>>();\n    rusty_inputs\n}\n"
  },
  {
    "path": "zngur-generator/src/rust.rs",
    "content": "use std::fmt::Write;\n\nuse itertools::Itertools;\nuse sha2::{Digest, Sha256};\n\nuse crate::{\n    ZngurTrait, ZngurWellknownTrait, ZngurWellknownTraitData,\n    cpp::{CppFnSig, CppLayoutPolicy, CppPath, CppTraitDefinition, CppTraitMethod, CppType},\n};\n\nuse zngur_def::*;\n\npub trait IntoCpp {\n    fn into_cpp(&self, namespace: &str, crate_name: &str) -> CppType;\n}\n\nimpl IntoCpp for RustPathAndGenerics {\n    fn into_cpp(&self, namespace: &str, crate_name: &str) -> CppType {\n        let RustPathAndGenerics {\n            path,\n            generics,\n            named_generics,\n        } = self;\n        let named_generics = named_generics.iter().sorted_by_key(|x| &x.0).map(|x| &x.1);\n        CppType {\n            path: CppPath::from_rust_path(path, namespace, crate_name),\n            generic_args: generics\n                .iter()\n                .chain(named_generics)\n                .map(|x| x.into_cpp(namespace, crate_name))\n                .collect(),\n        }\n    }\n}\n\nimpl IntoCpp for RustTrait {\n    fn into_cpp(&self, namespace: &str, crate_name: &str) -> CppType {\n        match self {\n            RustTrait::Normal(pg) => pg.into_cpp(namespace, crate_name),\n            RustTrait::Fn {\n                name,\n                inputs,\n                output,\n            } => CppType {\n                path: CppPath::from(&*format!(\"{namespace}::{name}\")),\n                generic_args: inputs\n                    .iter()\n                    .chain(Some(&**output))\n                    .map(|x| x.into_cpp(namespace, crate_name))\n                    .collect(),\n            },\n        }\n    }\n}\n\nimpl IntoCpp for RustType {\n    fn into_cpp(&self, namespace: &str, crate_name: &str) -> CppType {\n        fn for_builtin(this: &RustType, namespace: &str, crate_name: &str) -> Option<CppType> {\n            match this {\n                RustType::Primitive(s) => match s {\n                    PrimitiveRustType::Uint(s) => Some(CppType::from(&*format!(\"uint{s}_t\"))),\n                    PrimitiveRustType::Int(s) => Some(CppType::from(&*format!(\"int{s}_t\"))),\n                    PrimitiveRustType::Float(32) => Some(CppType::from(\"float_t\")),\n                    PrimitiveRustType::Float(64) => Some(CppType::from(\"double_t\")),\n                    PrimitiveRustType::Float(_) => unreachable!(),\n                    PrimitiveRustType::Usize => Some(CppType::from(\"size_t\")),\n                    PrimitiveRustType::Bool | PrimitiveRustType::Str | PrimitiveRustType::Char => {\n                        None\n                    }\n                    PrimitiveRustType::ZngurCppOpaqueOwnedObject => Some(CppType::from(&*format!(\n                        \"{namespace}::ZngurCppOpaqueOwnedObject\"\n                    ))),\n                },\n                RustType::Raw(Mutability::Mut, t) => Some(CppType::from(&*format!(\n                    \"{}*\",\n                    for_builtin(t, namespace, crate_name)?\n                        .to_string()\n                        .strip_prefix(\"::\")?\n                ))),\n                RustType::Raw(Mutability::Not, t) => Some(CppType::from(&*format!(\n                    \"{} const*\",\n                    for_builtin(t, namespace, crate_name)?\n                        .to_string()\n                        .strip_prefix(\"::\")?\n                ))),\n                _ => None,\n            }\n        }\n        if let Some(builtin) = for_builtin(self, namespace, crate_name) {\n            return builtin;\n        }\n        match self {\n            RustType::Primitive(s) => match s {\n                PrimitiveRustType::Bool => CppType::from(&*format!(\"{namespace}::Bool\")),\n                PrimitiveRustType::Str => CppType::from(&*format!(\"{namespace}::Str\")),\n                PrimitiveRustType::Char => CppType::from(&*format!(\"{namespace}::Char\")),\n                _ => unreachable!(),\n            },\n            RustType::Boxed(t) => CppType {\n                path: CppPath::from(&*format!(\"{namespace}::Box\")),\n                generic_args: vec![t.into_cpp(namespace, crate_name)],\n            },\n            RustType::Ref(m, t) => CppType {\n                path: match m {\n                    Mutability::Mut => CppPath::from(&*format!(\"{}::RefMut\", namespace)),\n                    Mutability::Not => CppPath::from(&*format!(\"{}::Ref\", namespace)),\n                },\n                generic_args: vec![t.into_cpp(namespace, crate_name)],\n            },\n            RustType::Slice(s) => CppType {\n                path: CppPath::from(&*format!(\"{namespace}::Slice\")),\n                generic_args: vec![s.into_cpp(namespace, crate_name)],\n            },\n            RustType::Raw(m, t) => CppType {\n                path: match m {\n                    Mutability::Mut => CppPath::from(&*format!(\"{namespace}::RawMut\")),\n                    Mutability::Not => CppPath::from(&*format!(\"{namespace}::Raw\")),\n                },\n                generic_args: vec![t.into_cpp(namespace, crate_name)],\n            },\n            RustType::Adt(pg) => pg.into_cpp(namespace, crate_name),\n            RustType::Tuple(v) => {\n                if v.is_empty() {\n                    return CppType::from(&*format!(\"{namespace}::Unit\"));\n                }\n                CppType {\n                    path: CppPath::from(&*format!(\"{namespace}::Tuple\")),\n                    generic_args: v\n                        .into_iter()\n                        .map(|x| x.into_cpp(namespace, crate_name))\n                        .collect(),\n                }\n            }\n            RustType::Dyn(tr, marker_bounds) => {\n                let tr_as_cpp_type = tr.into_cpp(namespace, crate_name);\n                CppType {\n                    path: CppPath::from(&*format!(\"{namespace}::Dyn\")),\n                    generic_args: [tr_as_cpp_type]\n                        .into_iter()\n                        .chain(\n                            marker_bounds\n                                .iter()\n                                .map(|x| CppType::from(&*format!(\"{namespace}::{x}\"))),\n                        )\n                        .collect(),\n                }\n            }\n            RustType::Impl(_, _) => panic!(\"impl Trait is invalid in C++\"),\n        }\n    }\n}\n\npub struct RustFile {\n    pub text: String,\n    pub panic_to_exception: bool,\n    pub mangling_base: String,\n}\n\nimpl RustFile {\n    pub fn new(mangling_base: &str) -> Self {\n        Self {\n            text: r#\"\n#[allow(dead_code)]\nmod zngur_types {\n    pub struct ZngurCppOpaqueBorrowedObject(());\n\n    #[repr(C)]\n    pub struct ZngurCppOpaqueOwnedObject {\n        data: *mut u8,\n        destructor: extern \"C\" fn(*mut u8),\n    }\n\n    impl ZngurCppOpaqueOwnedObject {\n        pub unsafe fn new(\n            data: *mut u8,\n            destructor: extern \"C\" fn(*mut u8),            \n        ) -> Self {\n            Self { data, destructor }\n        }\n\n        pub fn ptr(&self) -> *mut u8 {\n            self.data\n        }\n    }\n\n    impl Drop for ZngurCppOpaqueOwnedObject {\n        fn drop(&mut self) {\n            (self.destructor)(self.data)\n        }\n    }\n}\n\n#[allow(unused_imports)]\npub use zngur_types::ZngurCppOpaqueOwnedObject;\n#[allow(unused_imports)]\npub use zngur_types::ZngurCppOpaqueBorrowedObject;\n\nmacro_rules! __zngur_str_as_array {\n    ($s:expr) => {{\n        const VAL: &str = $s;\n        // SAFETY: `VAL` has at least size `N` because it's const len is right there.\n        const ARR: [u8; VAL.len()] = unsafe { *(VAL.as_bytes() as *const [u8]).cast() };\n        ARR\n    }};\n}\n\npub const fn __zngur_usize_num_digits(val: usize) -> usize {\n    // docs currently say 64bit only but that's a bug\n    if val == 0 { 1 } else { val.ilog10() as usize + 1 }\n}\n\npub const fn __zngur_usize_digit(val: usize, digit: usize) -> u8 {\n    let mut temp = val;\n    let mut i = 0;\n    while i < digit {\n        temp /= 10;\n        i += 1;\n    }\n    if temp == 0 && val > 0 {\n        ::core::panic!(\"no such digit!\")\n    } else {\n        (temp % 10) as u8\n    }\n}\n\npub const fn __zngur_digit_to_ascii(digit: u8) -> u8 {\n    ::core::assert!(digit <= 9);\n    digit + b'0'\n}\n\npub const fn __zngur_usize_to_digit_array<const N: usize>(val: usize) -> [u8; N] {\n    let mut arr: [u8; N] = [0; N];\n    let mut i = 0;\n    while i < N {\n        arr[N - 1 - i] = __zngur_digit_to_ascii(__zngur_usize_digit(val, i));\n        i += 1;\n    }\n    arr\n}\n\nmacro_rules! __zngur_usize_to_str {\n    ($x:expr) => {{\n        const VAL: usize = $x;\n        const ARR: [u8; __zngur_usize_num_digits(VAL)] = __zngur_usize_to_digit_array(VAL);\n        // SAFETY: `ARR` is an ascii byte array which is utf8 compliant\n        const STR: &str = unsafe { str::from_utf8_unchecked(&ARR) };\n        STR\n    }};\n}\n\npub const fn __zngur_const_str_array_concat<const T: usize, const N: usize, const M: usize>(\n    x: [u8; N],\n    y: [u8; M],\n) -> [u8; T] {\n    ::core::assert!(N + M == T);\n    let mut arr: [u8; T] = [0; T];\n    let mut i = 0;\n    while i < N {\n        arr[i] = x[i];\n        i += 1;\n    }\n    while i - N < M {\n        arr[i] = y[i - N];\n        i += 1;\n    }\n    arr\n}\n\nmacro_rules! __zngur_const_str_concat {\n\n    ( $x:expr, $y:expr $(,)? ) => {{\n        const X: &str = $x;\n        const Y: &str = $y;\n        const LEN: usize = X.len() + Y.len();\n        const ARR: [u8; LEN] = __zngur_const_str_array_concat::<LEN, {X.len()}, {Y.len()}>(\n            __zngur_str_as_array!(X),\n            __zngur_str_as_array!(Y),\n        );\n        // SAFETY: `ARR` is an concatenated utf8 byte array built from validated `const str&`\n        const STR: &str =  unsafe { str::from_utf8_unchecked(&ARR) };\n        STR\n    }};\n    ( $x:expr, $y:expr, $($rest:expr),+ $(,)? ) => {\n        __zngur_const_str_concat!($x, __zngur_const_str_concat!( $y, $($rest),+ ))\n    };\n\n}\n\nmacro_rules! __zngur_assert_is_copy {\n    ($x:ty $(,)?) => {\n        const _: () = {\n            const fn static_assert_is_copy<T: Copy>() {}\n            static_assert_is_copy::<$x>();\n        };\n    };\n}\n\nmacro_rules! __zngur_assert_size {\n    ($x:ty, $size:expr $(,)?) => {\n        const _: () = ::core::assert!(\n            $size == ::core::mem::size_of::<$x>(),\n            \"{}\",\n            __zngur_const_str_concat!(\n                \"zngur declared size of \",\n                stringify!($x),\n                \" is incorrect: expected \",\n                __zngur_usize_to_str!($size),\n                \" , real size is \",\n                __zngur_usize_to_str!(::core::mem::size_of::<$x>()),\n            )\n        );\n    };\n}\n\nmacro_rules! __zngur_assert_align {\n    ($x:ty, $align:expr $(,)?) => {\n        const _: () = ::core::assert!(\n            $align == ::core::mem::align_of::<$x>(),\n            \"{}\",\n            __zngur_const_str_concat!(\n                \"zngur declared align of \",\n                stringify!($x),\n                \" is incorrect: expected \",\n                __zngur_usize_to_str!($align),\n                \" , real align is \",\n                __zngur_usize_to_str!(::core::mem::align_of::<$x>()),\n            )\n        );\n    };\n}\n\nmacro_rules! __zngur_assert_size_conservative {\n    ($x:ty, $size:expr $(,)?) => {\n        const _: () = ::core::assert!(\n            $size >= ::core::mem::size_of::<$x>(),\n            \"{}\",\n            __zngur_const_str_concat!(\n                \"zngur declared conservative size of \",\n                stringify!($x),\n                \" is incorrect: expected size less than or equal to \",\n                __zngur_usize_to_str!($size),\n                \" , real size is \",\n                __zngur_usize_to_str!(::core::mem::size_of::<$x>()),\n            )\n        );\n    };\n}\n\nmacro_rules! __zngur_assert_align_conservative {\n    ($x:ty, $align:expr $(,)?) => {\n        const _: () = ::core::assert!(\n            $align >= ::core::mem::align_of::<$x>(),\n            \"{}\",\n            __zngur_const_str_concat!(\n                \"zngur declared conservative align of \",\n                stringify!($x),\n                \" is incorrect: expected align less than or equal to \",\n                __zngur_usize_to_str!($align),\n                \" , real align is \",\n                __zngur_usize_to_str!(::core::mem::align_of::<$x>()),\n            )\n        );\n    };\n}\n\nmacro_rules! __zngur_assert_has_field {\n    ($x:ty, $y:ty, $($field:tt)+ $(,)?) => {\n        const _: () = {\n            #[allow(dead_code)]\n            fn check_field(value: $x) -> $y {\n                value.$($field)+\n            }\n        };\n    };\n}\n\nmacro_rules! __zngur_assert_field_offset {\n    ($x:ty, $offset:expr, $($field:tt)+ $(,)?) => {\n        const _: () = ::core::assert!(\n            $offset == ::core::mem::offset_of!($x, $($field)+),\n            \"{}\",\n            __zngur_const_str_concat!(\n                \"zngur declared offset of field \",\n                stringify!($($field)+),\n                \" in \",\n                stringify!($x),\n                \" is incorrect: expected offset of \",\n                __zngur_usize_to_str!($offset),\n                \" , real offset is \",\n                __zngur_usize_to_str!(::core::mem::offset_of!($x, $($field)+)),\n            )\n        );\n    };\n}\n\"#\n            .to_owned(),\n            panic_to_exception: false,\n            mangling_base: mangling_base.to_owned(),\n        }\n    }\n}\n\nimpl Write for RustFile {\n    fn write_str(&mut self, s: &str) -> std::fmt::Result {\n        self.text.write_str(s)\n    }\n}\n\nmacro_rules! w {\n    ($dst:expr, $($arg:tt)*) => {\n        { let _ = write!($dst, $($arg)*); }\n    };\n}\n\nmacro_rules! wln {\n    ($dst:expr, $($arg:tt)*) => {\n        { let _ = writeln!($dst, $($arg)*); }\n    };\n}\n\npub fn hash_of_sig(sig: &[RustType]) -> String {\n    let mut text = \"\".to_owned();\n    for elem in sig {\n        text += &format!(\"{elem}+\");\n    }\n\n    let digset = Sha256::digest(&text);\n    hex::encode(&digset[..5])\n}\n\nfn mangle_name(name: &str, mangling_base: &str) -> String {\n    let mut name = \"_zngur_\"\n        .chars()\n        .chain(mangling_base.chars())\n        .chain(name.chars().filter(|c| !c.is_whitespace()))\n        .chain(Some('_'))\n        .collect::<String>();\n    let bads = [\n        (1, \"::<\", 'm'),\n        (1, \">::\", 'n'),\n        (1, \"->\", 'a'),\n        (2, \"&\", 'r'),\n        (2, \"=\", 'e'),\n        (2, \"<\", 'x'),\n        (2, \">\", 'y'),\n        (2, \"[\", 'j'),\n        (2, \"]\", 'k'),\n        (2, \"::\", 's'),\n        (2, \",\", 'c'),\n        (2, \"+\", 'l'),\n        (2, \"(\", 'p'),\n        (2, \")\", 'q'),\n        (2, \"@\", 'z'),\n        (2, \"-\", 'h'),\n    ];\n    while let Some((pos, which)) = bads.iter().filter_map(|x| Some((name.find(x.1)?, x))).min() {\n        name.replace_range(pos..pos + which.1.len(), \"_\");\n        w!(name, \"{}{pos}\", which.2);\n    }\n    name\n}\n\npub struct ConstructorMangledNames {\n    pub constructor: String,\n    pub match_check: String,\n}\n\nimpl RustFile {\n    fn mangle_name(&self, name: &str) -> String {\n        mangle_name(name, &self.mangling_base)\n    }\n\n    fn call_cpp_function(&mut self, name: &str, inputs: usize) {\n        for n in 0..inputs {\n            wln!(self, \"let mut i{n} = ::core::mem::MaybeUninit::new(i{n});\")\n        }\n        wln!(self, \"let mut r = ::core::mem::MaybeUninit::uninit();\");\n        w!(self, \"{name}\");\n        for n in 0..inputs {\n            w!(self, \"i{n}.as_mut_ptr() as *mut u8, \");\n        }\n        wln!(self, \"r.as_mut_ptr() as *mut u8);\");\n        wln!(self, \"r.assume_init()\");\n    }\n\n    pub fn add_static_is_copy_assert(&mut self, ty: &RustType) {\n        wln!(self, r#\"__zngur_assert_is_copy!({ty});\"#);\n    }\n\n    pub fn add_static_size_assert(&mut self, ty: &RustType, size: usize) {\n        wln!(self, r#\"__zngur_assert_size!({ty}, {size});\"#);\n    }\n\n    pub fn add_static_align_assert(&mut self, ty: &RustType, align: usize) {\n        wln!(self, r#\"__zngur_assert_align!({ty}, {align});\"#);\n    }\n\n    pub fn add_static_size_upper_bound_assert(&mut self, ty: &RustType, size: usize) {\n        wln!(self, r#\"__zngur_assert_size_conservative!({ty}, {size});\"#);\n    }\n\n    pub fn add_static_align_upper_bound_assert(&mut self, ty: &RustType, align: usize) {\n        wln!(\n            self,\n            r#\"__zngur_assert_align_conservative!({ty}, {align});\"#\n        );\n    }\n\n    pub(crate) fn add_builder_for_dyn_trait(\n        &mut self,\n        tr: &ZngurTrait,\n        namespace: &str,\n        crate_name: &str,\n    ) -> CppTraitDefinition {\n        assert!(matches!(tr.tr, RustTrait::Normal { .. }));\n        let mut method_mangled_name = vec![];\n        wln!(self, r#\"unsafe extern \"C\" {{\"#);\n        for method in &tr.methods {\n            let name = self.mangle_name(&tr.tr.to_string())\n                + \"_\"\n                + &method.name\n                + \"_\"\n                + &hash_of_sig(&method.generics)\n                + \"_\"\n                + &hash_of_sig(&method.inputs);\n            wln!(\n                self,\n                r#\"fn {name}(data: *mut u8, {} o: *mut u8);\"#,\n                method\n                    .inputs\n                    .iter()\n                    .enumerate()\n                    .map(|(n, _)| format!(\"i{n}: *mut u8,\"))\n                    .join(\" \")\n            );\n            method_mangled_name.push(name);\n        }\n        wln!(self, \"}}\");\n        let link_name = self.add_builder_for_dyn_trait_owned(tr, &method_mangled_name);\n        let link_name_ref = self.add_builder_for_dyn_trait_borrowed(tr, &method_mangled_name);\n        CppTraitDefinition::Normal {\n            as_ty: tr.tr.into_cpp(namespace, crate_name),\n            methods: tr\n                .methods\n                .clone()\n                .into_iter()\n                .zip(method_mangled_name)\n                .map(|(x, rust_link_name)| CppTraitMethod {\n                    name: x.name,\n                    rust_link_name,\n                    inputs: x\n                        .inputs\n                        .into_iter()\n                        .map(|x| x.into_cpp(namespace, crate_name))\n                        .collect(),\n                    output: x.output.into_cpp(namespace, crate_name),\n                })\n                .collect(),\n            link_name,\n            link_name_ref,\n        }\n    }\n\n    fn add_builder_for_dyn_trait_owned(\n        &mut self,\n        tr: &ZngurTrait,\n        method_mangled_name: &[String],\n    ) -> String {\n        let trait_name = tr.tr.to_string();\n        let (trait_without_assocs, assocs) = tr.tr.clone().take_assocs();\n        let mangled_name = self.mangle_name(&trait_name);\n        wln!(\n            self,\n            r#\"\n#[allow(non_snake_case)]\n#[unsafe(no_mangle)]\npub extern \"C\" fn {mangled_name}(\n    data: *mut u8,\n    destructor: extern \"C\" fn(*mut u8),\n    o: *mut u8,\n) {{\n    struct Wrapper {{ \n        value: ZngurCppOpaqueOwnedObject,\n    }}\n    impl {trait_without_assocs} for Wrapper {{\n\"#\n        );\n        for (name, ty) in assocs {\n            wln!(self, \"        type {name} = {ty};\");\n        }\n        for (method, rust_link_name) in tr.methods.iter().zip(method_mangled_name) {\n            w!(self, \"        fn {}(\", method.name);\n            match method.receiver {\n                crate::ZngurMethodReceiver::Static => {\n                    panic!(\"traits with static methods are not object safe\");\n                }\n                crate::ZngurMethodReceiver::Ref(Mutability::Not) => w!(self, \"&self\"),\n                crate::ZngurMethodReceiver::Ref(Mutability::Mut) => w!(self, \"&mut self\"),\n                crate::ZngurMethodReceiver::Move => w!(self, \"self\"),\n            }\n            for (i, ty) in method.inputs.iter().enumerate() {\n                w!(self, \", i{i}: {ty}\");\n            }\n            wln!(self, \") -> {} {{ unsafe {{\", method.output);\n            wln!(self, \"            let data = self.value.ptr();\");\n            self.call_cpp_function(&format!(\"{rust_link_name}(data, \"), method.inputs.len());\n            wln!(self, \"        }} }}\");\n        }\n        wln!(\n            self,\n            r#\"\n    }}\n    unsafe {{ \n        let this = Wrapper {{\n            value: ZngurCppOpaqueOwnedObject::new(data, destructor),\n        }};\n        let r: Box<dyn {trait_name}> = Box::new(this);\n        std::ptr::write(o as *mut _, r)\n    }}\n}}\"#\n        );\n        mangled_name\n    }\n\n    fn add_builder_for_dyn_trait_borrowed(\n        &mut self,\n        tr: &ZngurTrait,\n        method_mangled_name: &[String],\n    ) -> String {\n        let trait_name = tr.tr.to_string();\n        let (trait_without_assocs, assocs) = tr.tr.clone().take_assocs();\n        let mangled_name = self.mangle_name(&trait_name) + \"_borrowed\";\n        wln!(\n            self,\n            r#\"\n#[allow(non_snake_case)]\n#[unsafe(no_mangle)]\npub extern \"C\" fn {mangled_name}(\n    data: *mut u8,\n    o: *mut u8,\n) {{\n    struct Wrapper(ZngurCppOpaqueBorrowedObject);\n    impl {trait_without_assocs} for Wrapper {{\n\"#\n        );\n        for (name, ty) in assocs {\n            wln!(self, \"        type {name} = {ty};\");\n        }\n        for (method, rust_link_name) in tr.methods.iter().zip(method_mangled_name) {\n            w!(self, \"        fn {}(\", method.name);\n            match method.receiver {\n                crate::ZngurMethodReceiver::Static => {\n                    panic!(\"traits with static methods are not object safe\");\n                }\n                crate::ZngurMethodReceiver::Ref(Mutability::Not) => w!(self, \"&self\"),\n                crate::ZngurMethodReceiver::Ref(Mutability::Mut) => w!(self, \"&mut self\"),\n                crate::ZngurMethodReceiver::Move => w!(self, \"self\"),\n            }\n            for (i, ty) in method.inputs.iter().enumerate() {\n                w!(self, \", i{i}: {ty}\");\n            }\n            wln!(self, \") -> {} {{ unsafe {{\", method.output);\n            wln!(\n                self,\n                \"            let data = ::std::mem::transmute::<_, *mut u8>(self);\"\n            );\n            self.call_cpp_function(&format!(\"{rust_link_name}(data, \"), method.inputs.len());\n            wln!(self, \"        }} }}\");\n        }\n        wln!(\n            self,\n            r#\"\n    }}\n    unsafe {{ \n        let this = data as *mut Wrapper;\n        let r: &dyn {trait_name} = &*this;\n        std::ptr::write(o as *mut _, r)\n    }}\n}}\"#\n        );\n        mangled_name\n    }\n\n    pub fn add_builder_for_dyn_fn(\n        &mut self,\n        name: &str,\n        inputs: &[RustType],\n        output: &RustType,\n    ) -> String {\n        let mangled_name = self.mangle_name(&inputs.iter().chain(Some(output)).join(\", \"));\n        let trait_str = format!(\"{name}({}) -> {output}\", inputs.iter().join(\", \"));\n        wln!(\n            self,\n            r#\"\n#[allow(non_snake_case)]\n#[unsafe(no_mangle)]\npub extern \"C\" fn {mangled_name}(\n    data: *mut u8,\n    destructor: extern \"C\" fn(*mut u8),\n    call: extern \"C\" fn(data: *mut u8, {} o: *mut u8),\n    o: *mut u8,\n) {{\n    let this = unsafe {{ ZngurCppOpaqueOwnedObject::new(data, destructor) }};\n    let r: Box<dyn {trait_str}> = Box::new(move |{}| unsafe {{\n        _ = &this;\n        let data = this.ptr();\n\"#,\n            inputs\n                .iter()\n                .enumerate()\n                .map(|(n, _)| format!(\"i{n}: *mut u8, \"))\n                .join(\" \"),\n            inputs\n                .iter()\n                .enumerate()\n                .map(|(n, ty)| format!(\"i{n}: {ty}\"))\n                .join(\", \"),\n        );\n        self.call_cpp_function(\"call(data, \", inputs.len());\n        wln!(\n            self,\n            r#\"\n    }});\n    unsafe {{ std::ptr::write(o as *mut _, r) }}\n}}\"#\n        );\n        mangled_name\n    }\n\n    pub fn add_tuple_constructor(&mut self, fields: &[RustType]) -> String {\n        let constructor = self.mangle_name(&fields.iter().join(\"&\"));\n        w!(\n            self,\n            r#\"\n#[allow(non_snake_case)]\n#[unsafe(no_mangle)]\npub extern \"C\" fn {constructor}(\"#\n        );\n        for name in 0..fields.len() {\n            w!(self, \"f_{name}: *mut u8, \");\n        }\n        w!(\n            self,\n            r#\"o: *mut u8) {{ unsafe {{\n    ::std::ptr::write(o as *mut _, (\"#\n        );\n        for (name, ty) in fields.iter().enumerate() {\n            w!(self, \"::std::ptr::read(f_{name} as *mut {ty}), \");\n        }\n        wln!(self, \")) }} }}\");\n        constructor\n    }\n\n    pub fn add_constructor(\n        &mut self,\n        rust_name: &str,\n        args: &[(String, RustType)],\n    ) -> ConstructorMangledNames {\n        let constructor = self.mangle_name(rust_name);\n        let match_check = format!(\"{constructor}_check\");\n        w!(\n            self,\n            r#\"\n#[allow(non_snake_case)]\n#[unsafe(no_mangle)]\npub extern \"C\" fn {constructor}(\"#\n        );\n        for (name, _) in args {\n            w!(self, \"f_{name}: *mut u8, \");\n        }\n        w!(\n            self,\n            r#\"o: *mut u8) {{ unsafe {{\n    ::std::ptr::write(o as *mut _, {rust_name} {{ \"#\n        );\n        for (name, ty) in args {\n            w!(self, \"{name}: ::std::ptr::read(f_{name} as *mut {ty}), \");\n        }\n        wln!(self, \"}}) }} }}\");\n        w!(\n            self,\n            r#\"\n#[allow(non_snake_case)]\n#[unsafe(no_mangle)]\npub extern \"C\" fn {match_check}(i: *mut u8, o: *mut u8) {{ unsafe {{\n    *o = matches!(&*(i as *mut &_), {rust_name} {{ .. }}) as u8;\n}} }}\"#\n        );\n        ConstructorMangledNames {\n            constructor,\n            match_check,\n        }\n    }\n\n    pub(crate) fn add_field_assertions(\n        &mut self,\n        field: &ZngurField,\n        owner: &RustType,\n    ) -> Option<String> {\n        let ZngurField { name, ty, offset } = field;\n        wln!(self, r#\"__zngur_assert_has_field!({owner}, {ty}, {name});\"#);\n        if let Some(offset) = offset {\n            wln!(\n                self,\n                r#\"__zngur_assert_field_offset!({owner}, {offset}, {name});\"#\n            );\n            None\n        } else {\n            let mn = self.mangle_name(&format!(\"{}_field_{}_offset\", &owner, &name));\n            wln!(\n                self,\n                r#\"\n#[allow(non_snake_case)]\n#[unsafe(no_mangle)]\npub static {mn}: usize = ::std::mem::offset_of!({owner}, {name});\n                \"#\n            );\n            Some(mn)\n        }\n    }\n\n    pub fn add_extern_cpp_impl(\n        &mut self,\n        owner: &RustType,\n        tr: Option<&RustTrait>,\n        methods: &[ZngurMethod],\n    ) -> Vec<String> {\n        let mut mangled_names = vec![];\n        w!(self, r#\"unsafe extern \"C\" {{\"#);\n        for method in methods {\n            let mn = self.mangle_name(&format!(\"{}_extern_method_{}\", owner, method.name));\n            w!(\n                self,\n                r#\"\n    fn {mn}(\"#\n            );\n            let input_offset = if method.receiver == ZngurMethodReceiver::Static {\n                0\n            } else {\n                1\n            };\n            for n in 0..method.inputs.len() + input_offset {\n                w!(self, \"i{n}: *mut u8, \");\n            }\n            wln!(self, r#\"o: *mut u8);\"#);\n            mangled_names.push(mn);\n        }\n        w!(self, r#\"}}\"#);\n        match tr {\n            Some(tr) => {\n                let (tr, assocs) = tr.clone().take_assocs();\n                w!(self, r#\"impl {tr} for {owner} {{\"#);\n                for (name, ty) in assocs {\n                    w!(self, r#\"type {name} = {ty};\"#);\n                }\n            }\n            None => w!(self, r#\"impl {owner} {{\"#),\n        }\n        for (mn, method) in mangled_names.iter().zip(methods) {\n            if tr.is_none() {\n                w!(self, \"pub \");\n            }\n            w!(self, r#\"fn {}(\"#, method.name);\n            match method.receiver {\n                ZngurMethodReceiver::Static => (),\n                ZngurMethodReceiver::Ref(Mutability::Mut) => w!(self, \"&mut self, \"),\n                ZngurMethodReceiver::Ref(Mutability::Not) => w!(self, \"&self, \"),\n                ZngurMethodReceiver::Move => w!(self, \"self, \"),\n            }\n            let input_offset = if method.receiver == ZngurMethodReceiver::Static {\n                0\n            } else {\n                1\n            };\n            for (ty, n) in method.inputs.iter().zip(input_offset..) {\n                w!(self, \"i{n}: {ty}, \");\n            }\n            wln!(self, \") -> {} {{ unsafe {{\", method.output);\n            if method.receiver != ZngurMethodReceiver::Static {\n                wln!(self, \"let i0 = self;\");\n            }\n            self.call_cpp_function(&format!(\"{mn}(\"), method.inputs.len() + input_offset);\n            wln!(self, \"}} }}\");\n        }\n        w!(self, r#\"}}\"#);\n        mangled_names\n    }\n\n    pub fn add_extern_cpp_function(\n        &mut self,\n        rust_name: &str,\n        inputs: &[RustType],\n        output: &RustType,\n    ) -> String {\n        let mangled_name = self.mangle_name(rust_name);\n        w!(\n            self,\n            r#\"\nunsafe extern \"C\" {{ fn {mangled_name}(\"#\n        );\n        for (n, _) in inputs.iter().enumerate() {\n            w!(self, \"i{n}: *mut u8, \");\n        }\n        wln!(self, r#\"o: *mut u8); }}\"#);\n        w!(\n            self,\n            r#\"\npub fn {rust_name}(\"#\n        );\n        for (n, ty) in inputs.iter().enumerate() {\n            w!(self, \"i{n}: {ty}, \");\n        }\n        wln!(self, \") -> {output} {{ unsafe {{\");\n        self.call_cpp_function(&format!(\"{mangled_name}(\"), inputs.len());\n        wln!(self, \"}} }}\");\n        mangled_name\n    }\n\n    pub fn add_cpp_value_bridge(&mut self, ty: &RustType, field: &str) -> String {\n        let mangled_name = self.mangle_name(&format!(\"{ty}_cpp_value_{field}\"));\n        w!(\n            self,\n            r#\"\n#[allow(non_snake_case)]\n#[unsafe(no_mangle)]\npub extern \"C\" fn {mangled_name}(d: *mut u8) -> *mut ZngurCppOpaqueOwnedObject {{\n    unsafe {{ &mut (*(d as *mut {ty})).{field} }}\n}}\"#\n        );\n        mangled_name\n    }\n\n    pub fn add_function(\n        &mut self,\n        rust_name: &str,\n        inputs: &[RustType],\n        output: &RustType,\n        use_path: Option<Vec<String>>,\n        deref: Option<Mutability>,\n        namespace: &str,\n        crate_name: &str,\n    ) -> CppFnSig {\n        let mut mangled_name = self.mangle_name(rust_name) + \"_\" + &hash_of_sig(&inputs);\n        if deref.is_some() {\n            mangled_name += \"_deref\";\n        }\n        w!(\n            self,\n            r#\"\n#[allow(non_snake_case)]\n#[unsafe(no_mangle)]\n#[allow(unused_parens)]\npub extern \"C\" fn {mangled_name}(\"#\n        );\n        for n in 0..inputs.len() {\n            w!(self, \"i{n}: *mut u8, \");\n        }\n        let (modified_output, is_impl_trait) = if let RustType::Impl(tr, bounds) = output {\n            (\n                RustType::Boxed(Box::new(RustType::Dyn(tr.clone(), bounds.clone()))),\n                true,\n            )\n        } else {\n            (output.clone(), false)\n        };\n        wln!(self, \"o: *mut u8) {{ unsafe {{\");\n        self.wrap_in_catch_unwind(|this| {\n            if let Some(use_path) = use_path {\n                if use_path.first().is_some_and(|x| x == \"crate\") {\n                    wln!(this, \"    use {};\", use_path.iter().join(\"::\"));\n                } else {\n                    wln!(this, \"    use ::{};\", use_path.iter().join(\"::\"));\n                }\n            }\n\n            w!(\n                this,\n                \"    ::std::ptr::write(o as *mut {modified_output}, {impl_trait} {rust_name}(\",\n                impl_trait = if is_impl_trait { \"Box::new( \" } else { \"\" },\n            );\n            match deref {\n                Some(Mutability::Mut) => w!(this, \"::std::ops::DerefMut::deref_mut\"),\n                Some(Mutability::Not) => w!(this, \"::std::ops::Deref::deref\"),\n                None => {}\n            }\n            for (n, ty) in inputs.iter().enumerate() {\n                w!(this, \"(::std::ptr::read(i{n} as *mut {ty})), \");\n            }\n            if is_impl_trait {\n                wln!(this, \")));\");\n            } else {\n                wln!(this, \"));\");\n            }\n        });\n        wln!(self, \" }} }}\");\n        CppFnSig {\n            rust_link_name: mangled_name,\n            inputs: inputs\n                .iter()\n                .map(|ty| ty.into_cpp(namespace, crate_name))\n                .collect(),\n            output: modified_output.into_cpp(namespace, crate_name),\n        }\n    }\n\n    pub(crate) fn add_wellknown_trait(\n        &mut self,\n        ty: &RustType,\n        wellknown_trait: ZngurWellknownTrait,\n        is_unsized: bool,\n    ) -> ZngurWellknownTraitData {\n        match wellknown_trait {\n            ZngurWellknownTrait::Unsized => ZngurWellknownTraitData::Unsized,\n            ZngurWellknownTrait::Copy => ZngurWellknownTraitData::Copy,\n            ZngurWellknownTrait::Drop => {\n                let drop_in_place = self.mangle_name(&format!(\"{ty}=drop_in_place\"));\n                wln!(\n                    self,\n                    r#\"\n#[allow(non_snake_case)]\n#[unsafe(no_mangle)]\npub extern \"C\" fn {drop_in_place}(v: *mut u8) {{ unsafe {{\n    ::std::ptr::drop_in_place(v as *mut {ty});\n}} }}\"#\n                );\n                ZngurWellknownTraitData::Drop { drop_in_place }\n            }\n            ZngurWellknownTrait::Debug => {\n                let pretty_print = self.mangle_name(&format!(\"{ty}=debug_pretty\"));\n                let debug_print = self.mangle_name(&format!(\"{ty}=debug_print\"));\n                let dbg_ty = if !is_unsized {\n                    format!(\"{ty}\")\n                } else {\n                    format!(\"&{ty}\")\n                };\n                wln!(\n                    self,\n                    r#\"\n#[allow(non_snake_case)]\n#[unsafe(no_mangle)]\npub extern \"C\" fn {pretty_print}(v: *mut u8) {{\n    eprintln!(\"{{:#?}}\", unsafe {{ &*(v as *mut {dbg_ty}) }});\n}}\"#\n                );\n                wln!(\n                    self,\n                    r#\"\n#[allow(non_snake_case)]\n#[unsafe(no_mangle)]\npub extern \"C\" fn {debug_print}(v: *mut u8) {{\n    eprintln!(\"{{:?}}\", unsafe {{ &*(v as *mut {dbg_ty}) }});\n}}\"#\n                );\n                ZngurWellknownTraitData::Debug {\n                    pretty_print,\n                    debug_print,\n                }\n            }\n        }\n    }\n\n    fn wrap_in_catch_unwind(&mut self, f: impl FnOnce(&mut RustFile)) {\n        if !self.panic_to_exception {\n            f(self);\n        } else {\n            wln!(\n                self,\n                r#\"unsafe extern \"C\" {{\n                fn __zngur_mark_panicked();   \n            }}\n            let e = ::std::panic::catch_unwind(|| {{\"#\n            );\n            f(self);\n            wln!(self, \"}});\");\n            wln!(self, \"if let Err(_) = e {{ __zngur_mark_panicked(); }}\");\n        }\n    }\n\n    pub(crate) fn add_layout_policy_shim(\n        &mut self,\n        ty: &RustType,\n        layout: LayoutPolicy,\n    ) -> CppLayoutPolicy {\n        match layout {\n            LayoutPolicy::StackAllocated { size, align } => {\n                CppLayoutPolicy::StackAllocated { size, align }\n            }\n            LayoutPolicy::Conservative { size, align } => {\n                CppLayoutPolicy::StackAllocated { size, align }\n            }\n            LayoutPolicy::HeapAllocated => {\n                let size_fn = self.mangle_name(&format!(\"{ty}_size_fn\"));\n                let alloc_fn = self.mangle_name(&format!(\"{ty}_alloc_fn\"));\n                let free_fn = self.mangle_name(&format!(\"{ty}_free_fn\"));\n                wln!(\n                    self,\n                    r#\"\n                #[allow(non_snake_case)]\n                #[unsafe(no_mangle)]\n                pub fn {size_fn}() -> usize {{\n                    ::std::mem::size_of::<{ty}>()\n                }}\n        \n                #[allow(non_snake_case)]\n                #[unsafe(no_mangle)]\n                pub fn {alloc_fn}() -> *mut u8 {{\n                    unsafe {{ ::std::alloc::alloc(::std::alloc::Layout::new::<{ty}>()) }}\n                }}\n\n                #[allow(non_snake_case)]\n                #[unsafe(no_mangle)]\n                pub fn {free_fn}(p: *mut u8) {{\n                    unsafe {{ ::std::alloc::dealloc(p, ::std::alloc::Layout::new::<{ty}>()) }}\n                }}\n                \"#\n                );\n                CppLayoutPolicy::HeapAllocated {\n                    size_fn,\n                    alloc_fn,\n                    free_fn,\n                }\n            }\n            LayoutPolicy::OnlyByRef => CppLayoutPolicy::OnlyByRef,\n        }\n    }\n}\n"
  },
  {
    "path": "zngur-generator/src/template.rs",
    "content": "use crate::cpp::{\n    CppExportedFnDefinition, CppExportedImplDefinition, CppFnDefinition, CppTraitDefinition,\n    CppTypeDefinition,\n};\nuse askama::Template;\nuse indexmap::IndexMap;\nuse zngur_def::*;\nuse zngur_def::{ZngurMethodReceiver, ZngurWellknownTraitData};\n\nuse crate::rust::IntoCpp;\n\n/// Macro for template string interpolation over iterables with enumeration\n///\n/// Usage:\n/// - splat!(items, |idx, ty|, \"{ty} param{idx}\")\n/// - splat!(items.iter().skip(1), |n, t|, \"{t} i{n}\")\n/// - splat!(items, \"{el} i{n}\")  // Default names: n (index), el (element)\nmacro_rules! splat {\n    // Closure-style with custom variable names\n    ($inputs:expr, |$n:ident, $el:ident|, $pattern:literal $(, $format_vars:expr)* $(,)?) => {{\n        use itertools::Itertools;\n        #[allow(unused_variables)]\n        $inputs\n            .into_iter()\n            .enumerate()\n            .map(|($n, $el)| format!($pattern $(, $format_vars)*))\n            .join(\", \")\n    }};\n\n    ($inputs:expr, |$n:ident, _|, $pattern:literal, $($format_vars:expr,)* $(,)?) => {{\n      use itertools::Itertools;\n      #[allow(unused_variables)]\n      $inputs\n          .into_iter()\n          .enumerate()\n          .map(|($n, $el)| format!($pattern $(, $format_vars)*))\n          .join(\", \")\n  }};\n\n    // Default names fallback\n    ($inputs:expr, $pattern:literal) => {\n        splat!($inputs, |n, el|, $pattern)\n    };\n}\n\n#[derive(Template)]\n#[template(path = \"cpp_header.sptl\", escape = \"none\")]\npub(crate) struct CppHeaderTemplate<'a> {\n    pub(crate) panic_to_exception: bool,\n    pub(crate) additional_includes: &'a String,\n    pub(crate) fn_deps: &'a Vec<CppFnDefinition>,\n    pub(crate) type_defs: &'a Vec<CppTypeDefinition>,\n    pub(crate) trait_defs: &'a IndexMap<RustTrait, CppTraitDefinition>,\n    pub(crate) exported_impls: &'a Vec<CppExportedImplDefinition>,\n    pub(crate) exported_fn_defs: &'a Vec<CppExportedFnDefinition>,\n    pub(crate) rust_cfg_defines: &'a Vec<String>,\n    pub(crate) zng_header_in_place: bool,\n    pub(crate) namespace: &'a str,\n    pub(crate) crate_name: &'a str,\n}\n\nimpl<'a> CppHeaderTemplate<'a> {\n    pub fn cpp_handle_field_name(&self, name: &str) -> String {\n        crate::cpp::cpp_handle_field_name(name)\n    }\n}\n\n#[derive(Template)]\n#[template(path = \"zng_header.sptl\", escape = \"none\")]\npub(crate) struct ZngHeaderTemplate {\n    pub(crate) panic_to_exception: bool,\n    pub(crate) cpp_namespace: String,\n}\n\nimpl<'a> CppHeaderTemplate<'a> {\n    fn panic_handler(&self) -> String {\n        if self.panic_to_exception {\n            format!(\n                r#\"\n            if (__zngur_read_and_reset_rust_panic()) {{\n                throw ::{}::Panic{{}};\n            }}\n            \"#,\n                self.namespace\n            )\n        } else {\n            \"\".to_owned()\n        }\n    }\n    pub fn render_type_methods(&self, td: &crate::cpp::CppTypeDefinition) -> String {\n        use itertools::Itertools;\n        use zngur_def::{Mutability, ZngurMethodReceiver};\n        let mut s = String::new();\n\n        let is_unsized = td.has_unsized();\n\n        for method in &td.methods {\n            let ty_str = td.ty.to_string();\n            let fn_name = format!(\n                \"{}::{}\",\n                ty_str.strip_prefix(\"::\").unwrap_or(&ty_str),\n                method.name\n            );\n            let inputs = &method.sig.inputs;\n            let out = &method.sig.output;\n            let splat_inputs = inputs\n                .iter()\n                .enumerate()\n                .map(|(n, ty)| format!(\"{ty} i{n}\"))\n                .join(\", \");\n            let splat_skip_inputs = inputs\n                .iter()\n                .skip(1)\n                .enumerate()\n                .map(|(n, ty)| format!(\"{ty} i{n}\"))\n                .join(\", \");\n\n            let mut assume_deinit_str = String::new();\n            for n in 0..inputs.len() {\n                assume_deinit_str.push_str(&format!(\n                    \"::{}::__zngur_internal_assume_deinit(i{n}); \",\n                    self.namespace\n                ));\n            }\n\n            let mut rust_args = String::new();\n            if !inputs.is_empty() {\n                rust_args = inputs\n                    .iter()\n                    .enumerate()\n                    .map(|(n, _)| format!(\"::{}::__zngur_internal_data_ptr(i{n})\", self.namespace))\n                    .join(\", \")\n                    + \", \";\n            }\n\n            s.push_str(&format!(\n                r#\"\n    inline {out} {fn_name} ({splat_inputs}) noexcept {{\n      {out} o{{}};\n      {assume_deinit_str}\n      {rust_link_name} (\n        {rust_args}\n        ::{namespace}::__zngur_internal_data_ptr(o)\n      );\n      {panic_handler}\n      ::{namespace}::__zngur_internal_assume_init(o);\n      return o;\n    }}\n\"#,\n                out = out,\n                fn_name = fn_name,\n                splat_inputs = splat_inputs,\n                assume_deinit_str = assume_deinit_str,\n                rust_link_name = method.sig.rust_link_name,\n                rust_args = rust_args,\n                namespace = self.namespace,\n                panic_handler = self.panic_handler()\n            ));\n\n            if let ZngurMethodReceiver::Ref(m) = method.kind {\n                let ref_kinds: &[&str] = match m {\n                    Mutability::Mut => &[\"RefMut\"],\n                    Mutability::Not => &[\"Ref\", \"RefMut\"],\n                };\n                let field_kinds: &[&str] = match m {\n                    Mutability::Mut => &[\"FieldOwned\", \"FieldRefMut\"],\n                    Mutability::Not => &[\"FieldOwned\", \"FieldRefMut\", \"FieldRef\"],\n                };\n\n                let move_args = (0..(inputs.len().saturating_sub(1)))\n                    .map(|n| format!(\", ::std::move(i{n})\"))\n                    .join(\"\");\n\n                for field_kind in field_kinds {\n                    s.push_str(&format!(\n                        r#\"\n        template<typename Offset, typename... Offsets>\n        inline {out} {namespace}::{field_kind}< {ty}, Offset, Offsets... >::{method_name}(\n            {splat_skip_inputs}\n        ) const noexcept {{\n          return {fn_name}(\n            *this\n            {move_args}\n          );\n        }}\n\"#,\n                        out = out,\n                        namespace = self.namespace,\n                        field_kind = field_kind,\n                        ty = td.ty,\n                        method_name = method.name,\n                        splat_skip_inputs = splat_skip_inputs,\n                        fn_name = fn_name,\n                        move_args = move_args\n                    ));\n                }\n\n                for ref_kind in ref_kinds {\n                    s.push_str(&format!(\n                        r#\"\n        inline {out} {namespace}::{ref_kind}< {ty} >::{method_name}(\n            {splat_skip_inputs}\n        ) const noexcept {{\n          return {fn_name}(\n            *this\n            {move_args}\n          );\n        }}\n\"#,\n                        out = out,\n                        namespace = self.namespace,\n                        ref_kind = ref_kind,\n                        ty = td.ty,\n                        method_name = method.name,\n                        splat_skip_inputs = splat_skip_inputs,\n                        fn_name = fn_name,\n                        move_args = move_args\n                    ));\n                }\n            }\n\n            if !is_unsized\n                && !td.layout.is_only_by_ref()\n                && method.kind != ZngurMethodReceiver::Static\n            {\n                let this_arg = match method.kind {\n                    ZngurMethodReceiver::Ref(_) => \"*this\",\n                    ZngurMethodReceiver::Move => \"::std::move(*this)\",\n                    ZngurMethodReceiver::Static => unreachable!(),\n                };\n                let const_str = if method.kind == ZngurMethodReceiver::Ref(Mutability::Not) {\n                    \"const\"\n                } else {\n                    \"\"\n                };\n                let move_args = (0..(inputs.len().saturating_sub(1)))\n                    .map(|n| format!(\", ::std::move(i{n})\"))\n                    .join(\"\");\n\n                s.push_str(&format!(\n                    r#\"\n      inline {out} {fn_name}(\n            {splat_skip_inputs}\n      ) {const_str} noexcept {{\n        return {fn_name}(\n          {this_arg}\n          {move_args}\n        );\n      }}\n\"#,\n                    out = out,\n                    fn_name = fn_name,\n                    splat_skip_inputs = splat_skip_inputs,\n                    const_str = const_str,\n                    this_arg = this_arg,\n                    move_args = move_args\n                ));\n            }\n        }\n        s\n    }\n\n    pub fn render_from_trait(&self, td: &crate::cpp::CppTypeDefinition) -> String {\n        use crate::cpp::CppTraitDefinition;\n\n        use itertools::Itertools;\n        let tr = td.from_trait.as_ref().and_then(|k| self.trait_defs.get(k));\n        let name = td\n            .ty\n            .to_string()\n            .strip_prefix(\"::\")\n            .unwrap_or(&td.ty.to_string())\n            .to_string();\n        match tr {\n            Some(CppTraitDefinition::Fn { sig }) => {\n                let as_std_function = format!(\n                    \"::std::function< {}({})>\",\n                    sig.output,\n                    sig.inputs.iter().join(\", \")\n                );\n                let ii_names = sig\n                    .inputs\n                    .iter()\n                    .enumerate()\n                    .map(|(n, x)| {\n                        format!(\n                            \"::{}::__zngur_internal_move_from_rust< {x} >(i{n})\",\n                            self.namespace\n                        )\n                    })\n                    .join(\", \");\n                let uint8_t_ix = if sig.inputs.is_empty() {\n                    \"\".to_owned()\n                } else {\n                    sig.inputs\n                        .iter()\n                        .enumerate()\n                        .map(|(n, _ty)| format!(\"uint8_t* i{n}\"))\n                        .join(\", \")\n                        + \", \"\n                };\n                let out_ty = &sig.output;\n                let link_name = &sig.rust_link_name;\n                format!(\n                    r#\"\n    inline {name} {name}::make_box({as_std_function} f) {{\n      auto __zngur_data = new {as_std_function}(f);\n      {name} o;\n      ::{namespace}::__zngur_internal_assume_init(o);\n      {link_name} (\n        reinterpret_cast<uint8_t*>(__zngur_data),\n        [](uint8_t *d) {{ delete reinterpret_cast< {as_std_function}*>(d); }},\n        [](uint8_t *d, {uint8_t_ix} uint8_t* o) {{\n          auto dd = reinterpret_cast< {as_std_function} *>(d);\n          {out_ty} oo = (*dd)({ii_names});\n          ::{namespace}::__zngur_internal_move_to_rust< {out_ty} >(o, oo);\n        }},\n        ::{namespace}::__zngur_internal_data_ptr(o)\n      );\n      return o;\n    }}\n\"#,\n                    namespace = self.namespace\n                )\n            }\n            Some(CppTraitDefinition::Normal {\n                as_ty, link_name, ..\n            }) => {\n                format!(\n                    r#\"\n    template <typename T, typename... Args>\n    {name} {name}::make_box(Args&&... args) {{\n      auto __zngur_data = new T(::std::forward<Args>(args)...);\n      auto data_as_impl = dynamic_cast< {as_ty}*>(__zngur_data);\n      {name} o;\n      ::{namespace}::__zngur_internal_assume_init(o);\n      {link_name} (\n        reinterpret_cast<uint8_t*>(data_as_impl),\n        [](uint8_t *d) {{ delete reinterpret_cast< {as_ty}*>(d); }},\n        ::{namespace}::__zngur_internal_data_ptr(o)\n      );\n      return o;\n    }}\n\"#,\n                    namespace = self.namespace\n                )\n            }\n            None => \"\".to_owned(),\n        }\n    }\n\n    pub fn render_from_trait_ref(&self, td: &crate::cpp::CppTypeDefinition) -> String {\n        use crate::cpp::CppTraitDefinition;\n        let tr = td\n            .from_trait_ref\n            .as_ref()\n            .and_then(|k| self.trait_defs.get(k));\n        let name = td\n            .ty\n            .to_string()\n            .strip_prefix(\"::\")\n            .unwrap_or(&td.ty.to_string())\n            .to_string();\n        match tr {\n            Some(CppTraitDefinition::Fn { .. }) => \"\".to_owned(),\n            Some(CppTraitDefinition::Normal {\n                as_ty,\n                link_name_ref,\n                ..\n            }) => {\n                let mut s = String::new();\n                for ref_kind in [\"Ref\", \"RefMut\"] {\n                    s.push_str(&format!(\n                        r#\"\n      {namespace}::{ref_kind}< {name} >::{ref_kind}({as_ty}& args) {{\n        auto data_as_impl = &args;\n        ::{namespace}::__zngur_internal_assume_init(*this);\n        {link_name_ref}(\n          (uint8_t *)data_as_impl,\n          ::{namespace}::__zngur_internal_data_ptr(*this)\n        );\n      }}\n\"#,\n                        namespace = self.namespace\n                    ));\n                }\n                s\n            }\n            None => \"\".to_owned(),\n        }\n    }\n\n    pub fn render_fn_deps(&self) -> String {\n        use itertools::Itertools;\n        let mut s = String::new();\n        for fd in self.fn_deps {\n            let open_ns = fd.name.open_namespace();\n            let close_ns = fd.name.close_namespace();\n            let out = &fd.sig.output;\n            let name = fd.name.name();\n            let inputs = &fd.sig.inputs;\n\n            let splat_inputs = inputs\n                .iter()\n                .enumerate()\n                .map(|(n, ty)| format!(\"{ty} i{n}\"))\n                .join(\", \");\n\n            let mut assume_deinit_str = String::new();\n            for n in 0..inputs.len() {\n                assume_deinit_str.push_str(&format!(\n                    \"::{}::__zngur_internal_assume_deinit(i{n}); \",\n                    self.namespace\n                ));\n            }\n\n            let mut rust_args = String::new();\n            if !inputs.is_empty() {\n                rust_args = inputs\n                    .iter()\n                    .enumerate()\n                    .map(|(n, _)| format!(\"::{}::__zngur_internal_data_ptr(i{n})\", self.namespace))\n                    .join(\", \")\n                    + \", \";\n            }\n\n            s.push_str(&format!(\n                r#\"\n{open_ns}\n    inline {out} {name}({splat_inputs}) noexcept {{\n      {out} o{{}};\n      {assume_deinit_str}\n      {rust_link_name} (\n        {rust_args}\n        ::{namespace}::__zngur_internal_data_ptr(o)\n      );\n      {panic_handler}\n      ::{namespace}::__zngur_internal_assume_init(o);\n      return o;\n    }}\n{close_ns}\n\"#,\n                open_ns = open_ns,\n                out = out,\n                name = name,\n                splat_inputs = splat_inputs,\n                assume_deinit_str = assume_deinit_str,\n                rust_link_name = fd.sig.rust_link_name,\n                rust_args = rust_args,\n                namespace = self.namespace,\n                panic_handler = self.panic_handler(),\n                close_ns = close_ns\n            ));\n        }\n        s\n    }\n    pub fn render_exported_impls(&self) -> String {\n        use itertools::Itertools;\n        let mut s = String::new();\n        for imp in self.exported_impls {\n            let x = match &imp.tr {\n                Some(x) => format!(\"{x}\"),\n                None => format!(\"::{}::Inherent\", self.namespace),\n            };\n\n            s.push_str(&format!(\n                r#\"\n  template<>\n  class Impl< {ty}, {x} > {{\n    public:\n\"#,\n                ty = imp.ty,\n                x = x\n            ));\n\n            for (name, sig) in &imp.methods {\n                let inputs = &sig.inputs;\n                let splat_inputs = inputs.iter().map(|ty| format!(\"{ty}\")).join(\", \");\n\n                s.push_str(&format!(\n                    r#\"\n        static {out} {name}(\n          {splat_inputs}\n        );\n\"#,\n                    out = sig.output,\n                    name = name,\n                    splat_inputs = splat_inputs\n                ));\n            }\n\n            s.push_str(\"  };\\n\");\n        }\n        s\n    }\n\n    fn render_zng_header(&self) -> String {\n        let generator = ZngHeaderTemplate {\n            panic_to_exception: self.panic_to_exception,\n            cpp_namespace: self.namespace.to_owned(),\n        };\n        generator.render().unwrap()\n    }\n}\n\nimpl ZngHeaderTemplate {\n    pub fn is_ref_kind_ref(&self, ref_kind: &str) -> bool {\n        ref_kind == \"Ref\"\n    }\n    pub fn is_size_t(&self, ty: &str) -> bool {\n        ty == \"::size_t\"\n    }\n\n    pub fn is_printable(&self, ty: &str) -> bool {\n        ty.starts_with(\"int\")\n            || ty.starts_with(\"uint\")\n            || ty.starts_with(\"::size_t\")\n            || ty.starts_with(\"::double\")\n            || ty.starts_with(\"::float\")\n    }\n    // TODO: Docs - what do these represent? When will we change this list?\n    fn builtin_types(&self) -> Vec<String> {\n        let builtins = [8, 16, 32, 64]\n            .into_iter()\n            .flat_map(|x| [format!(\"int{x}_t\"), format!(\"uint{x}_t\")])\n            .chain([\"::double_t\".to_owned(), \"::float_t\".to_owned()])\n            .flat_map(|x| {\n                [\n                    x.clone(),\n                    format!(\"::{}::Ref<{x}>\", &self.cpp_namespace),\n                    format!(\"::{}::RefMut<{x}>\", &self.cpp_namespace),\n                ]\n            });\n        builtins\n            .chain([\n                format!(\"::{}::ZngurCppOpaqueOwnedObject\", &self.cpp_namespace),\n                \"::size_t\".to_owned(),\n            ])\n            .collect()\n    }\n}\n\n#[derive(Template)]\n#[template(path = \"cpp_source.sptl\", escape = \"none\")]\npub(crate) struct CppSourceTemplate<'a> {\n    pub(crate) header_file_name: &'a String,\n    pub(crate) trait_defs: &'a IndexMap<RustTrait, CppTraitDefinition>,\n    pub(crate) exported_fn_defs: &'a Vec<CppExportedFnDefinition>,\n    pub(crate) exported_impls: &'a Vec<CppExportedImplDefinition>,\n    pub(crate) cpp_namespace: &'a str,\n}\n"
  },
  {
    "path": "zngur-generator/templates/cpp_header.sptl",
    "content": "{# #language:cpp #}\n\n#pragma once\n\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n#include <csignal>\n#include <array>\n#include <iostream>\n#include <functional>\n#include <math.h>\n#include <type_traits>\n\n{% if !self.zng_header_in_place %}\n#include <zngur.h>\n{% else %}\n{{ self.render_zng_header() }}\n{% endif %}\n\n{{ self.additional_includes }}\n\n{% for def in self.rust_cfg_defines %}\n#define {{ def }}\n{% endfor %}\n\nextern \"C\" {\n  {% for f in self.fn_deps %}\n    void {{ f.sig.rust_link_name }} (\n      {% for n in 0..f.sig.inputs.len() %}\n        uint8_t*,\n      {% endfor %}\n      uint8_t* o\n    ) noexcept ;\n  {% endfor %}\n\n  {% for td in self.type_defs %}\n    {% for method in td.methods %}\n      void {{ method.sig.rust_link_name }} (\n        {% for n in 0..method.sig.inputs.len() %}\n          uint8_t*,\n        {% endfor %}\n        uint8_t* o\n      ) noexcept ;\n    {% endfor %}\n\n    {% for constructor in td.constructors %}\n      void {{ constructor.rust_link_name }} (\n        {% for n in 0..constructor.inputs.len() %}\n          uint8_t*,\n        {% endfor %}\n        uint8_t* o\n      ) noexcept ;\n    {% endfor %}\n\n    {% if let Some(cpp_value) = td.cpp_value %}\n      ::{{ self.namespace }}::ZngurCppOpaqueOwnedObject* {{ cpp_value.0 }}(uint8_t*);\n    {% endif %}\n\n    {% if !td.layout.is_stack_allocated() && !td.layout.is_only_by_ref() %}\n      size_t {{ td.layout.size_fn() }}();\n      uint8_t* {{ td.layout.alloc_fn() }}();\n      void {{ td.layout.free_fn() }}(uint8_t*);\n    {% endif %}\n\n    {% for field in td.fields %}\n      {% if let ZngurFieldDataOffset::Auto(field_offset_const_name) = field.offset %}\n      extern const uint8_t {{ field_offset_const_name }};\n      {% endif %}\n    {% endfor %}\n\n    {% for tr in td.wellknown_traits %}\n      {#  TODO: switch to match.  #}\n      {% if let ZngurWellknownTraitData::Debug { pretty_print, debug_print } = tr %}\n        void {{ pretty_print }}(uint8_t*);\n        void {{ debug_print }}(uint8_t*);\n      {% else if let ZngurWellknownTraitData::Drop { drop_in_place } = tr %}\n        void {{ drop_in_place }}(uint8_t*);\n      {% endif %}\n    {% endfor %}\n\n    {% for (_, td) in self.trait_defs %}\n      {% if let Some(sig) = td.as_fn() %}\n        void {{ sig.rust_link_name }}(uint8_t* __zngur_data, void destructor(uint8_t *),\n                                       void call(uint8_t *,\n                                          {% for n in 0..sig.inputs.len() %} uint8_t *, {% endfor %}uint8_t *o),\n                                       uint8_t *o\n        );\n      {% else if let Some(normal) = td.as_normal() %}\n        void {{ normal.2 }}(uint8_t *__zngur_data, void destructor(uint8_t *), uint8_t *o);\n        void {{ normal.3 }}(uint8_t *__zngur_data, uint8_t *o);\n      {% endif %}\n    {% endfor %}\n\n  // end self.type_defs\n  {% endfor %}\n\n} // extern \"C\"\n\n{% for td in self.type_defs %}\n  {{ td.ty.header() }}\n{% endfor %}\n\n{% for imp in self.exported_impls %}\n  {{ imp.ty.header() }}\n  {% if let Some(tr) = imp.tr %}\n    {{ tr.header() }}\n  {% endif %}\n{% endfor %}\n\nnamespace {{ self.namespace }} {\n\n{% for td in self.type_defs %}\n  {% if td.has_unsized() %}\n    template<>\n    struct zngur_is_unsized< {{ td.ty }} > : ::std::true_type {};\n  {% endif %}\n{% endfor %}\n\n}\n\n{% for (_, td) in self.trait_defs %}\n  {% if let Some(normal) = td.as_normal() %}\n    {{ normal.0.path.open_namespace() }}\n    {{ normal.0.specialization_decl() }} {\n      public:\n        virtual ~{{ normal.0.path.name() }}() {};\n        {% for method in normal.1 %}\n          virtual {{ method.output }} {{ method.name }} (\n            {{ splat!(&method.inputs, |n, x|, \"{x}\") }}\n          ) = 0;\n        {% endfor %}\n      };\n    {{ normal.0.path.close_namespace() }}\n  {% endif %}\n{% endfor %}\n\nnamespace {{ self.namespace }} {\n\n// Field specializations templates \n// (declared before types so fields instantiate the correct template)\n\n{% for td in self.type_defs %}\n\n{% for field_kind in [\"FieldOwned\", \"FieldRef\", \"FieldRefMut\"] %}\n  \n  template<typename Offset, typename... Offsets>\n  struct {{ field_kind }}< {{ td.ty }}, Offset, Offsets...> {\n\n    {% if !td.fields.is_empty() %}\n    union {\n    {% for (index, field) in td.fields.iter().enumerate() %}\n      ::{{ self.namespace }}::{{ field_kind }}<\n        {{ field.ty.into_cpp(self.namespace, self.crate_name) }},\n      {% if let Some(offset) = field.offset.as_offset() %}\n        ::{{ self.namespace }}::FieldStaticOffset< {{ td.ty }}, {{ offset }} >,\n      {% else %}\n        ::{{ self.namespace }}::FieldAutoOffset< {{ td.ty }}, {{ index }} >,\n      {% endif %}\n        Offset,\n        Offsets...\n      > {{ self.cpp_handle_field_name(field.name) }};\n    {% endfor %}\n    };\n    {% endif %}\n\n    {% for method in td.methods %}\n      {% if method.is_valid_field_method(field_kind) %}\n          {{ method.sig.output }} {{ method.name }}(\n            {{ splat!(method.sig.inputs.iter().skip(1), |n, ty|, \"{ty}\") }}\n          ) const noexcept ;\n      {% endif %}\n    {% endfor %}\n\n  }; // struct {{ field_kind }}< {{ td.ty }}, Offset, Offsets... >\n{% endfor %}\n\n{% endfor %}\n\n} // namespace {{ self.namespace }}\n\n{% for td in self.type_defs %}\n  {% let is_copy = td.has_copy() %}\n  {% let is_unsized = td.has_unsized() %}\n  {% let name = td.ty.path.name() %}\n\n  namespace {{ self.namespace }} {\n    template<>\n    struct __zngur_internal< {{ td.ty }} > {\n      static inline uint8_t* data_ptr(const {{ td.ty }}& t) noexcept ;\n      static inline void check_init(const {{ td.ty }}& t) noexcept ;\n      static inline void assume_init({{ td.ty }}& t) noexcept ;\n      static inline void assume_deinit({{ td.ty }}& t) noexcept ;\n      static inline size_t size_of() noexcept ;\n    };\n  }\n\n  {{ td.ty.path.open_namespace() }}\n    {{ td.ty.specialization_decl() }} {\n      public:\n    {% if td.layout.is_only_by_ref() %}\n        {{ name }}() = delete;\n\n          {% if !td.fields.is_empty() %}\n          union {\n          {% endif %}\n    {% else if td.layout.is_stack_allocated() %}\n        union alignas({{ td.layout.stack_align() }}) {\n          alignas({{ td.layout.stack_align() }}) mutable ::std::array< ::uint8_t, {{ td.layout.stack_size() }}> __zngur_data;\n        {% for (index, field) in td.fields.iter().enumerate() %}\n          ::{{ self.namespace }}::FieldOwned<\n            {{ field.ty.into_cpp(self.namespace, self.crate_name) }},\n          {% if let Some(offset) = field.offset.as_offset() %}\n            ::{{ self.namespace }}::FieldStaticOffset< {{ td.ty }}, {{ offset }} >\n          {% else %}\n            ::{{ self.namespace }}::FieldAutoOffset< {{ td.ty }}, {{ index }} >\n          {% endif %}\n          > {{ self.cpp_handle_field_name(field.name) }};\n        {% endfor %}\n        };\n    {% else %}\n      union {\n        ::uint8_t* __zngur_data;\n      {% for (index, field) in td.fields.iter().enumerate() %}\n        ::{{ self.namespace }}::FieldOwned<\n          {{ field.ty.into_cpp(self.namespace, self.crate_name) }},\n        {% if let Some(offset) = field.offset.as_offset() %}\n          ::{{ self.namespace }}::FieldStaticOffset< {{ td.ty }}, {{ offset }} >\n        {% else %}\n          ::{{ self.namespace }}::FieldAutoOffset< {{ td.ty }}, {{ index }} >\n        {% endif %}\n        > {{ self.cpp_handle_field_name(field.name) }};\n      {% endfor %}\n      };\n    {% endif %}\n\n    {% if !td.layout.is_only_by_ref() %}\n\n    {% if td.ty.path.to_string() == format!(\"::{}::Bool\", self.namespace) %}\n      public:\n        operator bool() {\n          return __zngur_data[0];\n        }\n        Bool(bool b) {\n          __zngur_data[0] = b;\n        }\n    {% endif %}\n\n    {% if td.ty.path.to_string() == format!(\"::{}::Char\", self.namespace) %}\n      public:\n        operator char32_t() const {\n          return *reinterpret_cast<const char32_t*>(__zngur_data.data());\n        }\n        Char(char32_t c) {\n          *reinterpret_cast<char32_t*>(__zngur_data.data()) = c;\n        }\n    {% endif %}\n\n    {% if !is_copy %}\n      bool drop_flag;\n    {% endif %}\n\n    {% let alloc_heap = td.layout.alloc_heap() %}\n    {% let free_heap = td.layout.free_heap() %}\n    {% let copy_data = td.layout.copy_data() %}\n\n    public:\n      {% if is_copy %}\n        {{ name }}() { {{ alloc_heap }} }\n        ~{{ name }}() { {{ free_heap }} }\n        {{ name }}(const {{ name }}& other) {\n          {{ alloc_heap }}\n          {{ copy_data }}\n        }\n        {{ name }}& operator=(const {{ name }}& other) {\n          {{ copy_data }}\n          return *this;\n        }\n        {{ name }}({{ name }}&& other) {\n          {{ alloc_heap }}\n          {{ copy_data }}\n        }\n        {{ name }}& operator=({{ name }}&& other) {\n          {{ copy_data }}\n          return *this;\n        }\n      {% else %}\n        {% let drop_in_place = td.drop_in_place() %}\n\n        {{ name }}() : drop_flag(false) { {{ alloc_heap }} }\n        ~{{ name }}() {\n          if (drop_flag) {\n            {{ drop_in_place }}(::{{ self.namespace }}::__zngur_internal_data_ptr(*this));\n          }\n          {{ free_heap }}\n        }\n        {{ name }}(const {{ name }}& other) = delete;\n        {{ name }}& operator=(const {{ name }}& other) = delete;\n        {{ name }}({{ name }}&& other) : drop_flag(false) {\n          {{ alloc_heap }}\n          *this = ::std::move(other);\n        }\n        {{ name }}& operator=({{ name }}&& other) {\n          if (this != &other) {\n            if (drop_flag) {\n              {{ drop_in_place }}(::{{ self.namespace }}::__zngur_internal_data_ptr(*this));\n            }\n            this->drop_flag = other.drop_flag;\n            {{ copy_data }}\n            other.drop_flag = false;\n          }\n          return *this;\n        }\n      {% endif %}\n\n      {{ td.render_make_box(name, self.namespace, self.crate_name) }}\n\n      {% if let Some(cpp_value) = td.cpp_value %}\n          inline {{ cpp_value.1 }}& cpp() {\n              return (*{{ cpp_value.0 }}(::{{ self.namespace }}::__zngur_internal_data_ptr(*this))).as_cpp< {{ cpp_value.1 }} >();\n          }\n      {% endif %}\n\n    {% endif %}\n\n    {% for method in td.methods %}\n        static {{ method.sig.output }} {{ method.name }}(\n          {{ splat!(&method.sig.inputs, |n, ty|, \"{ty}\") }}\n        ) noexcept ;\n        {% if method.kind != ZngurMethodReceiver::Static %}\n            {{ method.sig.output }} {{ method.name }}(\n              {{ splat!(method.sig.inputs.iter().skip(1), |n, ty|, \"{ty}\") }}\n            )\n            {% if method.is_ref_not_mut() %} const {% endif %} noexcept ;\n        {% endif %}\n    {% endfor %}\n\n    {% for constructor in td.constructors %}\n      {{ td.ty.path.0.last().unwrap() }}(\n        {{ splat!(&constructor.inputs, |n, ty|, \"{ty}\") }}\n      ) noexcept ;\n    {% endfor %}\n\n  }; // {{ td.ty.specialization_decl() }}\n\n{{ td.ty.path.close_namespace() }}\n\nnamespace {{ self.namespace }} {\n\n{% if td.layout.is_stack_allocated() %}\n  inline size_t __zngur_internal< {{ td.ty }} >::size_of() noexcept {\n      return {{ td.layout.stack_size() }};\n  }\n{% else if !td.layout.is_only_by_ref() %}\n  inline size_t __zngur_internal< {{ td.ty }} >::size_of() noexcept {\n      return {{ td.layout.size_fn() }}();\n  }\n\n  template <>\n  struct zngur_heap_allocated< {{ td.ty }} > : ::std::true_type {};\n{% endif %}\n\n{% if !td.layout.is_only_by_ref() %}\n  {% if is_copy %}\n    inline void __zngur_internal< {{ td.ty }} >::check_init(const {{ td.ty }}&) noexcept {}\n    inline void __zngur_internal< {{ td.ty }} >::assume_init({{ td.ty }}&) noexcept {}\n    inline void __zngur_internal< {{ td.ty }} >::assume_deinit({{ td.ty }}&) noexcept {}\n  {% else %}\n    inline void __zngur_internal< {{ td.ty }} >::check_init(const {{ td.ty }}& t) noexcept {\n        if (!t.drop_flag) {\n            ::std::cerr << \"Use of uninitialized or moved Zngur Rust object with type {{ td.ty }}\" << ::std::endl;\n            while (true) raise(SIGSEGV);\n        }\n    }\n\n    inline void __zngur_internal< {{ td.ty }} >::assume_init({{ td.ty }}& t) noexcept {\n        t.drop_flag = true;\n    }\n\n    inline void __zngur_internal< {{ td.ty }} >::assume_deinit({{ td.ty }}& t) noexcept {\n        ::{{ self.namespace }}::__zngur_internal_check_init< {{ td.ty }} >(t);\n        t.drop_flag = false;\n    }\n  {% endif %}\n\n  inline uint8_t* __zngur_internal< {{ td.ty }} >::data_ptr({{ td.ty }} const & t) noexcept {\n    {% if !td.layout.is_stack_allocated() %}\n      return const_cast<uint8_t*>(t.__zngur_data);\n    {% else %}\n      return const_cast<uint8_t*>(t.__zngur_data.data());\n    {% endif %}\n  }\n\n{% endif %}\n\n{% for (index, field) in td.fields.iter().enumerate() %}\n  {% if let ZngurFieldDataOffset::Auto(field_offset_const_name) = field.offset %}\n  template <>\n  struct FieldAutoOffset< {{ td.ty }}, {{ index }} > {\n    static constexpr size_t offset() noexcept { return {{ field_offset_const_name }}; }\n  };\n  {% endif %}\n{% endfor %}\n\n} // namespace {{ self.namespace }}\n\nnamespace {{ self.namespace }} {\n\n  template<>\n  struct RefMut< {{ td.ty }} > {\n  public:\n    RefMut() {\n      __zngur_data = {% if is_unsized %} {0, 0} {% else %} 0 {% endif %};\n    }\n\n    union {\n      {% if is_unsized %}::std::array<size_t, 2> {% else %}size_t{% endif %} __zngur_data;\n\n    {% if !is_unsized && !td.layout.is_only_by_ref() %}\n    {% for (index, field) in td.fields.iter().enumerate() %}\n      ::{{ self.namespace }}::FieldRefMut<\n        {{ field.ty.into_cpp(self.namespace, self.crate_name) }},\n      {% if let Some(offset) = field.offset.as_offset() %}\n        ::{{ self.namespace }}::FieldStaticOffset< {{ td.ty }}, {{ offset }}>\n      {% else %}\n        ::{{ self.namespace }}::FieldAutoOffset< {{ td.ty }}, {{ index }}>\n      {% endif %}\n      > {{ self.cpp_handle_field_name(field.name) }};\n    {% endfor %}\n    {% endif %}\n    };\n\n    {% if !is_unsized && !td.layout.is_only_by_ref() %}\n      RefMut(const {{ td.ty }}& t) {\n        ::{{ self.namespace }}::__zngur_internal_check_init< {{ td.ty }} >(t);\n        __zngur_data = reinterpret_cast<size_t>(__zngur_internal_data_ptr(t));\n      }\n    {% endif %}\n\n    {% if !is_unsized %}\n      // construct a ref from a FieldOwned if it's offset can be calculated at\n      // compile time\n      template <\n          typename Offset,\n          typename... Offsets,\n          typename ::std::enable_if<\n              zngur_detail::all_static_offset<Offset, Offsets...>::value,\n              bool>::type = true>\n      RefMut(const FieldOwned< {{ td.ty }}, Offset, Offsets... >& f) {\n          constexpr bool heap_allocated = __zngur_internal_calc_field<Offset, Offsets...>::heap_allocated();\n          constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n          if (heap_allocated) {\n            __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n          } else {\n\n            __zngur_data = reinterpret_cast<size_t>(&f) + offset;\n          }\n      }\n\n      // construct a ref from a FieldOwned if it's offset can not be calculated at\n      // compile time\n      template <\n          typename Offset,\n          typename... Offsets,\n          typename ::std::enable_if<\n              !zngur_detail::all_static_offset<Offset, Offsets...>::value,\n              bool>::type = true>\n      RefMut(const FieldOwned< {{ td.ty }}, Offset, Offsets... >& f) {\n          constexpr bool heap_allocated = __zngur_internal_calc_field<Offset, Offsets...>::heap_allocated();\n          size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n          if (heap_allocated) {\n            __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n          } else {\n\n            __zngur_data = reinterpret_cast<size_t>(&f) + offset;\n          }\n      }\n\n      // construct a ref from a FieldRefMut if all of it's offsets can be calculated\n      // at compile time\n      template <\n          typename Offset,\n          typename... Offsets,\n          typename ::std::enable_if<\n              zngur_detail::all_static_offset<Offset, Offsets...>::value,\n              bool>::type = true>\n      RefMut(const FieldRefMut< {{ td.ty }}, Offset, Offsets...>& f) {\n          constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n          __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n      }\n\n      // construct a ref from a FieldRefMut if any of it's offsets can not be\n      // calculated at compile time\n      template <\n          typename Offset,\n          typename... Offsets,\n          typename ::std::enable_if<\n              !zngur_detail::all_static_offset<Offset, Offsets...>::value,\n              bool>::type = true>\n      RefMut(const FieldRefMut< {{ td.ty }}, Offset, Offsets...>& f) {\n          size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n          __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n      }\n    {% endif %}\n\n    {{ td.render_make_box_ref(td.ty.path.name(), self.namespace, self.crate_name) }}\n\n    {% if let Some(cpp_value) = td.cpp_value %}\n      inline {{ cpp_value.1 }}& cpp() {\n          return (*{{ cpp_value.0 }}(reinterpret_cast<uint8_t*>(__zngur_data))).as_cpp< {{ cpp_value.1 }} >();\n      }\n    {% endif %}\n\n    {% if let Some(cpp_ref) = td.cpp_ref %}\n      inline {{ cpp_ref.0 }}& cpp() {\n          return *reinterpret_cast< {{ cpp_ref.0 }}* >(__zngur_data);\n      }\n      inline RefMut(const {{ cpp_ref.0 }}& t) : __zngur_data(reinterpret_cast<size_t>(&t)) {}\n    {% endif %}\n\n    {% for method in td.methods %}\n      {% if let ZngurMethodReceiver::Ref(_) = method.kind %}\n        {{ method.sig.output }} {{ method.name }}(\n          {{ splat!(method.sig.inputs.iter().skip(1), |n, ty|, \"{ty}\") }}\n        ) const noexcept ;\n      {% endif %}\n    {% endfor %}\n\n  }; // struct RefMut< {{ td.ty }} >\n\n  template<>\n  struct __zngur_internal< RefMut < {{ td.ty }} > > {\n    static inline uint8_t* data_ptr(const RefMut< {{ td.ty }} >& t) noexcept {\n        return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&t.__zngur_data));\n    }\n    static inline void assume_init(RefMut< {{ td.ty }} >&) noexcept {}\n    static inline void check_init(const RefMut< {{ td.ty }} >&) noexcept {}\n    static inline void assume_deinit(RefMut< {{ td.ty }} >&) noexcept {}\n    static inline size_t size_of() noexcept {\n        return {% if is_unsized %}16{% else %}8{% endif %};\n    }\n  };\n\n} // namespace {{ self.namespace }}\n\n// Ref specialization\n{% if td.ty.path.to_string() == format!(\"::{}::Str\", self.namespace) %}\n    auto operator\"\"_rs(const char* input, size_t len) -> ::{{ self.namespace }}::Ref<::{{ self.namespace }}::Str>;\n{% endif %}\n\nnamespace {{ self.namespace }} {\n\n  template<>\n  struct Ref< {{ td.ty }} > {\n  public:\n    Ref() {\n      __zngur_data = {% if is_unsized %} {0, 0} {% else %} 0 {% endif %};\n    }\n\n    union {\n      {% if is_unsized %}::std::array<size_t, 2>{% else %}size_t{% endif %} __zngur_data;\n\n    {% if !is_unsized && !td.layout.is_only_by_ref() %}\n    {% for (index, field) in td.fields.iter().enumerate() %}\n      ::{{ self.namespace }}::FieldRef<\n        {{ field.ty.into_cpp(self.namespace, self.crate_name) }},\n      {% if let Some(offset) = field.offset.as_offset() %}\n        ::{{ self.namespace }}::FieldStaticOffset< {{ td.ty }}, {{ offset }} >\n      {% else %}\n        ::{{ self.namespace }}::FieldAutoOffset< {{ td.ty }}, {{ index }} >\n      {% endif %}\n      > {{ self.cpp_handle_field_name(field.name) }};\n    {% endfor %}\n    {% endif %}\n    };\n\n    {% if !is_unsized && !td.layout.is_only_by_ref() %}\n    Ref(const {{ td.ty }}& t) {\n      ::{{ self.namespace }}::__zngur_internal_check_init< {{ td.ty }} >(t);\n      __zngur_data = reinterpret_cast<size_t>(__zngur_internal_data_ptr(t));\n    }\n    {% endif %}\n\n      Ref(RefMut< {{ td.ty }} > rm) {\n          __zngur_data = rm.__zngur_data;\n      }\n\n    {% if !is_unsized %}\n      // construct a ref from a FieldOwned if it's offset can be calculated at\n      // compile time\n      template <\n          typename Offset,\n          typename... Offsets,\n          typename ::std::enable_if<\n              zngur_detail::all_static_offset<Offset, Offsets...>::value,\n              bool>::type = true>\n      Ref(const FieldOwned< {{ td.ty }}, Offset, Offsets... >& f) {\n          constexpr bool heap_allocated = __zngur_internal_calc_field<Offset, Offsets...>::heap_allocated();\n          constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n          if (heap_allocated) {\n              __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n          } else {\n              __zngur_data = reinterpret_cast<size_t>(&f) + offset;\n          }\n      }\n\n      // construct a ref from a FieldOwned if it's offset can not be calculated at\n      // compile time\n      template <\n          typename Offset,\n          typename... Offsets,\n          typename ::std::enable_if<\n              !zngur_detail::all_static_offset<Offset, Offsets...>::value,\n              bool>::type = true>\n      Ref(const FieldOwned< {{ td.ty }}, Offset, Offsets... >& f) {\n          constexpr bool heap_allocated = __zngur_internal_calc_field<Offset, Offsets...>::heap_allocated();\n          size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n          if (heap_allocated) {\n              __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n          } else {\n              __zngur_data = reinterpret_cast<size_t>(&f) + offset;\n          }\n      }\n\n      // construct a ref from a FieldRef if all of it's offsets can be calculated\n      // at compile time\n      template <\n          typename Offset,\n          typename... Offsets,\n          typename ::std::enable_if<\n              zngur_detail::all_static_offset<Offset, Offsets...>::value,\n              bool>::type = true>\n      Ref(const FieldRef< {{ td.ty }}, Offset, Offsets...>& f) {\n          constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n          __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n      }\n\n      // construct a ref from a FieldRef if any of it's offsets can not be\n      // calculated at compile time\n      template <\n          typename Offset,\n          typename... Offsets,\n          typename ::std::enable_if<\n              !zngur_detail::all_static_offset<Offset, Offsets...>::value,\n              bool>::type = true>\n      Ref(const FieldRef< {{ td.ty }}, Offset, Offsets...>& f) {\n          size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n          __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n      }\n\n      // construct a ref from a FieldRefMut if all of it's offsets can be calculated\n      // at compile time\n      template <\n          typename Offset,\n          typename... Offsets,\n          typename ::std::enable_if<\n              zngur_detail::all_static_offset<Offset, Offsets...>::value,\n              bool>::type = true>\n      Ref(const FieldRefMut< {{ td.ty }}, Offset, Offsets...>& f) {\n          constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n          __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n      }\n\n      // construct a ref from a FieldRefMut if any of it's offsets can not be\n      // calculated at compile time\n      template <\n          typename Offset,\n          typename... Offsets,\n          typename ::std::enable_if<\n              !zngur_detail::all_static_offset<Offset, Offsets...>::value,\n              bool>::type = true>\n      Ref(const FieldRefMut< {{ td.ty }}, Offset, Offsets...>& f) {\n          size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n          __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n      }\n    {% endif %}\n\n    {{ td.render_make_box_ref_only(td.ty.path.name(), self.namespace, self.crate_name) }}\n\n    {% if let Some(cpp_value) = td.cpp_value %}\n      inline {{ cpp_value.1 }}& cpp() {\n        return (*{{ cpp_value.0 }}(reinterpret_cast<uint8_t*>(__zngur_data))).as_cpp< {{ cpp_value.1 }} >();\n      }\n    {% endif %}\n\n    {% if let Some(cpp_ref) = td.cpp_ref %}\n      inline {{ cpp_ref.0 }}& cpp() {\n        return *reinterpret_cast< {{ cpp_ref.0 }}* >(__zngur_data);\n      }\n      inline Ref(const {{ cpp_ref.0 }}& t) : __zngur_data(reinterpret_cast<size_t>(&t)) {}\n    {% endif %}\n\n    {% for method in td.methods %}\n      {% if method.is_ref_not_mut() %}\n        {{ method.sig.output }} {{ method.name }}({{ method.render_sig_inputs_skip_one() }}) const noexcept ;\n      {% endif %}\n    {% endfor %}\n\n    {% if td.ty.path.to_string() == format!(\"::{}::Str\", &self.namespace) %}\n      friend auto ::operator\"\"_rs(const char* input, size_t len) -> ::{{ self.namespace }}::Ref<::{{ self.namespace }}::Str>;\n    {% endif %}\n};\n\n{% for ref_kind in [\"Ref\", \"Raw\", \"RawMut\"] %}\n\ntemplate<>\nstruct __zngur_internal< {{ ref_kind }} < {{ td.ty }} > > {\n  static inline uint8_t* data_ptr(const {{ ref_kind }} < {{ td.ty }} >& t) noexcept {\n      return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&t.__zngur_data));\n  }\n  static inline void assume_init({{ ref_kind }} < {{ td.ty }} >&) noexcept {}\n  static inline void check_init(const {{ ref_kind }} < {{ td.ty }} >&) noexcept {}\n  static inline void assume_deinit({{ ref_kind }} < {{ td.ty }} >&) noexcept {}\n  static inline size_t size_of() noexcept {\n      return {% if is_unsized %}16{% else %}8{% endif %};\n  }\n};\n\n{% endfor %}\n\n} // namespace {{ self.namespace }}\n\n{% if td.ty.path.to_string() == format!(\"::{}::Str\", self.namespace) %}\n  inline ::{{ self.namespace }}::Ref<::{{ self.namespace }}::Str> operator\"\"_rs(const char* input, size_t len) {\n    ::{{ self.namespace }}::Ref<::{{ self.namespace }}::Str> o;\n    o.__zngur_data[0] = reinterpret_cast<size_t>(input);\n    o.__zngur_data[1] = len;\n    return o;\n  }\n{% endif %}\n\n{% if td.ty.path.to_string() == format!(\"::{}::Char\", self.namespace) %}\n  inline ::{{ self.namespace }}::Char operator\"\"_rs(char32_t c) {\n    if (c > 0x10FFFFu || (c >= 0xD800u && c <= 0xDFFFu)) {\n      return ::{{ self.namespace }}::Char(0xFFFDu);\n    }\n    return ::{{ self.namespace }}::Char(c);\n  }\n{% endif %}\n\n\n{% endfor %}\n\n\n{% for td in self.type_defs %}\n\n  {% let cpp_type = td.ty.to_string() %}\n  {% let name = cpp_type.strip_prefix(\"::\").unwrap() %}\n\n  {% for c in td.constructors %}\n    {% let fn_name = name.to_owned() + \"::\" + td.ty.path.0.last().unwrap() %}\n    {#  do default construction first to ensure allocation  #}\n    inline {{ fn_name }}({{ splat!(&c.inputs, |n, ty|, \"{ty} i{n}\") }}) noexcept : {{ fn_name }}() { \n      ::{{ self.namespace }}::__zngur_internal_assume_init(*this);\n      {{ c.rust_link_name }}(\n        {% for n in 0..c.inputs.len() %}\n          ::{{ self.namespace }}::__zngur_internal_data_ptr(i{{ n }}),\n        {% endfor %}\n        ::{{ self.namespace }}::__zngur_internal_data_ptr(*this)\n      );\n      {% for n in 0..c.inputs.len() %}\n        ::{{ self.namespace }}::__zngur_internal_assume_deinit(i{{ n }});\n      {% endfor %}\n    }\n  {% endfor %}\n\n  {{ self.render_from_trait(td) }}\n  {{ self.render_from_trait_ref(td) }}\n\n  {{ self.render_type_methods(td) }}\n\n\nnamespace {{ self.namespace }} {\n\n  {% for tr in td.wellknown_traits %}\n    {% if let ZngurWellknownTraitData::Debug { pretty_print, debug_print: _ } = tr %}\n      {% if !td.has_unsized() %}\n        template<>\n        struct ZngurPrettyPrinter< {{ td.ty }} > {\n          static inline void print( {{ td.ty }} const& t) {\n            ::{{ self.namespace }}::__zngur_internal_check_init< {{ td.ty }} >(t);\n            {{ pretty_print }}(::{{ self.namespace }}::__zngur_internal_data_ptr(t));\n          }\n        };\n\n        template<>\n        struct ZngurPrettyPrinter< Ref< {{ td.ty }} > > {\n          static inline void print(Ref< {{ td.ty }} > const& t) {\n            ::{{ self.namespace }}::__zngur_internal_check_init< Ref< {{ td.ty }} > >(t);\n            {{ pretty_print }}(reinterpret_cast<uint8_t*>(t.__zngur_data));\n          }\n        };\n\n        template<>\n        struct ZngurPrettyPrinter< RefMut< {{ td.ty }} > > {\n          static inline void print(RefMut< {{ td.ty }} > const& t) {\n            ::{{ self.namespace }}::__zngur_internal_check_init< RefMut< {{ td.ty }} > >(t);\n            {{ pretty_print }}(reinterpret_cast<uint8_t*>(t.__zngur_data));\n          }\n        };\n\n        template<typename Offset, typename... Offsets>\n        struct ZngurPrettyPrinter< FieldOwned< {{ td.ty }}, Offset, Offsets... > > {\n          static inline void print(FieldOwned< {{ td.ty }}, Offset, Offsets... > const& t) {\n            ZngurPrettyPrinter< Ref< {{ td.ty }} > >::print(t);\n          }\n        };\n\n        template<typename Offset, typename... Offsets>\n        struct ZngurPrettyPrinter< FieldRef< {{ td.ty }}, Offset, Offsets... > > {\n          static inline void print(FieldRef< {{ td.ty }}, Offset, Offsets... > const& t) {\n            ZngurPrettyPrinter< Ref< {{ td.ty }} > >::print(t);\n          }\n        };\n\n        template<typename Offset, typename... Offsets>\n        struct ZngurPrettyPrinter< FieldRefMut< {{ td.ty }}, Offset, Offsets... > > {\n          static inline void print(FieldRefMut< {{ td.ty }}, Offset, Offsets... > const& t) {\n            ZngurPrettyPrinter< Ref< {{ td.ty }} > >::print(t);\n          }\n        };\n      {% else %}\n        template<>\n        struct ZngurPrettyPrinter< Ref< {{ td.ty }} > > {\n          static inline void print(Ref< {{ td.ty }} > const& t) {\n            ::{{ self.namespace }}::__zngur_internal_check_init< Ref< {{ td.ty }} > >(t);\n            {{ pretty_print }}(::{{ self.namespace }}::__zngur_internal_data_ptr< Ref< {{ td.ty }} > >(t));\n          }\n        };\n\n        template<>\n        struct ZngurPrettyPrinter< RefMut< {{ td.ty }} > > {\n          static inline void print(RefMut< {{ td.ty }} > const& t) {\n            ::{{ self.namespace }}::__zngur_internal_check_init< RefMut< {{ td.ty }} > >(t);\n            {{ pretty_print }}(::{{ self.namespace }}::__zngur_internal_data_ptr< RefMut< {{ td.ty }} > >(t));\n          }\n        };\n      {% endif %}\n    {% endif %}\n  {% endfor %}\n} // namespace {{ self.namespace }}\n\n{% endfor %}\n\n  {{ self.render_fn_deps() }}\n\nnamespace {{ self.namespace }} {\nnamespace exported_functions {\n\n{% for func in self.exported_fn_defs %}\n  {{ func.sig.output }} {{ func.name }}(\n    {{ splat!(&func.sig.inputs, |n, ty|, \"{ty}\") }}\n  );\n{% endfor %}\n\n} // namespace exported_functions\n\n  {{ self.render_exported_impls() }}\n\n} // namespace {{ self.namespace }}\n"
  },
  {
    "path": "zngur-generator/templates/cpp_source.sptl",
    "content": "#include \"{{ self.header_file_name }}\"\n\nextern \"C\" {\n\n{% for (_, td) in self.trait_defs %}\n  {% if let Some(normal) = td.as_normal() %}\n    {% for method in normal.1 %}\n      void {{ method.rust_link_name }}(\n        uint8_t* data {% for n in 0..method.inputs.len() %}, uint8_t* i{{ n }}{% endfor %}, uint8_t* o\n      ) {\n        {{ normal.0 }}* data_typed = reinterpret_cast< {{ normal.0 }}* >(data);\n        {{ method.output }} oo = data_typed->{{ method.name }}(\n          {{ method.render_inputs(self.cpp_namespace) }}\n        );\n        ::{{ self.cpp_namespace }}::__zngur_internal_move_to_rust(o, oo);\n      }\n    {% endfor %}\n  {% endif %}\n{% endfor %}\n\n{% for func in self.exported_fn_defs %}\n  void {{ func.sig.rust_link_name }}(\n    {% for n in 0..func.sig.inputs.len() %}uint8_t* i{{ n }}, {% endfor %}uint8_t* o\n  ) {\n    {{ func.sig.output }} oo = ::{{ self.cpp_namespace }}::exported_functions::{{ func.name }}(\n      {{ func.sig.render_inputs(self.cpp_namespace) }}\n    );\n    ::{{ self.cpp_namespace }}::__zngur_internal_move_to_rust(o, oo);\n  }\n{% endfor %}\n\n{% for imp in self.exported_impls %}\n  {% for (name, sig) in imp.methods %}\n    void {{ sig.rust_link_name }}(\n      {% for n in 0..sig.inputs.len() %}uint8_t* i{{ n }}, {% endfor %}uint8_t* o\n    ) {\n      {{ sig.output }} oo = ::{{ self.cpp_namespace }}::Impl< {{ imp.ty }}, {{ imp.render_tr(self.cpp_namespace) }} >::{{ name }}(\n        {{ sig.render_inputs(self.cpp_namespace) }}\n      );\n      ::{{ self.cpp_namespace }}::__zngur_internal_move_to_rust(o, oo);\n    }\n  {% endfor %}\n{% endfor %}\n\n} // extern \"C\"\n"
  },
  {
    "path": "zngur-generator/templates/zng_header.sptl",
    "content": "{# #language:cpp #}\n\n#ifndef __ZNG_HEADER_INTERNAL_TYPES\n#define __ZNG_HEADER_INTERNAL_TYPES\n\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n#include <csignal>\n#include <array>\n#include <iostream>\n#include <functional>\n#include <math.h>\n#include <type_traits>\n\n{% if self.panic_to_exception %}\n  namespace {{ self.cpp_namespace }} {\n      class Panic {};\n  }\n  inline thread_local bool __zngur_rust_panicked_flag(false);\n\n#ifdef _MSC_VER\n    // MSVC: Functions use standard inline. Variables use selectany to prevent \n    // multiple-definition errors when included in multiple .cpp files.\n    #define ZNGUR_FFI_EXPORT_FUNC extern \"C\" inline\n    #define ZNGUR_FFI_EXPORT_VAR  extern \"C\" __declspec(selectany)\n#elif defined(__GNUC__) || defined(__clang__)\n    // GCC/Clang: 'used' prevents the linker from stripping them. 'weak' on \n    // the variable tells the linker to merge multiple definitions into one.\n    #define ZNGUR_FFI_EXPORT_FUNC extern \"C\" inline __attribute__((used))\n    #define ZNGUR_FFI_EXPORT_VAR  extern \"C\" __attribute__((weak, used))\n#else\n    #define ZNGUR_FFI_EXPORT_FUNC extern \"C\" inline\n    #define ZNGUR_FFI_EXPORT_VAR  extern \"C\"\n#endif\n\n  ZNGUR_FFI_EXPORT_FUNC void __zngur_mark_panicked() {\n    // TODO: While thread safe, you may end up with the wrong thread being\n    // notified of a panic\n    __zngur_rust_panicked_flag = true;\n  }\n  ZNGUR_FFI_EXPORT_FUNC bool __zngur_read_and_reset_rust_panic() {\n    bool out = __zngur_rust_panicked_flag;\n    __zngur_rust_panicked_flag = false;\n    return out;\n  }\n\n  // Force compilers that don't have `__attribute__((used))` to still export the functions by keeping\n  // function pointers.\n  ZNGUR_FFI_EXPORT_VAR void (* const __keep_zngur_mark_panicked)() = &__zngur_mark_panicked;\n  ZNGUR_FFI_EXPORT_VAR bool (* const __keep_zngur_read_and_reset_panic)() = &__zngur_read_and_reset_rust_panic;\n{% endif %}\n\n#ifndef zngur_dbg\n#define zngur_dbg(x) (::{{ self.cpp_namespace }}::zngur_dbg_impl(__FILE__, __LINE__, #x, x))\n#endif // zngur_dbg\n\nnamespace {{ self.cpp_namespace }} {\n\n  inline void* __zng_memcpy( void* dest, const void* src, std::size_t count ){\n    if (count > 0) {\n\t\treturn memcpy(dest, src, count);\n\t}\n\treturn dest;\n  }\n\n\n  template<typename T>\n  struct __zngur_internal {\n    static inline uint8_t* data_ptr(const T& t) noexcept;\n    static void assume_init(T& t) noexcept ;\n    static void assume_deinit(T& t) noexcept ;\n    static inline void check_init(const T&) noexcept;\n    static inline size_t size_of() noexcept ;\n  };\n\n  template<typename T>\n  inline uint8_t* __zngur_internal_data_ptr(const T& t) noexcept {\n    return __zngur_internal<T>::data_ptr(t);\n  }\n\n  template<typename T>\n  void __zngur_internal_assume_init(T& t) noexcept {\n    __zngur_internal<T>::assume_init(t);\n  }\n\n  template<typename T>\n  void __zngur_internal_assume_deinit(T& t) noexcept {\n    __zngur_internal<T>::assume_deinit(t);\n  }\n\n  template<typename T>\n  inline size_t __zngur_internal_size_of() noexcept {\n    return __zngur_internal<T>::size_of();\n  }\n\n  template<typename T>\n  inline void __zngur_internal_move_to_rust(uint8_t* dst, T& t) noexcept {\n    __zng_memcpy(dst, ::{{ self.cpp_namespace }}::__zngur_internal_data_ptr(t), ::{{ self.cpp_namespace }}::__zngur_internal_size_of<T>());\n    ::{{ self.cpp_namespace }}::__zngur_internal_assume_deinit(t);\n  }\n\n  template<typename T>\n  inline T __zngur_internal_move_from_rust(uint8_t* src) noexcept {\n    T t;\n    ::{{ self.cpp_namespace }}::__zngur_internal_assume_init(t);\n    __zng_memcpy(::{{ self.cpp_namespace }}::__zngur_internal_data_ptr(t), src, ::{{ self.cpp_namespace }}::__zngur_internal_size_of<T>());\n    return t;\n  }\n\n  template<typename T>\n  inline void __zngur_internal_check_init(const T& t) noexcept {\n    __zngur_internal<T>::check_init(t);\n  }\n\n  class ZngurCppOpaqueOwnedObject {\n    uint8_t* __zngur_data;\n    void (*destructor)(uint8_t*);\n\n  public:\n    template<typename T, typename... Args>\n    inline static ZngurCppOpaqueOwnedObject build(Args&&... args) {\n        ZngurCppOpaqueOwnedObject o;\n        o.__zngur_data = reinterpret_cast<uint8_t*>(new T(::std::forward<Args>(args)...));\n        o.destructor = [](uint8_t* d) {\n            delete reinterpret_cast<T*>(d);\n        };\n        return o;\n    }\n\n    template<typename T>\n    inline T& as_cpp() { return *reinterpret_cast<T *>(__zngur_data); }\n  };\n\n  template<typename T>\n  struct Ref;\n\n  template<typename T>\n  struct RefMut;\n\n\n  // offset encoded in type\n  template <typename Parent, size_t OFFSET>\n  struct FieldStaticOffset {};\n\n  // specialized per type to acquire offset from `extern const size_t`\n  template <typename Parent, size_t INDEX>\n  struct FieldAutoOffset {\n      static size_t offset() noexcept;\n  };\n\n  // specialize to record allocation strategy into type system\n  template <typename T>\n  struct zngur_heap_allocated : ::std::false_type {};\n\n  namespace zngur_detail {\n    // std::conjunction analog for c++11 support\n    template <typename... Conds>\n    struct conjunction : std::true_type {};\n\n    template <typename Cond, typename... Conds>\n    struct conjunction<Cond, Conds...>\n        : std::conditional<Cond::value, conjunction<Conds...>,\n                          std::false_type>::type {};\n\n    // Offset can be computed at compile time\n    template <typename...>\n    struct is_static_offset : std::false_type {};\n\n    // a static offset not behind a pointer can be computed\n    template <typename Parent, size_t OFFSET>\n    struct is_static_offset<FieldStaticOffset<Parent, OFFSET>>\n        : std::true_type {};\n\n    // All offsets can be compile time computed\n    template <typename First, typename... Rest>\n    using all_static_offset =\n        conjunction<is_static_offset<First>, is_static_offset<Rest>...>;\n  \n  }  // namespace zngur_detail\n\n  template <typename T>\n  struct __zngur_internal_field {\n      // offset for this type and offset\n      static constexpr size_t offset();\n      // is this offset behind a pointer\n      static constexpr bool heap_allocated();\n  };\n\n  template <typename Parent, size_t OFFSET>\n  struct __zngur_internal_field<FieldStaticOffset<Parent, OFFSET>> {\n      static constexpr size_t offset() { return OFFSET; }\n      static constexpr bool heap_allocated() { return zngur_heap_allocated<Parent>::value; }\n  };\n\n  template <typename Parent, size_t INDEX>\n  struct __zngur_internal_field<FieldAutoOffset<Parent, INDEX>> {\n      static size_t offset() {\n          return FieldAutoOffset<Parent, INDEX>::offset();\n      }\n      static constexpr bool heap_allocated() { return zngur_heap_allocated<Parent>::value; }\n  };\n\n  // NOTE: Offsets are in reverse order, last offset first.\n  // this allows offsets to be prepended in versions of c++ that don't have fold \n  // expressions (pre c++17)\n  template <typename... Offsets>\n  struct __zngur_internal_calc_field {\n      // used to statically calculate a total offset\n      static constexpr size_t offset();\n      // used to check if the owner of the first offset is heap allocated\n      static constexpr bool heap_allocated();\n  };\n\n  // base case\n  template <typename Offset>\n  struct __zngur_internal_calc_field<Offset> {\n      static constexpr size_t offset() {\n          return __zngur_internal_field<Offset>::offset();\n      }\n      static constexpr bool heap_allocated() {\n          return __zngur_internal_field<Offset>::heap_allocated();\n      }\n  };\n\n  // recursively calculate offsets for Fields\n  template <typename LastOffset, typename PrevOffset, typename... Offsets>\n  struct __zngur_internal_calc_field<LastOffset, PrevOffset, Offsets...> {\n      static constexpr size_t offset() {\n          return __zngur_internal_calc_field<PrevOffset, Offsets...>::offset() +\n                __zngur_internal_field<LastOffset>::offset();\n      }\n      static constexpr bool heap_allocated() {\n          return __zngur_internal_calc_field<PrevOffset, Offsets...>::heap_allocated();\n      }\n  };\n\n  template<typename T, typename Offset, typename... Offsets>\n  struct FieldOwned {\n    inline operator T() const noexcept { return *::{{ self.cpp_namespace }}::Ref<T>(*this); }\n  };\n\n  template<typename T, typename Offset, typename... Offsets>\n  struct FieldRef {\n    inline operator T() const noexcept { return *::{{ self.cpp_namespace }}::Ref<T>(*this); }\n  };\n\n  template<typename T, typename Offset, typename... Offsets>\n  struct FieldRefMut {\n    inline operator T() const noexcept { return *::{{ self.cpp_namespace }}::Ref<T>(*this); }\n  };\n\n#if __cplusplus >= 201703L\n  // deduction guides\n  template<typename T, typename Offset, typename... Offsets>\n  Ref(const FieldOwned<T, Offset, Offsets...> &f) -> Ref<T>;\n  template<typename T, typename Offset, typename... Offsets>\n  Ref(const FieldRef<T, Offset, Offsets...> &f) -> Ref<T>;\n  template<typename T, typename Offset, typename... Offsets>\n  Ref(const FieldRefMut<T, Offset, Offsets...> &f) -> Ref<T>;\n  template<typename T, typename Offset, typename... Offsets>\n  RefMut(const FieldOwned<T, Offset, Offsets...> &f) -> RefMut<T>;\n  template<typename T, typename Offset, typename... Offsets>\n  RefMut(const FieldRef<T, Offset, Offsets...> &f) -> RefMut<T>;\n  template<typename T, typename Offset, typename... Offsets>\n  RefMut(const FieldRefMut<T, Offset, Offsets...> &f) -> RefMut<T>;\n#endif\n\n  template<typename T>\n  struct zngur_is_unsized : ::std::false_type {};\n  struct zngur_fat_pointer {\n    uint8_t* __zngur_data;\n    size_t metadata;\n  };\n  template<typename T>\n  struct Raw {\n      using DataType = typename ::std::conditional< zngur_is_unsized<T>::value, zngur_fat_pointer, uint8_t* >::type;\n      DataType __zngur_data;\n      Raw() {}\n      Raw(Ref<T> value) {\n          __zng_memcpy(&__zngur_data, __zngur_internal_data_ptr<Ref<T>>(value), __zngur_internal_size_of<Ref<T>>());\n      }\n      Raw(RefMut<T> value) {\n          __zng_memcpy(&__zngur_data, __zngur_internal_data_ptr<RefMut<T>>(value), __zngur_internal_size_of<RefMut<T>>());\n      }\n      Raw(DataType data) : __zngur_data(data) {\n      }\n      Raw<T> offset(ptrdiff_t n) {\n          return Raw(__zngur_data + n * __zngur_internal_size_of<T>());\n      }\n      Ref<T> read_ref() {\n          Ref<T> value;\n          __zng_memcpy(__zngur_internal_data_ptr<Ref<T>>(value), &__zngur_data, __zngur_internal_size_of<Ref<T>>());\n          __zngur_internal_assume_init<Ref<T>>(value);\n          return value;\n      }\n  };\n  template<typename T>\n  struct RawMut {\n      using DataType = typename ::std::conditional< zngur_is_unsized<T>::value, zngur_fat_pointer, uint8_t* >::type;\n      DataType __zngur_data;\n      RawMut() {}\n      RawMut(RefMut<T> value) {\n          __zng_memcpy(&__zngur_data, __zngur_internal_data_ptr<RefMut<T>>(value), __zngur_internal_size_of<RefMut<T>>());\n      }\n      RawMut(DataType data) : __zngur_data(data) {\n      }\n      RawMut<T> offset(ptrdiff_t n) {\n          return RawMut(__zngur_data + n * __zngur_internal_size_of<T>());\n      }\n      T read() {\n          T value;\n          __zng_memcpy(__zngur_internal_data_ptr<T>(value), __zngur_data, __zngur_internal_size_of<T>());\n          __zngur_internal_assume_init<T>(value);\n          return value;\n      }\n      Ref<T> read_ref() {\n          Ref<T> value;\n          __zng_memcpy(__zngur_internal_data_ptr<Ref<T>>(value), &__zngur_data, __zngur_internal_size_of<Ref<T>>());\n          __zngur_internal_assume_init<Ref<T>>(value);\n          return value;\n      }\n      RefMut<T> read_mut() {\n          RefMut<T> value;\n          __zng_memcpy(__zngur_internal_data_ptr<RefMut<T>>(value), &__zngur_data, __zngur_internal_size_of<RefMut<T>>());\n          __zngur_internal_assume_init<RefMut<T>>(value);\n          return value;\n      }\n      void write(T value) {\n          __zng_memcpy(__zngur_data, __zngur_internal_data_ptr<T>(value), __zngur_internal_size_of<T>());\n          __zngur_internal_assume_deinit<T>(value);\n      }\n  };\n  template<typename... T>\n  struct Tuple;\n\n  template<> struct Tuple<  > {\n    public:\n      union alignas(1) {\n        alignas(1) mutable ::std::array< ::uint8_t, 0> __zngur_data;\n      };\n  };\n\n  using Unit = Tuple<>;\n\n  template<>\n  struct __zngur_internal< ::{{ self.cpp_namespace }}::Unit > {\n    static inline uint8_t* data_ptr(const ::{{ self.cpp_namespace }}::Unit& t) noexcept {\n        return const_cast<uint8_t*>(t.__zngur_data.data());\n    }\n    static inline void check_init(const ::{{ self.cpp_namespace }}::Unit&) noexcept {}\n    static inline void assume_init(::{{ self.cpp_namespace }}::Unit&) noexcept {}\n    static inline void assume_deinit(::{{ self.cpp_namespace }}::Unit&) noexcept {}\n    static inline size_t size_of() noexcept { return 0; }\n  };\n\n  template<>\n  struct RefMut< ::{{ self.cpp_namespace }}::Unit > {\n  public:\n    RefMut() { __zngur_data = 0; }\n    union { size_t __zngur_data; };\n    RefMut(const ::{{ self.cpp_namespace }}::Unit& t) {\n      __zngur_data = reinterpret_cast<size_t>(__zngur_internal_data_ptr(t));\n    }\n    template <typename Offset, typename... Offsets, typename ::std::enable_if<zngur_detail::is_static_offset<Offset, Offsets...>::value, bool>::type = true>\n    RefMut(const FieldOwned< ::{{ self.cpp_namespace }}::Unit, Offset, Offsets... >& f) {\n        constexpr bool heap_allocated = __zngur_internal_calc_field<Offset, Offsets...>::heap_allocated();\n        constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n        if (heap_allocated) { __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset; }\n        else { __zngur_data = reinterpret_cast<size_t>(&f) + offset; }\n    }\n    template <typename Offset, typename... Offsets, typename ::std::enable_if<!zngur_detail::is_static_offset<Offset, Offsets...>::value, bool>::type = true>\n    RefMut(const FieldOwned< ::{{ self.cpp_namespace }}::Unit, Offset, Offsets... >& f) {\n        constexpr bool heap_allocated = __zngur_internal_calc_field<Offset, Offsets...>::heap_allocated();\n        size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n        if (heap_allocated) { __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset; }\n        else { __zngur_data = reinterpret_cast<size_t>(&f) + offset; }\n    }\n    template <typename Offset, typename... Offsets, typename ::std::enable_if<zngur_detail::all_static_offset<Offset, Offsets...>::value, bool>::type = true>\n    RefMut(const FieldRefMut< ::{{ self.cpp_namespace }}::Unit, Offset, Offsets...>& f) {\n        constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n        __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n    template <typename Offset, typename... Offsets, typename ::std::enable_if<!zngur_detail::all_static_offset<Offset, Offsets...>::value, bool>::type = true>\n    RefMut(const FieldRefMut< ::{{ self.cpp_namespace }}::Unit, Offset, Offsets...>& f) {\n        size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n        __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n  };\n\n  template<>\n  struct __zngur_internal< RefMut < ::{{ self.cpp_namespace }}::Unit > > {\n    static inline uint8_t* data_ptr(const RefMut< ::{{ self.cpp_namespace }}::Unit >& t) noexcept {\n        return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&t.__zngur_data));\n    }\n    static inline void assume_init(RefMut< ::{{ self.cpp_namespace }}::Unit >&) noexcept {}\n    static inline void check_init(const RefMut< ::{{ self.cpp_namespace }}::Unit >&) noexcept {}\n    static inline void assume_deinit(RefMut< ::{{ self.cpp_namespace }}::Unit >&) noexcept {}\n    static inline size_t size_of() noexcept { return 8; }\n  };\n\n  template<>\n  struct Ref< ::{{ self.cpp_namespace }}::Unit > {\n  public:\n    Ref() { __zngur_data = 0; }\n    union { size_t __zngur_data; };\n    Ref(const ::{{ self.cpp_namespace }}::Unit& t) {\n      __zngur_data = reinterpret_cast<size_t>(__zngur_internal_data_ptr(t));\n    }\n    Ref(RefMut< ::{{ self.cpp_namespace }}::Unit > rm) { __zngur_data = rm.__zngur_data; }\n    template <typename Offset, typename... Offsets, typename ::std::enable_if<zngur_detail::is_static_offset<Offset, Offsets...>::value, bool>::type = true>\n    Ref(const FieldOwned< ::{{ self.cpp_namespace }}::Unit, Offset, Offsets... >& f) {\n        constexpr bool heap_allocated = __zngur_internal_calc_field<Offset, Offsets...>::heap_allocated();\n        constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n        if (heap_allocated) { __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset; }\n        else { __zngur_data = reinterpret_cast<size_t>(&f) + offset; }\n    }\n    template <typename Offset, typename... Offsets, typename ::std::enable_if<!zngur_detail::is_static_offset<Offset, Offsets...>::value, bool>::type = true>\n    Ref(const FieldOwned< ::{{ self.cpp_namespace }}::Unit, Offset, Offsets... >& f) {\n        constexpr bool heap_allocated = __zngur_internal_calc_field<Offset, Offsets...>::heap_allocated();\n        size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n        if (heap_allocated) { __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset; }\n        else { __zngur_data = reinterpret_cast<size_t>(&f) + offset; }\n    }\n    template <typename Offset, typename... Offsets, typename ::std::enable_if<zngur_detail::all_static_offset<Offset, Offsets...>::value, bool>::type = true>\n    Ref(const FieldRef< ::{{ self.cpp_namespace }}::Unit, Offset, Offsets...>& f) {\n        constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n        __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n    template <typename Offset, typename... Offsets, typename ::std::enable_if<!zngur_detail::all_static_offset<Offset, Offsets...>::value, bool>::type = true>\n    Ref(const FieldRef< ::{{ self.cpp_namespace }}::Unit, Offset, Offsets...>& f) {\n        size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n        __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n    template <typename Offset, typename... Offsets, typename ::std::enable_if<zngur_detail::all_static_offset<Offset, Offsets...>::value, bool>::type = true>\n    Ref(const FieldRefMut< ::{{ self.cpp_namespace }}::Unit, Offset, Offsets...>& f) {\n        constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n        __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n    template <typename Offset, typename... Offsets, typename ::std::enable_if<!zngur_detail::all_static_offset<Offset, Offsets...>::value, bool>::type = true>\n    Ref(const FieldRefMut< ::{{ self.cpp_namespace }}::Unit, Offset, Offsets...>& f) {\n        size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n        __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n  };\n\n  template<>\n  struct __zngur_internal< Ref < ::{{ self.cpp_namespace }}::Unit > > {\n    static inline uint8_t* data_ptr(const Ref < ::{{ self.cpp_namespace }}::Unit >& t) noexcept { return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&t.__zngur_data)); }\n    static inline void assume_init(Ref < ::{{ self.cpp_namespace }}::Unit >&) noexcept {}\n    static inline void check_init(const Ref < ::{{ self.cpp_namespace }}::Unit >&) noexcept {}\n    static inline void assume_deinit(Ref < ::{{ self.cpp_namespace }}::Unit >&) noexcept {}\n    static inline size_t size_of() noexcept { return 8; }\n  };\n\n  template<>\n  struct __zngur_internal< Raw < ::{{ self.cpp_namespace }}::Unit > > {\n    static inline uint8_t* data_ptr(const Raw < ::{{ self.cpp_namespace }}::Unit >& t) noexcept { return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&t.__zngur_data)); }\n    static inline void assume_init(Raw < ::{{ self.cpp_namespace }}::Unit >&) noexcept {}\n    static inline void check_init(const Raw < ::{{ self.cpp_namespace }}::Unit >&) noexcept {}\n    static inline void assume_deinit(Raw < ::{{ self.cpp_namespace }}::Unit >&) noexcept {}\n    static inline size_t size_of() noexcept { return 8; }\n  };\n\n  template<>\n  struct __zngur_internal< RawMut < ::{{ self.cpp_namespace }}::Unit > > {\n    static inline uint8_t* data_ptr(const RawMut < ::{{ self.cpp_namespace }}::Unit >& t) noexcept { return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&t.__zngur_data)); }\n    static inline void assume_init(RawMut < ::{{ self.cpp_namespace }}::Unit >&) noexcept {}\n    static inline void check_init(const RawMut < ::{{ self.cpp_namespace }}::Unit >&) noexcept {}\n    static inline void assume_deinit(RawMut < ::{{ self.cpp_namespace }}::Unit >&) noexcept {}\n    static inline size_t size_of() noexcept { return 8; }\n  };\n\n  template<typename T>\n  struct ZngurPrettyPrinter;\n\n  class Inherent;\n\n  template<typename Type, typename Trait = Inherent>\n  class Impl;\n\n  template<typename T>\n  T&& zngur_dbg_impl(const char* file_name, int line_number, const char* exp, T&& input) {\n    ::std::cerr << \"[\" << file_name << \":\" << line_number << \"] \" << exp << \" = \";\n    ZngurPrettyPrinter<typename ::std::remove_reference<T>::type>::print(input);\n    return ::std::forward<T>(input);\n  }\n\n  // specializations for Refs of Refs\n{% for ref_kind in [\"Ref\",  \"RefMut\"] %}\n  {% for nested_ref_kind in [\"Ref\", \"RefMut\"] %}\n\n  template<typename T>\n  struct {{ ref_kind }} < {{ nested_ref_kind }} < T > > {\n    {{ ref_kind }}() {\n      __zngur_data = 0;\n    }\n\n    {{ ref_kind }}(const {{ nested_ref_kind }} < T >& t) {\n      __zngur_data = reinterpret_cast<size_t>(__zngur_internal_data_ptr(t));\n    }\n    \n    // construct a ref from a FieldOwned if it's offset can be calculated at\n    // compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    {{ ref_kind }}(const FieldOwned< {{ nested_ref_kind }} < T >, Offset, Offsets... >& f) {\n      constexpr bool heap_allocated = __zngur_internal_calc_field<Offset, Offsets...>::heap_allocated();\n      constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      if (heap_allocated) {\n        __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n      } else {\n        __zngur_data = reinterpret_cast<size_t>(&f) + offset;\n      }\n    }\n\n    // construct a ref from a FieldOwned if it's offset can not be calculated at\n    // compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            !zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    {{ ref_kind }}(const FieldOwned< {{ nested_ref_kind }} < T >, Offset, Offsets... >& f) {\n      constexpr bool heap_allocated = __zngur_internal_calc_field<Offset, Offsets...>::heap_allocated();\n      size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      if (heap_allocated) {\n        __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n      } else {\n        __zngur_data = reinterpret_cast<size_t>(&f) + offset;\n      }\n    }\n\n    {% if self.is_ref_kind_ref(ref_kind) %}\n    // construct a ref from a FieldRef if all of it's offsets can be calculated\n    // at compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    {{ ref_kind }}(const FieldRef< {{ nested_ref_kind }} < T >, Offset, Offsets...>& f) {\n      constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n\n    // construct a ref from a FieldRef if any of it's offsets can not be\n    // calculated at compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            !zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    {{ ref_kind }}(const FieldRef< {{ nested_ref_kind }} < T >, Offset, Offsets...>& f) {\n      size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n    {% endif %}\n\n    // construct a ref from a FieldRefMut if all of it's offsets can be calculated\n    // at compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    {{ ref_kind }}(const FieldRefMut< {{ nested_ref_kind }} < T >, Offset, Offsets...>& f) {\n      constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n\n    // construct a ref from a FieldRefMut if any of it's offsets can not be\n    // calculated at compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            !zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    {{ ref_kind }}(const FieldRefMut< {{ nested_ref_kind }} < T >, Offset, Offsets...>& f) {\n      size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n\n    {{ nested_ref_kind }}< T >& operator*() {\n      return *reinterpret_cast< {{ nested_ref_kind }} < T >*>(__zngur_data);\n    }\n    {{ nested_ref_kind }}< T > const& operator*() const {\n      return *reinterpret_cast< {{ nested_ref_kind }} < T >*>(__zngur_data);\n    }\n\n  private:\n    size_t __zngur_data;\n    friend ::{{ self.cpp_namespace }}::__zngur_internal< {{ ref_kind }} < {{ nested_ref_kind }} < T > > >;\n    friend ::{{ self.cpp_namespace }}::ZngurPrettyPrinter< {{ ref_kind }} < {{ nested_ref_kind }} < T > > >;\n\n  };\n\n  template<typename T>\n  struct __zngur_internal< {{ ref_kind }} < {{ nested_ref_kind }} < T > > > {\n    static inline uint8_t* data_ptr(const {{ ref_kind }} < {{ nested_ref_kind }} < T > >& t) noexcept {\n        return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&t.__zngur_data));\n    }\n    static inline void assume_init({{ ref_kind }} < {{ nested_ref_kind }} < T > >&) noexcept {}\n\n    static inline void check_init(const {{ ref_kind }} < {{ nested_ref_kind }} < T > >&) noexcept {}\n\n    static inline void assume_deinit({{ ref_kind }} < {{ nested_ref_kind }} < T > >&) noexcept {}\n\n    static inline size_t size_of() noexcept {\n        return __zngur_internal_size_of< {{ nested_ref_kind }} < T > >({});\n    }\n  };\n\n  template<typename T>\n  struct ZngurPrettyPrinter< {{ ref_kind }} < {{ nested_ref_kind }} < T > > > {\n    static inline void print({{ ref_kind }} < {{ nested_ref_kind }} < T > > const& t) {\n      ::{{ self.cpp_namespace }}::__zngur_internal_check_init(t);\n      ::{{ self.cpp_namespace }}::ZngurPrettyPrinter< {{ nested_ref_kind }} < T > >::print( reinterpret_cast< const {{ nested_ref_kind }} < T > &>(t.__zngur_data) );\n    }\n  };\n\n  {% endfor %}\n{% endfor %}\n\n{% for ty in self.builtin_types() %}\n  {% let needs_endif = self.is_size_t(ty) %}\n  {% if needs_endif %}\n    #if defined(__APPLE__) || defined(__wasm__)\n  {% endif %}\n\n  template<>\n  struct __zngur_internal< {{ ty }} > {\n    static inline uint8_t* data_ptr(const {{ ty }}& t) noexcept {\n      return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&t));\n    }\n    static inline void assume_init({{ ty }}&) noexcept {}\n    static inline void assume_deinit({{ ty }}&) noexcept {}\n    static inline void check_init({{ ty }}&) noexcept {}\n    static inline size_t size_of() noexcept {\n      return sizeof({{ ty }});\n    }\n  };\n\n  template<>\n  struct __zngur_internal< {{ ty }}* > {\n    static inline uint8_t* data_ptr({{ ty }}* const & t) noexcept {\n      return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&t));\n    }\n    static inline void assume_init({{ ty }}*&) noexcept {}\n    static inline void assume_deinit({{ ty }}*&) noexcept {}\n    static inline void check_init({{ ty }}*&) noexcept {}\n    static inline size_t size_of() noexcept {\n      return sizeof({{ ty }});\n    }\n  };\n\n  template<>\n  struct __zngur_internal< {{ ty }} const* > {\n    static inline uint8_t* data_ptr({{ ty }} const* const & t) noexcept {\n      return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&t));\n    }\n    static inline void assume_init({{ ty }} const*&) noexcept {}\n    static inline void assume_deinit({{ ty }} const*&) noexcept {}\n    static inline void check_init({{ ty }} const*&) noexcept {}\n    static inline size_t size_of() noexcept {\n      return sizeof({{ ty }});\n    }\n  };\n\n\n  template<>\n  struct Ref< {{ ty }} > {\n    Ref() {\n      __zngur_data = 0;\n    }\n\n    Ref(const {{ ty }}& t) {\n      __zngur_data = reinterpret_cast<size_t>(__zngur_internal_data_ptr(t));\n    }\n\n    // construct a ref from a FieldOwned if all of it's offsets can be calculated at\n    // compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    Ref(const FieldOwned< {{ ty }}, Offset, Offsets... >& f) {\n      constexpr bool heap_allocated = __zngur_internal_calc_field<Offset, Offsets...>::heap_allocated();\n      constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      if (heap_allocated) {\n        __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n      } else {\n        __zngur_data = reinterpret_cast<size_t>(&f) + offset;\n      }\n    }\n\n    // construct a ref from a FieldOwned if any of it's offsets can not be calculated at\n    // compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            !zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    Ref(const FieldOwned< {{ ty }}, Offset, Offsets... >& f) {\n      constexpr bool heap_allocated = __zngur_internal_calc_field<Offset, Offsets...>::heap_allocated();\n      size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      if (heap_allocated) {\n        __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n      } else {\n        __zngur_data = reinterpret_cast<size_t>(&f) + offset;\n      }\n    }\n\n    // construct a ref from a FieldRef if all of it's offsets can be calculated\n    // at compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    Ref(const FieldRef< {{ ty }}, Offset, Offsets...>& f) {\n      constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n\n    // construct a ref from a FieldRef if any of it's offsets can not be\n    // calculated at compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            !zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    Ref(const FieldRef< {{ ty }}, Offset, Offsets...>& f) {\n        size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n        __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n\n    // construct a ref from a FieldRefMut if all of it's offsets can be calculated\n    // at compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    Ref(const FieldRefMut< {{ ty }}, Offset, Offsets...>& f) {\n      constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n\n    // construct a ref from a FieldRefMut if any of it's offsets can not be\n    // calculated at compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            !zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    Ref(const FieldRefMut< {{ ty }}, Offset, Offsets...>& f) {\n      size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n\n    {{ ty }}& operator*() {\n      return *reinterpret_cast< {{ ty }}*>(__zngur_data);\n    }\n\n    {{ ty }} const& operator*() const {\n      return *reinterpret_cast< {{ ty }}*>(__zngur_data);\n    }\n\n  private:\n    size_t __zngur_data;\n    friend ::{{ self.cpp_namespace }}::__zngur_internal<Ref< {{ ty }} > >;\n    friend ::{{ self.cpp_namespace }}::ZngurPrettyPrinter< Ref< {{ ty }} > >;\n\n  };\n\n  template<>\n  struct RefMut< {{ ty }} > {\n    RefMut() {\n      __zngur_data = 0;\n    }\n\n    RefMut({{ ty }}& t) {\n      __zngur_data = reinterpret_cast<size_t>(__zngur_internal_data_ptr(t));\n    }\n\n    // construct a ref from a FieldOwned if all of it's offsets can be calculated at\n    // compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    RefMut(const FieldOwned< {{ ty }}, Offset, Offsets... >& f) {\n      constexpr bool heap_allocated = __zngur_internal_calc_field<Offset, Offsets...>::heap_allocated();\n      constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      if (heap_allocated) {\n        __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n      } else {\n        __zngur_data = reinterpret_cast<size_t>(&f) + offset;\n      }\n    }\n\n    // construct a ref from a FieldOwned if any of it's offsets can not be calculated at\n    // compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            !zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    RefMut(const FieldOwned< {{ ty }}, Offset, Offsets... >& f) {\n      constexpr bool heap_allocated = __zngur_internal_calc_field<Offset, Offsets...>::heap_allocated();\n      size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      if (heap_allocated) {\n        __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n      } else {\n        __zngur_data = reinterpret_cast<size_t>(&f) + offset;\n      }\n    }\n\n    // construct a ref from a FieldRefMut if all of it's offsets can be calculated\n    // at compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    RefMut(const FieldRefMut< {{ ty }}, Offset, Offsets...>& f) {\n      constexpr size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n\n    // construct a ref from a FieldRefMut if any of it's offsets can not be\n    // calculated at compile time\n    template <\n        typename Offset,\n        typename... Offsets,\n        typename ::std::enable_if<\n            !zngur_detail::all_static_offset<Offset, Offsets...>::value,\n            bool>::type = true>\n    RefMut(const FieldRefMut< {{ ty }}, Offset, Offsets...>& f) {\n      size_t offset = __zngur_internal_calc_field<Offset, Offsets...>::offset();\n      __zngur_data = *reinterpret_cast<const size_t*>(&f) + offset;\n    }\n\n    {{ ty }}& operator*() {\n        return *reinterpret_cast< {{ ty }}*>(__zngur_data);\n    }\n\n    {{ ty }} const& operator*() const {\n        return *reinterpret_cast< {{ ty }}*>(__zngur_data);\n    }\n  private:\n    size_t __zngur_data;\n    friend ::{{ self.cpp_namespace }}::__zngur_internal<RefMut< {{ ty }} > >;\n    friend ::{{ self.cpp_namespace }}::ZngurPrettyPrinter< Ref< {{ ty }} > >;\n  };\n\n  {% let printable = self.is_printable(ty) %}\n  {% if printable %}\n    template<>\n    struct ZngurPrettyPrinter< {{ ty }} > {\n      static inline void print({{ ty }} const& t) {\n        ::std::cerr << t << ::std::endl;\n      }\n    };\n    template<>\n    struct ZngurPrettyPrinter< Ref< {{ ty }} > > {\n      static inline void print(Ref< {{ ty }} > const& t) {\n        ::std::cerr << *t << ::std::endl;\n      }\n    };\n    template<>\n    struct ZngurPrettyPrinter< RefMut< {{ ty }} > > {\n      static inline void print(RefMut< {{ ty }} > const& t) {\n        ::std::cerr << *t << ::std::endl;\n      }\n    };\n  {% endif %}\n\n  {% if needs_endif %}\n    #endif\n  {% endif %}\n\n// end builtin types\n{% endfor %}\n\n} // namespace {{ self.cpp_namespace }}\n\n#endif // __ZNG_HEADER_INTERNAL_TYPES\n"
  },
  {
    "path": "zngur-parser/Cargo.toml",
    "content": "[package]\nname = \"zngur-parser\"\ndescription = \"Parser of the zng file\"\nreadme = \"../README.md\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nariadne = \"0.3.0\"\nchumsky = { version = \"=1.0.0-alpha.8\", features = [] }\nitertools = \"0.11\"\nzngur-def = { version = \"=0.9.0\", path = \"../zngur-def\" }\n\n[dev-dependencies]\nexpect-test = \"1.4.1\"\nstrip-ansi-escapes = \"0.2.0\"\n"
  },
  {
    "path": "zngur-parser/src/cfg.rs",
    "content": "use std::collections::{HashMap, HashSet};\n\nuse crate::{\n    ParseContext, Span, Spanned, Token, ZngParser,\n    conditional::{MatchPattern, MatchPatternParse, Matchable, MatchableParse},\n    spanned,\n};\nuse chumsky::prelude::*;\n\n/// A configuration provider, Must be Clone.\npub trait RustCfgProvider: CloneableCfg {\n    /// Gets values associated with a config key if it's present.\n    fn get_cfg(&self, key: &str) -> Option<Vec<String>>;\n    /// Gets a list of feature names that are enabled\n    fn get_features(&self) -> Vec<String>;\n    /// Gets all config key:value pairs\n    ///\n    /// Returns a pair for every value of a key, if a key has no values emits a\n    /// (key, None) pair\n    fn get_cfg_pairs(&self) -> Vec<(String, Option<String>)>;\n}\n\npub trait CloneableCfg {\n    fn clone_box(&self) -> Box<dyn RustCfgProvider>;\n}\n\nimpl<T> CloneableCfg for T\nwhere\n    T: 'static + RustCfgProvider + Clone,\n{\n    fn clone_box(&self) -> Box<dyn RustCfgProvider> {\n        Box::new(self.clone())\n    }\n}\n\n#[derive(Copy, Clone)]\npub struct NullCfg;\n\nimpl RustCfgProvider for NullCfg {\n    fn get_cfg(&self, _key: &str) -> Option<Vec<String>> {\n        None\n    }\n    fn get_features(&self) -> Vec<String> {\n        Vec::new()\n    }\n    fn get_cfg_pairs(&self) -> Vec<(String, Option<String>)> {\n        Vec::new()\n    }\n}\n\n#[derive(Clone)]\npub struct InMemoryRustCfgProvider {\n    cfg: HashMap<String, Vec<String>>,\n}\n\nconst CARGO_FEATURE_PREFIX: &str = \"CARGO_FEATURE_\";\nconst CARGO_CFG_PREFIX: &str = \"CARGO_CFG_\";\n\nimpl InMemoryRustCfgProvider {\n    pub fn new() -> Self {\n        InMemoryRustCfgProvider {\n            cfg: HashMap::new(),\n        }\n    }\n\n    pub fn with_values<'a, CfgPairs, CfgKey, CfgValues>(mut self, cfg_values: CfgPairs) -> Self\n    where\n        CfgPairs: IntoIterator<Item = (CfgKey, CfgValues)>,\n        CfgKey: AsRef<str> + 'a,\n        CfgValues: Clone + IntoIterator + 'a,\n        <CfgValues as IntoIterator>::Item: AsRef<str>,\n    {\n        for (key, values) in cfg_values {\n            let entry = self.cfg.entry(key.as_ref().to_string()).or_default();\n            let values = values.clone().into_iter().map(|v| v.as_ref().to_string());\n            entry.reserve(values.size_hint().0);\n            for value in values {\n                if !entry.contains(&value) {\n                    entry.push(value);\n                }\n            }\n        }\n        self\n    }\n\n    pub fn load_from_cargo_env(mut self) -> Self {\n        // set to unify features that can appear in two locations\n        let mut features = HashSet::new();\n        for (k, v) in std::env::vars_os() {\n            // no panic if not unicode\n            let (Some(k), Some(v)) = (k.to_str(), v.to_str()) else {\n                continue;\n            };\n            if let Some(feature) = k.strip_prefix(CARGO_FEATURE_PREFIX) {\n                features.insert(feature.to_lowercase());\n            } else if let Some(key) = k.strip_prefix(CARGO_CFG_PREFIX) {\n                let key = key.to_lowercase();\n                let values: Vec<String> = v.split(\",\").map(str::to_owned).collect();\n                if key == \"feature\" {\n                    features.extend(values);\n                } else {\n                    let entry = self.cfg.entry(key.to_string()).or_default();\n                    entry.reserve(values.len());\n                    for value in values {\n                        if !entry.contains(&value) {\n                            entry.push(value);\n                        }\n                    }\n                }\n            }\n        }\n        if !features.is_empty() {\n            let features_entry = self.cfg.entry(\"feature\".to_string()).or_default();\n            features_entry.reserve(features.len());\n            features_entry.extend(features);\n        }\n        self\n    }\n}\n\nimpl Default for InMemoryRustCfgProvider {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl RustCfgProvider for InMemoryRustCfgProvider {\n    fn get_cfg(&self, key: &str) -> Option<Vec<String>> {\n        self.cfg.get(key).map(|values| values.to_vec())\n    }\n    fn get_features(&self) -> Vec<String> {\n        self.cfg.get(\"feature\").cloned().unwrap_or_default()\n    }\n    fn get_cfg_pairs(&self) -> Vec<(String, Option<String>)> {\n        self.cfg\n            .iter()\n            .flat_map(|(key, values)| {\n                if values.is_empty() {\n                    vec![(key.clone(), None)]\n                } else {\n                    values\n                        .iter()\n                        .map(|value| (key.clone(), Some(value.clone())))\n                        .collect()\n                }\n            })\n            .collect()\n    }\n}\n\n#[derive(Debug, Copy, Clone, PartialEq, Eq)]\npub(crate) enum CfgScrutinee<'src> {\n    Key(&'src str),\n    KeyWithItem(&'src str, &'src str),\n    Feature(&'src str),\n    AllFeatures,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub(crate) enum ProcessedCfgScrutinee {\n    Empty,\n    Some,\n    Values(Vec<String>),\n}\n#[derive(Debug, Clone, PartialEq, Eq)]\npub(crate) enum ProcessedCfgConditional {\n    Single(ProcessedCfgScrutinee),\n    Tuple(Vec<ProcessedCfgScrutinee>),\n}\n\n/// Match on config keys and features\n#[derive(Debug, Clone, PartialEq, Eq)]\npub(crate) enum CfgConditional<'src> {\n    Single(CfgScrutinee<'src>),\n    Tuple(Vec<CfgScrutinee<'src>>),\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub(crate) enum CfgPatternItem<'src> {\n    Empty, // a `_` pattern\n    Some,  // the config has \"some\" value for the key\n    None,  // the config has \"no\" value for the key\n    Str(&'src str),\n    Number(usize),\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub(crate) enum CfgPattern<'src> {\n    Single(CfgPatternItem<'src>, Span),\n    And(Vec<CfgPattern<'src>>, Span),\n    Or(Vec<CfgPattern<'src>>, Span),\n    Not(Box<CfgPattern<'src>>, Span),\n    Grouped(Box<CfgPattern<'src>>, Span),\n    Tuple(Vec<CfgPattern<'src>>, Span),\n}\n\nimpl<'src> MatchPattern for CfgPattern<'src> {\n    fn default_some(span: Span) -> Self {\n        CfgPattern::Single(CfgPatternItem::Some, span)\n    }\n}\nimpl<'src> MatchPatternParse<'src> for CfgPattern<'src> {\n    fn parser() -> impl ZngParser<'src, Self> {\n        let single = recursive(|pat| {\n            let literals = select! {\n                Token::Str(c) => CfgPatternItem::Str(c),\n                Token::Number(n) => CfgPatternItem::Number(n),\n            };\n            let atom = choice((\n                spanned(literals),\n                spanned(just(Token::Underscore).to(CfgPatternItem::Empty)),\n                spanned(just(Token::Ident(\"Some\")).to(CfgPatternItem::Some)),\n                spanned(just(Token::Ident(\"None\")).to(CfgPatternItem::None)),\n            ))\n            .map(|item| CfgPattern::Single(item.inner, item.span))\n            .or(spanned(\n                pat.delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),\n            )\n            .map(|item| CfgPattern::Grouped(Box::new(item.inner), item.span)));\n\n            let not_pat = just(Token::Bang)\n                .repeated()\n                .foldr_with(atom, |_op, rhs, e| CfgPattern::Not(Box::new(rhs), e.span()));\n\n            let and_pat = not_pat.clone().foldl_with(\n                just(Token::And).ignore_then(not_pat).repeated(),\n                |lhs, rhs, e| match lhs {\n                    CfgPattern::And(mut items, _span) => {\n                        items.push(rhs);\n                        CfgPattern::And(items, e.span())\n                    }\n                    _ => CfgPattern::And(vec![lhs, rhs], e.span()),\n                },\n            );\n\n            // or pat\n            and_pat.clone().foldl_with(\n                just(Token::Pipe).ignore_then(and_pat).repeated(),\n                |lhs, rhs, e| match lhs {\n                    CfgPattern::Or(mut items, _span) => {\n                        items.push(rhs);\n                        CfgPattern::Or(items, e.span())\n                    }\n                    _ => CfgPattern::Or(vec![lhs, rhs], e.span()),\n                },\n            )\n        });\n\n        spanned(\n            single\n                .clone()\n                .separated_by(just(Token::Comma))\n                .at_least(1)\n                .collect::<Vec<_>>()\n                .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),\n        )\n        .map(|item| CfgPattern::Tuple(item.inner, item.span))\n        .or(single)\n    }\n}\n\nimpl<'src> Matchable for CfgConditional<'src> {\n    type Pattern = CfgPattern<'src>;\n\n    fn eval(&self, pattern: &Self::Pattern, ctx: &mut ParseContext) -> bool {\n        let cfg = ctx.get_config_provider();\n\n        let process = |key: &CfgScrutinee<'src>| -> ProcessedCfgScrutinee {\n            match key {\n                CfgScrutinee::Key(key) => cfg\n                    .get_cfg(key)\n                    .map(|values| {\n                        if values.is_empty() {\n                            ProcessedCfgScrutinee::Some\n                        } else {\n                            ProcessedCfgScrutinee::Values(values)\n                        }\n                    })\n                    .unwrap_or(ProcessedCfgScrutinee::Empty),\n                CfgScrutinee::KeyWithItem(key, item) => cfg\n                    .get_cfg(key)\n                    .and_then(|values| {\n                        values\n                            .iter()\n                            .any(|value| value == item)\n                            .then_some(ProcessedCfgScrutinee::Some)\n                    })\n                    .unwrap_or(ProcessedCfgScrutinee::Empty),\n                CfgScrutinee::AllFeatures => ProcessedCfgScrutinee::Values(cfg.get_features()),\n                CfgScrutinee::Feature(feature) => {\n                    if cfg.get_features().iter().any(|value| value == feature) {\n                        ProcessedCfgScrutinee::Some\n                    } else {\n                        ProcessedCfgScrutinee::Empty\n                    }\n                }\n            }\n        };\n\n        let scrutinee = match self {\n            Self::Single(key) => ProcessedCfgConditional::Single(process(key)),\n            Self::Tuple(keys) => {\n                ProcessedCfgConditional::Tuple(keys.iter().map(process).collect::<Vec<_>>())\n            }\n        };\n\n        pattern.matches(&scrutinee, ctx)\n    }\n}\n\nimpl<'src> CfgScrutinee<'src> {\n    fn parser() -> impl ZngParser<'src, Self> {\n        select! {Token::Ident(c) => c, Token::Str(s) => s}\n            .separated_by(just(Token::Dot))\n            .at_least(1)\n            .at_most(2)\n            .collect::<Vec<_>>()\n            .map(|item| {\n                match &item[..] {\n                    [key] if key == &\"feature\" => CfgScrutinee::AllFeatures,\n                    [key, item] if key == &\"feature\" => CfgScrutinee::Feature(item),\n                    [key] => CfgScrutinee::Key(key),\n                    [key, item] => CfgScrutinee::KeyWithItem(key, item),\n                    // the above at_least(1) and at_most(2) calls\n                    // prevent this branch\n                    _ => unreachable!(),\n                }\n            })\n    }\n}\n\nimpl<'src> MatchableParse<'src> for CfgConditional<'src> {\n    fn parser() -> impl ZngParser<'src, Self> {\n        let directive = just([Token::Ident(\"cfg\"), Token::Bang]).ignore_then(\n            CfgScrutinee::parser().delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),\n        );\n\n        choice((\n            directive.clone().map(CfgConditional::Single),\n            directive\n                .separated_by(just(Token::Comma))\n                .allow_trailing()\n                .at_least(1)\n                .collect::<Vec<_>>()\n                .map(CfgConditional::Tuple)\n                .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),\n        ))\n    }\n\n    fn combined() -> Option<\n        crate::BoxedZngParser<\n            'src,\n            (\n                crate::Spanned<Self>,\n                crate::Spanned<<Self as Matchable>::Pattern>,\n            ),\n        >,\n    > {\n        let directive = just([Token::Ident(\"cfg\"), Token::Bang])\n            .ignore_then(\n                spanned(CfgScrutinee::parser())\n                    .then(\n                        just(Token::Eq)\n                            .ignore_then(spanned(CfgPattern::parser()))\n                            .or_not(),\n                    )\n                    .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),\n            )\n            .map_with(|(scrutinee, pat), e| {\n                (\n                    scrutinee,\n                    pat.unwrap_or_else(|| Spanned {\n                        inner: CfgPattern::default_some(e.span()),\n                        span: e.span(),\n                    }),\n                )\n            });\n        Some(\n            directive\n                .clone()\n                .map(|(scrutinee, pat)| {\n                    (\n                        Spanned {\n                            inner: CfgConditional::Single(scrutinee.inner),\n                            span: scrutinee.span,\n                        },\n                        pat,\n                    )\n                })\n                .boxed(),\n        )\n    }\n}\n\nimpl CfgPattern<'_> {\n    fn matches(&self, scrutinee: &ProcessedCfgConditional, ctx: &mut ParseContext) -> bool {\n        use ProcessedCfgConditional as PCC;\n        match (self, scrutinee) {\n            (Self::Tuple(pats, _), PCC::Single(_)) if pats.len() == 1 => {\n                let pat = pats.iter().last().unwrap();\n                // tuple is actually single\n                pat.matches(scrutinee, ctx)\n            }\n            (Self::Single(pat, _), PCC::Tuple(scrutinees)) if scrutinees.len() == 1 => {\n                let scrutinee = scrutinees.iter().last().unwrap();\n                // tuple is actually single\n                pat.matches(scrutinee)\n            }\n            (Self::Single(CfgPatternItem::Empty, _), PCC::Tuple(_)) => {\n                // empty pattern matches anything\n                true\n            }\n            (Self::Tuple(_, span), PCC::Single(_)) => {\n                ctx.add_error_str(\n                    \"Can not match tuple pattern against a single cfg value.\",\n                    *span,\n                );\n                false\n            }\n            (\n                Self::Single(_, span)\n                | Self::Not(_, span)\n                | Self::And(_, span)\n                | Self::Or(_, span)\n                | Self::Grouped(_, span),\n                PCC::Tuple(_),\n            ) => {\n                ctx.add_error_str(\n                    \"Can not match single pattern against multiple cfg values.\",\n                    *span,\n                );\n                false\n            }\n            (Self::Tuple(pats, span), PCC::Tuple(scrutinees)) => {\n                if scrutinees.len() != pats.len() {\n                    ctx.add_error_str(\n                        \"Number of patterns and number of scrutinees do not match.\",\n                        *span,\n                    );\n                    false\n                } else {\n                    pats.iter()\n                        .zip(scrutinees.iter())\n                        .all(|(pat, scrutinee)| pat.matches(&PCC::Single(scrutinee.clone()), ctx))\n                }\n            }\n            (Self::Single(pat, _), PCC::Single(scrutinee)) => pat.matches(scrutinee),\n            (Self::Grouped(pat, _), PCC::Single(_)) => pat.matches(scrutinee, ctx),\n            (Self::Not(pat, _), PCC::Single(_)) => !pat.matches(scrutinee, ctx),\n            (Self::And(pats, _), PCC::Single(_)) => {\n                pats.iter().all(|pat| pat.matches(scrutinee, ctx))\n            }\n            (Self::Or(pats, _), PCC::Single(_)) => {\n                pats.iter().any(|pat| pat.matches(scrutinee, ctx))\n            }\n        }\n    }\n}\n\nimpl CfgPatternItem<'_> {\n    fn matches(&self, scrutinee: &ProcessedCfgScrutinee) -> bool {\n        use ProcessedCfgScrutinee as PCS;\n        match self {\n            Self::Empty => true,\n            Self::Some => !matches!(scrutinee, PCS::Empty),\n            Self::None => matches!(scrutinee, PCS::Empty),\n            Self::Str(v) => match &scrutinee {\n                PCS::Empty | PCS::Some => false,\n                PCS::Values(values) => values.iter().any(|value| value == v),\n            },\n            Self::Number(n) => match &scrutinee {\n                PCS::Empty | PCS::Some => false,\n                PCS::Values(values) => values\n                    .iter()\n                    .any(|value| value.parse::<usize>().map(|v| v == *n).unwrap_or(false)),\n            },\n        }\n    }\n}\n"
  },
  {
    "path": "zngur-parser/src/conditional.rs",
    "content": "use crate::{BoxedZngParser, ParseContext, Span, Spanned, Token, ZngParser, spanned};\nuse chumsky::prelude::*;\n\n/// a type that can be matched against a Pattern\npub trait Matchable: core::fmt::Debug + Clone + PartialEq + Eq {\n    /// A pattern type to match Self against\n    type Pattern: MatchPattern;\n    /// compare self to `Pattern`\n    fn eval(&self, pattern: &Self::Pattern, ctx: &mut ParseContext) -> bool;\n}\n\n/// a type that can be matched against a Pattern\npub(crate) trait MatchableParse<'src>: Matchable {\n    /// return a parser for the item as it would appear in an `#if` or `#match` statement\n    fn parser() -> impl ZngParser<'src, Self>;\n\n    /// return an optional combined parser for use in `#if` statements\n    #[allow(clippy::complexity)]\n    fn combined()\n    -> Option<BoxedZngParser<'src, (Spanned<Self>, Spanned<<Self as Matchable>::Pattern>)>> {\n        None\n    }\n}\n\npub trait MatchPattern: core::fmt::Debug + Clone + PartialEq + Eq {\n    /// a pattern that matches the existence of \"some\" value\n    fn default_some(span: crate::Span) -> Self;\n}\n\n/// a Pattern that can be matched against\npub(crate) trait MatchPatternParse<'src>: MatchPattern {\n    /// return a parser for for the pattern\n    fn parser() -> impl ZngParser<'src, Self>;\n}\n\npub trait BodyItem: core::fmt::Debug + Clone + PartialEq + Eq {\n    /// The type Self turns into when added into the Spec\n    type Processed;\n\n    /// Transform self into `Processed` type\n    fn process(self, ctx: &mut ParseContext) -> Self::Processed;\n}\n\n/// a type that hold the body of a conditional statement\npub trait ConditionBody<Pattern: MatchPattern, Item: BodyItem>: core::fmt::Debug {\n    /// the pattern that guards this body\n    fn pattern(&self) -> &Pattern;\n}\n\n/// a trait that marks the Cardinality of items inside a body (One? or Many?)\npub trait ConditionBodyCardinality<Item: BodyItem>:\n    core::fmt::Debug + Clone + PartialEq + Eq\n{\n    /// the type that hold the body of the conditional statement\n    type Body<Pattern: MatchPattern>: ConditionBody<Pattern, Item> + Clone + PartialEq + Eq;\n    /// the type that holds the items in the body of a conditional statement\n    type Block: core::fmt::Debug + Clone + PartialEq + Eq + IntoIterator<Item = Spanned<Item>>;\n    /// the type that hold the items of a passing body\n    type EvalResult: IntoIterator<Item = Spanned<<Item as BodyItem>::Processed>>;\n    /// transform a single item into Self::Block\n    fn single_to_block(item: Spanned<Item>) -> Self::Block;\n    /// create a new empty Self::Bock\n    fn empty_block() -> Self::Block;\n    /// create a new Self::Body from a block and the pattern that guards it\n    fn new_body<Pattern: MatchPattern>(\n        pattern: Spanned<Pattern>,\n        block: Self::Block,\n    ) -> Self::Body<Pattern>;\n    /// transform a block into it's processed result\n    fn pass_block(block: &Self::Block, ctx: &mut ParseContext) -> Self::EvalResult;\n    /// transform a body into it's processed result\n    fn pass_body<Pattern: MatchPattern>(\n        body: &Self::Body<Pattern>,\n        ctx: &mut ParseContext,\n    ) -> Self::EvalResult;\n}\n\n/// a trait for a conditional item in a parsed spec\npub trait ConditionalItem<Item: BodyItem, Cardinality: ConditionBodyCardinality<Item>> {\n    /// Evaluate the statement and produce resulting items of the first arm that passes\n    fn eval(&self, ctx: &mut ParseContext) -> Option<Cardinality::EvalResult>;\n}\n\n/// a body of a conditional statement that holds 0..N Items\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct ConditionBodyMany<Pattern: MatchPattern, Item: BodyItem> {\n    pub pattern: Spanned<Pattern>,\n    pub block: Vec<Spanned<Item>>,\n}\n\n/// a body of a conditional statement that holds 0..1 items\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct ConditionBodySingle<Pattern: MatchPattern, Item: BodyItem> {\n    pub pattern: Spanned<Pattern>,\n    pub block: Option<Spanned<Item>>,\n}\n\nimpl<Pattern: MatchPattern, Item: BodyItem> ConditionBody<Pattern, Item>\n    for ConditionBodyMany<Pattern, Item>\n{\n    fn pattern(&self) -> &Pattern {\n        &self.pattern.inner\n    }\n}\n\nimpl<Pattern: MatchPattern, Item: BodyItem> ConditionBody<Pattern, Item>\n    for ConditionBodySingle<Pattern, Item>\n{\n    fn pattern(&self) -> &Pattern {\n        &self.pattern.inner\n    }\n}\n\n/// Marker type for a conditional statement that contextually only accepts one item\n#[derive(Debug, Copy, Clone, PartialEq, Eq)]\npub struct SingleItem;\n\nimpl<Item: BodyItem> ConditionBodyCardinality<Item> for SingleItem {\n    type Body<Pattern: MatchPattern> = ConditionBodySingle<Pattern, Item>;\n    type Block = Option<Spanned<Item>>;\n    type EvalResult = Option<Spanned<<Item as BodyItem>::Processed>>;\n\n    fn single_to_block(item: Spanned<Item>) -> Self::Block {\n        Some(item)\n    }\n\n    fn empty_block() -> Self::Block {\n        None\n    }\n\n    fn new_body<Pattern: MatchPattern>(\n        pattern: Spanned<Pattern>,\n        block: Self::Block,\n    ) -> Self::Body<Pattern> {\n        ConditionBodySingle { pattern, block }\n    }\n\n    fn pass_block(block: &Self::Block, ctx: &mut ParseContext) -> Self::EvalResult {\n        block.clone().map(|item| {\n            let span = item.span;\n            Spanned {\n                span,\n                inner: item.inner.process(ctx),\n            }\n        })\n    }\n\n    fn pass_body<Pattern: MatchPattern>(\n        body: &Self::Body<Pattern>,\n        ctx: &mut ParseContext,\n    ) -> Self::EvalResult {\n        Self::pass_block(&body.block, ctx)\n    }\n}\n\n/// Marker type for a conditional statement that contextually accepts any number of items\n#[derive(Debug, Copy, Clone, PartialEq, Eq)]\npub struct NItems;\n\nimpl<Item: BodyItem> ConditionBodyCardinality<Item> for NItems {\n    type Body<Pattern: MatchPattern> = ConditionBodyMany<Pattern, Item>;\n    type Block = Vec<Spanned<Item>>;\n    type EvalResult = Vec<Spanned<<Item as BodyItem>::Processed>>;\n\n    fn single_to_block(item: Spanned<Item>) -> Self::Block {\n        vec![item]\n    }\n\n    fn empty_block() -> Self::Block {\n        Vec::new()\n    }\n\n    fn new_body<Pattern: MatchPattern>(\n        pattern: Spanned<Pattern>,\n        block: Self::Block,\n    ) -> Self::Body<Pattern> {\n        ConditionBodyMany { pattern, block }\n    }\n\n    fn pass_block(block: &Self::Block, ctx: &mut ParseContext) -> Self::EvalResult {\n        block\n            .iter()\n            .cloned()\n            .map(|item| {\n                let span = item.span;\n                Spanned {\n                    span,\n                    inner: item.inner.process(ctx),\n                }\n            })\n            .collect()\n    }\n\n    fn pass_body<Pattern: MatchPattern>(\n        body: &Self::Body<Pattern>,\n        ctx: &mut ParseContext,\n    ) -> Self::EvalResult {\n        Self::pass_block(&body.block, ctx)\n    }\n}\n\n/// a guard for an #if statement\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum ConditionGuard<Scrutinee: Matchable> {\n    Single {\n        scrutinee: Spanned<Scrutinee>,\n        pattern: Spanned<<Scrutinee as Matchable>::Pattern>,\n        span: Span,\n    },\n    And(Vec<ConditionGuard<Scrutinee>>, Span),\n    Or(Vec<ConditionGuard<Scrutinee>>, Span),\n    Not(Box<ConditionGuard<Scrutinee>>, Span),\n    Grouped(Box<ConditionGuard<Scrutinee>>, Span),\n}\n\nimpl<Scrutinee: Matchable> ConditionGuard<Scrutinee> {\n    fn eval(&self, ctx: &mut ParseContext) -> bool {\n        match self {\n            Self::Single {\n                scrutinee, pattern, ..\n            } => scrutinee.inner.eval(&pattern.inner, ctx),\n            Self::And(items, _) => items.iter().all(|item| item.eval(ctx)),\n            Self::Or(items, _) => items.iter().any(|item| item.eval(ctx)),\n            Self::Not(item, _) => !item.eval(ctx),\n            Self::Grouped(item, _) => item.eval(ctx),\n        }\n    }\n}\n\n/// a branch of an `#if` statement\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct ConditionBranch<\n    Scrutinee: Matchable,\n    Item: BodyItem,\n    Cardinality: ConditionBodyCardinality<Item>,\n> {\n    pub guard: ConditionGuard<Scrutinee>,\n    pub block: <Cardinality as ConditionBodyCardinality<Item>>::Block,\n}\n\n/// a complete `#if {} #else if #else {}` statement\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct ConditionIf<\n    Scrutinee: Matchable,\n    Item: BodyItem,\n    Cardinality: ConditionBodyCardinality<Item>,\n> {\n    pub arms: Vec<ConditionBranch<Scrutinee, Item, Cardinality>>,\n    pub fallback: Option<Cardinality::Block>,\n}\n\n/// a `#match` statement\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct ConditionMatch<\n    Scrutinee: Matchable,\n    Item: BodyItem,\n    Cardinality: ConditionBodyCardinality<Item>,\n> {\n    pub scrutinee: Spanned<Scrutinee>,\n    pub arms: Vec<\n        Spanned<\n            <Cardinality as ConditionBodyCardinality<Item>>::Body<\n                <Scrutinee as Matchable>::Pattern,\n            >,\n        >,\n    >,\n}\n\nimpl<Scrutinee: Matchable, Item: BodyItem, Cardinality: ConditionBodyCardinality<Item>>\n    ConditionalItem<Item, Cardinality> for ConditionBranch<Scrutinee, Item, Cardinality>\n{\n    fn eval(\n        &self,\n        ctx: &mut ParseContext,\n    ) -> Option<<Cardinality as ConditionBodyCardinality<Item>>::EvalResult> {\n        if self.guard.eval(ctx) {\n            return Some(<Cardinality as ConditionBodyCardinality<Item>>::pass_block(\n                &self.block,\n                ctx,\n            ));\n        }\n        None\n    }\n}\n\nimpl<Scrutinee: Matchable, Item: BodyItem, Cardinality: ConditionBodyCardinality<Item>>\n    ConditionalItem<Item, Cardinality> for ConditionMatch<Scrutinee, Item, Cardinality>\n{\n    fn eval(\n        &self,\n        ctx: &mut ParseContext,\n    ) -> Option<<Cardinality as ConditionBodyCardinality<Item>>::EvalResult> {\n        for arm in &self.arms {\n            let pattern = arm.inner.pattern();\n            if self.scrutinee.inner.eval(pattern, ctx) {\n                return Some(<Cardinality as ConditionBodyCardinality<Item>>::pass_body(\n                    &arm.inner, ctx,\n                ));\n            }\n        }\n        None\n    }\n}\n\nimpl<Scrutinee: Matchable, Item: BodyItem, Cardinality: ConditionBodyCardinality<Item>>\n    ConditionalItem<Item, Cardinality> for ConditionIf<Scrutinee, Item, Cardinality>\n{\n    fn eval(\n        &self,\n        ctx: &mut ParseContext,\n    ) -> Option<<Cardinality as ConditionBodyCardinality<Item>>::EvalResult> {\n        for arm in &self.arms {\n            if let Some(result) = arm.eval(ctx) {\n                return Some(result);\n            }\n        }\n        if let Some(fallback) = &self.fallback {\n            return Some(<Cardinality as ConditionBodyCardinality<Item>>::pass_block(\n                fallback, ctx,\n            ));\n        }\n        None\n    }\n}\n\n/// a conditional item behind an if or match statement\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum Condition<\n    Scrutinee: Matchable,\n    Item: BodyItem,\n    Cardinality: ConditionBodyCardinality<Item>,\n> {\n    If(ConditionIf<Scrutinee, Item, Cardinality>),\n    Match(ConditionMatch<Scrutinee, Item, Cardinality>),\n}\n\nimpl<Scrutinee: Matchable, Item: BodyItem, Cardinality: ConditionBodyCardinality<Item>>\n    ConditionalItem<Item, Cardinality> for Condition<Scrutinee, Item, Cardinality>\n{\n    fn eval(\n        &self,\n        ctx: &mut ParseContext,\n    ) -> Option<<Cardinality as ConditionBodyCardinality<Item>>::EvalResult> {\n        match self {\n            Self::If(item) => item.eval(ctx),\n            Self::Match(item) => item.eval(ctx),\n        }\n    }\n}\n\n/// a trait that helps build combined parsers for ConditionalItem's that accept `#if {} #else {}` or `#match`\npub trait Conditional<'src, Item: BodyItem, Cardinality: ConditionBodyCardinality<Item>> {\n    type Scrutinee: MatchableParse<'src>;\n    fn if_parser(\n        item_parser: impl ZngParser<'src, Item> + 'src,\n    ) -> BoxedZngParser<'src, Condition<Self::Scrutinee, Item, Cardinality>>;\n    fn match_parser(\n        item_parser: impl ZngParser<'src, Item> + 'src,\n    ) -> BoxedZngParser<'src, Condition<Self::Scrutinee, Item, Cardinality>>;\n}\n\n/// a parser for a block used in a SingleItemBody\npub fn block_for_single<'src, Item: BodyItem>(\n    item_parser: impl ZngParser<'src, Item>,\n) -> impl ZngParser<'src, Option<Spanned<Item>>> {\n    spanned(item_parser)\n        .repeated()\n        .at_most(1)\n        .collect::<Vec<_>>()\n        .map(|items| {\n            // should be 1 or zero because of `.at_most(1)`\n            items.into_iter().next()\n        })\n}\n\n/// a parser for a block used in a ManyItemBody\npub fn block_for_many<'src, Item: BodyItem>(\n    item_parser: impl ZngParser<'src, Item>,\n) -> impl ZngParser<'src, Vec<Spanned<Item>>> {\n    spanned(item_parser).repeated().collect::<Vec<_>>()\n}\n\n/// parser for a guarded block used in `#if`\npub fn guarded_block<\n    'src,\n    Scrutinee: MatchableParse<'src> + 'src,\n    Item: BodyItem,\n    Cardinality: ConditionBodyCardinality<Item>,\n>(\n    block: impl ZngParser<'src, Cardinality::Block>,\n) -> impl ZngParser<'src, ConditionBranch<Scrutinee, Item, Cardinality>>\nwhere\n    <Scrutinee as Matchable>::Pattern: MatchPatternParse<'src>,\n{\n    let guard = recursive(|guard| {\n        let single = if let Some(combined) = <Scrutinee as MatchableParse<'src>>::combined() {\n            combined\n        } else {\n            spanned(<Scrutinee as MatchableParse<'src>>::parser())\n                .then(\n                    just(Token::Eq)\n                        .ignore_then(spanned(\n                            <<Scrutinee as Matchable>::Pattern as MatchPatternParse<'src>>::parser(\n                            ),\n                        ))\n                        .or_not()\n                        .map_with(|pat, e| {\n                            pat.unwrap_or_else(|| Spanned {\n                                inner: <Scrutinee as Matchable>::Pattern::default_some(e.span()),\n                                span: e.span(),\n                            })\n                        }),\n                )\n                .boxed()\n        }\n        .map_with(|(scrutinee, pattern), e| ConditionGuard::Single {\n            scrutinee,\n            pattern,\n            span: e.span(),\n        })\n        .or(\n            spanned(guard.delimited_by(just(Token::ParenOpen), just(Token::ParenClose)))\n                .map(|item| ConditionGuard::Grouped(Box::new(item.inner), item.span)),\n        );\n\n        let not_pat = just(Token::Bang)\n            .repeated()\n            .foldr_with(single, |_op, rhs, e| {\n                ConditionGuard::Not(Box::new(rhs), e.span())\n            });\n\n        let and_pat = not_pat.clone().foldl_with(\n            just([Token::And, Token::And])\n                .ignore_then(not_pat)\n                .repeated(),\n            |lhs, rhs, e| match lhs {\n                ConditionGuard::And(mut items, _span) => {\n                    items.push(rhs);\n                    ConditionGuard::And(items, e.span())\n                }\n                _ => ConditionGuard::And(vec![lhs, rhs], e.span()),\n            },\n        );\n\n        // or pat\n        and_pat.clone().foldl_with(\n            just([Token::Pipe, Token::Pipe])\n                .ignore_then(and_pat)\n                .repeated(),\n            |lhs, rhs, e| match lhs {\n                ConditionGuard::Or(mut items, _span) => {\n                    items.push(rhs);\n                    ConditionGuard::Or(items, e.span())\n                }\n                _ => ConditionGuard::Or(vec![lhs, rhs], e.span()),\n            },\n        )\n    });\n\n    guard\n        .then(block.delimited_by(just(Token::BraceOpen), just(Token::BraceClose)))\n        .map(move |(guard, block)| ConditionBranch { guard, block })\n}\n\n/// parser for an `#if {} #else if {} #else {}` statement\npub fn if_stmnt<\n    'src,\n    Scrutinee: MatchableParse<'src>,\n    Item: BodyItem,\n    Cardinality: ConditionBodyCardinality<Item>,\n>(\n    guard: impl ZngParser<'src, ConditionBranch<Scrutinee, Item, Cardinality>>,\n    fallback: impl ZngParser<'src, Cardinality::Block>,\n) -> impl ZngParser<'src, ConditionIf<Scrutinee, Item, Cardinality>>\nwhere\n    <Scrutinee as Matchable>::Pattern: MatchPatternParse<'src>,\n{\n    just([Token::Sharp, Token::KwIf])\n        .ignore_then(guard.clone())\n        .then(\n            just([Token::Sharp, Token::KwElse, Token::KwIf])\n                .ignore_then(guard)\n                .repeated()\n                .collect::<Vec<_>>()\n                .or_not(),\n        )\n        .then(\n            just([Token::Sharp, Token::KwElse])\n                .ignore_then(fallback.delimited_by(just(Token::BraceOpen), just(Token::BraceClose)))\n                .or_not(),\n        )\n        .map(|((if_block, else_if_blocks), else_block)| {\n            let mut arms: Vec<ConditionBranch<Scrutinee, Item, Cardinality>> = vec![if_block];\n            arms.extend(else_if_blocks.unwrap_or_default());\n            ConditionIf {\n                arms,\n                fallback: else_block,\n            }\n        })\n}\n\n/// a parser for the arm of a `#match` statement\nfn match_arm<\n    'src,\n    Scrutinee: MatchableParse<'src>,\n    Item: BodyItem,\n    Cardinality: ConditionBodyCardinality<Item>,\n>(\n    block: impl ZngParser<'src, Cardinality::Block>,\n    item_parser: impl ZngParser<'src, Item>,\n) -> impl ZngParser<\n    'src,\n    <Cardinality as ConditionBodyCardinality<Item>>::Body<<Scrutinee as Matchable>::Pattern>,\n>\nwhere\n    <Scrutinee as Matchable>::Pattern: MatchPatternParse<'src>,\n{\n    let arm_choices = (\n        block.delimited_by(just(Token::BraceOpen), just(Token::BraceClose)),\n        spanned(item_parser).map(<Cardinality as ConditionBodyCardinality<Item>>::single_to_block),\n        just([Token::BraceOpen, Token::BraceClose])\n            .map(|_| <Cardinality as ConditionBodyCardinality<Item>>::empty_block()),\n    );\n    spanned(<<Scrutinee as Matchable>::Pattern as MatchPatternParse<\n        'src,\n    >>::parser())\n    .then(just(Token::ArrowArm).ignore_then(choice(arm_choices)))\n    .map(|(pattern, block)| {\n        <Cardinality as ConditionBodyCardinality<Item>>::new_body(pattern, block)\n    })\n}\n\n/// a parser for a `#match` statement\nfn match_stmt<\n    'src,\n    Scrutinee: MatchableParse<'src>,\n    Item: BodyItem,\n    Cardinality: ConditionBodyCardinality<Item>,\n>(\n    block: impl ZngParser<'src, Cardinality::Block>,\n    item_parser: impl ZngParser<'src, Item>,\n) -> impl ZngParser<'src, ConditionMatch<Scrutinee, Item, Cardinality>>\nwhere\n    <Scrutinee as Matchable>::Pattern: MatchPatternParse<'src>,\n{\n    let arm = match_arm::<Scrutinee, Item, Cardinality>(block, item_parser);\n\n    just([Token::Sharp, Token::KwMatch])\n        .ignore_then(spanned(<Scrutinee as MatchableParse>::parser()))\n        .then(\n            spanned(arm)\n                .separated_by(just(Token::Comma).or_not())\n                .allow_trailing()\n                .collect::<Vec<_>>()\n                .delimited_by(just(Token::BraceOpen), just(Token::BraceClose)),\n        )\n        .map(|(scrutinee, arms)| ConditionMatch { scrutinee, arms })\n}\n\npub fn conditional_item<\n    'src,\n    Item: BodyItem,\n    Cond: Conditional<'src, Item, Cardinality>,\n    Cardinality: ConditionBodyCardinality<Item>,\n>(\n    item_parser: impl ZngParser<'src, Item> + 'src,\n) -> impl ZngParser<\n    'src,\n    Condition<<Cond as Conditional<'src, Item, Cardinality>>::Scrutinee, Item, Cardinality>,\n> {\n    let if_parser = <Cond as Conditional<'src, Item, Cardinality>>::if_parser(item_parser.clone()).try_map_with(|match_, e| {\n        if !e.state().unstable_features.cfg_if {\n            Err(Rich::custom(e.span(), \"`#if` statements are unstable. Enable them by using `#unstable(cfg_if)` at the top of the file.\"))\n        } else {\n            Ok(match_)\n        }\n    });\n    let match_parser = <Cond as Conditional<'src, Item, Cardinality>>::match_parser(item_parser).try_map_with(|match_, e| {\n        if !e.state().unstable_features.cfg_match {\n            Err(Rich::custom(e.span(), \"`#match` statements are unstable. Enable them by using `#unstable(cfg_match)` at the top of the file.\"))\n        } else {\n            Ok(match_)\n        }\n    });\n    choice((if_parser, match_parser))\n}\n\nimpl<'src, Scrutinee: MatchableParse<'src> + 'src, Item: BodyItem + 'src>\n    Conditional<'src, Item, SingleItem> for Scrutinee\nwhere\n    <Scrutinee as Matchable>::Pattern: MatchPatternParse<'src>,\n{\n    type Scrutinee = Scrutinee;\n    fn if_parser(\n        item_parser: impl ZngParser<'src, Item> + 'src,\n    ) -> BoxedZngParser<'src, Condition<Scrutinee, Item, SingleItem>> {\n        let block = block_for_single::<Item>(item_parser);\n        let guard = guarded_block::<Scrutinee, Item, SingleItem>(block.clone());\n\n        if_stmnt::<Scrutinee, Item, SingleItem>(guard, block)\n            .map(|item| Condition::<Scrutinee, Item, SingleItem>::If(item))\n            .boxed()\n    }\n\n    fn match_parser(\n        item_parser: impl ZngParser<'src, Item> + 'src,\n    ) -> BoxedZngParser<'src, Condition<Scrutinee, Item, SingleItem>> {\n        let block = block_for_single::<Item>(item_parser.clone());\n        match_stmt::<Scrutinee, Item, SingleItem>(block, item_parser)\n            .map(|item| Condition::<Scrutinee, Item, SingleItem>::Match(item))\n            .boxed()\n    }\n}\n\nimpl<'src, Scrutinee: MatchableParse<'src> + 'src, Item: BodyItem + 'src>\n    Conditional<'src, Item, NItems> for Scrutinee\nwhere\n    <Scrutinee as Matchable>::Pattern: MatchPatternParse<'src>,\n{\n    type Scrutinee = Scrutinee;\n    fn if_parser(\n        item_parser: impl ZngParser<'src, Item> + 'src,\n    ) -> BoxedZngParser<'src, Condition<Scrutinee, Item, NItems>> {\n        let block = block_for_many::<Item>(item_parser);\n        let guard = guarded_block::<Scrutinee, Item, NItems>(block.clone());\n\n        if_stmnt::<Scrutinee, Item, NItems>(guard, block)\n            .map(|item| Condition::<Scrutinee, Item, NItems>::If(item))\n            .boxed()\n    }\n\n    fn match_parser(\n        item_parser: impl ZngParser<'src, Item> + 'src,\n    ) -> BoxedZngParser<'src, Condition<Scrutinee, Item, NItems>> {\n        let block = block_for_many::<Item>(item_parser.clone());\n        match_stmt::<Scrutinee, Item, NItems>(block, item_parser)\n            .map(|item| Condition::<Scrutinee, Item, NItems>::Match(item))\n            .boxed()\n    }\n}\n"
  },
  {
    "path": "zngur-parser/src/lib.rs",
    "content": "use std::{collections::HashMap, fmt::Display, path::Component};\n\n#[cfg(not(test))]\nuse std::process::exit;\n\nuse ariadne::{Color, Label, Report, ReportKind, sources};\nuse chumsky::prelude::*;\nuse itertools::{Either, Itertools};\n\nuse zngur_def::{\n    AdditionalIncludes, ConvertPanicToException, CppRef, CppValue, Import, LayoutPolicy, Merge,\n    MergeFailure, ModuleImport, Mutability, PrimitiveRustType, RustPathAndGenerics, RustTrait,\n    RustType, ZngurConstructor, ZngurExternCppFn, ZngurExternCppImpl, ZngurField, ZngurFn,\n    ZngurMethod, ZngurMethodDetails, ZngurMethodReceiver, ZngurSpec, ZngurTrait, ZngurType,\n    ZngurWellknownTrait,\n};\n\npub type Span = SimpleSpan<usize>;\n\n/// Result of parsing a .zng file, containing both the spec and the list of all processed files.\n#[derive(Debug)]\npub struct ParseResult {\n    /// The parsed Zngur specification\n    pub spec: ZngurSpec,\n    /// All .zng files that were processed (main file + transitive imports)\n    pub processed_files: Vec<std::path::PathBuf>,\n}\n\n#[cfg(test)]\nmod tests;\n\npub mod cfg;\nmod conditional;\n\nuse crate::{\n    cfg::{CfgConditional, RustCfgProvider},\n    conditional::{Condition, ConditionalItem, NItems, conditional_item},\n};\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub struct Spanned<T> {\n    inner: T,\n    span: Span,\n}\n\ntype ParserInput<'a> = chumsky::input::MappedInput<\n    Token<'a>,\n    Span,\n    &'a [(Token<'a>, Span)],\n    Box<\n        dyn for<'x> Fn(\n            &'x (Token<'_>, chumsky::span::SimpleSpan),\n        ) -> (&'x Token<'x>, &'x SimpleSpan),\n    >,\n>;\n\n#[derive(Default)]\npub struct UnstableFeatures {\n    pub cfg_match: bool,\n    pub cfg_if: bool,\n}\n\n#[derive(Default)]\npub struct ZngParserState {\n    pub unstable_features: UnstableFeatures,\n}\n\ntype ZngParserExtra<'a> =\n    extra::Full<Rich<'a, Token<'a>, Span>, extra::SimpleState<ZngParserState>, ()>;\n\ntype BoxedZngParser<'a, Item> = chumsky::Boxed<'a, 'a, ParserInput<'a>, Item, ZngParserExtra<'a>>;\n\n/// Effective trait alias for verbose chumsky Parser Trait\npub(crate) trait ZngParser<'a, Item>:\n    Parser<'a, ParserInput<'a>, Item, ZngParserExtra<'a>> + Clone\n{\n}\nimpl<'a, T, Item> ZngParser<'a, Item> for T where\n    T: Parser<'a, ParserInput<'a>, Item, ZngParserExtra<'a>> + Clone\n{\n}\n\n#[derive(Debug)]\npub struct ParsedZngFile<'a>(Vec<ParsedItem<'a>>);\n\n#[derive(Debug)]\npub struct ProcessedZngFile<'a> {\n    aliases: Vec<ParsedAlias<'a>>,\n    items: Vec<ProcessedItem<'a>>,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\nenum ParsedPathStart {\n    Absolute,\n    Relative,\n    Crate,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nstruct ParsedPath<'a> {\n    start: ParsedPathStart,\n    segments: Vec<&'a str>,\n    span: Span,\n}\n\n#[derive(Debug, Clone)]\nstruct Scope<'a> {\n    aliases: Vec<ParsedAlias<'a>>,\n    base: Vec<String>,\n}\n\nimpl<'a> Scope<'a> {\n    /// Create a new root scope containing the specified aliases.\n    fn new_root(aliases: Vec<ParsedAlias<'a>>) -> Scope<'a> {\n        Scope {\n            aliases,\n            base: Vec::new(),\n        }\n    }\n\n    /// Resolve a path according to the current scope.\n    fn resolve_path(&self, path: ParsedPath<'a>) -> Vec<String> {\n        // Check to see if the path refers to an alias:\n        if let Some(expanded_alias) = self\n            .aliases\n            .iter()\n            .find_map(|alias| alias.expand(&path, &self.base))\n        {\n            expanded_alias\n        } else {\n            path.to_zngur(&self.base)\n        }\n    }\n\n    /// Create a fully-qualified path relative to this scope's base path.\n    fn simple_relative_path(&self, relative_item_name: &str) -> Vec<String> {\n        self.base\n            .iter()\n            .cloned()\n            .chain(Some(relative_item_name.to_string()))\n            .collect()\n    }\n\n    fn sub_scope(&self, new_aliases: &[ParsedAlias<'a>], nested_path: ParsedPath<'a>) -> Scope<'_> {\n        let base = nested_path.to_zngur(&self.base);\n        let mut mod_aliases = new_aliases.to_vec();\n        mod_aliases.extend_from_slice(&self.aliases);\n\n        Scope {\n            aliases: mod_aliases,\n            base,\n        }\n    }\n}\n\nimpl ParsedPath<'_> {\n    fn to_zngur(self, base: &[String]) -> Vec<String> {\n        match self.start {\n            ParsedPathStart::Absolute => self.segments.into_iter().map(|x| x.to_owned()).collect(),\n            ParsedPathStart::Relative => base\n                .iter()\n                .map(|x| x.as_str())\n                .chain(self.segments)\n                .map(|x| x.to_owned())\n                .collect(),\n            ParsedPathStart::Crate => [\"crate\"]\n                .into_iter()\n                .chain(self.segments)\n                .map(|x| x.to_owned())\n                .collect(),\n        }\n    }\n\n    fn matches_alias(&self, alias: &ParsedAlias<'_>) -> bool {\n        match self.start {\n            ParsedPathStart::Absolute | ParsedPathStart::Crate => false,\n            ParsedPathStart::Relative => self\n                .segments\n                .first()\n                .is_some_and(|part| *part == alias.name),\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct ParsedAlias<'a> {\n    name: &'a str,\n    path: ParsedPath<'a>,\n    span: Span,\n}\n\nimpl ParsedAlias<'_> {\n    fn expand(&self, path: &ParsedPath<'_>, base: &[String]) -> Option<Vec<String>> {\n        if path.matches_alias(self) {\n            match self.path.start {\n                ParsedPathStart::Absolute => Some(\n                    self.path\n                        .segments\n                        .iter()\n                        .chain(path.segments.iter().skip(1))\n                        .map(|seg| (*seg).to_owned())\n                        .collect(),\n                ),\n                ParsedPathStart::Crate => Some(\n                    [\"crate\"]\n                        .into_iter()\n                        .chain(self.path.segments.iter().cloned())\n                        .chain(path.segments.iter().skip(1).cloned())\n                        .map(|seg| (*seg).to_owned())\n                        .collect(),\n                ),\n                ParsedPathStart::Relative => Some(\n                    base.iter()\n                        .map(|x| x.as_str())\n                        .chain(self.path.segments.iter().cloned())\n                        .chain(path.segments.iter().skip(1).cloned())\n                        .map(|seg| (*seg).to_owned())\n                        .collect(),\n                ),\n            }\n        } else {\n            None\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nstruct ParsedImportPath {\n    path: std::path::PathBuf,\n    span: Span,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nenum ParsedItem<'a> {\n    ConvertPanicToException(Span),\n    CppAdditionalInclude(&'a str),\n    UnstableFeature(&'a str),\n    Mod {\n        path: ParsedPath<'a>,\n        items: Vec<ParsedItem<'a>>,\n    },\n    Type {\n        ty: Spanned<ParsedRustType<'a>>,\n        items: Vec<Spanned<ParsedTypeItem<'a>>>,\n    },\n    Trait {\n        tr: Spanned<ParsedRustTrait<'a>>,\n        methods: Vec<ParsedMethod<'a>>,\n    },\n    Fn(Spanned<ParsedMethod<'a>>),\n    ExternCpp(Vec<ParsedExternCppItem<'a>>),\n    Alias(ParsedAlias<'a>),\n    Import(ParsedImportPath),\n    ModuleImport {\n        path: std::path::PathBuf,\n        span: Span,\n    },\n    MatchOnCfg(Condition<CfgConditional<'a>, ParsedItem<'a>, NItems>),\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nenum ProcessedItem<'a> {\n    ConvertPanicToException(Span),\n    CppAdditionalInclude(&'a str),\n    Mod {\n        path: ParsedPath<'a>,\n        items: Vec<ProcessedItem<'a>>,\n        aliases: Vec<ParsedAlias<'a>>,\n    },\n    Type {\n        ty: Spanned<ParsedRustType<'a>>,\n        items: Vec<Spanned<ParsedTypeItem<'a>>>,\n    },\n    Trait {\n        tr: Spanned<ParsedRustTrait<'a>>,\n        methods: Vec<ParsedMethod<'a>>,\n    },\n    Fn(Spanned<ParsedMethod<'a>>),\n    ExternCpp(Vec<ParsedExternCppItem<'a>>),\n    Import(ParsedImportPath),\n    ModuleImport {\n        path: std::path::PathBuf,\n        span: Span,\n    },\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nenum ParsedExternCppItem<'a> {\n    Function(Spanned<ParsedMethod<'a>>),\n    Impl {\n        tr: Option<ParsedRustTrait<'a>>,\n        ty: Spanned<ParsedRustType<'a>>,\n        methods: Vec<ParsedMethod<'a>>,\n    },\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nenum ParsedConstructorArgs<'a> {\n    Unit,\n    Tuple(Vec<ParsedRustType<'a>>),\n    Named(Vec<(&'a str, ParsedRustType<'a>)>),\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nenum ParsedLayoutPolicy<'a> {\n    StackAllocated(Vec<(Spanned<&'a str>, usize)>),\n    Conservative(Vec<(Spanned<&'a str>, usize)>),\n    HeapAllocated,\n    OnlyByRef,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nenum ParsedTypeItem<'a> {\n    Layout(Span, ParsedLayoutPolicy<'a>),\n    Traits(Vec<Spanned<ZngurWellknownTrait>>),\n    Constructor {\n        name: Option<&'a str>,\n        args: ParsedConstructorArgs<'a>,\n    },\n    Field {\n        name: String,\n        ty: ParsedRustType<'a>,\n        offset: Option<usize>,\n    },\n    Method {\n        data: ParsedMethod<'a>,\n        use_path: Option<ParsedPath<'a>>,\n        deref: Option<ParsedRustType<'a>>,\n    },\n    CppValue {\n        field: &'a str,\n        cpp_type: &'a str,\n    },\n    CppRef {\n        cpp_type: &'a str,\n    },\n    MatchOnCfg(Condition<CfgConditional<'a>, ParsedTypeItem<'a>, NItems>),\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nstruct ParsedMethod<'a> {\n    name: &'a str,\n    receiver: ZngurMethodReceiver,\n    generics: Vec<ParsedRustType<'a>>,\n    inputs: Vec<ParsedRustType<'a>>,\n    output: ParsedRustType<'a>,\n}\n\nimpl ParsedMethod<'_> {\n    fn to_zngur(self, scope: &Scope<'_>) -> ZngurMethod {\n        ZngurMethod {\n            name: self.name.to_owned(),\n            generics: self\n                .generics\n                .into_iter()\n                .map(|x| x.to_zngur(scope))\n                .collect(),\n            receiver: self.receiver,\n            inputs: self.inputs.into_iter().map(|x| x.to_zngur(scope)).collect(),\n            output: self.output.to_zngur(scope),\n        }\n    }\n}\n\nfn checked_merge<T, U>(src: T, dst: &mut U, span: Span, ctx: &mut ParseContext)\nwhere\n    T: Merge<U>,\n{\n    match src.merge(dst) {\n        Ok(()) => {}\n        Err(e) => match e {\n            MergeFailure::Conflict(s) => {\n                ctx.add_error_str(&s, span);\n            }\n        },\n    }\n}\n\nimpl ProcessedItem<'_> {\n    fn add_to_zngur_spec(self, r: &mut ZngurSpec, scope: &Scope<'_>, ctx: &mut ParseContext) {\n        match self {\n            ProcessedItem::Mod {\n                path,\n                items,\n                aliases,\n            } => {\n                let sub_scope = scope.sub_scope(&aliases, path);\n                for item in items {\n                    item.add_to_zngur_spec(r, &sub_scope, ctx);\n                }\n            }\n            ProcessedItem::Import(path) => {\n                if path.path.is_absolute() {\n                    ctx.add_error_str(\"Absolute paths imports are not supported.\", path.span)\n                }\n                match path.path.components().next() {\n                    Some(Component::CurDir) | Some(Component::ParentDir) => {\n                        r.imports.push(Import(path.path));\n                    }\n                    _ => ctx.add_error_str(\n                        \"Module import is not supported. Use a relative path instead.\",\n                        path.span,\n                    ),\n                }\n            }\n            ProcessedItem::ModuleImport { path, span: _ } => {\n                r.imported_modules.push(ModuleImport { path: path.clone() });\n            }\n            ProcessedItem::Type { ty, items } => {\n                if ty.inner == ParsedRustType::Tuple(vec![]) {\n                    // We add unit type implicitly.\n                    ctx.add_error_str(\n                        \"Unit type is declared implicitly. Remove this entirely.\",\n                        ty.span,\n                    );\n                }\n\n                let mut methods = vec![];\n                let mut constructors = vec![];\n                let mut fields = vec![];\n                let mut wellknown_traits = vec![];\n                let mut layout = None;\n                let mut layout_span = None;\n                let mut cpp_value = None;\n                let mut cpp_ref = None;\n                let mut to_process = items;\n                to_process.reverse(); // create a stack of items to process\n                while let Some(item) = to_process.pop() {\n                    let item_span = item.span;\n                    let item = item.inner;\n                    match item {\n                        ParsedTypeItem::Layout(span, p) => {\n                            let mut check_size_align = |props: Vec<(Spanned<&str>, usize)>| {\n                                let mut size = None;\n                                let mut align = None;\n                                for (key, value) in props {\n                                    match key.inner {\n                                        \"size\" => size = Some(value),\n                                        \"align\" => align = Some(value),\n                                        _ => ctx.add_error_str(\"Unknown property\", key.span),\n                                    }\n                                }\n                                let Some(size) = size else {\n                                    ctx.add_error_str(\n                                        \"Size is not declared for this type\",\n                                        ty.span,\n                                    );\n                                    return None;\n                                };\n                                let Some(align) = align else {\n                                    ctx.add_error_str(\n                                        \"Align is not declared for this type\",\n                                        ty.span,\n                                    );\n                                    return None;\n                                };\n                                Some((size, align))\n                            };\n                            layout = Some(match p {\n                                ParsedLayoutPolicy::StackAllocated(p) => {\n                                    let Some((size, align)) = check_size_align(p) else {\n                                        continue;\n                                    };\n                                    LayoutPolicy::StackAllocated { size, align }\n                                }\n                                ParsedLayoutPolicy::Conservative(p) => {\n                                    let Some((size, align)) = check_size_align(p) else {\n                                        continue;\n                                    };\n                                    LayoutPolicy::Conservative { size, align }\n                                }\n                                ParsedLayoutPolicy::HeapAllocated => LayoutPolicy::HeapAllocated,\n                                ParsedLayoutPolicy::OnlyByRef => LayoutPolicy::OnlyByRef,\n                            });\n                            match layout_span {\n                                Some(_) => {\n                                    ctx.add_error_str(\"Duplicate layout policy found\", span);\n                                }\n                                None => layout_span = Some(span),\n                            }\n                        }\n                        ParsedTypeItem::Traits(tr) => {\n                            wellknown_traits.extend(tr);\n                        }\n                        ParsedTypeItem::Constructor { name, args } => {\n                            constructors.push(ZngurConstructor {\n                                name: name.map(|x| x.to_owned()),\n                                inputs: match args {\n                                    ParsedConstructorArgs::Unit => vec![],\n                                    ParsedConstructorArgs::Tuple(t) => t\n                                        .into_iter()\n                                        .enumerate()\n                                        .map(|(i, t)| (i.to_string(), t.to_zngur(scope)))\n                                        .collect(),\n                                    ParsedConstructorArgs::Named(t) => t\n                                        .into_iter()\n                                        .map(|(i, t)| (i.to_owned(), t.to_zngur(scope)))\n                                        .collect(),\n                                },\n                            })\n                        }\n                        ParsedTypeItem::Field { name, ty, offset } => {\n                            fields.push(ZngurField {\n                                name: name.to_owned(),\n                                ty: ty.to_zngur(scope),\n                                offset,\n                            });\n                        }\n                        ParsedTypeItem::Method {\n                            data,\n                            use_path,\n                            deref,\n                        } => {\n                            let deref = deref.and_then(|x| {\n                                let deref_type = x.to_zngur(scope);\n                                let receiver_mutability = match data.receiver {\n                                    ZngurMethodReceiver::Ref(mutability) => mutability,\n                                    ZngurMethodReceiver::Static | ZngurMethodReceiver::Move => {\n                                        ctx.add_error_str(\n                                            \"Deref needs reference receiver\",\n                                            item_span,\n                                        );\n                                        return None;\n                                    }\n                                };\n                                Some((deref_type, receiver_mutability))\n                            });\n                            methods.push(ZngurMethodDetails {\n                                data: data.to_zngur(scope),\n                                use_path: use_path.map(|x| scope.resolve_path(x)),\n                                deref,\n                            });\n                        }\n                        ParsedTypeItem::CppValue { field, cpp_type } => {\n                            cpp_value = Some(CppValue(field.to_owned(), cpp_type.to_owned()));\n                        }\n                        ParsedTypeItem::CppRef { cpp_type } => {\n                            match layout_span {\n                                Some(span) => {\n                                    ctx.add_error_str(\"Duplicate layout policy found\", span);\n                                    continue;\n                                }\n                                None => {\n                                    layout = Some(LayoutPolicy::ZERO_SIZED_TYPE);\n                                    layout_span = Some(item_span);\n                                }\n                            }\n                            cpp_ref = Some(CppRef(cpp_type.to_owned()));\n                        }\n                        ParsedTypeItem::MatchOnCfg(match_) => {\n                            let result = match_.eval(ctx);\n                            if let Some(result) = result {\n                                to_process.extend(result);\n                            }\n                        }\n                    }\n                }\n                let is_unsized = wellknown_traits\n                    .iter()\n                    .find(|x| x.inner == ZngurWellknownTrait::Unsized)\n                    .cloned();\n                let is_copy = wellknown_traits\n                    .iter()\n                    .find(|x| x.inner == ZngurWellknownTrait::Copy)\n                    .cloned();\n                let mut wt = wellknown_traits\n                    .into_iter()\n                    .map(|x| x.inner)\n                    .collect::<Vec<_>>();\n                if is_copy.is_none() && is_unsized.is_none() {\n                    wt.push(ZngurWellknownTrait::Drop);\n                }\n                if let Some(is_unsized) = is_unsized {\n                    if let Some(span) = layout_span {\n                        ctx.add_report(\n                            Report::build(\n                                ReportKind::Error,\n                                ctx.filename().to_string(),\n                                span.start,\n                            )\n                            .with_message(\"Duplicate layout policy found for unsized type.\")\n                            .with_label(\n                                Label::new((ctx.filename().to_string(), span.start..span.end))\n                                    .with_message(\n                                        \"Unsized types have implicit layout policy, remove this.\",\n                                    )\n                                    .with_color(Color::Red),\n                            )\n                            .with_label(\n                                Label::new((\n                                    ctx.filename().to_string(),\n                                    is_unsized.span.start..is_unsized.span.end,\n                                ))\n                                .with_message(\"Type declared as unsized here.\")\n                                .with_color(Color::Blue),\n                            )\n                            .finish(),\n                        )\n                    }\n                    layout = Some(LayoutPolicy::OnlyByRef);\n                }\n                if let Some(layout) = layout {\n                    checked_merge(\n                        ZngurType {\n                            ty: ty.inner.to_zngur(scope),\n                            layout,\n                            methods,\n                            wellknown_traits: wt,\n                            constructors,\n                            fields,\n                            cpp_value,\n                            cpp_ref,\n                        },\n                        r,\n                        ty.span,\n                        ctx,\n                    );\n                } else {\n                    ctx.add_error_str(\n                        \"No layout policy found for this type. \\\nUse one of `#layout(size = X, align = Y)`, `#heap_allocated` or `#only_by_ref`.\",\n                        ty.span,\n                    );\n                };\n            }\n            ProcessedItem::Trait { tr, methods } => {\n                checked_merge(\n                    ZngurTrait {\n                        tr: tr.inner.to_zngur(scope),\n                        methods: methods.into_iter().map(|m| m.to_zngur(scope)).collect(),\n                    },\n                    r,\n                    tr.span,\n                    ctx,\n                );\n            }\n            ProcessedItem::Fn(f) => {\n                let method = f.inner.to_zngur(scope);\n                checked_merge(\n                    ZngurFn {\n                        path: RustPathAndGenerics {\n                            path: scope.simple_relative_path(&method.name),\n                            generics: method.generics,\n                            named_generics: vec![],\n                        },\n                        inputs: method.inputs,\n                        output: method.output,\n                    },\n                    r,\n                    f.span,\n                    ctx,\n                );\n            }\n            ProcessedItem::ExternCpp(items) => {\n                for item in items {\n                    match item {\n                        ParsedExternCppItem::Function(method) => {\n                            let span = method.span;\n                            let method = method.inner.to_zngur(scope);\n                            checked_merge(\n                                ZngurExternCppFn {\n                                    name: method.name.to_string(),\n                                    inputs: method.inputs,\n                                    output: method.output,\n                                },\n                                r,\n                                span,\n                                ctx,\n                            );\n                        }\n                        ParsedExternCppItem::Impl { tr, ty, methods } => {\n                            checked_merge(\n                                ZngurExternCppImpl {\n                                    tr: tr.map(|x| x.to_zngur(scope)),\n                                    ty: ty.inner.to_zngur(scope),\n                                    methods: methods\n                                        .into_iter()\n                                        .map(|x| x.to_zngur(scope))\n                                        .collect(),\n                                },\n                                r,\n                                ty.span,\n                                ctx,\n                            );\n                        }\n                    }\n                }\n            }\n            ProcessedItem::CppAdditionalInclude(s) => {\n                match AdditionalIncludes(s.to_owned()).merge(r) {\n                    Ok(()) => {}\n                    Err(_) => {\n                        unreachable!() // For now, additional includes can't have conflicts.\n                    }\n                }\n            }\n            ProcessedItem::ConvertPanicToException(span) => {\n                if ctx.depth > 0 {\n                    ctx.add_error_str(\n                        \"Using `#convert_panic_to_exception` in imported zngur files is not supported. This directive can only be used in the main zngur file.\",\n                        span,\n                    );\n                    return;\n                }\n                match ConvertPanicToException(true).merge(r) {\n                    Ok(()) => {}\n                    Err(_) => {\n                        unreachable!() // For now, CPtE also can't have conflicts.\n                    }\n                }\n            }\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nenum ParsedRustType<'a> {\n    Primitive(PrimitiveRustType),\n    Ref(Mutability, Box<ParsedRustType<'a>>),\n    Raw(Mutability, Box<ParsedRustType<'a>>),\n    Boxed(Box<ParsedRustType<'a>>),\n    Slice(Box<ParsedRustType<'a>>),\n    Dyn(ParsedRustTrait<'a>, Vec<&'a str>),\n    Impl(ParsedRustTrait<'a>, Vec<&'a str>),\n    Tuple(Vec<ParsedRustType<'a>>),\n    Adt(ParsedRustPathAndGenerics<'a>),\n}\n\nimpl ParsedRustType<'_> {\n    fn to_zngur(self, scope: &Scope<'_>) -> RustType {\n        match self {\n            ParsedRustType::Primitive(s) => RustType::Primitive(s),\n            ParsedRustType::Ref(m, s) => RustType::Ref(m, Box::new(s.to_zngur(scope))),\n            ParsedRustType::Raw(m, s) => RustType::Raw(m, Box::new(s.to_zngur(scope))),\n            ParsedRustType::Boxed(s) => RustType::Boxed(Box::new(s.to_zngur(scope))),\n            ParsedRustType::Slice(s) => RustType::Slice(Box::new(s.to_zngur(scope))),\n            ParsedRustType::Dyn(tr, bounds) => RustType::Dyn(\n                tr.to_zngur(scope),\n                bounds.into_iter().map(|x| x.to_owned()).collect(),\n            ),\n            ParsedRustType::Impl(tr, bounds) => RustType::Impl(\n                tr.to_zngur(scope),\n                bounds.into_iter().map(|x| x.to_owned()).collect(),\n            ),\n            ParsedRustType::Tuple(v) => {\n                RustType::Tuple(v.into_iter().map(|s| s.to_zngur(scope)).collect())\n            }\n            ParsedRustType::Adt(s) => RustType::Adt(s.to_zngur(scope)),\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nenum ParsedRustTrait<'a> {\n    Normal(ParsedRustPathAndGenerics<'a>),\n    Fn {\n        name: &'a str,\n        inputs: Vec<ParsedRustType<'a>>,\n        output: Box<ParsedRustType<'a>>,\n    },\n}\n\nimpl ParsedRustTrait<'_> {\n    fn to_zngur(self, scope: &Scope<'_>) -> RustTrait {\n        match self {\n            ParsedRustTrait::Normal(s) => RustTrait::Normal(s.to_zngur(scope)),\n            ParsedRustTrait::Fn {\n                name,\n                inputs,\n                output,\n            } => RustTrait::Fn {\n                name: name.to_owned(),\n                inputs: inputs.into_iter().map(|s| s.to_zngur(scope)).collect(),\n                output: Box::new(output.to_zngur(scope)),\n            },\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nstruct ParsedRustPathAndGenerics<'a> {\n    path: ParsedPath<'a>,\n    generics: Vec<ParsedRustType<'a>>,\n    named_generics: Vec<(&'a str, ParsedRustType<'a>)>,\n}\n\nimpl ParsedRustPathAndGenerics<'_> {\n    fn to_zngur(self, scope: &Scope<'_>) -> RustPathAndGenerics {\n        RustPathAndGenerics {\n            path: scope.resolve_path(self.path),\n            generics: self\n                .generics\n                .into_iter()\n                .map(|x| x.to_zngur(scope))\n                .collect(),\n            named_generics: self\n                .named_generics\n                .into_iter()\n                .map(|(name, x)| (name.to_owned(), x.to_zngur(scope)))\n                .collect(),\n        }\n    }\n}\n\nstruct ParseContext<'a, 'b> {\n    path: std::path::PathBuf,\n    text: &'a str,\n    depth: usize,\n    reports: Vec<Report<'b, (String, std::ops::Range<usize>)>>,\n    source_cache: std::collections::HashMap<std::path::PathBuf, String>,\n    /// All .zng files processed during parsing (main file + imports)\n    processed_files: Vec<std::path::PathBuf>,\n    cfg_provider: Box<dyn RustCfgProvider>,\n}\n\nimpl<'a, 'b> ParseContext<'a, 'b> {\n    fn new(path: std::path::PathBuf, text: &'a str, cfg: Box<dyn RustCfgProvider>) -> Self {\n        let processed_files = vec![path.clone()];\n        Self {\n            path,\n            text,\n            depth: 0,\n            reports: Vec::new(),\n            source_cache: HashMap::new(),\n            processed_files,\n            cfg_provider: cfg,\n        }\n    }\n\n    fn with_depth(\n        path: std::path::PathBuf,\n        text: &'a str,\n        depth: usize,\n        cfg: Box<dyn RustCfgProvider>,\n    ) -> Self {\n        let processed_files = vec![path.clone()];\n        Self {\n            path,\n            text,\n            depth,\n            reports: Vec::new(),\n            source_cache: HashMap::new(),\n            processed_files,\n            cfg_provider: cfg,\n        }\n    }\n\n    fn filename(&self) -> &str {\n        self.path.file_name().unwrap().to_str().unwrap()\n    }\n\n    fn add_report(&mut self, report: Report<'b, (String, std::ops::Range<usize>)>) {\n        self.reports.push(report);\n    }\n    fn add_errors<'err_src>(&mut self, errs: impl Iterator<Item = Rich<'err_src, String>>) {\n        let filename = self.filename().to_string();\n        self.reports.extend(errs.map(|e| {\n            Report::build(ReportKind::Error, &filename, e.span().start)\n                .with_message(e.to_string())\n                .with_label(\n                    Label::new((filename.clone(), e.span().into_range()))\n                        .with_message(e.reason().to_string())\n                        .with_color(Color::Red),\n                )\n                .with_labels(e.contexts().map(|(label, span)| {\n                    Label::new((filename.clone(), span.into_range()))\n                        .with_message(format!(\"while parsing this {}\", label))\n                        .with_color(Color::Yellow)\n                }))\n                .finish()\n        }));\n    }\n\n    fn add_error_str(&mut self, error: &str, span: Span) {\n        self.add_errors([Rich::custom(span, error)].into_iter());\n    }\n\n    fn consume_from(&mut self, mut other: ParseContext<'_, 'b>) {\n        // Always merge processed files, regardless of errors\n        self.processed_files.append(&mut other.processed_files);\n        if other.has_errors() {\n            self.reports.extend(other.reports);\n            self.source_cache.insert(other.path, other.text.to_string());\n            self.source_cache.extend(other.source_cache);\n        }\n    }\n\n    fn has_errors(&self) -> bool {\n        !self.reports.is_empty()\n    }\n\n    #[cfg(test)]\n    fn emit_ariadne_errors(&self) -> ! {\n        let mut r = Vec::<u8>::new();\n        for err in &self.reports {\n            err.write(\n                sources(\n                    [(self.filename().to_string(), self.text)]\n                        .into_iter()\n                        .chain(\n                            self.source_cache\n                                .iter()\n                                .map(|(path, text)| {\n                                    (\n                                        path.file_name().unwrap().to_str().unwrap().to_string(),\n                                        text.as_str(),\n                                    )\n                                })\n                                .collect::<Vec<_>>()\n                                .into_iter(),\n                        ),\n                ),\n                &mut r,\n            )\n            .unwrap();\n        }\n        std::panic::resume_unwind(Box::new(tests::ErrorText(\n            String::from_utf8(strip_ansi_escapes::strip(r)).unwrap(),\n        )));\n    }\n\n    #[cfg(not(test))]\n    fn emit_ariadne_errors(&self) -> ! {\n        for err in &self.reports {\n            err.eprint(sources(\n                [(self.filename().to_string(), self.text)]\n                    .into_iter()\n                    .chain(\n                        self.source_cache\n                            .iter()\n                            .map(|(path, text)| {\n                                (\n                                    path.file_name().unwrap().to_str().unwrap().to_string(),\n                                    text.as_str(),\n                                )\n                            })\n                            .collect::<Vec<_>>()\n                            .into_iter(),\n                    ),\n            ))\n            .unwrap();\n        }\n        exit(101);\n    }\n\n    fn get_config_provider(&self) -> &dyn RustCfgProvider {\n        self.cfg_provider.as_ref()\n    }\n}\n\n/// A trait for types which can resolve filesystem-like paths relative to a given directory.\npub trait ImportResolver {\n    fn resolve_import(\n        &self,\n        cwd: &std::path::Path,\n        relpath: &std::path::Path,\n    ) -> Result<String, String>;\n}\n\n/// A default implementation of ImportResolver which uses conventional filesystem paths and semantics.\nstruct DefaultImportResolver;\n\nimpl ImportResolver for DefaultImportResolver {\n    fn resolve_import(\n        &self,\n        cwd: &std::path::Path,\n        relpath: &std::path::Path,\n    ) -> Result<String, String> {\n        let path = cwd\n            .join(relpath)\n            .canonicalize()\n            .map_err(|e| e.to_string())?;\n        std::fs::read_to_string(path).map_err(|e| e.to_string())\n    }\n}\n\nimpl<'a> ParsedZngFile<'a> {\n    fn parse_into(zngur: &mut ZngurSpec, ctx: &mut ParseContext, resolver: &impl ImportResolver) {\n        let (tokens, errs) = lexer().parse(ctx.text).into_output_errors();\n        let Some(tokens) = tokens else {\n            ctx.add_errors(errs.into_iter().map(|e| e.map_token(|c| c.to_string())));\n            ctx.emit_ariadne_errors();\n        };\n        let tokens: ParserInput<'_> = tokens.as_slice().map(\n            (ctx.text.len()..ctx.text.len()).into(),\n            Box::new(|(t, s)| (t, s)),\n        );\n        let (ast, errs) = file_parser()\n            .map_with(|ast, extra| (ast, extra.span()))\n            .parse_with_state(tokens, &mut extra::SimpleState(ZngParserState::default()))\n            .into_output_errors();\n        let Some(ast) = ast else {\n            ctx.add_errors(errs.into_iter().map(|e| e.map_token(|c| c.to_string())));\n            ctx.emit_ariadne_errors();\n        };\n\n        let (aliases, items) = partition_parsed_items(\n            ast.0\n                .0\n                .into_iter()\n                .map(|item| process_parsed_item(item, ctx)),\n        );\n        ProcessedZngFile::new(aliases, items).into_zngur_spec(zngur, ctx);\n\n        if let Some(dirname) = ctx.path.to_owned().parent() {\n            for import in std::mem::take(&mut zngur.imports) {\n                match resolver.resolve_import(dirname, &import.0) {\n                    Ok(text) => {\n                        let mut nested_ctx = ParseContext::with_depth(\n                            dirname.join(&import.0),\n                            &text,\n                            ctx.depth + 1,\n                            ctx.get_config_provider().clone_box(),\n                        );\n                        Self::parse_into(zngur, &mut nested_ctx, resolver);\n                        ctx.consume_from(nested_ctx);\n                    }\n                    Err(_) => {\n                        // TODO: emit a better error. How should we get a span here?\n                        // I'd like to avoid putting a ParsedImportPath in ZngurSpec, and\n                        // also not have to pass a filename to add_to_zngur_spec.\n                        ctx.add_report(\n                            Report::build(ReportKind::Error, ctx.filename(), 0)\n                                .with_message(format!(\n                                    \"Import path not found: {}\",\n                                    import.0.display()\n                                ))\n                                .finish(),\n                        );\n                    }\n                }\n            }\n        }\n    }\n\n    /// Parse a .zng file and return both the spec and list of all processed files.\n    pub fn parse(path: std::path::PathBuf, cfg: Box<dyn RustCfgProvider>) -> ParseResult {\n        let mut zngur = ZngurSpec::default();\n        zngur.rust_cfg.extend(cfg.get_cfg_pairs());\n        let text = std::fs::read_to_string(&path).unwrap();\n        let mut ctx = ParseContext::new(path.clone(), &text, cfg.clone_box());\n        Self::parse_into(&mut zngur, &mut ctx, &DefaultImportResolver);\n        if ctx.has_errors() {\n            // add report of cfg values used\n            ctx.add_report(\n                Report::build(\n                    ReportKind::Custom(\"cfg values\", ariadne::Color::Green),\n                    path.file_name().unwrap_or_default().to_string_lossy(),\n                    0,\n                )\n                .with_message(\n                    cfg.get_cfg_pairs()\n                        .into_iter()\n                        .map(|(key, value)| match value {\n                            Some(value) => format!(\"{key}=\\\"{value}\\\"\"),\n                            None => key,\n                        })\n                        .join(\"\\n\")\n                        .to_string(),\n                )\n                .finish(),\n            );\n            ctx.emit_ariadne_errors();\n        }\n        ParseResult {\n            spec: zngur,\n            processed_files: ctx.processed_files,\n        }\n    }\n\n    /// Parse a .zng file from a string. Mainly useful for testing.\n    pub fn parse_str(text: &str, cfg: impl RustCfgProvider + 'static) -> ParseResult {\n        let mut zngur = ZngurSpec::default();\n        let mut ctx = ParseContext::new(std::path::PathBuf::from(\"test.zng\"), text, Box::new(cfg));\n        Self::parse_into(&mut zngur, &mut ctx, &DefaultImportResolver);\n        if ctx.has_errors() {\n            ctx.emit_ariadne_errors();\n        }\n        ParseResult {\n            spec: zngur,\n            processed_files: ctx.processed_files,\n        }\n    }\n\n    #[cfg(test)]\n    pub(crate) fn parse_str_with_resolver(\n        text: &str,\n        cfg: impl RustCfgProvider + 'static,\n        resolver: &impl ImportResolver,\n    ) -> ParseResult {\n        let mut zngur = ZngurSpec::default();\n        let mut ctx = ParseContext::new(std::path::PathBuf::from(\"test.zng\"), text, Box::new(cfg));\n        Self::parse_into(&mut zngur, &mut ctx, resolver);\n        if ctx.has_errors() {\n            ctx.emit_ariadne_errors();\n        }\n        ParseResult {\n            spec: zngur,\n            processed_files: ctx.processed_files,\n        }\n    }\n}\n\npub(crate) enum ProcessedItemOrAlias<'a> {\n    Ignore,\n    Processed(ProcessedItem<'a>),\n    Alias(ParsedAlias<'a>),\n    ChildItems(Vec<ProcessedItemOrAlias<'a>>),\n}\n\nfn process_parsed_item<'a>(\n    item: ParsedItem<'a>,\n    ctx: &mut ParseContext,\n) -> ProcessedItemOrAlias<'a> {\n    use ProcessedItemOrAlias as Ret;\n    match item {\n        ParsedItem::Alias(alias) => Ret::Alias(alias),\n        ParsedItem::ConvertPanicToException(span) => {\n            Ret::Processed(ProcessedItem::ConvertPanicToException(span))\n        }\n        ParsedItem::UnstableFeature(_) => {\n            // ignore\n            Ret::Ignore\n        }\n        ParsedItem::CppAdditionalInclude(inc) => {\n            Ret::Processed(ProcessedItem::CppAdditionalInclude(inc))\n        }\n        ParsedItem::Mod { path, items } => {\n            let (aliases, items) = partition_parsed_items(\n                items.into_iter().map(|item| process_parsed_item(item, ctx)),\n            );\n            Ret::Processed(ProcessedItem::Mod {\n                path,\n                items,\n                aliases,\n            })\n        }\n        ParsedItem::Type { ty, items } => Ret::Processed(ProcessedItem::Type { ty, items }),\n        ParsedItem::Trait { tr, methods } => Ret::Processed(ProcessedItem::Trait { tr, methods }),\n        ParsedItem::Fn(method) => Ret::Processed(ProcessedItem::Fn(method)),\n        ParsedItem::ExternCpp(items) => Ret::Processed(ProcessedItem::ExternCpp(items)),\n        ParsedItem::Import(path) => Ret::Processed(ProcessedItem::Import(path)),\n        ParsedItem::ModuleImport { path, span } => {\n            Ret::Processed(ProcessedItem::ModuleImport { path, span })\n        }\n        ParsedItem::MatchOnCfg(match_) => Ret::ChildItems(\n            match_\n                .eval(ctx)\n                .unwrap_or_default() // unwrap or empty\n                .into_iter()\n                .map(|item| item.inner)\n                .collect(),\n        ),\n    }\n}\n\nfn partition_parsed_items<'a>(\n    items: impl IntoIterator<Item = ProcessedItemOrAlias<'a>>,\n) -> (Vec<ParsedAlias<'a>>, Vec<ProcessedItem<'a>>) {\n    let mut aliases = Vec::new();\n    let mut processed = Vec::new();\n    for item in items.into_iter() {\n        match item {\n            ProcessedItemOrAlias::Ignore => continue,\n            ProcessedItemOrAlias::Processed(p) => processed.push(p),\n            ProcessedItemOrAlias::Alias(a) => aliases.push(a),\n            ProcessedItemOrAlias::ChildItems(children) => {\n                let (child_aliases, child_items) = partition_parsed_items(children);\n                aliases.extend(child_aliases);\n                processed.extend(child_items);\n            }\n        }\n    }\n    (aliases, processed)\n}\n\nimpl<'a> ProcessedZngFile<'a> {\n    fn new(aliases: Vec<ParsedAlias<'a>>, items: Vec<ProcessedItem<'a>>) -> Self {\n        ProcessedZngFile { aliases, items }\n    }\n\n    fn into_zngur_spec(self, zngur: &mut ZngurSpec, ctx: &mut ParseContext) {\n        let root_scope = Scope::new_root(self.aliases);\n\n        for item in self.items {\n            item.add_to_zngur_spec(zngur, &root_scope, ctx);\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\nenum Token<'a> {\n    Arrow,\n    ArrowArm,\n    AngleOpen,\n    AngleClose,\n    BracketOpen,\n    BracketClose,\n    Colon,\n    ColonColon,\n    ParenOpen,\n    ParenClose,\n    BraceOpen,\n    BraceClose,\n    And,\n    Star,\n    Sharp,\n    Plus,\n    Eq,\n    Question,\n    Comma,\n    Semicolon,\n    Pipe,\n    Underscore,\n    Dot,\n    Bang,\n    KwAs,\n    KwAsync,\n    KwDyn,\n    KwUse,\n    KwFor,\n    KwMod,\n    KwCrate,\n    KwType,\n    KwTrait,\n    KwFn,\n    KwMut,\n    KwConst,\n    KwExtern,\n    KwImpl,\n    KwImport,\n    KwMerge,\n    KwIf,\n    KwElse,\n    KwMatch,\n    Ident(&'a str),\n    Str(&'a str),\n    Number(usize),\n}\n\nimpl<'a> Token<'a> {\n    fn ident_or_kw(ident: &'a str) -> Self {\n        match ident {\n            \"as\" => Token::KwAs,\n            \"async\" => Token::KwAsync,\n            \"dyn\" => Token::KwDyn,\n            \"mod\" => Token::KwMod,\n            \"type\" => Token::KwType,\n            \"trait\" => Token::KwTrait,\n            \"crate\" => Token::KwCrate,\n            \"fn\" => Token::KwFn,\n            \"mut\" => Token::KwMut,\n            \"const\" => Token::KwConst,\n            \"use\" => Token::KwUse,\n            \"for\" => Token::KwFor,\n            \"extern\" => Token::KwExtern,\n            \"impl\" => Token::KwImpl,\n            \"import\" => Token::KwImport,\n            \"merge\" => Token::KwMerge,\n            \"if\" => Token::KwIf,\n            \"else\" => Token::KwElse,\n            \"match\" => Token::KwMatch,\n            x => Token::Ident(x),\n        }\n    }\n}\n\nimpl Display for Token<'_> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Token::Arrow => write!(f, \"->\"),\n            Token::ArrowArm => write!(f, \"=>\"),\n            Token::AngleOpen => write!(f, \"<\"),\n            Token::AngleClose => write!(f, \">\"),\n            Token::BracketOpen => write!(f, \"[\"),\n            Token::BracketClose => write!(f, \"]\"),\n            Token::ParenOpen => write!(f, \"(\"),\n            Token::ParenClose => write!(f, \")\"),\n            Token::BraceOpen => write!(f, \"{{\"),\n            Token::BraceClose => write!(f, \"}}\"),\n            Token::Colon => write!(f, \":\"),\n            Token::ColonColon => write!(f, \"::\"),\n            Token::And => write!(f, \"&\"),\n            Token::Star => write!(f, \"*\"),\n            Token::Sharp => write!(f, \"#\"),\n            Token::Plus => write!(f, \"+\"),\n            Token::Eq => write!(f, \"=\"),\n            Token::Question => write!(f, \"?\"),\n            Token::Comma => write!(f, \",\"),\n            Token::Semicolon => write!(f, \";\"),\n            Token::Pipe => write!(f, \"|\"),\n            Token::Underscore => write!(f, \"_\"),\n            Token::Dot => write!(f, \".\"),\n            Token::Bang => write!(f, \"!\"),\n            Token::KwAs => write!(f, \"as\"),\n            Token::KwAsync => write!(f, \"async\"),\n            Token::KwDyn => write!(f, \"dyn\"),\n            Token::KwUse => write!(f, \"use\"),\n            Token::KwFor => write!(f, \"for\"),\n            Token::KwMod => write!(f, \"mod\"),\n            Token::KwCrate => write!(f, \"crate\"),\n            Token::KwType => write!(f, \"type\"),\n            Token::KwTrait => write!(f, \"trait\"),\n            Token::KwFn => write!(f, \"fn\"),\n            Token::KwMut => write!(f, \"mut\"),\n            Token::KwConst => write!(f, \"const\"),\n            Token::KwExtern => write!(f, \"extern\"),\n            Token::KwImpl => write!(f, \"impl\"),\n            Token::KwImport => write!(f, \"import\"),\n            Token::KwMerge => write!(f, \"merge\"),\n            Token::KwIf => write!(f, \"if\"),\n            Token::KwElse => write!(f, \"else\"),\n            Token::KwMatch => write!(f, \"match\"),\n            Token::Ident(i) => write!(f, \"{i}\"),\n            Token::Number(n) => write!(f, \"{n}\"),\n            Token::Str(s) => write!(f, r#\"\"{s}\"\"#),\n        }\n    }\n}\n\nfn lexer<'src>()\n-> impl Parser<'src, &'src str, Vec<(Token<'src>, Span)>, extra::Err<Rich<'src, char, Span>>> {\n    let token = choice((\n        choice([\n            just(\"->\").to(Token::Arrow),\n            just(\"=>\").to(Token::ArrowArm),\n            just(\"<\").to(Token::AngleOpen),\n            just(\">\").to(Token::AngleClose),\n            just(\"[\").to(Token::BracketOpen),\n            just(\"]\").to(Token::BracketClose),\n            just(\"(\").to(Token::ParenOpen),\n            just(\")\").to(Token::ParenClose),\n            just(\"{\").to(Token::BraceOpen),\n            just(\"}\").to(Token::BraceClose),\n            just(\"::\").to(Token::ColonColon),\n            just(\":\").to(Token::Colon),\n            just(\"&\").to(Token::And),\n            just(\"*\").to(Token::Star),\n            just(\"#\").to(Token::Sharp),\n            just(\"+\").to(Token::Plus),\n            just(\"=\").to(Token::Eq),\n            just(\"?\").to(Token::Question),\n            just(\",\").to(Token::Comma),\n            just(\";\").to(Token::Semicolon),\n            just(\"|\").to(Token::Pipe),\n            just(\"_\").to(Token::Underscore),\n            just(\".\").to(Token::Dot),\n            just(\"!\").to(Token::Bang),\n        ]),\n        text::ident().map(Token::ident_or_kw),\n        text::int(10).map(|x: &str| Token::Number(x.parse().unwrap())),\n        just('\"')\n            .ignore_then(none_of('\"').repeated().to_slice().map(Token::Str))\n            .then_ignore(just('\"')),\n    ));\n\n    let comment = just(\"//\")\n        .then(any().and_is(just('\\n').not()).repeated())\n        .padded();\n\n    token\n        .map_with(|tok, extra| (tok, extra.span()))\n        .padded_by(comment.repeated())\n        .padded()\n        .repeated()\n        .collect()\n}\n\nfn alias<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {\n    just(Token::KwUse)\n        .ignore_then(path())\n        .then_ignore(just(Token::KwAs))\n        .then(select! {\n            Token::Ident(c) => c,\n        })\n        .then_ignore(just(Token::Semicolon))\n        .map_with(|(path, name), extra| {\n            ParsedItem::Alias(ParsedAlias {\n                name,\n                path,\n                span: extra.span(),\n            })\n        })\n        .boxed()\n}\n\nfn file_parser<'a>()\n-> impl Parser<'a, ParserInput<'a>, ParsedZngFile<'a>, ZngParserExtra<'a>> + Clone {\n    item().repeated().collect::<Vec<_>>().map(ParsedZngFile)\n}\n\nfn rust_type<'a>() -> Boxed<'a, 'a, ParserInput<'a>, ParsedRustType<'a>, ZngParserExtra<'a>> {\n    let as_scalar = |s: &str, head: char| -> Option<u32> {\n        let s = s.strip_prefix(head)?;\n        s.parse().ok()\n    };\n\n    let scalar = select! {\n        Token::Ident(\"bool\") => PrimitiveRustType::Bool,\n        Token::Ident(\"str\") => PrimitiveRustType::Str,\n        Token::Ident(\"char\") => PrimitiveRustType::Char,\n        Token::Ident(\"ZngurCppOpaqueOwnedObject\") => PrimitiveRustType::ZngurCppOpaqueOwnedObject,\n        Token::Ident(\"usize\") => PrimitiveRustType::Usize,\n        Token::Ident(c) if as_scalar(c, 'u').is_some() => PrimitiveRustType::Uint(as_scalar(c, 'u').unwrap()),\n        Token::Ident(c) if as_scalar(c, 'i').is_some() => PrimitiveRustType::Int(as_scalar(c, 'i').unwrap()),\n        Token::Ident(c) if as_scalar(c, 'f').is_some() => PrimitiveRustType::Float(as_scalar(c, 'f').unwrap()),\n    }.map(ParsedRustType::Primitive);\n\n    recursive(|parser| {\n        let parser = parser.boxed();\n        let pg = rust_path_and_generics(parser.clone());\n        let adt = pg.clone().map(ParsedRustType::Adt);\n\n        let dyn_trait = just(Token::KwDyn)\n            .or(just(Token::KwImpl))\n            .then(rust_trait(parser.clone()))\n            .then(\n                just(Token::Plus)\n                    .ignore_then(select! {\n                        Token::Ident(c) => c,\n                    })\n                    .repeated()\n                    .collect::<Vec<_>>(),\n            )\n            .map(|((token, first), rest)| match token {\n                Token::KwDyn => ParsedRustType::Dyn(first, rest),\n                Token::KwImpl => ParsedRustType::Impl(first, rest),\n                _ => unreachable!(),\n            });\n        let boxed = just(Token::Ident(\"Box\"))\n            .then(rust_generics(parser.clone()))\n            .map(|(_, x)| {\n                assert_eq!(x.len(), 1);\n                ParsedRustType::Boxed(Box::new(x.into_iter().next().unwrap().right().unwrap()))\n            });\n        let unit = just(Token::ParenOpen)\n            .then(just(Token::ParenClose))\n            .map(|_| ParsedRustType::Tuple(vec![]));\n        let tuple = parser\n            .clone()\n            .separated_by(just(Token::Comma))\n            .allow_trailing()\n            .collect::<Vec<_>>()\n            .delimited_by(just(Token::ParenOpen), just(Token::ParenClose))\n            .map(|xs| ParsedRustType::Tuple(xs));\n        let slice = parser\n            .clone()\n            .map(|x| ParsedRustType::Slice(Box::new(x)))\n            .delimited_by(just(Token::BracketOpen), just(Token::BracketClose));\n        let reference = just(Token::And)\n            .ignore_then(\n                just(Token::KwMut)\n                    .to(Mutability::Mut)\n                    .or(empty().to(Mutability::Not)),\n            )\n            .then(parser.clone())\n            .map(|(m, x)| ParsedRustType::Ref(m, Box::new(x)));\n        let raw_ptr = just(Token::Star)\n            .ignore_then(\n                just(Token::KwMut)\n                    .to(Mutability::Mut)\n                    .or(just(Token::KwConst).to(Mutability::Not)),\n            )\n            .then(parser)\n            .map(|(m, x)| ParsedRustType::Raw(m, Box::new(x)));\n        choice((\n            scalar, boxed, unit, tuple, slice, adt, reference, raw_ptr, dyn_trait,\n        ))\n    })\n    .boxed()\n}\n\nfn rust_generics<'a>(\n    rust_type: Boxed<'a, 'a, ParserInput<'a>, ParsedRustType<'a>, ZngParserExtra<'a>>,\n) -> impl Parser<\n    'a,\n    ParserInput<'a>,\n    Vec<Either<(&'a str, ParsedRustType<'a>), ParsedRustType<'a>>>,\n    ZngParserExtra<'a>,\n> + Clone {\n    let named_generic = select! {\n        Token::Ident(c) => c,\n    }\n    .then_ignore(just(Token::Eq))\n    .then(rust_type.clone())\n    .map(Either::Left);\n    just(Token::ColonColon).repeated().at_most(1).ignore_then(\n        named_generic\n            .or(rust_type.clone().map(Either::Right))\n            .separated_by(just(Token::Comma))\n            .allow_trailing()\n            .collect::<Vec<_>>()\n            .delimited_by(just(Token::AngleOpen), just(Token::AngleClose)),\n    )\n}\n\nfn rust_path_and_generics<'a>(\n    rust_type: Boxed<'a, 'a, ParserInput<'a>, ParsedRustType<'a>, ZngParserExtra<'a>>,\n) -> impl Parser<'a, ParserInput<'a>, ParsedRustPathAndGenerics<'a>, ZngParserExtra<'a>> + Clone {\n    let generics = rust_generics(rust_type.clone());\n    path()\n        .then(generics.clone().repeated().at_most(1).collect::<Vec<_>>())\n        .map(|x| {\n            let generics = x.1.into_iter().next().unwrap_or_default();\n            let (named_generics, generics) = generics.into_iter().partition_map(|x| x);\n            ParsedRustPathAndGenerics {\n                path: x.0,\n                generics,\n                named_generics,\n            }\n        })\n}\n\nfn fn_args<'a>(\n    rust_type: Boxed<'a, 'a, ParserInput<'a>, ParsedRustType<'a>, ZngParserExtra<'a>>,\n) -> impl Parser<'a, ParserInput<'a>, (Vec<ParsedRustType<'a>>, ParsedRustType<'a>), ZngParserExtra<'a>>\n+ Clone {\n    rust_type\n        .clone()\n        .separated_by(just(Token::Comma))\n        .allow_trailing()\n        .collect::<Vec<_>>()\n        .delimited_by(just(Token::ParenOpen), just(Token::ParenClose))\n        .then(\n            just(Token::Arrow)\n                .ignore_then(rust_type)\n                .or(empty().to(ParsedRustType::Tuple(vec![]))),\n        )\n        .boxed()\n}\n\nfn spanned<'a, T>(\n    parser: impl Parser<'a, ParserInput<'a>, T, ZngParserExtra<'a>> + Clone,\n) -> impl Parser<'a, ParserInput<'a>, Spanned<T>, ZngParserExtra<'a>> + Clone {\n    parser.map_with(|inner, extra| Spanned {\n        inner,\n        span: extra.span(),\n    })\n}\n\nfn rust_trait<'a>(\n    rust_type: Boxed<'a, 'a, ParserInput<'a>, ParsedRustType<'a>, ZngParserExtra<'a>>,\n) -> impl Parser<'a, ParserInput<'a>, ParsedRustTrait<'a>, ZngParserExtra<'a>> + Clone {\n    let fn_trait = select! {\n        Token::Ident(c) => c,\n    }\n    .then(fn_args(rust_type.clone()))\n    .map(|x| ParsedRustTrait::Fn {\n        name: x.0,\n        inputs: x.1.0,\n        output: Box::new(x.1.1),\n    });\n\n    let rust_trait = fn_trait.or(rust_path_and_generics(rust_type).map(ParsedRustTrait::Normal));\n    rust_trait\n}\n\nfn method<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedMethod<'a>, ZngParserExtra<'a>> + Clone {\n    spanned(just(Token::KwAsync))\n        .or_not()\n        .then_ignore(just(Token::KwFn))\n        .then(select! {\n            Token::Ident(c) => c,\n        })\n        .then(\n            rust_type()\n                .separated_by(just(Token::Comma))\n                .collect::<Vec<_>>()\n                .delimited_by(just(Token::AngleOpen), just(Token::AngleClose))\n                .or(empty().to(vec![])),\n        )\n        .then(fn_args(rust_type()))\n        .map(|(((opt_async, name), generics), args)| {\n            let is_self = |c: &ParsedRustType<'_>| {\n                if let ParsedRustType::Adt(c) = c {\n                    c.path.start == ParsedPathStart::Relative\n                        && &c.path.segments == &[\"self\"]\n                        && c.generics.is_empty()\n                } else {\n                    false\n                }\n            };\n            let (inputs, receiver) = match args.0.get(0) {\n                Some(x) if is_self(&x) => (args.0[1..].to_vec(), ZngurMethodReceiver::Move),\n                Some(ParsedRustType::Ref(m, x)) if is_self(&x) => {\n                    (args.0[1..].to_vec(), ZngurMethodReceiver::Ref(*m))\n                }\n                _ => (args.0, ZngurMethodReceiver::Static),\n            };\n            let mut output = args.1;\n            if let Some(async_kw) = opt_async {\n                output = ParsedRustType::Impl(\n                    ParsedRustTrait::Normal(ParsedRustPathAndGenerics {\n                        path: ParsedPath {\n                            start: ParsedPathStart::Absolute,\n                            segments: vec![\"std\", \"future\", \"Future\"],\n                            span: async_kw.span,\n                        },\n                        generics: vec![],\n                        named_generics: vec![(\"Output\", output)],\n                    }),\n                    vec![],\n                )\n            }\n            ParsedMethod {\n                name,\n                receiver,\n                generics,\n                inputs,\n                output,\n            }\n        })\n}\n\nfn inner_type_item<'a>()\n-> impl Parser<'a, ParserInput<'a>, ParsedTypeItem<'a>, ZngParserExtra<'a>> + Clone {\n    let property_item = (spanned(select! {\n        Token::Ident(c) => c,\n    }))\n    .then_ignore(just(Token::Eq))\n    .then(select! {\n        Token::Number(c) => c,\n    });\n    let layout = just([Token::Sharp, Token::Ident(\"layout\")])\n        .ignore_then(\n            property_item\n                .clone()\n                .separated_by(just(Token::Comma))\n                .collect::<Vec<_>>()\n                .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),\n        )\n        .map(ParsedLayoutPolicy::StackAllocated)\n        .or(just([Token::Sharp, Token::Ident(\"layout_conservative\")])\n            .ignore_then(\n                property_item\n                    .separated_by(just(Token::Comma))\n                    .collect::<Vec<_>>()\n                    .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),\n            )\n            .map(ParsedLayoutPolicy::Conservative))\n        .or(just([Token::Sharp, Token::Ident(\"only_by_ref\")]).to(ParsedLayoutPolicy::OnlyByRef))\n        .or(just([Token::Sharp, Token::Ident(\"heap_allocated\")])\n            .to(ParsedLayoutPolicy::HeapAllocated))\n        .map_with(|x, extra| ParsedTypeItem::Layout(extra.span(), x))\n        .boxed();\n    let trait_item = select! {\n        Token::Ident(\"Debug\") => ZngurWellknownTrait::Debug,\n        Token::Ident(\"Copy\") => ZngurWellknownTrait::Copy,\n    }\n    .or(just(Token::Question)\n        .then(just(Token::Ident(\"Sized\")))\n        .to(ZngurWellknownTrait::Unsized));\n    let traits = just(Token::Ident(\"wellknown_traits\"))\n        .ignore_then(\n            spanned(trait_item)\n                .separated_by(just(Token::Comma))\n                .collect::<Vec<_>>()\n                .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),\n        )\n        .map(ParsedTypeItem::Traits)\n        .boxed();\n    let constructor_args = rust_type()\n        .separated_by(just(Token::Comma))\n        .collect::<Vec<_>>()\n        .delimited_by(just(Token::ParenOpen), just(Token::ParenClose))\n        .map(ParsedConstructorArgs::Tuple)\n        .or((select! {\n            Token::Ident(c) => c,\n        })\n        .boxed()\n        .then_ignore(just(Token::Colon))\n        .then(rust_type())\n        .separated_by(just(Token::Comma))\n        .collect::<Vec<_>>()\n        .delimited_by(just(Token::BraceOpen), just(Token::BraceClose))\n        .map(ParsedConstructorArgs::Named))\n        .or(empty().to(ParsedConstructorArgs::Unit))\n        .boxed();\n    let constructor = just(Token::Ident(\"constructor\")).ignore_then(\n        (select! {\n            Token::Ident(c) => Some(c),\n        })\n        .or(empty().to(None))\n        .then(constructor_args)\n        .map(|(name, args)| ParsedTypeItem::Constructor { name, args }),\n    );\n    let field = just(Token::Ident(\"field\")).ignore_then(\n        (select! {\n            Token::Ident(c) => c.to_owned(),\n            Token::Number(c) => c.to_string(),\n        })\n        .then(\n            just(Token::Ident(\"offset\"))\n                .then(just(Token::Eq))\n                .ignore_then(select! {\n                    Token::Number(c) => Some(c),\n                    Token::Ident(\"auto\") => None,\n                })\n                .then(\n                    just(Token::Comma)\n                        .then(just(Token::KwType))\n                        .then(just(Token::Eq))\n                        .ignore_then(rust_type()),\n                )\n                .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),\n        )\n        .map(|(name, (offset, ty))| ParsedTypeItem::Field { name, ty, offset }),\n    );\n    let cpp_value = just(Token::Sharp)\n        .then(just(Token::Ident(\"cpp_value\")))\n        .ignore_then(select! {\n            Token::Str(c) => c,\n        })\n        .then(select! {\n            Token::Str(c) => c,\n        })\n        .map(|x| ParsedTypeItem::CppValue {\n            field: x.0,\n            cpp_type: x.1,\n        });\n    let cpp_ref = just(Token::Sharp)\n        .then(just(Token::Ident(\"cpp_ref\")))\n        .ignore_then(select! {\n            Token::Str(c) => c,\n        })\n        .map(|x| ParsedTypeItem::CppRef { cpp_type: x });\n    recursive(|item| {\n        let inner_item = choice((\n            layout,\n            traits,\n            constructor,\n            field,\n            cpp_value,\n            cpp_ref,\n            method()\n                .then(\n                    just(Token::KwUse)\n                        .ignore_then(path())\n                        .map(Some)\n                        .or(empty().to(None)),\n                )\n                .then(\n                    just(Token::Ident(\"deref\"))\n                        .ignore_then(rust_type())\n                        .map(Some)\n                        .or(empty().to(None)),\n                )\n                .map(|((data, use_path), deref)| ParsedTypeItem::Method {\n                    deref,\n                    use_path,\n                    data,\n                }),\n        ));\n\n        let match_stmt =\n            conditional_item::<_, CfgConditional<'a>, NItems>(item).map(ParsedTypeItem::MatchOnCfg);\n\n        choice((match_stmt, inner_item.then_ignore(just(Token::Semicolon))))\n    })\n}\n\nfn type_item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {\n    just(Token::KwType)\n        .ignore_then(spanned(rust_type()))\n        .then(\n            spanned(inner_type_item())\n                .repeated()\n                .collect::<Vec<_>>()\n                .delimited_by(just(Token::BraceOpen), just(Token::BraceClose)),\n        )\n        .map(|(ty, items)| ParsedItem::Type { ty, items })\n        .boxed()\n}\n\nfn trait_item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone\n{\n    just(Token::KwTrait)\n        .ignore_then(spanned(rust_trait(rust_type())))\n        .then(\n            method()\n                .then_ignore(just(Token::Semicolon))\n                .repeated()\n                .collect::<Vec<_>>()\n                .delimited_by(just(Token::BraceOpen), just(Token::BraceClose)),\n        )\n        .map(|(tr, methods)| ParsedItem::Trait { tr, methods })\n        .boxed()\n}\n\nfn fn_item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {\n    spanned(method())\n        .then_ignore(just(Token::Semicolon))\n        .map(ParsedItem::Fn)\n}\n\nfn additional_include_item<'a>()\n-> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {\n    just(Token::Sharp)\n        .ignore_then(choice((\n            just(Token::Ident(\"cpp_additional_includes\")).ignore_then(select! {\n                Token::Str(c) => ParsedItem::CppAdditionalInclude(c),\n            }),\n            just(Token::Ident(\"convert_panic_to_exception\"))\n                .map_with(|_, extra| ParsedItem::ConvertPanicToException(extra.span())),\n        )))\n        .boxed()\n}\n\nfn extern_cpp_item<'a>()\n-> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {\n    let function = spanned(method())\n        .then_ignore(just(Token::Semicolon))\n        .map(ParsedExternCppItem::Function);\n    let impl_block = just(Token::KwImpl)\n        .ignore_then(\n            rust_trait(rust_type())\n                .then_ignore(just(Token::KwFor))\n                .map(Some)\n                .or(empty().to(None))\n                .then(spanned(rust_type())),\n        )\n        .then(\n            method()\n                .then_ignore(just(Token::Semicolon))\n                .repeated()\n                .collect::<Vec<_>>()\n                .delimited_by(just(Token::BraceOpen), just(Token::BraceClose)),\n        )\n        .map(|((tr, ty), methods)| ParsedExternCppItem::Impl { tr, ty, methods });\n    just(Token::KwExtern)\n        .then(just(Token::Str(\"C++\")))\n        .ignore_then(\n            function\n                .or(impl_block)\n                .repeated()\n                .collect::<Vec<_>>()\n                .delimited_by(just(Token::BraceOpen), just(Token::BraceClose))\n                .boxed(),\n        )\n        .map(ParsedItem::ExternCpp)\n        .boxed()\n}\n\nfn unstable_feature<'a>()\n-> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {\n    just([Token::Sharp, Token::Ident(\"unstable\")]).ignore_then(\n        select! { Token::Ident(feat) => feat }\n            .delimited_by(just(Token::ParenOpen), just(Token::ParenClose))\n            .try_map_with(|feat, e| match feat {\n                \"cfg_match\" => {\n                    let ctx: &mut extra::SimpleState<ZngParserState> = e.state();\n                    ctx.unstable_features.cfg_match = true;\n                    Ok(ParsedItem::UnstableFeature(\"cfg_match\"))\n                }\n                \"cfg_if\" => {\n                    let ctx: &mut extra::SimpleState<ZngParserState> = e.state();\n                    ctx.unstable_features.cfg_if = true;\n                    Ok(ParsedItem::UnstableFeature(\"cfg_if\"))\n                }\n                _ => Err(Rich::custom(\n                    e.span(),\n                    format!(\"unknown unstable feature '{feat}'\"),\n                )),\n            }),\n    )\n}\n\nfn item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {\n    recursive(|item| {\n        choice((\n            unstable_feature(),\n            just(Token::KwMod)\n                .ignore_then(path())\n                .then(\n                    item.clone()\n                        .repeated()\n                        .collect::<Vec<_>>()\n                        .delimited_by(just(Token::BraceOpen), just(Token::BraceClose)),\n                )\n                .map(|(path, items)| ParsedItem::Mod { path, items }),\n            type_item(),\n            trait_item(),\n            extern_cpp_item(),\n            fn_item(),\n            additional_include_item(),\n            import_item(),\n            module_import_item(),\n            alias(),\n            conditional_item::<_, CfgConditional<'a>, NItems>(item).map(ParsedItem::MatchOnCfg),\n        ))\n    })\n    .boxed()\n}\n\nfn import_item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone\n{\n    just(Token::KwMerge)\n        .ignore_then(select! {\n            Token::Str(path) => path,\n        })\n        .then_ignore(just(Token::Semicolon))\n        .map_with(|path, extra| {\n            ParsedItem::Import(ParsedImportPath {\n                path: std::path::PathBuf::from(path),\n                span: extra.span(),\n            })\n        })\n        .boxed()\n}\n\nfn module_import_item<'a>()\n-> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {\n    just(Token::KwImport)\n        .ignore_then(select! { Token::Str(path) => path })\n        .then_ignore(just(Token::Semicolon))\n        .map_with(|path, extra| ParsedItem::ModuleImport {\n            path: std::path::PathBuf::from(path),\n            span: extra.span(),\n        })\n        .boxed()\n}\n\nfn path<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedPath<'a>, ZngParserExtra<'a>> + Clone {\n    let start = choice((\n        just(Token::ColonColon).to(ParsedPathStart::Absolute),\n        just(Token::KwCrate)\n            .then(just(Token::ColonColon))\n            .to(ParsedPathStart::Crate),\n        empty().to(ParsedPathStart::Relative),\n    ));\n\n    start\n        .then(\n            (select! {\n                Token::Ident(c) => c,\n            })\n            .separated_by(just(Token::ColonColon))\n            .at_least(1)\n            .collect::<Vec<_>>(),\n        )\n        .or(just(Token::KwCrate).to((ParsedPathStart::Crate, vec![])))\n        .map_with(|(start, segments), extra| ParsedPath {\n            start,\n            segments,\n            span: extra.span(),\n        })\n        .boxed()\n}\n\nimpl<'a> conditional::BodyItem for crate::ParsedTypeItem<'a> {\n    type Processed = Self;\n\n    fn process(self, _ctx: &mut ParseContext) -> Self::Processed {\n        self\n    }\n}\n\nimpl<'a> conditional::BodyItem for crate::ParsedItem<'a> {\n    type Processed = ProcessedItemOrAlias<'a>;\n\n    fn process(self, ctx: &mut ParseContext) -> Self::Processed {\n        crate::process_parsed_item(self, ctx)\n    }\n}\n"
  },
  {
    "path": "zngur-parser/src/tests.rs",
    "content": "use std::panic::catch_unwind;\n\nuse expect_test::{Expect, expect};\nuse zngur_def::{LayoutPolicy, RustPathAndGenerics, RustType, ZngurSpec};\n\nuse crate::{\n    ImportResolver, ParsedZngFile,\n    cfg::{InMemoryRustCfgProvider, NullCfg, RustCfgProvider},\n};\n\nfn check_success(zng: &str) {\n    let _ = ParsedZngFile::parse_str(zng, NullCfg);\n}\n\npub struct ErrorText(pub String);\n\nfn check_fail(zng: &str, error: Expect) {\n    let r = catch_unwind(|| {\n        let _ = ParsedZngFile::parse_str(zng, NullCfg);\n    });\n    match r {\n        Ok(_) => panic!(\"Parsing succeeded but we expected fail\"),\n        Err(e) => match e.downcast::<ErrorText>() {\n            Ok(t) => error.assert_eq(&t.0),\n            Err(e) => std::panic::resume_unwind(e),\n        },\n    }\n}\n\nfn check_fail_with_cfg(\n    zng: &str,\n    cfg: impl RustCfgProvider + std::panic::UnwindSafe + 'static,\n    error: Expect,\n) {\n    let r = catch_unwind(|| {\n        let _ = ParsedZngFile::parse_str(zng, cfg);\n    });\n    match r {\n        Ok(_) => panic!(\"Parsing succeeded but we expected fail\"),\n        Err(e) => match e.downcast::<ErrorText>() {\n            Ok(t) => error.assert_eq(&t.0),\n            Err(e) => std::panic::resume_unwind(e),\n        },\n    }\n}\n\nfn check_import_fail(zng: &str, error: Expect, resolver: &MockFilesystem) {\n    let r = catch_unwind(|| {\n        let _ = ParsedZngFile::parse_str_with_resolver(zng, NullCfg, resolver);\n    });\n\n    match r {\n        Ok(_) => panic!(\"Parsing succeeded but we expected fail\"),\n        Err(e) => match e.downcast::<ErrorText>() {\n            Ok(t) => error.assert_eq(&t.0),\n            Err(e) => std::panic::resume_unwind(e),\n        },\n    }\n}\n\n// useful for debugging a test that should succeeded on parse\nfn catch_parse_fail(\n    zng: &str,\n    cfg: impl RustCfgProvider + std::panic::UnwindSafe + 'static,\n) -> crate::ParseResult {\n    let r = catch_unwind(move || ParsedZngFile::parse_str(zng, cfg));\n\n    match r {\n        Ok(r) => r,\n        Err(e) => match e.downcast::<ErrorText>() {\n            Ok(t) => {\n                eprintln!(\"{}\", &t.0);\n                crate::ParseResult {\n                    spec: ZngurSpec::default(),\n                    processed_files: Vec::new(),\n                }\n            }\n            Err(e) => std::panic::resume_unwind(e),\n        },\n    }\n}\n\n#[test]\nfn parse_unit() {\n    check_fail(\n        r#\"\ntype () {\n    #layout(size = 0, align = 1);\n    wellknown_traits(Copy);\n}\n    \"#,\n        expect![[r#\"\n            Error: Unit type is declared implicitly. Remove this entirely.\n               ╭─[test.zng:2:6]\n               │\n             2 │ type () {\n               │      ─┬  \n               │       ╰── Unit type is declared implicitly. Remove this entirely.\n            ───╯\n        \"#]],\n    );\n}\n\n#[test]\nfn parse_tuple() {\n    check_success(\n        r#\"\ntype (i8, u8) {\n    #layout(size = 0, align = 1);\n}\n    \"#,\n    );\n}\n\n#[test]\nfn typo_in_wellknown_trait() {\n    check_fail(\n        r#\"\ntype () {\n    #layout(size = 0, align = 1);\n    welcome_traits(Copy);\n}\n    \"#,\n        expect![[r#\"\n            Error: found 'welcome_traits' expected '#', 'wellknown_traits', 'constructor', 'field', 'async', 'fn', or '}'\n               ╭─[test.zng:4:5]\n               │\n             4 │     welcome_traits(Copy);\n               │     ───────┬──────  \n               │            ╰──────── found 'welcome_traits' expected '#', 'wellknown_traits', 'constructor', 'field', 'async', 'fn', or '}'\n            ───╯\n        \"#]],\n    );\n}\n\n#[test]\nfn multiple_layout_policies() {\n    check_fail(\n        r#\"\ntype ::std::string::String {\n    #layout(size = 24, align = 8);\n    #heap_allocated;\n}\n    \"#,\n        expect![[r#\"\n            Error: Duplicate layout policy found\n               ╭─[test.zng:4:5]\n               │\n             4 │     #heap_allocated;\n               │     ───────┬───────  \n               │            ╰───────── Duplicate layout policy found\n            ───╯\n        \"#]],\n    );\n}\n\n#[test]\nfn cpp_ref_should_not_need_layout_info() {\n    check_fail(\n        r#\"\ntype crate::Way {\n    #layout(size = 1, align = 2);\n\n    #cpp_ref \"::osmium::Way\";\n}\n    \"#,\n        expect![[r#\"\n            Error: Duplicate layout policy found\n               ╭─[test.zng:3:5]\n               │\n             3 │     #layout(size = 1, align = 2);\n               │     ──────────────┬─────────────  \n               │                   ╰─────────────── Duplicate layout policy found\n            ───╯\n        \"#]],\n    );\n    check_success(\n        r#\"\ntype crate::Way {\n    #cpp_ref \"::osmium::Way\";\n}\n    \"#,\n    );\n}\n\nmacro_rules! assert_ty_path {\n    ($path_expected:expr, $ty:expr) => {{\n        let RustType::Adt(RustPathAndGenerics { path: p, .. }) = $ty else {\n            panic!(\"type `{:?}` is not a path\", $ty);\n        };\n        assert_eq!(p.as_slice(), $path_expected);\n    }};\n}\n\n#[test]\nfn alias_expands_correctly() {\n    let parsed = ParsedZngFile::parse_str(\n        r#\"\nuse ::std::string::String as MyString;\ntype MyString {\n    #layout(size = 24, align = 8);\n}\n    \"#,\n        NullCfg,\n    );\n    let ty = parsed.spec.types.first().expect(\"no type parsed\");\n    let RustType::Adt(RustPathAndGenerics { path: p, .. }) = &ty.ty else {\n        panic!(\"no match?\");\n    };\n    assert_eq!(p.as_slice(), [\"std\", \"string\", \"String\"]);\n}\n\n#[test]\nfn alias_expands_nearest_scope_first() {\n    let parsed = ParsedZngFile::parse_str(\n        r#\"\nuse ::std::string::String as MyString;\nmod crate {\n    use MyLocalString as MyString;\n    type MyString {\n        #layout(size = 24, align = 8);\n    }\n}\n    \"#,\n        NullCfg,\n    );\n    let ty = parsed.spec.types.first().expect(\"no type parsed\");\n    let RustType::Adt(RustPathAndGenerics { path: p, .. }) = &ty.ty else {\n        panic!(\"no match?\");\n    };\n    assert_eq!(p.as_slice(), [\"crate\", \"MyLocalString\"]);\n}\n\nstruct MockFilesystem {\n    files: std::collections::HashMap<std::path::PathBuf, String>,\n}\n\nimpl MockFilesystem {\n    fn new(\n        files: impl IntoIterator<Item = (impl Into<std::path::PathBuf>, impl Into<String>)>,\n    ) -> Self {\n        Self {\n            files: files\n                .into_iter()\n                .map(|(k, v)| (k.into(), v.into()))\n                .collect(),\n        }\n    }\n}\n\nimpl ImportResolver for MockFilesystem {\n    fn resolve_import(\n        &self,\n        cwd: &std::path::Path,\n        relpath: &std::path::Path,\n    ) -> Result<String, String> {\n        let path = cwd.join(relpath);\n        self.files\n            .get(&path)\n            .cloned()\n            .ok_or_else(|| format!(\"File not found: {}\", path.display()))\n    }\n}\n\n#[test]\nfn import_parser_test() {\n    let resolver = MockFilesystem::new(vec![(\n        \"./relative/path.zng\",\n        \"type Imported { #layout(size = 1, align = 1); }\",\n    )]);\n\n    let parsed = ParsedZngFile::parse_str_with_resolver(\n        r#\"\nmerge \"./relative/path.zng\";\ntype Example {\n    #layout(size = 1, align = 1);\n}\n    \"#,\n        NullCfg,\n        &resolver,\n    );\n    assert_eq!(parsed.spec.types.len(), 2);\n}\n\n#[test]\nfn module_import_prohibited() {\n    let resolver = MockFilesystem::new(vec![] as Vec<(&str, &str)>);\n\n    check_import_fail(\n        r#\"\n    merge \"foo/bar.zng\";\n    \"#,\n        expect![[r#\"\n            Error: Module import is not supported. Use a relative path instead.\n               ╭─[test.zng:2:5]\n               │\n             2 │     merge \"foo/bar.zng\";\n               │     ──────────┬─────────  \n               │               ╰─────────── Module import is not supported. Use a relative path instead.\n            ───╯\n        \"#]],\n        &resolver,\n    );\n}\n\n#[test]\nfn import_has_conflict() {\n    // Test that an import which introduces a conflict produces a reasonable error message.\n    let resolver = MockFilesystem::new(vec![(\n        \"./a.zng\",\n        r#\"\n      type A {\n        #layout(size = 1, align = 1);\n      }\n    \"#,\n    )]);\n\n    check_import_fail(\n        r#\"\n    merge \"./a.zng\";\n    type A {\n      #layout(size = 2, align = 2);\n    }\n\"#,\n        expect![[r#\"\n            Error: Duplicate layout policy found\n               ╭─[a.zng:2:12]\n               │\n             2 │       type A {\n               │            ┬  \n               │            ╰── Duplicate layout policy found\n            ───╯\n        \"#]],\n        &resolver,\n    );\n}\n\n#[test]\nfn import_not_found() {\n    let resolver = MockFilesystem::new(vec![] as Vec<(&str, &str)>);\n    check_import_fail(\n        r#\"\n    merge \"./a.zng\";\n    \"#,\n        expect![[r#\"\n            Error: Import path not found: ./a.zng\n        \"#]],\n        &resolver,\n    );\n}\n\n#[test]\nfn import_has_mismatched_method_signature() {\n    let resolver = MockFilesystem::new(vec![(\n        \"./a.zng\",\n        \"type A { #layout(size = 1, align = 1); fn foo(i32) -> i32; }\",\n    )]);\n\n    check_import_fail(\n        r#\"\n  merge \"./a.zng\";\n  type A {\n    #layout(size = 1, align = 1);\n    fn foo(i64) -> i64;\n  }\n  \"#,\n        expect![[r#\"\n            Error: Method mismatch\n               ╭─[a.zng:1:6]\n               │\n             1 │ type A { #layout(size = 1, align = 1); fn foo(i32) -> i32; }\n               │      ┬  \n               │      ╰── Method mismatch\n            ───╯\n        \"#]],\n        &resolver,\n    );\n}\n\n#[test]\nfn import_has_mismatched_field() {\n    let resolver = MockFilesystem::new(vec![(\n        \"./a.zng\",\n        \"type A {\n        #layout(size = 1, align = 1);\n        field x (offset = 0, type = i32);\n    }\",\n    )]);\n\n    check_import_fail(\n        r#\"\n  merge \"./a.zng\";\n  type A {\n    #layout(size = 1, align = 1);\n    field x (offset = 0, type = i64);\n  }\n  \"#,\n        expect![[r#\"\n            Error: Field mismatch\n               ╭─[a.zng:1:6]\n               │\n             1 │ type A {\n               │      ┬  \n               │      ╰── Field mismatch\n            ───╯\n        \"#]],\n        &resolver,\n    );\n}\n\n#[test]\nfn convert_panic_to_exception_in_imported_file_fails() {\n    let resolver = MockFilesystem::new(vec![(\n        \"./imported.zng\",\n        r#\"\n        #convert_panic_to_exception\n        type A {\n            #layout(size = 1, align = 1);\n        }\n        \"#,\n    )]);\n\n    check_import_fail(\n        r#\"\nmerge \"./imported.zng\";\ntype B {\n    #layout(size = 1, align = 1);\n}\n        \"#,\n        expect![[r#\"\n            Error: Using `#convert_panic_to_exception` in imported zngur files is not supported. This directive can only be used in the main zngur file.\n               ╭─[imported.zng:2:10]\n               │\n             2 │         #convert_panic_to_exception\n               │          ─────────────┬────────────  \n               │                       ╰────────────── Using `#convert_panic_to_exception` in imported zngur files is not supported. This directive can only be used in the main zngur file.\n            ───╯\n        \"#]],\n        &resolver,\n    );\n}\n\n#[test]\nfn convert_panic_to_exception_in_main_file_succeeds() {\n    check_success(\n        r#\"\n#convert_panic_to_exception\ntype A {\n    #layout(size = 1, align = 1);\n}\n        \"#,\n    );\n}\n\n// Tests for processed_files tracking (depfile support)\n\n#[test]\nfn processed_files_single_file() {\n    let parsed = ParsedZngFile::parse_str(\n        r#\"\ntype A {\n    #layout(size = 1, align = 1);\n}\n        \"#,\n        NullCfg,\n    );\n    // Should have exactly one file (test.zng)\n    assert_eq!(parsed.processed_files.len(), 1);\n    assert_eq!(\n        parsed.processed_files[0]\n            .file_name()\n            .unwrap()\n            .to_str()\n            .unwrap(),\n        \"test.zng\"\n    );\n}\n\n#[test]\nfn processed_files_with_import() {\n    let resolver = MockFilesystem::new(vec![(\n        \"./imported.zng\",\n        \"type Imported { #layout(size = 1, align = 1); }\",\n    )]);\n\n    let parsed = ParsedZngFile::parse_str_with_resolver(\n        r#\"\nmerge \"./imported.zng\";\ntype Main {\n    #layout(size = 1, align = 1);\n}\n        \"#,\n        NullCfg,\n        &resolver,\n    );\n    // Should have two files: main (test.zng) + imported\n    assert_eq!(parsed.processed_files.len(), 2);\n    let file_names: Vec<_> = parsed\n        .processed_files\n        .iter()\n        .map(|p| p.file_name().unwrap().to_str().unwrap())\n        .collect();\n    assert!(file_names.contains(&\"test.zng\"));\n    assert!(file_names.contains(&\"imported.zng\"));\n}\n\n#[test]\nfn processed_files_with_nested_imports() {\n    let resolver = MockFilesystem::new(vec![\n        (\n            \"./a.zng\",\n            r#\"merge \"./b.zng\"; type A { #layout(size = 1, align = 1); }\"#,\n        ),\n        (\n            \"./b.zng\",\n            r#\"merge \"./c.zng\"; type B { #layout(size = 1, align = 1); }\"#,\n        ),\n        (\"./c.zng\", \"type C { #layout(size = 1, align = 1); }\"),\n    ]);\n\n    let parsed = ParsedZngFile::parse_str_with_resolver(\n        r#\"\nmerge \"./a.zng\";\ntype Main {\n    #layout(size = 1, align = 1);\n}\n        \"#,\n        NullCfg,\n        &resolver,\n    );\n    // Should have four files: main + a + b + c\n    assert_eq!(parsed.processed_files.len(), 4);\n    let file_names: Vec<_> = parsed\n        .processed_files\n        .iter()\n        .map(|p| p.file_name().unwrap().to_str().unwrap())\n        .collect();\n    assert!(file_names.contains(&\"test.zng\"));\n    assert!(file_names.contains(&\"a.zng\"));\n    assert!(file_names.contains(&\"b.zng\"));\n    assert!(file_names.contains(&\"c.zng\"));\n}\n\nfn assert_layout(wanted_size: usize, wanted_align: usize, layout: &LayoutPolicy) {\n    if !matches!(layout, LayoutPolicy::StackAllocated { size, align } if *size == wanted_size && *align == wanted_align)\n    {\n        panic!(\n            \"no match: StackAllocated {{ size: {wanted_size}, align: {wanted_align} }} != {:?} \",\n            layout\n        );\n    };\n}\n\nstatic EMPTY_CFG: [(&str, &[&str]); 0] = [];\n\n#[test]\nfn test_if_conditional_type_item() {\n    let source = r#\"\n#unstable(cfg_if)\n\ntype ::std::string::String {\n    #if cfg!(target_pointer_width = \"64\") {\n        #layout(size = 24, align = 8);\n    } #else if cfg!(target_pointer_width = \"32\") {\n        #layout(size = 12, align = 4);\n    } #else {\n        // silly size for testing\n        #layout(size = 27, align = 9);\n    }\n}\n    \"#;\n    let parsed = catch_parse_fail(\n        source,\n        InMemoryRustCfgProvider::default().with_values([(\"target_pointer_width\", &[\"64\"])]),\n    );\n    let ty = parsed.spec.types.first().expect(\"no type parsed\");\n    assert_layout(24, 8, &ty.layout);\n    let parsed = catch_parse_fail(\n        source,\n        InMemoryRustCfgProvider::default().with_values([(\"target_pointer_width\", &[\"32\"])]),\n    );\n    let ty = parsed.spec.types.first().expect(\"no type parsed\");\n    assert_layout(12, 4, &ty.layout);\n    let parsed = catch_parse_fail(source, NullCfg);\n    let ty = parsed.spec.types.first().expect(\"no type parsed\");\n\n    assert_layout(27, 9, &ty.layout);\n}\n\n#[test]\nfn test_match_conditional_type_item() {\n    let source = r#\"\n#unstable(cfg_match)\n\ntype ::std::string::String {\n    #match cfg!(target_pointer_width) {\n        // single item arm\n        \"64\" => #layout(size = 24, align = 8);\n        // match usize numbers\n        32 => {\n            #layout(size = 12, align = 4);\n        },\n     \n        _ => {\n            // silly size for testing\n            #layout(size = 27, align = 9);\n        }\n    }\n}\n    \"#;\n    let parsed = catch_parse_fail(\n        source,\n        InMemoryRustCfgProvider::default().with_values([(\"target_pointer_width\", &[\"64\"])]),\n    );\n    let ty = parsed.spec.types.first().expect(\"no type parsed\");\n    assert_layout(24, 8, &ty.layout);\n    let parsed = catch_parse_fail(\n        source,\n        InMemoryRustCfgProvider::default().with_values([(\"target_pointer_width\", &[\"32\"])]),\n    );\n    let ty = parsed.spec.types.first().expect(\"no type parsed\");\n    assert_layout(12, 4, &ty.layout);\n    let parsed = catch_parse_fail(source, NullCfg);\n    let ty = parsed.spec.types.first().expect(\"no type parsed\");\n\n    assert_layout(27, 9, &ty.layout);\n}\n\nmacro_rules! test_paths_with_cfg {\n    ($src:expr, $features_path_pairs:expr) => {\n        for (cfg, path) in $features_path_pairs.iter().map(|(cfg, path)| {\n            (\n                cfg.into_iter().copied().collect::<Vec<_>>(),\n                path.iter().map(|s| s.to_string()).collect::<Vec<_>>(),\n            )\n        }) {\n            let parsed =\n                catch_parse_fail($src, InMemoryRustCfgProvider::default().with_values(cfg));\n            let ty = parsed.spec.types.first().expect(\"no type parsed\");\n            assert_ty_path!(path, &ty.ty);\n        }\n    };\n}\n\ntype CfgPathPairs<'a> = &'a [(&'a [(&'a str, &'a [&'a str])], &'a [&'a str])];\n\n#[test]\nfn conditional_if_spec_item() {\n    let source = r#\"\n#unstable(cfg_if)\n\n#if cfg!(feature = \"foo\") {\n    type crate::Foo {\n        #layout(size = 1, align = 1);\n    }\n} #else {\n    type crate::Bar {\n        #layout(size = 1, align = 1);\n    }\n}\n    \"#;\n\n    let pairs: CfgPathPairs = &[\n        (&[(\"feature\", &[\"foo\"])], &[\"crate\", \"Foo\"]),\n        (&EMPTY_CFG, &[\"crate\", \"Bar\"]),\n    ];\n    test_paths_with_cfg!(source, pairs);\n}\n\n#[test]\nfn conditional_match_spec_item() {\n    let source = r#\"\n#unstable(cfg_match)\n\n#match cfg!(feature) {\n    \"foo\" => type crate::Foo {\n        #layout(size = 1, align = 1);\n    }\n    _ => {\n        type crate::Bar {\n            #layout(size = 1, align = 1);\n        }\n    }\n}\n    \"#;\n    let pairs: CfgPathPairs = &[\n        (&[(\"feature\", &[\"foo\"])], &[\"crate\", \"Foo\"]),\n        (&EMPTY_CFG, &[\"crate\", \"Bar\"]),\n    ];\n    test_paths_with_cfg!(source, pairs);\n}\n\n#[test]\nfn match_pattern_single_cfg() {\n    let source = r#\"\n#unstable(cfg_match)\n\n#match cfg!(feature) {\n    \"bar\" | \"zigza\" => type crate::BarZigZa {\n        #layout(size = 1, align = 1);\n    }\n    // match two values from a cfg value as a set \n    \"foo\" & \"baz\" => type crate::FooBaz {\n        #layout(size = 1, align = 1);\n    }\n    // negative matching (no feature baz)\n    \"foo\" & !\"baz\" => type crate::FooNoBaz {\n        #layout(size = 1, align = 1);\n    }\n    _ => {\n        type crate::Zoop {\n            #layout(size = 1, align = 1);\n        }\n    }\n}\n    \"#;\n    let pairs: CfgPathPairs = &[\n        (&EMPTY_CFG, &[\"crate\", \"Zoop\"]),\n        (&[(\"feature\", &[\"foo\"])], &[\"crate\", \"FooNoBaz\"]),\n        (&[(\"feature\", &[\"bar\"])], &[\"crate\", \"BarZigZa\"]),\n        (&[(\"feature\", &[\"zigza\"])], &[\"crate\", \"BarZigZa\"]),\n        (&[(\"feature\", &[\"foo\", \"baz\"])], &[\"crate\", \"FooBaz\"]),\n    ];\n    test_paths_with_cfg!(source, pairs);\n}\n\n#[test]\nfn if_pattern_multi_cfg() {\n    let source = r#\"\n#unstable(cfg_if)\n// match two cfg keys as a set\n#if cfg!(feature.foo) && cfg!(target_pointer_width = 32) {\n    type crate::Foo32 {\n        #layout(size = 1, align = 1);\n    }\n} #else if cfg!(feature.foo = None) && cfg!(target_pointer_width = 64) {\n    type crate::NoFoo64 {\n        #layout(size = 1, align = 1);\n    }\n} #else if (cfg!(feature.foo = Some) && cfg!(target_pointer_width = 64)) || cfg!(feature.baz) {\n    type crate::Foo64_OrBaz {\n        #layout(size = 1, align = 1);\n    }\n} #else {\n    type crate::SpecialFoo {\n        #layout(size = 1, align = 1);\n    }\n}\n    \"#;\n    let pairs: CfgPathPairs = &[\n        (\n            &[(\"target_pointer_width\", &[\"32\"]), (\"feature\", &[\"foo\"])],\n            &[\"crate\", \"Foo32\"],\n        ),\n        (\n            &[(\"target_pointer_width\", &[\"64\"]), (\"feature\", &[\"bar\"])],\n            &[\"crate\", \"NoFoo64\"],\n        ),\n        (\n            &[(\"target_pointer_width\", &[\"64\"]), (\"feature\", &[\"foo\"])],\n            &[\"crate\", \"Foo64_OrBaz\"],\n        ),\n        (\n            &[(\"target_pointer_width\", &[\"32\"]), (\"feature\", &[\"baz\"])],\n            &[\"crate\", \"Foo64_OrBaz\"],\n        ),\n        (&[(\"feature\", &[\"foo\"])], &[\"crate\", \"SpecialFoo\"]),\n        (&EMPTY_CFG, &[\"crate\", \"SpecialFoo\"]),\n    ];\n    test_paths_with_cfg!(source, pairs);\n}\n\n#[test]\nfn match_pattern_multi_cfg() {\n    let source = r#\"\n#unstable(cfg_match)\n\n#match (cfg!(feature.foo), cfg!(target_pointer_width)) {\n    // match two cfg keys as a set\n    (Some, \"32\") => type crate::Foo32 {\n        #layout(size = 1, align = 1);\n    }\n    (None, 64) => type crate::NoFoo64 {\n        #layout(size = 1, align = 1);\n    }\n    _ => {\n        type crate::SpecialFoo {\n            #layout(size = 1, align = 1);\n        }\n    }\n}\n    \"#;\n    let pairs: CfgPathPairs = &[\n        (\n            &[(\"target_pointer_width\", &[\"32\"]), (\"feature\", &[\"foo\"])],\n            &[\"crate\", \"Foo32\"],\n        ),\n        (\n            &[(\"target_pointer_width\", &[\"64\"]), (\"feature\", &[\"bar\"])],\n            &[\"crate\", \"NoFoo64\"],\n        ),\n        (&[(\"feature\", &[\"foo\"])], &[\"crate\", \"SpecialFoo\"]),\n        (&EMPTY_CFG, &[\"crate\", \"SpecialFoo\"]),\n    ];\n    test_paths_with_cfg!(source, pairs);\n}\n\n#[test]\nfn match_pattern_multi_cfg_bad_pattern() {\n    let source = r#\"\n#unstable(cfg_match)\n\n#match (cfg!(feature.foo), cfg!(target_pointer_width)) {\n    (Some, \"32\") => type crate::Foo32 { \n        // would succeed if cfg match attempted\n        #layout(size = 1, align = 1);\n    }\n    \"64\" => type crate::NoFoo64 { \n        // will fail: cardinality of pattern and tuple don't match\n        #layout(size = 1, align = 1);\n    }\n    _ => {\n        type crate::SpecialFoo {\n            #layout(size = 1, align = 1);\n        }\n    }\n}\n    \"#;\n    check_fail_with_cfg(\n        source,\n        InMemoryRustCfgProvider::default().with_values([(\"target_pointer_width\", &[\"64\"])]),\n        expect![[r#\"\n            Error: Can not match single pattern against multiple cfg values.\n               ╭─[test.zng:9:5]\n               │\n             9 │     \"64\" => type crate::NoFoo64 {\n               │     ──┬─  \n               │       ╰─── Can not match single pattern against multiple cfg values.\n            ───╯\n        \"#]],\n    );\n}\n\n#[test]\nfn match_pattern_multi_cfg_bad_pattern2() {\n    let source = r#\"\n#unstable(cfg_match)\n\n#match (cfg!(feature.foo), cfg!(target_pointer_width), cfg!(target_feature) ) {\n    (Some, \"32\", \"avx\" & \"avx2\") => type crate::Foo32 { \n        // would succeed if cfg match attempted\n        #layout(size = 1, align = 1);\n    }\n    (None, \"64\") => type crate::NoFoo64 { \n        // will fail: cardinality of pattern and tuple don't match\n        #layout(size = 1, align = 1);\n    }\n    _ => {\n        type crate::SpecialFoo {\n            #layout(size = 1, align = 1);\n        }\n    }\n}\n    \"#;\n    let cfg: [(&str, &[&str]); 2] = [\n        (\"target_pointer_width\", &[\"64\"]),\n        (\"target_feature\", &[\"avx\", \"avx2\"]),\n    ];\n    check_fail_with_cfg(\n        source,\n        InMemoryRustCfgProvider::default().with_values(cfg),\n        expect![[r#\"\n            Error: Number of patterns and number of scrutinees do not match.\n               ╭─[test.zng:9:5]\n               │\n             9 │     (None, \"64\") => type crate::NoFoo64 {\n               │     ──────┬─────  \n               │           ╰─────── Number of patterns and number of scrutinees do not match.\n            ───╯\n        \"#]],\n    );\n}\n\n#[test]\nfn cfg_match_unstable() {\n    let source = r#\"\n#match cfg!(feature) {\n    \"foo\" => type crate::Foo {\n        #layout(size = 1, align = 1);\n    }\n    _ => {\n        type crate::Bar {\n            #layout(size = 1, align = 1);\n        }\n    }\n}\n    \"#;\n    check_fail_with_cfg(\n        source,\n        InMemoryRustCfgProvider::default().with_values([(\"feature\", &[\"foo\"])]),\n        expect![[r#\"\n            Error: `#match` statements are unstable. Enable them by using `#unstable(cfg_match)` at the top of the file.\n                ╭─[test.zng:2:1]\n                │\n              2 │ ╭─▶ #match cfg!(feature) {\n                ┆ ┆   \n             11 │ ├─▶ }\n                │ │       \n                │ ╰─────── `#match` statements are unstable. Enable them by using `#unstable(cfg_match)` at the top of the file.\n            ────╯\n        \"#]],\n    );\n}\n\n#[test]\nfn module_import_parser_test() {\n    let parsed = crate::ParsedZngFile::parse_str(\n        r#\"\nimport \"module.zng\";\n\"#,\n        crate::cfg::NullCfg,\n    );\n    assert_eq!(parsed.spec.imported_modules.len(), 1);\n    assert_eq!(\n        parsed.spec.imported_modules[0].path.to_str().unwrap(),\n        \"module.zng\"\n    );\n}\n"
  }
]