Showing preview only (559K chars total). Download the full file or copy to clipboard to get everything.
Repository: HKalbasi/zngur
Branch: main
Commit: cce4441a58de
Files: 213
Total size: 508.1 KB
Directory structure:
gitextract_ukr27c6s/
├── .cargo/
│ └── config.toml
├── .github/
│ └── workflows/
│ ├── ci.yml
│ ├── publish.yml
│ └── site.yml
├── .gitignore
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── benchmark/
│ ├── .gitignore
│ ├── Cargo.toml
│ ├── benches/
│ │ └── simple.rs
│ ├── build.rs
│ ├── impls.cpp
│ ├── main.zng
│ └── src/
│ └── lib.rs
├── cspell-words.txt
├── cspell.json
├── dprint.json
├── examples/
│ ├── .gitignore
│ ├── char/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── conditional/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── cxx_demo/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ ├── blobstore.cpp
│ │ ├── build.rs
│ │ ├── expected_output.txt
│ │ ├── main.zng
│ │ └── src/
│ │ └── main.rs
│ ├── cxx_demo_split/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ ├── blobstore.cpp
│ │ ├── build.rs
│ │ ├── expected_output.txt
│ │ ├── main.zng
│ │ └── src/
│ │ └── main.rs
│ ├── impl_trait/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── memory_management/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── multiple_modules/
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── aggregation/
│ │ │ ├── Cargo.toml
│ │ │ ├── aggregation.zng
│ │ │ ├── impls.cpp
│ │ │ ├── src/
│ │ │ │ └── lib.rs
│ │ │ └── stats.h
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── packet/
│ │ │ ├── Cargo.toml
│ │ │ ├── packet.zng
│ │ │ └── src/
│ │ │ └── lib.rs
│ │ ├── processor/
│ │ │ ├── Cargo.toml
│ │ │ ├── processor.zng
│ │ │ └── src/
│ │ │ └── lib.rs
│ │ ├── receiver/
│ │ │ ├── Cargo.toml
│ │ │ ├── receiver.zng
│ │ │ └── src/
│ │ │ └── lib.rs
│ │ └── src/
│ │ └── lib.rs
│ ├── raw_pointer/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── rayon/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── rayon_split/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── regression_test1/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── rustyline/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── simple/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── simple_import/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── bar.cpp
│ │ ├── bar.zng
│ │ ├── expected_output.txt
│ │ ├── foo.cpp
│ │ ├── foo.zng
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ ├── primitives.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── tutorial/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── tutorial-wasm32/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main32.zng
│ │ └── src/
│ │ └── lib.rs
│ └── tutorial_cpp/
│ ├── Cargo.toml
│ ├── README.md
│ ├── build.rs
│ ├── expected_output.txt
│ ├── impls.cpp
│ ├── inventory.h
│ ├── main.zng
│ └── src/
│ └── main.rs
├── mise.toml
├── xtask/
│ ├── Cargo.toml
│ └── src/
│ ├── ci.rs
│ ├── format_book.rs
│ ├── format_templates.rs
│ └── main.rs
├── zngur/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
├── zngur-autozng/
│ ├── Cargo.toml
│ └── src/
│ └── main.rs
├── zngur-cli/
│ ├── Cargo.toml
│ └── src/
│ ├── cfg_extractor.rs
│ └── main.rs
├── zngur-def/
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs
│ └── merge.rs
├── zngur-generator/
│ ├── Cargo.toml
│ ├── src/
│ │ ├── cpp.rs
│ │ ├── lib.rs
│ │ ├── rust.rs
│ │ └── template.rs
│ └── templates/
│ ├── cpp_header.sptl
│ ├── cpp_source.sptl
│ └── zng_header.sptl
└── zngur-parser/
├── Cargo.toml
└── src/
├── cfg.rs
├── conditional.rs
├── lib.rs
└── tests.rs
================================================
FILE CONTENTS
================================================
================================================
FILE: .cargo/config.toml
================================================
[alias]
xtask = "run --package xtask --"
================================================
FILE: .github/workflows/ci.yml
================================================
name: CI
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
env:
CARGO_TERM_COLOR: always
jobs:
build-mac:
runs-on: macos-14
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v3
- uses: jdx/mise-action@v3
- name: Install Rust stable
run: |
rustup toolchain install stable
rustup target add wasm32-wasip1
rustup component add rustfmt
- name: Install Clang 19
run: brew install llvm@19
- name: Run `cargo xtask ci`
run: CC=$(brew --prefix llvm@19)/bin/clang CXX=$(brew --prefix llvm@19)/bin/clang++ cargo xtask ci
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
cpp_compiler:
- clang++
- g++
env:
CXX: ${{ matrix.cpp_compiler }}
steps:
- uses: actions/checkout@v3
- uses: jdx/mise-action@v3
- name: Install Rust stable
run: |
rustup toolchain install stable
rustup target add wasm32-wasip1
rustup component add rustfmt
- name: Install LLD for clang++
if: matrix.cpp_compiler == 'clang++'
run: sudo apt-get update && sudo apt-get install -y lld
- name: Run CI (clang++)
if: matrix.cpp_compiler == 'clang++'
run: CC=clang cargo xtask ci
- name: Run CI (g++)
if: matrix.cpp_compiler == 'g++'
run: cargo xtask ci
build-nightly:
runs-on: ubuntu-latest
strategy:
fail-fast: false
env:
CXX: g++
steps:
- uses: actions/checkout@v3
- uses: jdx/mise-action@v3
- name: Install Rust nightly
run: |
rustup toolchain install nightly
rustup default nightly
rustup target add wasm32-wasip1
rustup component add rustfmt
- name: Run CI (g++ nightly)
run: cargo xtask ci
build-win:
runs-on: windows-2022
steps:
- name: Turn off autocrlf
run: |
git config --global core.autocrlf false
- uses: actions/checkout@v3
- name: Enter VS Developer shell
uses: ilammy/msvc-dev-cmd@v1
with:
arch: amd64
vsversion: 2022
- uses: jdx/mise-action@v3
- name: Install Rust stable
run: |
rustup toolchain install stable
rustup target add wasm32-wasip1
rustup component add rustfmt
- name: Run `cargo xtask ci`
run: cargo xtask ci
================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish
on:
workflow_dispatch:
jobs:
publish:
name: Publish
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
token: ${{ secrets.PAT }}
fetch-depth: 0
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: Install cargo-workspaces
uses: actions-rs/install@v0.1
with:
crate: cargo-workspaces
version: 0.2.44
- name: Release
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
shell: bash
run: |
# Check if we can skip releasing a new version
# (there are no changes and the job was not manually triggered)
export CHANGED=$(cargo workspaces changed --include-merged-tags --ignore-changes "**/Cargo.toml")
if [[ -z "$CHANGED" && "$GITHUB_EVENT_NAME" != "workflow_dispatch" ]]; then
# Nothing has changed, so don't publish a new version
echo "No changes detected, skipping publish."
exit 0
fi
# Update version
git config --global user.email "runner@gha.local"
git config --global user.name "Github Action"
cargo workspaces -v version -ay --force '*' --include-merged-tags --no-git-commit --exact minor
export VERSION=$(cd zngur; cargo pkgid | sed -E 's/.*#(.*)/\1/g')
# Commit and publish
git commit -am "Release $VERSION"
git tag "v$VERSION"
cargo workspaces -v publish --from-git --skip-published
git push --tags
git push
================================================
FILE: .github/workflows/site.yml
================================================
name: Deploy
on:
push:
branches:
- main
paths:
- book/**
- .github/workflows/site.yml
workflow_dispatch:
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
permissions:
contents: write
timeout-minutes: 30
steps:
- uses: actions/checkout@v3
- uses: dtolnay/install@mdbook
- run: mdbook --version
- name: Build
run: |
cd book
mdbook build
- uses: crazy-max/ghaction-github-pages@v3.1.0
with:
build_dir: book/book
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .gitignore
================================================
/target
a.out
a.out.dSYM
*.exe
*.obj
*.bat
*.a
*.o
.vscode
compile_commands.json
zngur-autozng/doc.json
perf.data
perf.data.old
actual_output.txt
flamegraph.svg
generated*.*
================================================
FILE: Cargo.toml
================================================
[workspace]
members = [
"zngur",
"zngur-cli",
"zngur-def",
"zngur-generator",
"zngur-parser",
"zngur-autozng",
"examples/*",
"xtask",
"benchmark",
]
# Exclude tutorial-wasm32 from default workspace builds since it requires extra dependencies
exclude = [
"examples/tutorial-wasm32",
]
resolver = "2"
[workspace.package]
edition = "2024"
rust-version = "1.85"
license = "MIT OR Apache-2.0"
[profile.dev]
opt-level = 3
[profile.release]
lto = true
================================================
FILE: LICENSE-APACHE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
================================================
FILE: LICENSE-MIT
================================================
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# Zngur
[<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)
[<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)
[<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)
[<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)
Zngur (/zængɑr/) is a C++/Rust interop tool. It tries to expose arbitrary Rust types, methods and functions, while preserving its
semantics and ergonomics as much as possible. Using Zngur, you can use arbitrary Rust crates in your C++ code as easily as using it in
normal Rust code, and you can write idiomatic Rusty APIs for your C++ library inside C++. See [the documentation](https://hkalbasi.github.io/zngur/)
for more info.
## Demo
```C++
#include <iostream>
#include <vector>
#include "./generated.h"
// Rust values are available in the `::rust` namespace from their absolute path
// in Rust
template <typename T> using Vec = rust::std::vec::Vec<T>;
template <typename T> using Option = rust::std::option::Option<T>;
template <typename T> using BoxDyn = rust::Box<rust::Dyn<T>>;
// You can implement Rust traits for your classes
template <typename T>
class VectorIterator : public rust::std::iter::Iterator<T> {
std::vector<T> vec;
size_t pos;
public:
VectorIterator(std::vector<T> &&v) : vec(v), pos(0) {}
~VectorIterator() {
std::cout << "vector iterator has been destructed" << std::endl;
}
Option<T> next() override {
if (pos >= vec.size()) {
return Option<T>::None();
}
T value = vec[pos++];
// You can construct Rust enum with fields in C++
return Option<T>::Some(value);
}
};
int main() {
// You can call Rust functions that return things by value, and store that
// value in your stack.
auto s = Vec<int32_t>::new_();
s.push(2);
Vec<int32_t>::push(s, 5);
s.push(7);
Vec<int32_t>::push(s, 3);
// You can call Rust functions just like normal Rust.
std::cout << s.clone().into_iter().sum() << std::endl;
// You can catch Rust panics as C++ exceptions
try {
std::cout << "s[2] = " << *s.get(2).unwrap() << std::endl;
std::cout << "s[4] = " << *s.get(4).unwrap() << std::endl;
} catch (rust::Panic e) {
std::cout << "Rust panic happened" << std::endl;
}
int state = 0;
// You can convert a C++ lambda into a `Box<dyn Fn>` and friends.
auto f = BoxDyn<rust::Fn<int32_t, int32_t>>::make_box([&](int32_t x) {
state += x;
std::cout << "hello " << x << " " << state << "\n";
return x * 2;
});
// And pass it to Rust functions that accept closures.
auto x = s.into_iter().map(std::move(f)).sum();
std::cout << x << " " << state << "\n";
std::vector<int32_t> vec{10, 20, 60};
// You can convert a C++ type that implements `Trait` to a `Box<dyn Trait>`.
// `make_box` is similar to the `make_unique`, it takes constructor arguments
// and construct it inside the `Box` (instead of `unique_ptr`).
auto vec_as_iter = BoxDyn<rust::std::iter::Iterator<int32_t>>::make_box<
VectorIterator<int32_t>>(std::move(vec));
// Then use it like a normal Rust value.
auto t = vec_as_iter.collect();
// Some utilities are also provided. For example, `zngur_dbg` is the
// equivalent of `dbg!` macro.
zngur_dbg(t);
}
```
Output:
```
17
s[2] = 7
thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', examples/simple/src/generated.rs:186:39
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
s[4] = Rust panic happened
hello 2 2
hello 5 7
hello 7 14
hello 3 17
34 17
vector iterator has been destructed
[main.cpp:71] t = [
10,
20,
60,
]
```
See the [`examples/simple`](https://github.com/HKalbasi/zngur/blob/main/examples/simple) if you want to build and run it.
## Installation
The `zngur` CLI tool can be installed with cargo:
```
cargo install zngur-cli
```
<br>
## Contributing
Because our examples require invoking a built `zngur` binary, we use `xtask` to orchestrate the build process and validate correctness across all examples.
1. **Install mise**: This project uses `mise` for tool management. Install it from [mise.jdx.dev](https://mise.jdx.dev/) or via your package manager.
2. **Install dependencies**: Run `mise install` to install the required tools. See [`mise.toml`](/mise.toml) for the list of installed tools.
3. **Run the CI locally**: The official command to run our CI is:
```bash
CXX=clang++ cargo xtask ci
```
You can use any of the C++ compilers mentioned in our CI workflow: `clang++` or `g++`.
Other compilers may work, but are not guaranteed to by our CI testing.
### Formatting
You may run `cargo xtask format-book` to run `mdformat` on the `/book` directory.
#### License
<sup>
Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
</sup>
<br>
<sub>
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this project by you, as defined in the Apache-2.0 license,
shall be dual licensed as above, without any additional terms or conditions.
</sub>
================================================
FILE: benchmark/.gitignore
================================================
/target
================================================
FILE: benchmark/Cargo.toml
================================================
[package]
name = "benchmark"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[dependencies]
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
[build-dependencies]
cc = "1.0"
build-rs = "0.1.2"
zngur = { path = "../zngur" }
[[bench]]
name = "simple"
harness = false
================================================
FILE: benchmark/benches/simple.rs
================================================
use criterion::{Criterion, criterion_group, criterion_main};
use std::hint::black_box;
fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("build_vec_by_push 10_000 rust", |b| {
b.iter(|| benchmark::build_vec_by_push_rust(black_box(10_000)))
});
c.bench_function("build_vec_by_push 10_000 cpp", |b| {
b.iter(|| benchmark::build_vec_by_push_cpp(black_box(10_000)))
});
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
================================================
FILE: benchmark/build.rs
================================================
use zngur::Zngur;
fn main() {
build::rerun_if_changed("main.zng");
build::rerun_if_changed("impls.cpp");
#[cfg(not(target_os = "windows"))]
let cxx = std::env::var("CXX").unwrap_or("c++".to_owned());
#[cfg(not(target_os = "windows"))]
let lto_enabled = cxx.ends_with("clang++") && cfg!(target_os = "linux");
#[cfg(not(target_os = "windows"))]
if lto_enabled {
build::rustc_env("RUSTC_FLAGS", "-C linker-plugin-lto -C linker=clang");
build::rustc_link_arg("-fuse-ld=lld");
}
let crate_dir = build::cargo_manifest_dir();
let out_dir = build::out_dir();
Zngur::from_zng_file(crate_dir.join("main.zng"))
.with_cpp_file(out_dir.join("generated.cpp"))
.with_h_file(out_dir.join("generated.h"))
.with_rs_file(out_dir.join("generated.rs"))
.with_zng_header_in_place_as(true)
.generate();
let my_build = &mut cc::Build::new();
let my_build = my_build.cpp(true).std("c++17");
#[cfg(not(target_os = "windows"))]
my_build.compiler(cxx);
my_build.include(&crate_dir).include(&out_dir);
#[cfg(not(target_os = "windows"))]
if lto_enabled {
my_build.flag("-flto");
}
let my_build = || my_build.clone();
my_build()
.file(out_dir.join("generated.cpp"))
.compile("zngur_generated");
my_build().file("impls.cpp").compile("impls");
}
================================================
FILE: benchmark/impls.cpp
================================================
#include <generated.h>
template <typename T>
using Vec = rust::std::vec::Vec<T>;
using u64 = uint64_t;
namespace rust::exported_functions {
auto build_vec_by_push_cpp(u64 n) -> Vec<u64> {
auto v = Vec<u64>::new_();
for (u64 i = 0; i < n; ++i) {
v.push(i);
}
return v;
}
}
================================================
FILE: benchmark/main.zng
================================================
type ::std::vec::Vec<u64> {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
fn new() -> ::std::vec::Vec<u64>;
fn push(&mut self, u64);
}
extern "C++" {
fn build_vec_by_push_cpp(u64) -> ::std::vec::Vec<u64>;
}
================================================
FILE: benchmark/src/lib.rs
================================================
mod generated {
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
}
pub fn build_vec_by_push_rust(n: u64) -> Vec<u64> {
let mut v = Vec::new();
for i in 0..n {
v.push(i);
}
v
}
pub fn build_vec_by_push_cpp(n: u64) -> Vec<u64> {
generated::build_vec_by_push_cpp(n)
}
================================================
FILE: cspell-words.txt
================================================
alignas
alignof
assocs
autozng
barbaz
barbazxxx
blobstore
cerr
chumsky
cloneable
Conds
constexpr
cout
cplusplus
CPTE
Crubit
csignal
cstddef
cstdint
cstring
CXXFLAGS
decltype
delem
deinit
depfile
digset
discontiguous
emsdk
endl
fastlink
flto
foldl
foldr
funcs
fvec
GNUC
hkalbasi
ilog
impls
indexmap
inplace
itertools
libexample
LIBPATH
libyourcrate
lwasi
mdformat
memcpy
moveit
msvc
newtype
noexcept
nmake
ntdll
pmut
primitve
println
ptrdiff
refmut
relpath
repr
respecify
rlib
rustc
RUSTC
RUSTFLAGS
RUSTLIB
Rustup
rustup
rustyline
Rustyline
scrutinee
scrutinees
serde
SIGSEGV
sptl
sref
ssize
staticlib
strvec
stmnt
unimportability
Uninit
uninit
usize
userenv
WASI
WINLIBS
wasi
WASIFLAGS
wasip
wasmtime
xshell
xtask
zngur
Zngur
Zngur's
zngur's
zængɑr
zigza
zoop
ifndef
endif
ifdef
selectany
declspec
elif
askama
endfor
================================================
FILE: cspell.json
================================================
{
"$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json",
"version": "0.2",
"dictionaryDefinitions": [
{
"name": "project-words",
"path": "./cspell-words.txt",
"addWords": true
}
],
"dictionaries": [
"project-words"
],
"ignorePaths": [
"target",
"*generated*.*",
"/cspell-words.txt",
"*.zng.h",
"*.svg",
"examples/**/Makefile",
"examples/**/NMakefile",
"actual_output.txt"
]
}
================================================
FILE: dprint.json
================================================
{
"markdown": {
"lineWidth": 100,
"emphasisKind": "asterisks",
"strongKind": "asterisks",
"textWrap": "maintain",
"ignoreDirective": "dprint-ignore",
"ignoreFileDirective": "dprint-ignore-file",
"ignoreStartDirective": "dprint-ignore-start",
"ignoreEndDirective": "dprint-ignore-end",
"newLineKind": "lf"
},
"includes": ["book/src/**/*.md", "*.md"],
"excludes": [],
"plugins": ["https://plugins.dprint.dev/markdown-0.17.8.wasm"]
}
================================================
FILE: examples/.gitignore
================================================
zngur.h
*.zng.*
================================================
FILE: examples/char/.gitignore
================================================
generated.h
generated.rs
================================================
FILE: examples/char/Cargo.toml
================================================
[package]
name = "example-char"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["staticlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
================================================
FILE: examples/char/Makefile
================================================
a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_char.a
${CXX} -std=c++11 -Werror -I. main.cpp -g -L ../../target/release/ -l example_char
../../target/release/libexample_char.a:
cargo build --release
generated.h ./src/generated.rs: main.zng
cd ../../zngur-cli && cargo run g -i ../examples/char/main.zng --crate-name "crate"
.PHONY: ../../target/release/libexample_char.a generated.h clean
clean:
rm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt
================================================
FILE: examples/char/NMakefile
================================================
CXX = cl.exe
# MSVC doesn't support earlier that c++14
CXXFLAGS = /W4 /DEBUG /EHsc /std:c++14
WINLIBS = ntdll.lib
EXAMPLE_NAME = char
GENERATED = generated.h src/generated.rs
RUSTLIB_PATH = ../../target/release/
RUSTLIB = example_$(EXAMPLE_NAME).lib
a.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)
$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)
$(RUSTLIB_PATH)/$(RUSTLIB) :
cargo build --release
$(GENERATED) : main.zng
cd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name "crate"
clean :
- del /f /q generated.h generated.cpp src\generated.rs a.exe main.obj actual_output.txt 2>nul
================================================
FILE: examples/char/expected_output.txt
================================================
Rust received char: 'A' (U+0041)
Rust received char: 'é' (U+00E9)
Rust received char: 'Z' (U+005A)
Rust received char: '�' (U+FFFD)
================================================
FILE: examples/char/main.cpp
================================================
#include "./generated.h"
using ::operator""_rs;
int main() {
// Pass a char literal directly using the _rs suffix
rust::crate::CharPrinter::print(U'A'_rs);
// Pass a char from a char32_t variable
char32_t c = U'\u00E9'; // é
rust::crate::CharPrinter::print(operator""_rs(c));
// Use a char in a predicate
if (rust::crate::CharPrinter::is_alphabetic(U'z'_rs)) {
rust::crate::CharPrinter::print(rust::crate::CharPrinter::to_uppercase(U'z'_rs));
}
// Invalid chars are replaced with U+FFFD
char32_t invalid = 0xD800; // Surrogate code point
rust::crate::CharPrinter::print(operator""_rs(invalid));
return 0;
}
================================================
FILE: examples/char/main.zng
================================================
type char {
#layout(size = 4, align = 4);
wellknown_traits(Copy);
}
type bool {
#layout(size = 1, align = 1);
wellknown_traits(Copy);
}
type crate::CharPrinter {
#layout(size = 0, align = 1);
fn print(char);
fn is_alphabetic(char) -> bool;
fn to_uppercase(char) -> char;
}
================================================
FILE: examples/char/src/lib.rs
================================================
#[rustfmt::skip]
mod generated;
struct CharPrinter;
impl CharPrinter {
fn print(c: char) {
println!("Rust received char: '{}' (U+{:04X})", c, c as u32);
}
fn is_alphabetic(c: char) -> bool {
c.is_alphabetic()
}
fn to_uppercase(c: char) -> char {
c.to_uppercase().next().unwrap_or(c)
}
}
================================================
FILE: examples/conditional/.gitignore
================================================
generated.h
generated.rs
generated*.rs
generated.cpp
history.txt
b.out
================================================
FILE: examples/conditional/Cargo.toml
================================================
[package]
name = "example-conditional"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["staticlib"]
[features]
default = []
float-values = []
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
================================================
FILE: examples/conditional/Makefile
================================================
both:: a.out b.out
a.out: main.cpp include/float/generated.h src/lib.rs ../../target/release/libexample_conditional.a
${CXX} -std=c++20 -Werror main.cpp -g -I include/float -o a.out -L../../target/release -l example_conditional
b.out: main.cpp include/int/generated.h src/lib.rs ../../target/debug/libexample_conditional.a
${CXX} -std=c++20 -Werror main.cpp -g -I include/int -o b.out -L../../target/debug -l example_conditional
../../target/release/libexample_conditional.a: ./src/generated_float.rs
cargo build --release -F "float-values"
../../target/debug/libexample_conditional.a: ./src/generated_int.rs
cargo build
include/float/generated.h ./src/generated_float.rs: main.zng
mkdir -p include/float
cd ../../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"
include/int/generated.h ./src/generated_int.rs: main.zng
mkdir -p include/int
cd ../../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"
.PHONY: ../../target/release/libexample_conditional.a ../../target/debug/libexample_conditional.a include/float/generated.h include/int/generated.h clean
clean:
rm -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
================================================
FILE: examples/conditional/NMakefile
================================================
CXX = cl.exe
CXXFLAGS = /W4 /DEBUG /EHsc /std:c++20
WINLIBS = ntdll.lib Userenv.lib Ws2_32.lib
EXAMPLE_NAME = conditional
GENERATED_A = include/float/generated.h ./src/generated_float.rs
GENERATED_B = include/int/generated.h ./src/generated_int.rs
RUSTLIB_PATH_A = ../../target/release/
RUSTLIB_PATH_B = ../../target/debug/
RUSTLIB = example_$(EXAMPLE_NAME).lib
all : a.exe b.exe
a.exe : main.cpp src/lib.rs $(GENERATED_A) $(RUSTLIB_PATH_A)/$(RUSTLIB)
$(CXX) $(CXXFLAGS) /c main.cpp /I include/float /Fo: "a"
$(CXX) $(CXXFLAGS) a.obj /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH_A)
b.exe : main.cpp src/lib.rs $(GENERATED_B) $(RUSTLIB_PATH_B)/$(RUSTLIB)
$(CXX) $(CXXFLAGS) /c main.cpp /I include/int /Fo: "b"
$(CXX) $(CXXFLAGS) b.obj /Fe:b.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH_B)
$(RUSTLIB_PATH_A)/$(RUSTLIB) :
cargo build --release -F "float-values"
$(RUSTLIB_PATH_B)/$(RUSTLIB) :
cargo build
$(GENERATED_A) : main.zng
IF NOT EXIST "include" mkdir include
IF NOT EXIST "include\float" mkdir "include\float"
cd ../../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"
$(GENERATED_B) : main.zng
IF NOT EXIST "include" mkdir include
IF NOT EXIST "include\int" mkdir "include\int"
cd ../../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"
clean :
- 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
================================================
FILE: examples/conditional/README.md
================================================
# Example: Conditional
A example, used to demonstrate conditional compilation
To run this example:
```
make
./a.out
```
================================================
FILE: examples/conditional/expected_output.txt
================================================
KVPair(size = 32, align = 8){foo : 1.000000}
[main.cpp:44] pair = KeyValuePair[f64] { key: "foo", value: 1.0, }
KVPair(size = 32, align = 8){bar : 2.000000}
[main.cpp:44] pair = KeyValuePair[f64] { key: "bar", value: 2.0, }
KVPair(size = 32, align = 8){baz : 3.000000}
[main.cpp:44] pair = KeyValuePair[f64] { key: "baz", value: 3.0, }
KVPair(size = 32, align = 8){abc : 4.000000}
[main.cpp:44] pair = KeyValuePair[f64] { key: "abc", value: 4.0, }
KVPair(size = 32, align = 8){foo : 1}
[main.cpp:44] pair = KeyValuePair[i32] { key: "foo", value: 1, }(with debug_assertions)
KVPair(size = 32, align = 8){bar : 2}
[main.cpp:44] pair = KeyValuePair[i32] { key: "bar", value: 2, }(with debug_assertions)
KVPair(size = 32, align = 8){baz : 3}
[main.cpp:44] pair = KeyValuePair[i32] { key: "baz", value: 3, }(with debug_assertions)
KVPair(size = 32, align = 8){abc : 4}
[main.cpp:44] pair = KeyValuePair[i32] { key: "abc", value: 4, }(with debug_assertions)
================================================
FILE: examples/conditional/main.cpp
================================================
#include <cmath>
#include <iostream>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "generated.h"
// Rust values are available in the `::rust` namespace from their absolute path
// in Rust
template <typename T> using Vec = rust::std::vec::Vec<T>;
template <typename T> using Option = rust::std::option::Option<T>;
using KVPair = rust::crate::KeyValuePair;
#ifdef ZNGUR_CFG_FEATURE_FLOAT_VALUES
using KVPairValue_T = ::std::double_t;
#else
using KVPairValue_T = ::std::int32_t;
#endif
int main() {
auto s = Vec<KVPair>::new_();
std::vector<std::pair<rust::Ref<rust::Str>, int>> pairs = {
{"foo"_rs, 1}, {"bar"_rs, 2}, {"baz"_rs, 3}, {"abc"_rs, 4}};
for (const auto &[key, value] : pairs) {
s.push(KVPair{key.to_owned(), static_cast<KVPairValue_T>(value)});
}
auto it = s.iter();
for (auto next = it.next(); next.matches_Some(); next = it.next()) {
auto pair = next.unwrap();
rust::Ref<rust::std::string::String> key = pair.key;
KVPairValue_T value = pair.value;
std::cout << "KVPair(size = " << KVPair::self_size()
<< ", align = " << KVPair::self_align() << "){"
<< std::string_view(
reinterpret_cast<const char *>(key.as_str().as_ptr()),
key.len())
<< " : " << std::to_string(value) << "}\n";
zngur_dbg(pair);
}
}
================================================
FILE: examples/conditional/main.zng
================================================
#convert_panic_to_exception
#unstable(cfg_if)
type str {
wellknown_traits(?Sized, Debug);
fn as_ptr(&self) -> *const u8;
fn len(&self) -> usize;
fn to_owned(&self) -> ::std::string::String;
}
type ::std::string::String {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
fn clone(&self) -> ::std::string::String;
fn push_str(&mut self, &str);
fn len(&self) -> usize;
fn as_str(&self) -> &str;
}
mod crate {
type KeyValuePair {
#layout(size = 32, align = 8);
wellknown_traits(Debug);
#if cfg!(feature."float-values") {
constructor { key: ::std::string::String, value: f64 };
} #else {
constructor { key: ::std::string::String, value: i32 };
}
fn self_size() -> usize;
fn self_align() -> usize;
field key (offset = 0, type = ::std::string::String );
#if cfg!(feature."float-values") {
field value (offset = 24, type = f64 );
} #else {
field value (offset = 24, type = i32 );
}
}
}
mod ::std {
type option::Option<usize> {
#layout(size = 16, align = 8);
constructor None;
constructor Some(usize);
fn unwrap(self) -> usize;
}
type option::Option<crate::KeyValuePair> {
#layout(size = 32, align = 8);
constructor None;
constructor Some(crate::KeyValuePair);
fn unwrap(self) -> crate::KeyValuePair;
}
type option::Option<&crate::KeyValuePair> {
#layout(size = 8, align = 8);
wellknown_traits(Copy);
constructor None;
constructor Some(&crate::KeyValuePair);
fn unwrap(self) -> &crate::KeyValuePair;
}
mod vec {
type Vec<crate::KeyValuePair> {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
fn new() -> Vec<crate::KeyValuePair>;
fn push(&mut self, crate::KeyValuePair);
fn get(&self, usize) -> ::std::option::Option<&crate::KeyValuePair> deref [crate::KeyValuePair];
fn iter(&self) -> ::std::slice::Iter<crate::KeyValuePair> deref [crate::KeyValuePair];
}
}
mod slice {
type Iter<crate::KeyValuePair> {
#layout(size = 16, align = 8);
fn len(&self) -> usize;
fn size_hint(&self) -> (usize, ::std::option::Option<usize>);
fn count(self) -> usize;
fn next(&mut self) -> ::std::option::Option<&crate::KeyValuePair>;
}
}
}
type (usize, ::std::option::Option<usize>) {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
field 0 (offset = 0, type = usize);
field 1 (offset = 8, type = ::std::option::Option<usize> );
}
================================================
FILE: examples/conditional/src/lib.rs
================================================
/// only in place to allow both build to build sid by side in CI
#[rustfmt::skip]
#[cfg(feature = "float-values")]
mod generated_float;
#[rustfmt::skip]
#[cfg(not(feature = "float-values"))]
mod generated_int;
struct KeyValuePair {
pub key: String,
#[cfg(feature = "float-values")]
pub value: f64,
#[cfg(not(feature = "float-values"))]
pub value: i32,
}
impl KeyValuePair {
fn self_size() -> usize {
std::mem::size_of::<Self>()
}
fn self_align() -> usize {
std::mem::align_of::<Self>()
}
}
#[cfg(debug_assertions)]
impl std::fmt::Debug for KeyValuePair {
#[cfg(feature = "float-values")]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"KeyValuePair[f64] {{ key: {:?}, value: {:?}, }}(with debug_assertions)",
&self.key, &self.value
)
}
#[cfg(not(feature = "float-values"))]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"KeyValuePair[i32] {{ key: {:?}, value: {:?}, }}(with debug_assertions)",
&self.key, &self.value
)
}
}
#[cfg(not(debug_assertions))]
impl std::fmt::Debug for KeyValuePair {
#[cfg(feature = "float-values")]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"KeyValuePair[f64] {{ key: {:?}, value: {:?}, }}",
&self.key, &self.value
)
}
#[cfg(not(feature = "float-values"))]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"KeyValuePair[i32] {{ key: {:?}, value: {:?}, }}",
&self.key, &self.value
)
}
}
================================================
FILE: examples/cxx_demo/.gitignore
================================================
generated.h
generated.rs
generated.cpp
history.txt
================================================
FILE: examples/cxx_demo/Cargo.toml
================================================
[package]
name = "example-cxx_demo"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[build-dependencies]
cc = "1.0"
build-rs = "0.1.2"
zngur = { path = "../../zngur" }
================================================
FILE: examples/cxx_demo/README.md
================================================
# Example: CXX demo
This example tries to replicate [the CXX demo](https://github.com/dtolnay/cxx/tree/master/demo) using Zngur. It tries to keep it as close
as possible to the original CXX example, so it doesn't use Zngur features that may make the code easier, more readable, and more
performant. To see an example that uses all Zngur features in C++ to Rust codes, go to the osmium example.
To run this example:
```
cargo run
```
================================================
FILE: examples/cxx_demo/blobstore.cpp
================================================
#include <algorithm>
#include <cstdint>
#include <set>
#include <unordered_map>
#include "./generated.h"
class BlobStore : public rust::crate::BlobStoreTrait {
class Impl {
friend BlobStore;
using Blob = struct {
std::string data;
std::set<std::string> tags;
};
std::unordered_map<uint64_t, Blob> blobs;
};
public:
uint64_t put(rust::RefMut<rust::crate::MultiBuf> buf) override {
std::string contents;
// Traverse the caller's chunk iterator.
//
// In reality there might be sophisticated batching of chunks and/or
// parallel upload implemented by the blob_store's C++ client.
while (true) {
auto chunk = buf.next_chunk();
if (chunk.len() == 0) {
break;
}
contents.append(reinterpret_cast<const char *>(chunk.as_ptr()),
chunk.len());
}
// Insert into map and provide caller the handle.
auto blob_id = std::hash<std::string>{}(contents);
impl.blobs[blob_id] = {std::move(contents), {}};
return blob_id;
}
rust::Unit tag(::uint64_t blob_id,
rust::Ref<rust::Str> tag) override {
impl.blobs[blob_id].tags.emplace((char *)tag.as_ptr(), tag.len());
return rust::Unit{};
}
rust::crate::BlobMetadata metadata(::uint64_t blob_id) override {
rust::crate::BlobMetadata r = rust::crate::BlobMetadata::default_();
auto blob = impl.blobs.find(blob_id);
if (blob != impl.blobs.end()) {
r.set_size(blob->second.data.size());
std::for_each(blob->second.tags.cbegin(), blob->second.tags.cend(),
[&](auto &t) {
r.push_tag(reinterpret_cast<const int8_t *>(t.c_str()));
});
}
return r;
}
private:
Impl impl;
};
rust::Box<rust::Dyn<rust::crate::BlobStoreTrait>>
rust::exported_functions::new_blob_store_client() {
return rust::Box<rust::Dyn<rust::crate::BlobStoreTrait>>::make_box<
BlobStore>();
}
================================================
FILE: examples/cxx_demo/build.rs
================================================
#[cfg(not(target_os = "windows"))]
use std::env;
use zngur::Zngur;
fn main() {
build::rerun_if_changed("main.zng");
build::rerun_if_changed("blobstore.cpp");
build::rerun_if_changed("src/");
build::rerun_if_env_changed("CXX");
#[cfg(not(target_os = "windows"))]
let cxx = env::var("CXX").unwrap_or("c++".to_owned());
let crate_dir = build::cargo_manifest_dir();
Zngur::from_zng_file(crate_dir.join("main.zng"))
.with_cpp_file(crate_dir.join("generated.cpp"))
.with_h_file(crate_dir.join("generated.h"))
.with_rs_file(crate_dir.join("./src/generated.rs"))
.with_crate_name("crate")
.with_zng_header_in_place()
.generate();
let my_build = &mut cc::Build::new();
let my_build = my_build.cpp(true).std("c++17");
#[cfg(not(target_os = "windows"))]
my_build.compiler(&cxx);
let my_build = || my_build.clone();
my_build().file("generated.cpp").compile("zngur_generated");
my_build().file("blobstore.cpp").compile("blobstore");
}
================================================
FILE: examples/cxx_demo/expected_output.txt
================================================
metadata = BlobMetadata { size: 19, tags: ["rust"] }
================================================
FILE: examples/cxx_demo/main.zng
================================================
type [u8] {
wellknown_traits(?Sized);
fn as_ptr(&self) -> *const u8;
fn len(&self) -> usize;
}
type str {
wellknown_traits(?Sized);
fn as_ptr(&self) -> *const u8;
fn len(&self) -> usize;
}
mod crate {
type MultiBuf {
#layout(size = 32, align = 8);
fn next_chunk(&mut self) -> &[u8];
}
type BlobMetadata {
#layout(size = 32, align = 8);
fn default() -> BlobMetadata;
fn set_size(&mut self, usize);
fn push_tag(&mut self, *const i8);
}
trait BlobStoreTrait {
fn put(&self, &mut MultiBuf) -> u64;
fn tag(&self, u64, &str);
fn metadata(&self, u64) -> BlobMetadata;
}
type Box<dyn BlobStoreTrait> {
#layout(size = 16, align = 8);
fn put(&self, &mut MultiBuf) -> u64 deref dyn BlobStoreTrait;
fn tag(&self, u64, &str) deref dyn BlobStoreTrait;
fn metadata(&self, u64) -> BlobMetadata deref dyn BlobStoreTrait;
}
}
extern "C++" {
fn new_blob_store_client() -> Box<dyn crate::BlobStoreTrait>;
}
================================================
FILE: examples/cxx_demo/src/main.rs
================================================
#[rustfmt::skip]
mod generated;
use generated::new_blob_store_client;
// An iterator over contiguous chunks of a discontiguous file object. Toy
// implementation uses a Vec<Vec<u8>> but in reality this might be iterating
// over some more complex Rust data structure like a rope, or maybe loading
// chunks lazily from somewhere.
pub struct MultiBuf {
chunks: Vec<Vec<u8>>,
pos: usize,
}
impl MultiBuf {
pub fn next_chunk(&mut self) -> &[u8] {
let next = self.chunks.get(self.pos);
self.pos += 1;
next.map_or(&[], Vec::as_slice)
}
}
#[derive(Debug, Default)]
struct BlobMetadata {
size: usize,
tags: Vec<String>,
}
impl BlobMetadata {
fn set_size(&mut self, size: usize) {
self.size = size;
}
fn push_tag(&mut self, c: *const i8) {
self.tags.push(
String::from_utf8_lossy(unsafe { std::ffi::CStr::from_ptr(c).to_bytes() }).to_string(),
);
}
}
trait BlobStoreTrait {
fn put(&self, buf: &mut MultiBuf) -> u64;
fn tag(&self, blob_id: u64, tag: &str);
fn metadata(&self, blob_id: u64) -> BlobMetadata;
}
fn main() {
let client = new_blob_store_client();
// Upload a blob_.
let chunks = vec![b"fearless".to_vec(), b"concurrency".to_vec()];
let mut buf = MultiBuf { chunks, pos: 0 };
let blob_id = client.put(&mut buf);
// Add a tag.
client.tag(blob_id, "rust");
// Read back the tags.
let metadata = client.metadata(blob_id);
println!("metadata = {:?}", metadata);
}
================================================
FILE: examples/cxx_demo_split/.gitignore
================================================
generated.h
generated.rs
generated.cpp
history.txt
================================================
FILE: examples/cxx_demo_split/Cargo.toml
================================================
[package]
name = "example-cxx_demo_split"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[build-dependencies]
cc = "1.0"
build-rs = "0.1.2"
zngur = { path = "../../zngur" }
================================================
FILE: examples/cxx_demo_split/README.md
================================================
# Example: CXX demo
This example tries to replicate [the CXX demo](https://github.com/dtolnay/cxx/tree/master/demo) using Zngur. It tries to keep it as close
as possible to the original CXX example, so it doesn't use Zngur features that may make the code easier, more readable, and more
performant. To see an example that uses all Zngur features in C++ to Rust codes, go to the osmium example.
To run this example:
```
cargo run
```
================================================
FILE: examples/cxx_demo_split/blobstore.cpp
================================================
#include <algorithm>
#include <cstdint>
#include <set>
#include <unordered_map>
#include "./generated.h"
class BlobStore : public rust::crate::BlobStoreTrait {
class Impl {
friend BlobStore;
using Blob = struct {
std::string data;
std::set<std::string> tags;
};
std::unordered_map<uint64_t, Blob> blobs;
};
public:
uint64_t put(rust::RefMut<rust::crate::MultiBuf> buf) override {
std::string contents;
// Traverse the caller's chunk iterator.
//
// In reality there might be sophisticated batching of chunks and/or
// parallel upload implemented by the blob_store's C++ client.
while (true) {
auto chunk = buf.next_chunk();
if (chunk.len() == 0) {
break;
}
contents.append(reinterpret_cast<const char *>(chunk.as_ptr()),
chunk.len());
}
// Insert into map and provide caller the handle.
auto blob_id = std::hash<std::string>{}(contents);
impl.blobs[blob_id] = {std::move(contents), {}};
return blob_id;
}
rust::Unit tag(::uint64_t blob_id,
rust::Ref<rust::Str> tag) override {
impl.blobs[blob_id].tags.emplace((char *)tag.as_ptr(), tag.len());
return rust::Unit{};
}
rust::crate::BlobMetadata metadata(::uint64_t blob_id) override {
rust::crate::BlobMetadata r = rust::crate::BlobMetadata::default_();
auto blob = impl.blobs.find(blob_id);
if (blob != impl.blobs.end()) {
r.set_size(blob->second.data.size());
std::for_each(blob->second.tags.cbegin(), blob->second.tags.cend(),
[&](auto &t) {
r.push_tag(reinterpret_cast<const int8_t *>(t.c_str()));
});
}
return r;
}
private:
Impl impl;
};
rust::Box<rust::Dyn<rust::crate::BlobStoreTrait>>
rust::exported_functions::new_blob_store_client() {
return rust::Box<rust::Dyn<rust::crate::BlobStoreTrait>>::make_box<
BlobStore>();
}
================================================
FILE: examples/cxx_demo_split/build.rs
================================================
#[cfg(not(target_os = "windows"))]
use std::env;
use zngur::Zngur;
fn main() {
build::rerun_if_changed("main.zng");
build::rerun_if_changed("blobstore.cpp");
build::rerun_if_changed("src/");
build::rerun_if_changed("zngur.h");
build::rerun_if_env_changed("CXX");
#[cfg(not(target_os = "windows"))]
let cxx = env::var("CXX").unwrap_or("c++".to_owned());
let crate_dir = build::cargo_manifest_dir();
Zngur::from_zng_file(crate_dir.join("main.zng"))
.with_cpp_file(crate_dir.join("generated.cpp"))
.with_h_file(crate_dir.join("generated.h"))
.with_rs_file(crate_dir.join("./src/generated.rs"))
.with_crate_name("crate")
.with_zng_header("zngur.h")
.generate();
let my_build = &mut cc::Build::new();
let my_build = my_build.cpp(true).std("c++17").include(".");
#[cfg(not(target_os = "windows"))]
my_build.compiler(&cxx);
let my_build = || my_build.clone();
my_build().file("generated.cpp").compile("zngur_generated");
my_build().file("blobstore.cpp").compile("blobstore");
}
================================================
FILE: examples/cxx_demo_split/expected_output.txt
================================================
metadata = BlobMetadata { size: 19, tags: ["rust"] }
================================================
FILE: examples/cxx_demo_split/main.zng
================================================
type [u8] {
wellknown_traits(?Sized);
fn as_ptr(&self) -> *const u8;
fn len(&self) -> usize;
}
type str {
wellknown_traits(?Sized);
fn as_ptr(&self) -> *const u8;
fn len(&self) -> usize;
}
mod crate {
type MultiBuf {
#layout(size = 32, align = 8);
fn next_chunk(&mut self) -> &[u8];
}
type BlobMetadata {
#layout(size = 32, align = 8);
fn default() -> BlobMetadata;
fn set_size(&mut self, usize);
fn push_tag(&mut self, *const i8);
}
trait BlobStoreTrait {
fn put(&self, &mut MultiBuf) -> u64;
fn tag(&self, u64, &str);
fn metadata(&self, u64) -> BlobMetadata;
}
type Box<dyn BlobStoreTrait> {
#layout(size = 16, align = 8);
fn put(&self, &mut MultiBuf) -> u64 deref dyn BlobStoreTrait;
fn tag(&self, u64, &str) deref dyn BlobStoreTrait;
fn metadata(&self, u64) -> BlobMetadata deref dyn BlobStoreTrait;
}
}
extern "C++" {
fn new_blob_store_client() -> Box<dyn crate::BlobStoreTrait>;
}
================================================
FILE: examples/cxx_demo_split/src/main.rs
================================================
#[rustfmt::skip]
mod generated;
use generated::new_blob_store_client;
// An iterator over contiguous chunks of a discontiguous file object. Toy
// implementation uses a Vec<Vec<u8>> but in reality this might be iterating
// over some more complex Rust data structure like a rope, or maybe loading
// chunks lazily from somewhere.
pub struct MultiBuf {
chunks: Vec<Vec<u8>>,
pos: usize,
}
impl MultiBuf {
pub fn next_chunk(&mut self) -> &[u8] {
let next = self.chunks.get(self.pos);
self.pos += 1;
next.map_or(&[], Vec::as_slice)
}
}
#[derive(Debug, Default)]
struct BlobMetadata {
size: usize,
tags: Vec<String>,
}
impl BlobMetadata {
fn set_size(&mut self, size: usize) {
self.size = size;
}
fn push_tag(&mut self, c: *const i8) {
self.tags.push(
String::from_utf8_lossy(unsafe { std::ffi::CStr::from_ptr(c).to_bytes() }).to_string(),
);
}
}
trait BlobStoreTrait {
fn put(&self, buf: &mut MultiBuf) -> u64;
fn tag(&self, blob_id: u64, tag: &str);
fn metadata(&self, blob_id: u64) -> BlobMetadata;
}
fn main() {
let client = new_blob_store_client();
// Upload a blob_.
let chunks = vec![b"fearless".to_vec(), b"concurrency".to_vec()];
let mut buf = MultiBuf { chunks, pos: 0 };
let blob_id = client.put(&mut buf);
// Add a tag.
client.tag(blob_id, "rust");
// Read back the tags.
let metadata = client.metadata(blob_id);
println!("metadata = {:?}", metadata);
}
================================================
FILE: examples/impl_trait/.gitignore
================================================
generated.h
generated.rs
generated.cpp
================================================
FILE: examples/impl_trait/Cargo.toml
================================================
[package]
name = "example-impl-trait"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["staticlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
================================================
FILE: examples/impl_trait/Makefile
================================================
a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_impl_trait.a
${CXX} -std=c++20 -Werror main.cpp -g -L ../../target/release/ -l example_impl_trait
../../target/release/libexample_impl_trait.a:
cargo build --release
generated.h ./src/generated.rs: main.zng
cd ../../zngur-cli && cargo run g -i ../examples/impl_trait/main.zng --crate-name "crate"
.PHONY: ../../target/release/libexample_impl_trait.a generated.h clean
clean:
rm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt
================================================
FILE: examples/impl_trait/NMakefile
================================================
CXX = cl.exe
CXXFLAGS = /W4 /DEBUG /EHsc /std:c++20
WINLIBS = ntdll.lib
EXAMPLE_NAME = impl_trait
GENERATED = generated.h src/generated.rs
RUSTLIB_PATH = ../../target/release/
RUSTLIB = example_$(EXAMPLE_NAME).lib
a.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)
$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)
$(RUSTLIB_PATH)/$(RUSTLIB) :
cargo build --release
$(GENERATED) : main.zng
cd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name "crate"
clean :
- del /f /q generated.h generated.cpp src\generated.rs a.exe main.obj actual_output.txt 2>nul
================================================
FILE: examples/impl_trait/README.md
================================================
# Example: Regression test 1
A example, used to check previous Zngur problems in CI.
To run this example:
```
make
./a.out
```
================================================
FILE: examples/impl_trait/expected_output.txt
================================================
Print debug -- 5
Print debug -- "hello"
Print debug -- 4
Print debug -- "foo"
Print debug -- "foo"
Print debug -- "Rust futures are lazy"
Async func 1
Future done with result 43
Async func 2
Future done with result 44
Print debug -- "Before calling impl_future"
Before async block
Print debug -- "Before polling impl_future"
Inside async block
Future done with result 45
================================================
FILE: examples/impl_trait/main.cpp
================================================
#include <iostream>
#include <vector>
#include "./generated.h"
using DynDebug = rust::Dyn<rust::std::fmt::Debug>;
int main() {
rust::crate::argument_position_impl_trait(5);
rust::crate::argument_position_impl_trait("hello"_rs.to_owned());
rust::crate::argument_position_impl_trait(
rust::crate::return_position_impl_trait());
rust::Box<DynDebug> elem = rust::crate::both_impl_trait("foo"_rs);
rust::crate::argument_position_impl_trait(elem.deref());
rust::crate::argument_position_impl_trait(std::move(elem));
auto future = rust::crate::async_func1();
rust::crate::argument_position_impl_trait(
"Rust futures are lazy"_rs.to_owned());
rust::crate::busy_wait_future(std::move(future));
rust::crate::busy_wait_future(rust::crate::async_func2());
rust::crate::argument_position_impl_trait(
"Before calling impl_future"_rs.to_owned());
future = rust::crate::impl_future();
rust::crate::argument_position_impl_trait(
"Before polling impl_future"_rs.to_owned());
rust::crate::busy_wait_future(std::move(future));
}
================================================
FILE: examples/impl_trait/main.zng
================================================
#convert_panic_to_exception
type str {
wellknown_traits(?Sized, Debug);
fn as_ptr(&self) -> *const u8;
fn len(&self) -> usize;
fn to_owned(&self) -> ::std::string::String;
}
type dyn ::std::fmt::Debug {
wellknown_traits(?Sized, Debug);
}
type Box<dyn ::std::fmt::Debug> {
#layout(size = 16, align = 8);
fn deref(&self) -> &dyn ::std::fmt::Debug use ::std::ops::Deref;
}
type Box<dyn ::std::future::Future<Output = i32>> {
#layout(size = 16, align = 8);
}
type ::std::string::String {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
fn clone(&self) -> ::std::string::String;
fn push_str(&mut self, &str);
fn len(&self) -> usize;
}
mod crate {
fn argument_position_impl_trait(i32);
fn argument_position_impl_trait(::std::string::String);
fn argument_position_impl_trait(Box<dyn ::std::fmt::Debug>);
fn argument_position_impl_trait(&dyn ::std::fmt::Debug);
fn return_position_impl_trait() -> impl ::std::fmt::Debug;
fn both_impl_trait(&str) -> impl ::std::fmt::Debug;
fn async_func1() -> impl ::std::future::Future<Output = i32>;
async fn async_func2() -> i32;
async fn impl_future() -> i32;
fn busy_wait_future(Box<dyn ::std::future::Future<Output = i32>>) -> i32;
}
================================================
FILE: examples/impl_trait/src/lib.rs
================================================
use std::{
fmt::Debug,
task::{Context, Waker},
};
#[rustfmt::skip]
mod generated;
fn argument_position_impl_trait(arg: impl Debug) {
println!("Print debug -- {arg:?}");
}
fn return_position_impl_trait() -> impl Debug {
4
}
fn both_impl_trait(input: impl Debug) -> impl Debug {
input
}
async fn async_func1() -> i32 {
println!("Async func 1");
43
}
async fn async_func2() -> i32 {
println!("Async func 2");
44
}
fn impl_future() -> impl Future<Output = i32> {
println!("Before async block");
async {
println!("Inside async block");
45
}
}
fn busy_wait_future<T: Debug>(fut: Box<dyn Future<Output = T>>) -> T {
let mut fut = Box::into_pin(fut);
let waker = Waker::noop();
let mut cx = Context::from_waker(waker);
loop {
match fut.as_mut().poll(&mut cx) {
std::task::Poll::Ready(r) => {
println!("Future done with result {r:?}");
return r;
}
std::task::Poll::Pending => (),
}
}
}
================================================
FILE: examples/memory_management/.gitignore
================================================
generated.h
generated.rs
generated.cpp
================================================
FILE: examples/memory_management/Cargo.toml
================================================
[package]
name = "example-memory_management"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["staticlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
================================================
FILE: examples/memory_management/Makefile
================================================
a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_memory_management.a
${CXX} -std=c++17 -Werror main.cpp generated.cpp -g -L ../../target/release/ -l example_memory_management
../../target/release/libexample_memory_management.a:
cargo build --release
generated.h generated.cpp ./src/generated.rs: main.zng
cd ../../zngur-cli && cargo run g -i ../examples/memory_management/main.zng --crate-name "crate"
.PHONY: ../../target/release/libexample_memory_management.a generated.h clean
clean:
rm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt
================================================
FILE: examples/memory_management/NMakefile
================================================
CXX = cl.exe
CXXFLAGS = /W4 /DEBUG /EHsc /std:c++20
WINLIBS = ntdll.lib
EXAMPLE_NAME = memory_management
GENERATED = generated.h src/generated.rs
RUSTLIB_PATH = ../../target/release/
RUSTLIB = example_$(EXAMPLE_NAME).lib
a.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)
$(CXX) $(CXXFLAGS) main.cpp generated.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)
$(RUSTLIB_PATH)/$(RUSTLIB) :
cargo build --release
$(GENERATED) : main.zng
cd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name "crate"
clean :
- del /f /q generated.h generated.cpp src\generated.rs a.exe main.obj generated.obj actual_output.txt 2>nul
================================================
FILE: examples/memory_management/README.md
================================================
# Example: Memory management
Explains the corner cases of memory management by code.
To run this example:
```
make
./a.out
```
================================================
FILE: examples/memory_management/expected_output.txt
================================================
Checkpoint 1
PrintOnDrop(B) has been dropped
Checkpoint 2
Checkpoint 3
Checkpoint 4
PrintOnDrop(A) has been dropped
Checkpoint 5
PrintOnDrop(cpp_V3) has been dropped
PrintOnDrop(cpp_V2) has been dropped
Checkpoint 6
PrintOnDrop(cpp_V1) has been dropped
Checkpoint 7
Checkpoint 8
PrintOnDrop(rust_V1) has been dropped
PrintOnDrop(rust_V2) has been dropped
Checkpoint 9
PrintOnDrop(rust_V1) has been dropped
PrintOnDrop(rust_V2) has been dropped
Checkpoint 10
Checkpoint 11
PrintOnDrop(P) has been dropped
PrintOnDrop(P) has been dropped
Checkpoint 12
PrintOnDrop(P) has been dropped
PrintOnDrop(Q) has been dropped
Checkpoint 13
PrintOnDrop(Q) has been dropped
Checkpoint 14
Checkpoint 15
Checkpoint 16
PrintOnDrop(P2) has been dropped
PrintOnDrop(P2) has been dropped
Checkpoint 17
PrintOnDrop(P2) has been dropped
PrintOnDrop(Q2) has been dropped
Checkpoint 18
Checkpoint 19
PrintOnDrop(Q2) has been dropped
Checkpoint 20
Checkpoint 21
PrintOnDrop(A) has been dropped
Checkpoint 22
thread panicked at examples/memory_management/src/lib.rs:30:9:
consume_and_panic executed with value B
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
PrintOnDrop(B) has been dropped
PrintOnDrop(A) has been dropped
Checkpoint 24
Checkpoint 25
Checkpoint 26
PrintOnDrop(first) has been dropped
PrintOnDrop(second) has been dropped
Checkpoint 27
Checkpoint 28
PrintOnDrop(elem1) has been dropped
Checkpoint 29
PrintOnDrop(elem1) has been dropped
Checkpoint 30
PrintOnDrop(elem1) has been dropped
PrintOnDrop(elem2) has been dropped
Checkpoint 31
[main.cpp:113] PrintOnDrop("dbg_A"_rs) = PrintOnDrop(
"dbg_A",
)
Checkpoint 32
[main.cpp:115] std::move(p1) = PrintOnDrop(
"dbg_A",
)
Checkpoint 33
[main.cpp:117] p2 = PrintOnDrop(
"dbg_A",
)
Checkpoint 34
PrintOnDrop(dbg_A) has been dropped
Checkpoint 35
Checkpoint 36
Checkpoint 37
PrintOnDrop(option_B) has been dropped
Checkpoint 38
Checkpoint 39
PrintOnDrop(option_A) has been dropped
Checkpoint 40
Checkpoint 41
Checkpoint 42
PrintOnDrop(elem1) has been dropped
Checkpoint 42
PrintOnDrop(elem2) has been dropped
Checkpoint 42
PrintOnDrop(elem3) has been dropped
Checkpoint 43
Checkpoint 44
PrintOnDrop(field_0) has been dropped
PrintOnDrop(field_2) has been dropped
Checkpoint 45
PrintOnDrop(C) has been dropped
================================================
FILE: examples/memory_management/main.cpp
================================================
#include <cstdint>
#include <iostream>
#include <vector>
#include "./generated.h"
template <typename T> using Vec = rust::std::vec::Vec<T>;
template <typename T> using Option = rust::std::option::Option<T>;
template <typename T> using BoxDyn = rust::Box<rust::Dyn<T>>;
template <typename T> using RmDyn = rust::RefMut<rust::Dyn<T>>;
using namespace rust::crate;
class CppPrintOnDropHolder : public PrintOnDropConsumer {
rust::Unit consume(PrintOnDrop p) override {
item = std::move(p);
return {};
}
PrintOnDrop item;
};
int main() {
auto p1 = PrintOnDrop("A"_rs);
auto p2 = PrintOnDrop("B"_rs);
auto p3 = PrintOnDrop("C"_rs);
std::cout << "Checkpoint 1" << std::endl;
p2 = std::move(p1);
std::cout << "Checkpoint 2" << std::endl;
{
std::cout << "Checkpoint 3" << std::endl;
PrintOnDrop p{std::move(p2)};
std::cout << "Checkpoint 4" << std::endl;
}
{
std::vector<PrintOnDrop> vec1;
vec1.emplace_back("cpp_V1"_rs);
vec1.emplace_back("cpp_V2"_rs);
vec1.emplace_back("cpp_V3"_rs);
std::cout << "Checkpoint 5" << std::endl;
vec1.pop_back();
vec1.pop_back();
std::cout << "Checkpoint 6" << std::endl;
}
{
std::cout << "Checkpoint 7" << std::endl;
Vec<PrintOnDrop> vec2 = Vec<PrintOnDrop>::new_();
vec2.push(PrintOnDrop("rust_V1"_rs));
vec2.push(PrintOnDrop("rust_V2"_rs));
std::cout << "Checkpoint 8" << std::endl;
vec2.clone(); // Clone and drop immediately
std::cout << "Checkpoint 9" << std::endl;
}
{
CppPrintOnDropHolder c;
{
std::cout << "Checkpoint 10" << std::endl;
auto holder = BoxDyn<PrintOnDropConsumer>::make_box<CppPrintOnDropHolder>(
std::move(c));
std::cout << "Checkpoint 11" << std::endl;
consume_n_times(holder.deref_mut(), "P"_rs, 3);
std::cout << "Checkpoint 12" << std::endl;
consume_n_times(holder.deref_mut(), "Q"_rs, 2);
std::cout << "Checkpoint 13" << std::endl;
}
std::cout << "Checkpoint 14" << std::endl;
}
{
CppPrintOnDropHolder c;
{
std::cout << "Checkpoint 15" << std::endl;
auto holder = RmDyn<PrintOnDropConsumer>(c);
std::cout << "Checkpoint 16" << std::endl;
consume_n_times(holder, "P2"_rs, 3);
std::cout << "Checkpoint 17" << std::endl;
consume_n_times(holder, "Q2"_rs, 2);
std::cout << "Checkpoint 18" << std::endl;
}
std::cout << "Checkpoint 19" << std::endl;
}
std::cout << "Checkpoint 20" << std::endl;
try {
PrintOnDrop a{"A"_rs};
std::cout << "Checkpoint 21" << std::endl;
consume_and_panic(a.clone(), false);
std::cout << "Checkpoint 22" << std::endl;
consume_and_panic("B"_rs, true);
std::cout << "Checkpoint 23" << std::endl;
} catch (rust::Panic e) {
std::cout << "Checkpoint 24" << std::endl;
}
{
std::cout << "Checkpoint 25" << std::endl;
PrintOnDropPair p{"first"_rs,
"second"_rs};
std::cout << "Checkpoint 26" << std::endl;
}
{
std::cout << "Checkpoint 27" << std::endl;
Vec<PrintOnDrop> vec2 = Vec<PrintOnDrop>::new_();
vec2.push(PrintOnDrop("elem1"_rs));
vec2.push(PrintOnDrop("elem2"_rs));
std::cout << "Checkpoint 28" << std::endl;
vec2.get(0).unwrap().clone();
{
auto vec_slice = vec2.deref();
auto tmp = vec_slice.get(0).unwrap().clone();
std::cout << "Checkpoint 29" << std::endl;
}
std::cout << "Checkpoint 30" << std::endl;
}
std::cout << "Checkpoint 31" << std::endl;
{
auto p1 = zngur_dbg(PrintOnDrop("dbg_A"_rs));
std::cout << "Checkpoint 32" << std::endl;
auto p2 = zngur_dbg(std::move(p1));
std::cout << "Checkpoint 33" << std::endl;
zngur_dbg(p2);
std::cout << "Checkpoint 34" << std::endl;
}
std::cout << "Checkpoint 35" << std::endl;
{
auto p1 = Option<PrintOnDrop>::Some(
PrintOnDrop("option_A"_rs));
std::cout << "Checkpoint 36" << std::endl;
auto p2 = Option<PrintOnDrop>::Some(
PrintOnDrop("option_B"_rs));
std::cout << "Checkpoint 37" << std::endl;
p2.take();
std::cout << "Checkpoint 38" << std::endl;
p2.take();
std::cout << "Checkpoint 39" << std::endl;
}
std::cout << "Checkpoint 40" << std::endl;
{
rust::Ref<rust::Str> elems[3] = {"elem1"_rs, "elem2"_rs, "elem3"_rs};
int i = 0;
auto iter = rust::std::iter::from_fn(
rust::Box<rust::Dyn<rust::Fn<Option<PrintOnDrop>>>>::make_box([&] {
if (i == 3) {
return Option<PrintOnDrop>::None();
}
return Option<PrintOnDrop>::Some(
PrintOnDrop(elems[i++]));
}));
std::cout << "Checkpoint 41" << std::endl;
iter.for_each(
rust::Box<rust::Dyn<rust::Fn<PrintOnDrop, rust::Unit>>>::make_box(
[](PrintOnDrop p) -> rust::Unit {
std::cout << "Checkpoint 42" << std::endl;
return {};
}));
}
std::cout << "Checkpoint 43" << std::endl;
{
auto tuple = rust::Tuple<PrintOnDrop, int32_t, PrintOnDrop>(
PrintOnDrop("field_0"_rs), 5,
PrintOnDrop("field_2"_rs));
std::cout << "Checkpoint 44" << std::endl;
}
std::cout << "Checkpoint 45" << std::endl;
}
================================================
FILE: examples/memory_management/main.zng
================================================
#convert_panic_to_exception
type (crate::PrintOnDrop, i32, crate::PrintOnDrop) {
#layout(size = 40, align = 8);
}
type bool {
#layout(size = 1, align = 1);
wellknown_traits(Copy);
}
type str {
wellknown_traits(?Sized);
}
type Box<dyn Fn() -> ::std::option::Option<crate::PrintOnDrop>> {
#layout(size = 16, align = 8);
}
type Box<dyn Fn(crate::PrintOnDrop)> {
#layout(size = 16, align = 8);
}
mod crate {
type PrintOnDropPair {
#layout(size = 32, align = 8);
constructor { first: PrintOnDrop, second: PrintOnDrop };
}
type PrintOnDrop {
#layout(size = 16, align = 8);
wellknown_traits(Debug);
constructor(&str);
fn clone(&self) -> PrintOnDrop;
}
type [PrintOnDrop] {
wellknown_traits(?Sized);
fn get(&self, usize) -> ::std::option::Option<&crate::PrintOnDrop>;
}
trait PrintOnDropConsumer {
fn consume(&mut self, PrintOnDrop);
}
type Box<dyn PrintOnDropConsumer> {
#layout(size = 16, align = 8);
fn deref_mut(&mut self) -> &mut dyn PrintOnDropConsumer use ::std::ops::DerefMut;
}
type dyn PrintOnDropConsumer {
wellknown_traits(?Sized);
}
fn consume_n_times(&mut dyn PrintOnDropConsumer, &str, usize);
fn consume_and_panic(PrintOnDrop, bool) -> PrintOnDrop;
}
mod ::std {
mod option {
type Option<&crate::PrintOnDrop> {
#layout(size = 8, align = 8);
fn unwrap(self) -> &crate::PrintOnDrop;
}
type Option<crate::PrintOnDrop> {
#layout(size = 16, align = 8);
constructor Some(crate::PrintOnDrop);
constructor None;
fn take(&mut self) -> Option<crate::PrintOnDrop>;
}
}
mod iter {
type FromFn<Box<dyn Fn() -> ::std::option::Option<crate::PrintOnDrop>>> {
#layout(size = 16, align = 8);
fn for_each<Box<dyn Fn(crate::PrintOnDrop)>>(self, Box<dyn Fn(crate::PrintOnDrop)>);
}
fn from_fn<crate::PrintOnDrop, Box<dyn Fn() -> ::std::option::Option<crate::PrintOnDrop>>>(
Box<dyn Fn() -> ::std::option::Option<crate::PrintOnDrop>>
) -> FromFn<Box<dyn Fn() -> ::std::option::Option<crate::PrintOnDrop>>>;
}
mod vec {
type Vec<crate::PrintOnDrop> {
#layout(size = 24, align = 8);
fn new() -> Vec<crate::PrintOnDrop>;
fn push(&mut self, crate::PrintOnDrop);
fn clone(&self) -> Vec<crate::PrintOnDrop>;
fn get(&self, usize) -> ::std::option::Option<&crate::PrintOnDrop> deref [crate::PrintOnDrop];
fn deref(&self) -> &[crate::PrintOnDrop] use ::std::ops::Deref;
}
}
}
================================================
FILE: examples/memory_management/src/lib.rs
================================================
#[rustfmt::skip]
mod generated;
#[derive(Debug, Clone)]
pub struct PrintOnDrop(&'static str);
pub struct PrintOnDropPair {
pub first: PrintOnDrop,
pub second: PrintOnDrop,
}
impl Drop for PrintOnDrop {
fn drop(&mut self) {
println!("PrintOnDrop({}) has been dropped", self.0);
}
}
trait PrintOnDropConsumer {
fn consume(&mut self, p: PrintOnDrop);
}
fn consume_n_times(consumer: &mut dyn PrintOnDropConsumer, name: &'static str, times: usize) {
for _ in 0..times {
consumer.consume(PrintOnDrop(name));
}
}
fn consume_and_panic(p: PrintOnDrop, do_panic: bool) -> PrintOnDrop {
if do_panic {
panic!("consume_and_panic executed with value {}", p.0);
}
p
}
================================================
FILE: examples/multiple_modules/Cargo.toml
================================================
[package]
name = "example-multiple-modules"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["staticlib"]
[dependencies]
packet = { path = "packet" }
receiver = { path = "receiver" }
aggregation = { path = "aggregation" }
processor = { path = "processor" }
================================================
FILE: examples/multiple_modules/Makefile
================================================
ZNGUR_CLI = cd ../../zngur-cli && cargo run
a.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
${CXX} -std=c++11 -Werror -I. -Iaggregation main.cpp aggregation.a -g -L ../../target/release/ -l example_multiple_modules
../../target/release/libexample_multiple_modules.a:
cargo build --release
aggregation.a: aggregation/impls.cpp aggregation/generated.cpp aggregation.zng.h zngur.h
${CXX} -c -std=c++11 -Werror -I. -Iaggregation -o aggregation/generated.o aggregation/generated.cpp
${CXX} -c -std=c++11 -Werror -I. -Iaggregation -o aggregation/impls.o aggregation/impls.cpp
ld -r -o aggregation.a aggregation/impls.o aggregation/generated.o
packet.zng.h packet/src/packet.zng.rs: packet/packet.zng
${ZNGUR_CLI} g ../examples/multiple_modules/packet/packet.zng \
--h-file=../examples/multiple_modules/packet.zng.h \
--rs-file=../examples/multiple_modules/packet/src/packet.zng.rs \
--crate-name "packet"
receiver.zng.h receiver/src/receiver.zng.rs: receiver/receiver.zng packet.zng.h
${ZNGUR_CLI} g ../examples/multiple_modules/receiver/receiver.zng \
--h-file=../examples/multiple_modules/receiver.zng.h \
--rs-file=../examples/multiple_modules/receiver/src/receiver.zng.rs \
--crate-name "receiver"
aggregation.zng.h aggregation/src/aggregation.zng.rs aggregation/generated.cpp: aggregation/aggregation.zng packet.zng.h
${ZNGUR_CLI} g ../examples/multiple_modules/aggregation/aggregation.zng \
--h-file=../examples/multiple_modules/aggregation.zng.h \
--rs-file=../examples/multiple_modules/aggregation/src/aggregation.zng.rs \
--crate-name "aggregation"
processor.zng.h processor/src/processor.zng.rs: processor/processor.zng receiver.zng.h aggregation.zng.h
${ZNGUR_CLI} g ../examples/multiple_modules/processor/processor.zng \
--h-file=../examples/multiple_modules/processor.zng.h \
--rs-file=../examples/multiple_modules/processor/src/processor.zng.rs \
--crate-name "processor"
zngur.h:
${ZNGUR_CLI} -- make-zng-header ../examples/multiple_modules/zngur.h
.PHONY: ../../target/release/libexample_multiple_modules.a clean run
run: a.out
./a.out
clean:
rm -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
================================================
FILE: examples/multiple_modules/aggregation/Cargo.toml
================================================
[package]
name = "aggregation"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["rlib"]
[dependencies]
packet = { path = "../packet" }
================================================
FILE: examples/multiple_modules/aggregation/aggregation.zng
================================================
import "packet.zng";
#cpp_additional_includes "
#include <stats.h>
"
type crate::StatsAccumulator {
#layout(size = 16, align = 8);
constructor(ZngurCppOpaqueOwnedObject);
#cpp_value "0" "::cpp_stats::StatsAccumulator";
}
extern "C++" {
impl crate::StatsAccumulator {
fn create() -> crate::StatsAccumulator;
fn add_packet(&mut self, packet::Packet);
fn print_report(&self);
}
}
================================================
FILE: examples/multiple_modules/aggregation/impls.cpp
================================================
#include <aggregation.zng.h>
#include <packet.zng.h>
#include <stats.h>
using rust::aggregation::StatsAccumulator;
using rust::packet::Packet;
// We need to implement the methods declared in aggregation.zng
StatsAccumulator rust::Impl<StatsAccumulator>::create() {
return StatsAccumulator(
rust::ZngurCppOpaqueOwnedObject::build<cpp_stats::StatsAccumulator>());
}
rust::Unit
rust::Impl<StatsAccumulator>::add_packet(rust::RefMut<StatsAccumulator> self,
Packet p) {
self.cpp().add_packet(p);
return {};
}
rust::Unit
rust::Impl<StatsAccumulator>::print_report(rust::Ref<StatsAccumulator> self) {
self.cpp().print_report();
return {};
}
================================================
FILE: examples/multiple_modules/aggregation/src/lib.rs
================================================
#[rustfmt::skip]
#[path = "aggregation.zng.rs"]
mod generated;
pub use packet::Packet;
pub struct StatsAccumulator(pub generated::ZngurCppOpaqueOwnedObject);
================================================
FILE: examples/multiple_modules/aggregation/stats.h
================================================
#pragma once
#include <iostream>
#include <numeric>
#include <vector>
// We include packet.zng.h to use Packet methods
#include <packet.zng.h>
namespace cpp_stats {
class StatsAccumulator {
std::vector<uint64_t> timestamps;
std::vector<uint32_t> sizes;
public:
StatsAccumulator() = default;
void add_packet(const rust::packet::Packet &p) {
timestamps.push_back(p.timestamp());
sizes.push_back(p.size());
}
void print_report() const {
uint64_t total_size = std::accumulate(sizes.begin(), sizes.end(), 0ULL);
double latency_avg = 0;
for (int i = 1; i < timestamps.size(); ++i) {
latency_avg += static_cast<double>(timestamps[i] - timestamps[i - 1]) /
(timestamps.size() - 1);
}
std::cout << "LatencyAnalysis Report:" << std::endl;
std::cout << "Total Packets: " << timestamps.size() << std::endl;
std::cout << "Total Bytes: " << total_size << std::endl;
if (!timestamps.empty()) {
std::cout << "Average Latency: " << latency_avg << std::endl;
}
}
};
} // namespace cpp_stats
================================================
FILE: examples/multiple_modules/expected_output.txt
================================================
Starting LatencyAnalysis simulation...
LatencyAnalysis Report:
Total Packets: 5
Total Bytes: 150
Average Latency: 100
================================================
FILE: examples/multiple_modules/main.cpp
================================================
#include <iostream>
#include <aggregation.zng.h>
#include <packet.zng.h>
#include <processor.zng.h>
#include <receiver.zng.h>
int main() {
auto processor = rust::std::option::Option<rust::processor::Processor>::Some(
rust::processor::Processor::new_());
auto receiver = rust::std::option::Option<rust::receiver::Receiver>::Some(
rust::receiver::Receiver::new_());
auto stats =
rust::Impl<rust::aggregation::StatsAccumulator, rust::Inherent>::create();
std::cout << "Starting LatencyAnalysis simulation..." << std::endl;
processor.unwrap().run(receiver.unwrap(), stats, 5);
rust::Impl<rust::aggregation::StatsAccumulator, rust::Inherent>::print_report(
stats);
return 0;
}
================================================
FILE: examples/multiple_modules/packet/Cargo.toml
================================================
[package]
name = "packet"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["rlib"]
[dependencies]
================================================
FILE: examples/multiple_modules/packet/packet.zng
================================================
type crate::Packet {
#layout(size = 16, align = 8); // u64 timestamp, u32 size
fn new(u64, u32) -> crate::Packet;
fn timestamp(&self) -> u64;
fn size(&self) -> u32;
}
================================================
FILE: examples/multiple_modules/packet/src/lib.rs
================================================
pub struct Packet(pub u64, pub u32);
impl Packet {
pub fn new(timestamp: u64, size: u32) -> Self {
Packet(timestamp, size)
}
pub fn timestamp(&self) -> u64 {
self.0
}
pub fn size(&self) -> u32 {
self.1
}
}
#[rustfmt::skip]
#[path = "packet.zng.rs"]
mod generated;
================================================
FILE: examples/multiple_modules/processor/Cargo.toml
================================================
[package]
name = "processor"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["rlib"]
[dependencies]
receiver = { path = "../receiver" }
aggregation = { path = "../aggregation" }
================================================
FILE: examples/multiple_modules/processor/processor.zng
================================================
import "receiver.zng";
import "aggregation.zng";
type crate::Processor {
#layout(size = 0, align = 1);
fn new() -> crate::Processor;
fn run(&self, &mut receiver::Receiver, &mut aggregation::StatsAccumulator, u32);
}
// This isn't necessary for the example but we want to test that specialization
// of the same type across modules works properly (See receiver.zng)
type ::std::option::Option<crate::Processor> {
#layout(size = 1, align = 1);
constructor None;
constructor Some(crate::Processor);
fn unwrap(self) -> crate::Processor;
}
================================================
FILE: examples/multiple_modules/processor/src/lib.rs
================================================
pub use aggregation::StatsAccumulator;
pub use receiver::Receiver;
pub struct Processor;
impl Processor {
pub fn new() -> Self {
Processor
}
pub fn run(
&self,
receiver: &mut receiver::Receiver,
stats: &mut aggregation::StatsAccumulator,
count: u32,
) {
for _ in 0..count {
let packet = receiver.next_packet();
stats.add_packet(packet);
}
}
}
#[rustfmt::skip]
#[path = "processor.zng.rs"]
mod generated;
================================================
FILE: examples/multiple_modules/receiver/Cargo.toml
================================================
[package]
name = "receiver"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["rlib"]
[dependencies]
packet = { path = "../packet" }
================================================
FILE: examples/multiple_modules/receiver/receiver.zng
================================================
import "packet.zng";
type crate::Receiver {
#layout(size = 8, align = 8); // count: u64
fn new() -> crate::Receiver;
fn next_packet(&mut self) -> packet::Packet;
}
// This isn't necessary for the example but we want to test that specialization
// of the same type across modules works properly (See processor.zng)
type ::std::option::Option<crate::Receiver> {
#layout(size = 16, align = 8);
constructor None;
constructor Some(crate::Receiver);
fn unwrap(self) -> crate::Receiver;
}
================================================
FILE: examples/multiple_modules/receiver/src/lib.rs
================================================
pub use packet::Packet;
pub struct Receiver {
count: u64,
}
impl Receiver {
pub fn new() -> Self {
Receiver { count: 0 }
}
pub fn next_packet(&mut self) -> Packet {
self.count += 1;
// Simulate packet: timestamp = count * 100, size = count * 10
Packet::new(self.count * 100, (self.count * 10) as u32)
}
}
#[rustfmt::skip]
#[path = "receiver.zng.rs"]
mod generated;
================================================
FILE: examples/multiple_modules/src/lib.rs
================================================
// Re-export everything from child crates to ensure symbols are included in the staticlib
#![allow(unused)]
pub use aggregation::*;
pub use packet::*;
pub use processor::*;
pub use receiver::*;
================================================
FILE: examples/raw_pointer/.gitignore
================================================
generated.h
generated.rs
generated.cpp
================================================
FILE: examples/raw_pointer/Cargo.toml
================================================
[package]
name = "example-raw-pointer"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["staticlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
================================================
FILE: examples/raw_pointer/Makefile
================================================
a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_raw_pointer.a
${CXX} --std=c++17 -Werror main.cpp -g -L ../../target/release/ -l example_raw_pointer
../../target/release/libexample_raw_pointer.a:
cargo build --release
generated.h ./src/generated.rs: main.zng
cd ../../zngur-cli && cargo run g -i ../examples/raw_pointer/main.zng --crate-name "crate"
.PHONY: ../../target/release/libexample_raw_pointer.a generated.h clean
clean:
rm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt
================================================
FILE: examples/raw_pointer/NMakefile
================================================
CXX = cl.exe
CXXFLAGS = /W4 /DEBUG /EHsc /std:c++17 # c++17 is needed for panic to exceptions
WINLIBS = ntdll.lib
EXAMPLE_NAME = raw_pointer
GENERATED = generated.h src/generated.rs
RUSTLIB_PATH = ../../target/release/
RUSTLIB = example_$(EXAMPLE_NAME).lib
a.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)
$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)
$(RUSTLIB_PATH)/$(RUSTLIB) :
cargo build --release
$(GENERATED) : main.zng
cd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name "crate"
clean :
- del /f /q generated.h generated.cpp src\generated.rs a.exe main.obj actual_output.txt 2>nul
================================================
FILE: examples/raw_pointer/README.md
================================================
# Example: Simple
A simple example, used as a demo in the main README file.
To run this example:
```
make
./a.out
```
================================================
FILE: examples/raw_pointer/expected_output.txt
================================================
[main.cpp:13] s = [
2,
7,
]
[main.cpp:20] s = [
2,
7,
3,
10,
2,
]
[main.cpp:25] ss = [
[
2,
7,
3,
10,
2,
],
[],
]
[main.cpp:32] ss = [
[
2,
7,
3,
10,
2,
],
[],
[],
[
2,
7,
3,
10,
2,
],
[
2,
7,
3,
10,
2,
],
]
[main.cpp:38] s2 = [
2,
7,
3,
10,
2,
4,
]
[main.cpp:40] ss_ptr.read_ref() = [
2,
7,
3,
10,
2,
]
[main.cpp:43] s3_ref_mut = [
2000,
]
[main.cpp:44] ss = [
[
2,
7,
3,
10,
2,
],
[],
[
2000,
],
[
2,
7,
3,
10,
2,
],
]
[main.cpp:48] s4_raw_mut.read_ref() = [
2000,
5,
]
[main.cpp:49] ss = [
[
2,
7,
3,
10,
2,
],
[],
[
2000,
5,
],
[
2,
7,
3,
10,
2,
],
]
[main.cpp:52] s4_raw.read_ref() = [
2000,
5,
]
[main.cpp:55] ss_ptr2.offset(2).read_ref() = [
2000,
5,
]
[main.cpp:56] ss_ptr2.offset(4).offset(-2).read_ref() = [
2000,
5,
]
[main.cpp:60] s5_raw_mut.read_ref().to_vec() = [
10,
20,
3,
]
================================================
FILE: examples/raw_pointer/main.cpp
================================================
#include <vector>
#include "./generated.h"
template <typename T>
using Vec = rust::std::vec::Vec<T>;
int main()
{
Vec<int32_t> s = Vec<int32_t>::new_();
s.push(2);
s.push(7);
zngur_dbg(s);
s.reserve(3);
int32_t* s_ptr = s.as_mut_ptr();
s_ptr[2] = 3;
s_ptr[3] = 10;
s_ptr[4] = 2;
s.set_len(5);
zngur_dbg(s);
Vec<Vec<int32_t>> ss = Vec<Vec<int32_t>>::new_();
ss.push(s.clone());
ss.push(Vec<int32_t>::new_());
zngur_dbg(ss);
ss.reserve(3);
rust::RawMut<Vec<int32_t>> ss_ptr = ss.as_mut_ptr();
ss_ptr.offset(2).write(Vec<int32_t>::new_());
ss_ptr.offset(3).write(s.clone());
ss_ptr.offset(4).write(s.clone());
ss.set_len(5);
zngur_dbg(ss);
Vec<int32_t> s2 = ss_ptr.offset(4).read();
ss.set_len(4);
s2.push(4);
zngur_dbg(s2);
zngur_dbg(ss_ptr.read_ref());
auto s3_ref_mut = ss_ptr.offset(2).read_mut();
s3_ref_mut.push(2000);
zngur_dbg(s3_ref_mut);
zngur_dbg(ss);
rust::RawMut<Vec<int32_t>> s4_raw_mut = ss.get_mut(2).unwrap();
s4_raw_mut.read_mut().push(5);
zngur_dbg(s4_raw_mut.read_ref());
zngur_dbg(ss);
rust::Raw<Vec<int32_t>> s4_raw = ss.get_mut(2).unwrap();
zngur_dbg(s4_raw.read_ref());
rust::Raw<Vec<int32_t>> ss_ptr2 = ss.as_ptr();
zngur_dbg(ss_ptr2.offset(2).read_ref());
zngur_dbg(ss_ptr2.offset(4).offset(-2).read_ref());
std::vector<int32_t> v { 10, 20, 3, 15 };
rust::RawMut<rust::Slice<int32_t>> s5_raw_mut { { reinterpret_cast<uint8_t*>(v.data()), 3 } };
zngur_dbg(s5_raw_mut.read_ref().to_vec());
}
================================================
FILE: examples/raw_pointer/main.zng
================================================
#convert_panic_to_exception
type str {
wellknown_traits(?Sized);
fn to_owned(&self) -> ::std::string::String;
}
type ::std::string::String {
#heap_allocated;
}
type [i32] {
wellknown_traits(?Sized);
fn as_ptr(&self) -> *const i32;
fn len(&self) -> usize;
fn to_vec(&self) -> ::std::vec::Vec<i32>;
}
mod ::std {
mod option {
type Option<&mut ::std::vec::Vec<i32>> {
#layout(size = 8, align = 8);
fn unwrap(self) -> &mut ::std::vec::Vec<i32>;
}
}
mod vec {
type Vec<i32> {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
fn new() -> Vec<i32>;
fn push(&mut self, i32);
fn clone(&self) -> Vec<i32>;
fn reserve(&mut self, usize);
fn set_len(&mut self, usize);
fn as_mut_ptr(&mut self) -> *mut i32;
}
type Vec<Vec<i32>> {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
fn new() -> Vec<Vec<i32>>;
fn push(&mut self, Vec<i32>);
fn clone(&self) -> Vec<Vec<i32>>;
fn get_mut(&mut self, usize) -> ::std::option::Option<&mut Vec<i32>> deref [Vec<i32>];
fn reserve(&mut self, usize);
fn set_len(&mut self, usize);
fn as_mut_ptr(&mut self) -> *mut Vec<i32>;
fn as_ptr(&self) -> *const Vec<i32>;
}
}
}
================================================
FILE: examples/raw_pointer/src/lib.rs
================================================
#[rustfmt::skip]
mod generated;
================================================
FILE: examples/rayon/.gitignore
================================================
generated.h
generated.rs
generated.cpp
history.txt
================================================
FILE: examples/rayon/Cargo.toml
================================================
[package]
name = "example-rayon"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["staticlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rayon = "1.7.0"
================================================
FILE: examples/rayon/Makefile
================================================
a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_rayon.a
${CXX} -std=c++11 -Werror main.cpp -g -L ../../target/release/ -l example_rayon
../../target/release/libexample_rayon.a:
cargo build --release
generated.h ./src/generated.rs: main.zng
cd ../../zngur-cli && cargo run g -i ../examples/rayon/main.zng --crate-name "crate"
.PHONY: ../../target/release/libexample_rayon.a generated.h clean
clean:
rm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt
================================================
FILE: examples/rayon/NMakefile
================================================
CXX = cl.exe
CXXFLAGS = /W4 /DEBUG /EHsc /std:c++14 # c++14 is as low as msvc goes
WINLIBS = ntdll.lib
EXAMPLE_NAME = rayon
GENERATED = generated.h src/generated.rs
RUSTLIB_PATH = ../../target/release/
RUSTLIB = example_$(EXAMPLE_NAME).lib
a.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)
$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)
$(RUSTLIB_PATH)/$(RUSTLIB) :
cargo build --release
$(GENERATED) : main.zng
cd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name "crate"
clean :
- del /f /q generated.h generated.cpp src\generated.rs a.exe main.obj actual_output.txt 2>nul
================================================
FILE: examples/rayon/README.md
================================================
# Example: Rayon
Calculates the sum and the number of prime numbers in `1..10000000` with multiple cores using [rayon](https://github.com/rayon-rs/rayon).
To run this example:
```
make
./a.out
```
================================================
FILE: examples/rayon/expected_output.txt
================================================
Sum = 50000005000000
Count of primes = 664579
================================================
FILE: examples/rayon/main.cpp
================================================
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <numeric>
#include <vector>
#include "./generated.h"
template <typename T> using Box = rust::Box<T>;
template <typename T> using Ref = rust::Ref<T>;
template <typename... T> using Dyn = rust::Dyn<T...>;
template <typename... T> using Fn = rust::Fn<T...>;
using rust::Bool;
using rust::Send;
using rust::Sync;
bool is_prime(uint64_t v) {
if (v < 2)
return 0;
for (int i = 2; i * i <= v; i += 1) {
if (v % i == 0) {
return 0;
}
}
return 1;
}
int main() {
std::vector<uint64_t> v(10000000);
std::iota(v.begin(), v.end(), 1);
auto slice = rust::std::slice::from_raw_parts(v.data(), v.size());
auto f = Box<Dyn<Fn<Ref<uint64_t>, Bool>, Sync, Send>>::make_box(
[&](Ref<uint64_t> x) { return is_prime(*x); });
std::cout << "Sum = " << slice.par_iter().sum() << std::endl;
std::cout << "Count of primes = "
<< slice.par_iter().copied().filter(std::move(f)).count()
<< std::endl;
}
================================================
FILE: examples/rayon/main.zng
================================================
type bool {
#layout(size = 1, align = 1);
wellknown_traits(Copy);
}
type ::std::option::Option<&u64> {
#layout(size = 8, align = 8);
wellknown_traits(Debug, Copy);
fn unwrap(self) -> &u64;
}
type Box<dyn Fn(&u64) -> bool + Sync + Send> {
#layout(size = 16, align = 8);
}
type ::rayon::iter::Filter<::rayon::iter::Copied<::rayon::slice::Iter<u64>>, Box<dyn Fn(&u64) -> bool + Sync + Send>> {
#layout(size = 32, align = 8);
fn count(self) -> usize use ::rayon::iter::ParallelIterator;
}
type ::rayon::slice::Iter<u64> {
#layout(size = 16, align = 8);
fn sum<u64>(self) -> u64 use ::rayon::iter::ParallelIterator;
fn copied<u64>(self) -> ::rayon::iter::Copied<::rayon::slice::Iter<u64>> use ::rayon::iter::ParallelIterator;
}
type ::rayon::iter::Copied<::rayon::slice::Iter<u64>> {
#layout(size = 16, align = 8);
fn filter<Box<dyn Fn(&u64) -> bool + Sync + Send>>(self, Box<dyn Fn(&u64) -> bool + Sync + Send>)
-> ::rayon::iter::Filter<::rayon::iter::Copied<::rayon::slice::Iter<u64>>, Box<dyn Fn(&u64) -> bool + Sync + Send>>
use ::rayon::iter::ParallelIterator;
}
type [u64] {
wellknown_traits(?Sized);
fn get(&self, usize) -> ::std::option::Option<&u64>;
fn par_iter(&self) -> ::rayon::slice::Iter<u64> use ::rayon::iter::IntoParallelRefIterator;
}
mod ::std::slice {
fn from_raw_parts(*const u64, usize) -> &[u64];
}
================================================
FILE: examples/rayon/src/lib.rs
================================================
#[rustfmt::skip]
mod generated;
================================================
FILE: examples/rayon_split/.gitignore
================================================
generated.h
generated.rs
generated.cpp
history.txt
================================================
FILE: examples/rayon_split/Cargo.toml
================================================
[package]
name = "example-rayon_split"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["staticlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rayon = "1.7.0"
================================================
FILE: examples/rayon_split/Makefile
================================================
a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_rayon_split.a
${CXX} -std=c++11 -Werror main.cpp -g -L ../../target/release/ -l example_rayon_split -I .
../../target/release/libexample_rayon_split.a:
cargo build --release
generated.h ./src/generated.rs: main.zng zngur.h
cd ../../zngur-cli && cargo run g ../examples/rayon_split/main.zng --crate-name "crate"
zngur.h:
cd ../../zngur-cli && cargo run h ../examples/rayon_split/zngur.h
.PHONY: ../../target/release/libexample_rayon_split.a generated.h clean
clean:
rm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt zngur.h
================================================
FILE: examples/rayon_split/NMakefile
================================================
CXX = cl.exe
CXXFLAGS = /W4 /DEBUG /EHsc /external:I . /external:W0 /std:c++14 # c++14 is as low as msvc goes
WINLIBS = ntdll.lib
EXAMPLE_NAME = rayon_split
GENERATED = generated.h src/generated.rs
RUSTLIB_PATH = ../../target/release/
RUSTLIB = example_$(EXAMPLE_NAME).lib
a.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)
$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)
$(RUSTLIB_PATH)/$(RUSTLIB) :
cargo build --release
$(GENERATED) : main.zng zngur.h
cd ../../zngur-cli && cargo run g ../examples/$(EXAMPLE_NAME)/main.zng --crate-name "crate"
zngur.h:
cd ../../zngur-cli && cargo run h ../examples/$(EXAMPLE_NAME)/zngur.h
clean :
- del /f /q generated.h generated.cpp src\generated.rs a.exe main.obj actual_output.txt 2>nul
================================================
FILE: examples/rayon_split/README.md
================================================
# Example: Rayon
Calculates the sum and the number of prime numbers in `1..10000000` with multiple cores using [rayon](https://github.com/rayon-rs/rayon).
To run this example:
```
make
./a.out
```
================================================
FILE: examples/rayon_split/expected_output.txt
================================================
Sum = 50000005000000
Count of primes = 664579
================================================
FILE: examples/rayon_split/main.cpp
================================================
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <numeric>
#include <vector>
#include "./generated.h"
template <typename T> using Box = rust::Box<T>;
template <typename T> using Ref = rust::Ref<T>;
template <typename... T> using Dyn = rust::Dyn<T...>;
template <typename... T> using Fn = rust::Fn<T...>;
using rust::Bool;
using rust::Send;
using rust::Sync;
bool is_prime(uint64_t v) {
if (v < 2)
return 0;
for (int i = 2; i * i <= v; i += 1) {
if (v % i == 0) {
return 0;
}
}
return 1;
}
int main() {
std::vector<uint64_t> v(10000000);
std::iota(v.begin(), v.end(), 1);
auto slice = rust::std::slice::from_raw_parts(v.data(), v.size());
auto f = Box<Dyn<Fn<Ref<uint64_t>, Bool>, Sync, Send>>::make_box(
[&](Ref<uint64_t> x) { return is_prime(*x); });
std::cout << "Sum = " << slice.par_iter().sum() << std::endl;
std::cout << "Count of primes = "
<< slice.par_iter().copied().filter(std::move(f)).count()
<< std::endl;
}
================================================
FILE: examples/rayon_split/main.zng
================================================
type bool {
#layout(size = 1, align = 1);
wellknown_traits(Copy);
}
type ::std::option::Option<&u64> {
#layout(size = 8, align = 8);
wellknown_traits(Debug, Copy);
fn unwrap(self) -> &u64;
}
type Box<dyn Fn(&u64) -> bool + Sync + Send> {
#layout(size = 16, align = 8);
}
type ::rayon::iter::Filter<::rayon::iter::Copied<::rayon::slice::Iter<u64>>, Box<dyn Fn(&u64) -> bool + Sync + Send>> {
#layout(size = 32, align = 8);
fn count(self) -> usize use ::rayon::iter::ParallelIterator;
}
type ::rayon::slice::Iter<u64> {
#layout(size = 16, align = 8);
fn sum<u64>(self) -> u64 use ::rayon::iter::ParallelIterator;
fn copied<u64>(self) -> ::rayon::iter::Copied<::rayon::slice::Iter<u64>> use ::rayon::iter::ParallelIterator;
}
type ::rayon::iter::Copied<::rayon::slice::Iter<u64>> {
#layout(size = 16, align = 8);
fn filter<Box<dyn Fn(&u64) -> bool + Sync + Send>>(self, Box<dyn Fn(&u64) -> bool + Sync + Send>)
-> ::rayon::iter::Filter<::rayon::iter::Copied<::rayon::slice::Iter<u64>>, Box<dyn Fn(&u64) -> bool + Sync + Send>>
use ::rayon::iter::ParallelIterator;
}
type [u64] {
wellknown_traits(?Sized);
fn get(&self, usize) -> ::std::option::Option<&u64>;
fn par_iter(&self) -> ::rayon::slice::Iter<u64> use ::rayon::iter::IntoParallelRefIterator;
}
mod ::std::slice {
fn from_raw_parts(*const u64, usize) -> &[u64];
}
================================================
FILE: examples/rayon_split/src/lib.rs
================================================
#[rustfmt::skip]
mod generated;
================================================
FILE: examples/regression_test1/.gitignore
================================================
generated.h
generated.rs
generated.cpp
================================================
FILE: examples/regression_test1/Cargo.toml
================================================
[package]
name = "example-regression-test1"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["staticlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
================================================
FILE: examples/regression_test1/Makefile
================================================
a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_regression_test1.a
${CXX} -std=c++20 -Werror main.cpp -g -L ../../target/release/ -l example_regression_test1
../../target/release/libexample_regression_test1.a:
cargo build --release
generated.h ./src/generated.rs: main.zng
cd ../../zngur-cli && cargo run g -i ../examples/regression_test1/main.zng --crate-name "crate"
.PHONY: ../../target/release/libexample_regression_test1.a generated.h clean
clean:
rm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt
================================================
FILE: examples/regression_test1/NMakefile
================================================
CXX = cl.exe
CXXFLAGS = /W4 /DEBUG /EHsc /std:c++20
WINLIBS = ntdll.lib
EXAMPLE_NAME = regression_test1
GENERATED = generated.h src/generated.rs
RUSTLIB_PATH = ../../target/release/
RUSTLIB = example_$(EXAMPLE_NAME).lib
a.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)
$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)
$(RUSTLIB_PATH)/$(RUSTLIB) :
cargo build --release
$(GENERATED) : main.zng
cd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name "crate"
clean :
- del /f /q generated.h generated.cpp src\generated.rs a.exe main.obj actual_output.txt 2>nul
================================================
FILE: examples/regression_test1/README.md
================================================
# Example: Regression test 1
A example, used to check previous Zngur problems in CI.
To run this example:
```
make
./a.out
```
================================================
FILE: examples/regression_test1/expected_output.txt
================================================
Test dbg works for Ref and RefMut -- started
[main.cpp:11] v1 = "foo"
[main.cpp:13] v2 = "foo"
[main.cpp:15] v3 = "foo"
[main.cpp:16] v2 = "foo"
[main.cpp:17] v4 = "foo"
[main.cpp:19] v5 = "foo"
[main.cpp:20] "bar"_rs = "bar"
[main.cpp:21] v4 = "foobar"
Test dbg works for Ref and RefMut -- finished
Test fields and constructor work -- started
[main.cpp:31] v1 = Foo {
field1: 1,
field2: "bar",
}
[main.cpp:32] v1.field2 = "bar"
[main.cpp:33] v1.field2.len() = 3
[main.cpp:35] v1 = Foo {
field1: 1,
field2: "barbaz",
}
[main.cpp:39] v2 = (
"kkk",
Foo {
field1: 1,
field2: "barbaz",
},
)
[main.cpp:40] v2.f0 = "kkk"
[main.cpp:41] v2.f1 = Foo {
field1: 1,
field2: "barbaz",
}
[main.cpp:42] v2.f1.field2 = "barbaz"
[main.cpp:46] v3.f0 = "kkk"
[main.cpp:47] v3.f1 = Foo {
field1: 1,
field2: "barbazxxx",
}
[main.cpp:48] v3.f1.field2 = "barbazxxx"
[main.cpp:51] v3.f1.field2.len() = 9
[main.cpp:55] v4.f0 = "kkk"
[main.cpp:56] v4.f1 = Foo {
field1: 1,
field2: "barbazxxx",
}
[main.cpp:57] v4.f1.field2 = "barbazxxx"
[main.cpp:59] v4.f1.field2.len() = 12
Test fields and constructor work -- finished
Test Field* underlying conversions -- started
[main.cpp:71] v0 = 42
[main.cpp:75] v1 = "hi"
[main.cpp:79] sref.len() = 2
[main.cpp:82] int32_t(pref.f0) = 42
[main.cpp:83] pref.f1.len() = 2
[main.cpp:86] int32_t(pmut.f0) = 42
[main.cpp:88] pmut.f1.len() = 3
Test Field* underlying conversions -- finished
Test floats -- started
[main.cpp:98] *r1 = 12.3
[main.cpp:100] v1 = 12.3
[main.cpp:105] fvec = [
42.24,
147.0,
]
[main.cpp:106] fvec.get(0) = Some(
42.24,
)
[main.cpp:107] fvec.get(2) = None
[main.cpp:108] *fvec.get(1).unwrap() = 147
[main.cpp:110] fvec = [
42.24,
5.43,
]
Test floats -- finished
Test dyn Fn() with multiple arguments -- started
scope passed to dyn Fn -- started
Inner function called
scope passed to dyn Fn -- finished
End of call_dyn_fn_multi_args
Test dyn Fn() with multiple arguments -- finished
Test Ref<Ref<T>> -- started
[main.cpp:131] strvec = [
"a str",
"foobar",
"a third str",
]
[main.cpp:132] strvec.get(0) = Some(
"a str",
)
[main.cpp:133] strvec.get(2) = Some(
"a third str",
)
[main.cpp:134] *strvec.get(1).unwrap() = "foobar"
[main.cpp:136] strvec = [
"a str",
"flip flop",
"a third str",
]
Test Ref<Ref<T>> -- finished
Test zero-sized type -- started
Method call on ZST
[main.cpp:143] zst = ZeroSizedType
Test zero-sized type -- finished
Test nested Ref<T> where T is #heap_allocated and auto field offsets -- started
[main.cpp:158] a = TypeA {
foo: 10,
bar: FieldTypeA {
fizz: FieldTypeC {
buzz_1: 20,
buzz_2: 30,
buzz_3: 40,
},
},
baz: FieldTypeB {
fizz: FieldTypeC {
buzz_1: 50,
buzz_2: 60,
buzz_3: 70,
},
},
}
[main.cpp:159] ::rust::Ref<int32_t>(a.foo) = 10
[main.cpp:160] ::rust::Ref<int32_t>(a.bar.fizz.buzz_2) = 30
[main.cpp:161] ::rust::RefMut<int32_t>(a.baz.fizz.buzz_3) = 70
[main.cpp:164] ::rust::Ref<int32_t>(a_fa_fizz.buzz_1) = 20
[main.cpp:166] ::rust::Ref<int32_t>(a_fb_fizz.buzz_2) = 60
[main.cpp:177] b = TypeB {
foo: 100,
bar: FieldTypeA {
fizz: FieldTypeC {
buzz_1: 200,
buzz_2: 300,
buzz_3: 400,
},
},
baz: FieldTypeB {
fizz: FieldTypeC {
buzz_1: 500,
buzz_2: 600,
buzz_3: 700,
},
},
}
[main.cpp:178] ::rust::Ref<int32_t>(b.foo) = 100
[main.cpp:179] ::rust::Ref<int32_t>(b.bar.fizz.buzz_2) = 300
[main.cpp:180] ::rust::RefMut<int32_t>(b.baz.fizz.buzz_3) = 700
[main.cpp:183] ::rust::Ref<int32_t>(b_fa_fizz.buzz_1) = 200
[main.cpp:185] ::rust::Ref<int32_t>(b_fb_fizz.buzz_2) = 600
[main.cpp:190] fa = FieldTypeA {
fizz: FieldTypeC {
buzz_1: 21,
buzz_2: 31,
buzz_3: 41,
},
}
[main.cpp:191] ::rust::Ref<int32_t>(fa.fizz.buzz_1) = 21
[main.cpp:192] ::rust::Ref<int32_t>(fa.fizz.buzz_3) = 41
[main.cpp:197] fa = FieldTypeA {
fizz: FieldTypeC {
buzz_1: 21,
buzz_2: 31,
buzz_3: 41,
},
}
[main.cpp:198] ::rust::Ref<int32_t>(fb.fizz.buzz_2) = 61
[main.cpp:199] ::rust::Ref<int32_t>(fb.fizz.buzz_3) = 71
Test nested Ref<T> where T is #heap_allocated and auto field offsets -- finished
Test #layout_conservative -- started
[main.cpp:208] c_layout = ConservativeLayoutType {
field1: 3.14159,
field2: 42,
field3: "A string at some unknown offset",
}
Rust( size = 32 , align = 8 )
c++( size = 48 , align = 8 )
[main.cpp:220] layouts = [
ConservativeLayoutType {
field1: 3.14159,
field2: 42,
field3: "A string at some unknown offset",
},
ConservativeLayoutType {
field1: 2.71828,
field2: 1000,
field3: "Another test string",
},
]
[main.cpp:221] layouts.get(0) = Some(
ConservativeLayoutType {
field1: 3.14159,
field2: 42,
field3: "A string at some unknown offset",
},
)
[main.cpp:222] layouts.get(1) = Some(
ConservativeLayoutType {
field1: 2.71828,
field2: 1000,
field3: "Another test string",
},
)
[main.cpp:223] layouts.get(1).unwrap() = ConservativeLayoutType {
field1: 2.71828,
field2: 1000,
field3: "Another test string",
}
[main.cpp:225] layouts = [
ConservativeLayoutType {
field1: 3.14159,
field2: 42,
field3: "A string at some unknown offset",
},
ConservativeLayoutType {
field1: 2.71828,
field2: 10,
field3: "Another test string",
},
]
Test #layout_conservative -- finished
================================================
FILE: examples/regression_test1/main.cpp
================================================
#include <iostream>
#include <vector>
#include "./generated.h"
void test_dbg_works_for_ref_and_refmut() {
auto scope =
rust::crate::Scoped::new_("Test dbg works for Ref and RefMut"_rs);
rust::Ref<rust::Str> v1 = "foo"_rs;
zngur_dbg(v1);
rust::std::string::String v2 = v1.to_owned();
zngur_dbg(v2);
rust::Ref<rust::std::string::String> v3 = v2;
zngur_dbg(v3);
rust::std::string::String v4 = std::move(zngur_dbg(v2));
zngur_dbg(v4);
rust::RefMut<rust::std::string::String> v5 = v4;
zngur_dbg(v5);
v5.push_str(zngur_dbg("bar"_rs));
zngur_dbg(v4);
}
template <typename T>
concept has_push_str = requires(T v, rust::Ref<rust::Str> s) { v.push_str(s); };
void test_fields_and_constructor() {
auto scope = rust::crate::Scoped::new_("Test fields and constructor work"_rs);
rust::crate::Foo v1 = rust::crate::Foo{1, "bar"_rs.to_owned()};
zngur_dbg(v1);
zngur_dbg(v1.field2);
zngur_dbg(v1.field2.len());
v1.field2.push_str("baz"_rs);
zngur_dbg(v1);
rust::Tuple<rust::std::string::String, rust::crate::Foo> v2{
"kkk"_rs.to_owned(), std::move(v1)};
zngur_dbg(v2);
zngur_dbg(v2.f0);
zngur_dbg(v2.f1);
zngur_dbg(v2.f1.field2);
v2.f1.field2.push_str("xxx"_rs);
rust::Ref<rust::Tuple<rust::std::string::String, rust::crate::Foo>> v3 = v2;
zngur_dbg(v3.f0);
zngur_dbg(v3.f1);
zngur_dbg(v3.f1.field2);
static_assert(has_push_str<decltype(v2.f1.field2)>);
static_assert(!has_push_str<decltype(v3.f1.field2)>);
zngur_dbg(v3.f1.field2.len());
rust::RefMut<rust::Tuple<rust::std::string::String, rust::crate::Foo>> v4 =
v2;
zngur_dbg(v4.f0);
zngur_dbg(v4.f1);
zngur_dbg(v4.f1.field2);
v4.f1.field2.push_str("yyy"_rs);
zngur_dbg(v4.f1.field2.len());
}
void test_field_underlying_conversions() {
auto scope =
rust::crate::Scoped::new_("Test Field* underlying conversions"_rs);
rust::Tuple<int32_t, rust::std::string::String> pair{42, "hi"_rs.to_owned()};
// FieldOwned conversion to Ref and value
rust::Ref<int32_t> r0 = pair.f0;
int32_t v0 = pair.f0;
zngur_dbg(v0);
// Types which are not `Copy` cannot support implicit conversion to T.
// We must use `.clone()` or similar methods to get a copy.
rust::std::string::String v1 = pair.f1.clone();
zngur_dbg(v1);
// FieldOwned<String> to Ref<String> and call a method
rust::Ref<rust::std::string::String> sref = pair.f1;
zngur_dbg(sref.len());
rust::Ref<rust::Tuple<int32_t, rust::std::string::String>> pref = pair;
zngur_dbg(int32_t(pref.f0));
zngur_dbg(pref.f1.len());
rust::RefMut<rust::Tuple<int32_t, rust::std::string::String>> pmut = pair;
zngur_dbg(int32_t(pmut.f0));
pmut.f1.push_str("!"_rs);
zngur_dbg(pmut.f1.len());
}
void test_floats() {
auto scope = rust::crate::Scoped::new_("Test floats"_rs);
rust::Tuple<float, double> pair{42.24, 12.3};
// FieldOwned conversion to Ref and value
rust::Ref<double> r1 = pair.f1;
zngur_dbg(*r1);
double v1 = pair.f1;
zngur_dbg(v1);
rust::std::vec::Vec<float> fvec = rust::std::vec::Vec<float>::new_();
fvec.push(pair.f0);
fvec.push(147);
zngur_dbg(fvec);
zngur_dbg(fvec.get(0));
zngur_dbg(fvec.get(2));
zngur_dbg(*fvec.get(1).unwrap());
*fvec.get_mut(1).unwrap() = 5.43;
zngur_dbg(fvec);
}
void test_dyn_fn_with_multiple_arguments() {
auto scope = rust::crate::Scoped::new_("Test dyn Fn() with multiple arguments"_rs);
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(
[](int32_t arg0, rust::crate::Scoped arg1, rust::Ref<rust::Str> arg2) {
std::cout << "Inner function called" << std::endl;
return rust::Unit{};
}
));
}
void test_refref() {
auto scope = rust::crate::Scoped::new_("Test Ref<Ref<T>>"_rs);
rust::std::vec::Vec<rust::Ref<rust::Str>> strvec = rust::std::vec::Vec<rust::Ref<rust::Str>>::new_();
strvec.push("a str"_rs);
strvec.push("foobar"_rs);
strvec.push("a third str"_rs);
zngur_dbg(strvec);
zngur_dbg(strvec.get(0));
zngur_dbg(strvec.get(2));
zngur_dbg(*strvec.get(1).unwrap());
*strvec.get_mut(1).unwrap() = "flip flop"_rs;
zngur_dbg(strvec);
}
void test_zero_sized_type() {
auto scope = rust::crate::Scoped::new_("Test zero-sized type"_rs);
auto zst = rust::crate::ZeroSizedType::new_();
zst.method();
zngur_dbg(zst);
}
void test_nested_heap_refs_and_auto_field_offset() {
auto scope = rust::crate::Scoped::new_("Test nested Ref<T> where T is #heap_allocated and auto field offsets"_rs);
auto a = ::rust::crate::TypeA {
10,
::rust::crate::FieldTypeA {
::rust::crate::FieldTypeC { 20, 30, 40 }
},
::rust::crate::FieldTypeB {
::rust::crate::FieldTypeC { 50, 60, 70 }
},
};
zngur_dbg(a);
zngur_dbg(::rust::Ref<int32_t>(a.foo));
zngur_dbg(::rust::Ref<int32_t>(a.bar.fizz.buzz_2));
zngur_dbg(::rust::RefMut<int32_t>(a.baz.fizz.buzz_3));
auto a_fa_fizz = ::rust::Ref<::rust::crate::FieldTypeC>(a.bar.fizz);
zngur_dbg(::rust::Ref<int32_t>(a_fa_fizz.buzz_1));
auto a_fb_fizz = ::rust::Ref<::rust::crate::FieldTypeC>(a.baz.fizz);
zngur_dbg(::rust::Ref<int32_t>(a_fb_fizz.buzz_2));
auto b = ::rust::crate::TypeB {
100,
::rust::crate::FieldTypeA {
::rust::crate::FieldTypeC { 200, 300, 400 }
},
::rust::crate::FieldTypeB {
::rust::crate::FieldTypeC { 500, 600, 700 }
},
};
zngur_dbg(b);
zngur_dbg(::rust::Ref<int32_t>(b.foo));
zngur_dbg(::rust::Ref<int32_t>(b.bar.fizz.buzz_2));
zngur_dbg(::rust::RefMut<int32_t>(b.baz.fizz.buzz_3));
auto b_fa_fizz = ::rust::Ref<::rust::crate::FieldTypeC>(b.bar.fizz);
zngur_dbg(::rust::Ref<int32_t>(b_fa_fizz.buzz_1));
auto b_fb_fizz = ::rust::Ref<::rust::crate::FieldTypeC>(b.baz.fizz);
zngur_dbg(::rust::Ref<int32_t>(b_fb_fizz.buzz_2));
auto fa = ::rust::crate::FieldTypeA {
::rust::crate::FieldTypeC { 21, 31, 41 }
};
zngur_dbg(fa);
zngur_dbg(::rust::Ref<int32_t>(fa.fizz.buzz_1));
zngur_dbg(::rust::Ref<int32_t>(fa.fizz.buzz_3));
auto fb = ::rust::crate::FieldTypeB {
::rust::crate::FieldTypeC { 51, 61, 71 }
};
zngur_dbg(fa);
zngur_dbg(::rust::Ref<int32_t>(fb.fizz.buzz_2));
zngur_dbg(::rust::Ref<int32_t>(fb.fizz.buzz_3));
}
void test_conservative_layout() {
auto scope = rust::crate::Scoped::new_("Test #layout_conservative"_rs);
auto c_layout = ::rust::crate::ConservativeLayoutType {
3.14159, 42, "A string at some unknown offset"_rs.to_owned()
};
zngur_dbg(c_layout);
std::cout << "Rust( size = " << c_layout.mem_size() << " , align = " << c_layout.mem_align() << " )\n";
std::cout << "c++( size = " << sizeof(c_layout.__zngur_data) << " , align = " << alignof(decltype(c_layout)) << " )\n";
rust::std::vec::Vec<::rust::crate::ConservativeLayoutType> layouts = rust::std::vec::Vec<::rust::crate::ConservativeLayoutType>::new_();
layouts.push(std::move(c_layout));
layouts.push(
::rust::crate::ConservativeLayoutType {
2.71828, 1000, "Another test string"_rs.to_owned()
}
);
zngur_dbg(layouts);
zngur_dbg(layouts.get(0));
zngur_dbg(layouts.get(1));
zngur_dbg(layouts.get(1).unwrap());
*::rust::RefMut<int32_t>(layouts.get_mut(1).unwrap().field2) = 10;
zngur_dbg(layouts);
}
int main() {
test_dbg_works_for_ref_and_refmut();
test_fields_and_constructor();
test_field_underlying_conversions();
test_floats();
test_dyn_fn_with_multiple_arguments();
test_refref();
test_zero_sized_type();
test_nested_heap_refs_and_auto_field_offset();
test_conservative_layout();
}
================================================
FILE: examples/regression_test1/main.zng
================================================
#convert_panic_to_exception
type bool {
#layout(size = 1, align = 1);
wellknown_traits(Copy);
}
type str {
wellknown_traits(?Sized, Debug);
fn as_ptr(&self) -> *const u8;
fn len(&self) -> usize;
fn to_owned(&self) -> ::std::string::String;
}
type ::std::string::String {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
fn clone(&self) -> ::std::string::String;
fn push_str(&mut self, &str);
fn len(&self) -> usize;
}
type crate::Foo {
#layout(size = 32, align = 8);
wellknown_traits(Debug);
constructor { field1: i32, field2: ::std::string::String };
field field2 (offset = 0, type = ::std::string::String);
}
type (::std::string::String, crate::Foo) {
#layout(size = 56, align = 8);
wellknown_traits(Debug);
field 0 (offset = 0, type = ::std::string::String);
field 1 (offset = 24, type = crate::Foo);
}
type (i32, ::std::string::String) {
#layout(size = 32, align = 8);
wellknown_traits(Debug);
field 0 (offset = 0, type = i32);
field 1 (offset = 8, type = ::std::string::String);
}
type (f32, f64) {
#layout(size = 16, align = 8);
wellknown_traits(Debug);
field 0 (offset = 0, type = f32);
field 1 (offset = 8, type = f64);
}
mod ::std::option {
type Option<&f32> {
#layout(size = 8, align = 8);
wellknown_traits(Debug, Copy);
fn is_some(&self) -> bool;
fn unwrap(self) -> &f32;
}
type Option<&mut f32> {
#layout(size = 8, align = 8);
wellknown_traits(Debug);
fn is_some(&self) -> bool;
fn unwrap(self) -> &f32;
}
type Option<&&str> {
#layout(size = 8, align = 8);
wellknown_traits(Debug, Copy);
fn is_some(&self) -> bool;
fn unwrap(self) -> &&str;
}
type Option<&mut &str> {
#layout(size = 8, align = 8);
wellknown_traits(Debug);
fn is_some(&self) -> bool;
fn unwrap(self) -> &mut &str;
}
type Option<&crate::ConservativeLayoutType> {
#layout(size = 8, align = 8);
wellknown_traits(Debug, Copy);
fn is_some(&self) -> bool;
fn unwrap(self) -> &crate::ConservativeLayoutType;
}
type Option<&mut crate::ConservativeLayoutType> {
#layout(size = 8, align = 8);
wellknown_traits(Debug);
fn is_some(&self) -> bool;
fn unwrap(self) -> &mut crate::ConservativeLayoutType;
}
}
mod ::std::vec {
type Vec<f32> {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
fn new() -> Vec<f32>;
fn get(&self, usize) -> ::std::option::Option<&f32> deref [f32];
fn get_mut(&mut self, usize) -> ::std::option::Option<&mut f32> deref [f32];
fn push(&mut self, f32);
}
type Vec<&str> {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
fn new() -> Vec<&str>;
fn get(&self, usize) -> ::std::option::Option<&&str> deref [&str];
fn get_mut(&mut self, usize) -> ::std::option::Option<&mut &str> deref [&str];
fn push(&mut self, &str);
}
type Vec<crate::ConservativeLayoutType> {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
fn new() -> Vec<crate::ConservativeLayoutType>;
fn get(&self, usize) -> ::std::option::Option<&crate::ConservativeLayoutType> deref [crate::ConservativeLayoutType];
fn get_mut(&mut self, usize) -> ::std::option::Option<&mut crate::ConservativeLayoutType> deref [crate::ConservativeLayoutType];
fn push(&mut self, crate::ConservativeLayoutType);
}
}
type crate::Scoped {
#layout(size = 16, align = 8);
fn new(&str) -> crate::Scoped;
}
type Box<dyn Fn(i32, crate::Scoped, &str)> {
#layout(size = 16, align = 8);
}
type crate::ZeroSizedType {
#layout(size = 0, align = 1);
wellknown_traits(Debug);
fn new() -> crate::ZeroSizedType;
fn method(&self);
}
mod crate {
fn call_dyn_fn_multi_args(Box<dyn Fn(i32, crate::Scoped, &str)>);
}
type crate::FieldTypeA {
#layout(size = 12, align = 4);
wellknown_traits(Debug, Copy);
constructor { fizz: crate::FieldTypeC };
field fizz (offset = 0, type = crate::FieldTypeC );
}
type crate::FieldTypeB {
#heap_allocated;
wellknown_traits(Debug, Copy);
constructor { fizz: crate::FieldTypeC };
field fizz (offset = 0, type = crate::FieldTypeC );
}
type crate::FieldTypeC {
#layout(size = 12, align = 4);
wellknown_traits(Debug, Copy);
constructor { buzz_1: i32, buzz_2: i32, buzz_3: i32 };
field buzz_1 (offset = auto, type = i32 );
field buzz_2 (offset = auto, type = i32 );
field buzz_3 (offset = auto, type = i32 );
}
type crate::TypeA {
#layout(size = 28, align = 4);
wellknown_traits(Debug, Copy);
constructor { foo: i32, bar: crate::FieldTypeA, baz: crate::FieldTypeB };
field foo (offset = 0, type = i32 );
field bar (offset = 4, type = crate::FieldTypeA );
field baz (offset = 16, type = crate::FieldTypeB );
}
type crate::TypeB {
#heap_allocated;
wellknown_traits(Debug, Copy);
constructor { foo: i32, bar: crate::FieldTypeA, baz: crate::FieldTypeB };
field foo (offset = 0, type = i32 );
field bar (offset = 4, type = crate::FieldTypeA );
field baz (offset = 16, type = crate::FieldTypeB );
}
type crate::ConservativeLayoutType {
// bigger than the real size of 32
#layout_conservative(size = 48, align = 8 );
wellknown_traits(Debug);
constructor { field1: f32, field2: i32, field3: ::std::string::String };
field field1 (offset = auto, type = f32 );
field field2 (offset = auto, type = i32 );
field field3 (offset = auto, type = ::std::string::String );
fn mem_size(&self) -> usize;
fn mem_align(&self) -> usize;
}
================================================
FILE: examples/regression_test1/src/lib.rs
================================================
#[rustfmt::skip]
mod generated;
#[allow(unused)]
#[derive(Debug)]
struct Foo {
field1: i32,
field2: String,
}
#[allow(unused)]
#[derive(Debug, Copy, Clone)]
struct FieldTypeA {
pub fizz: FieldTypeC,
}
#[allow(unused)]
#[derive(Debug, Copy, Clone)]
// heap allocated
struct FieldTypeB {
pub fizz: FieldTypeC,
}
#[allow(unused)]
#[derive(Debug, Copy, Clone)]
// auto field offset
struct FieldTypeC {
pub buzz_1: i32,
pub buzz_2: i32,
pub buzz_3: i32,
}
#[allow(unused)]
#[derive(Debug, Copy, Clone)]
struct TypeA {
pub foo: i32,
pub bar: FieldTypeA,
pub baz: FieldTypeB,
}
#[allow(unused)]
#[derive(Debug, Copy, Clone)]
// heap allocated
struct TypeB {
pub foo: i32,
pub bar: FieldTypeA,
pub baz: FieldTypeB,
}
#[allow(unused)]
#[derive(Debug)]
/// auto field offset + layout_conservative
struct ConservativeLayoutType {
pub field1: f32,
pub field2: i32,
pub field3: String,
}
#[allow(unused)]
impl ConservativeLayoutType {
pub fn mem_size(&self) -> usize {
std::mem::size_of::<Self>()
}
pub fn mem_align(&self) -> usize {
std::mem::align_of::<Self>()
}
}
struct Scoped(&'static str);
impl Scoped {
fn new(message: &'static str) -> Self {
println!("{message} -- started");
Self(message)
}
}
impl Drop for Scoped {
fn drop(&mut self) {
println!("{} -- finished", self.0);
println!();
}
}
fn call_dyn_fn_multi_args(func: Box<dyn Fn(i32, crate::Scoped, &str)>) {
let scope = Scoped::new("scope passed to dyn Fn");
func(2, scope, "hello");
println!("End of call_dyn_fn_multi_args");
}
#[derive(Debug)]
struct ZeroSizedType;
impl ZeroSizedType {
fn new() -> Self {
Self
}
fn method(&self) {
println!("Method call on ZST");
}
}
================================================
FILE: examples/rustyline/.gitignore
================================================
generated.h
generated.rs
history.txt
================================================
FILE: examples/rustyline/Cargo.toml
================================================
[package]
name = "example-rustyline"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["staticlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rustyline = "12.0.0"
================================================
FILE: examples/rustyline/Makefile
================================================
a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_rustyline.a
${CXX} -std=c++11 -Werror main.cpp -g -L ../../target/release/ -l example_rustyline
../../target/release/libexample_rustyline.a:
cargo build --release
generated.h ./src/generated.rs: main.zng
cd ../../zngur-cli && cargo run g -i ../examples/rustyline/main.zng --crate-name "crate"
.PHONY: ../../target/release/libexample_rustyline.a generated.h clean
clean:
rm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt
================================================
FILE: examples/rustyline/NMakefile
================================================
CXX = cl.exe
CXXFLAGS = /W4 /DEBUG /EHsc /std:c++20
WINLIBS = ntdll.lib User32.lib
EXAMPLE_NAME = rustyline
GENERATED = generated.h src/generated.rs
RUSTLIB_PATH = ../../target/release/
RUSTLIB = example_$(EXAMPLE_NAME).lib
a.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)
$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)
$(RUSTLIB_PATH)/$(RUSTLIB) :
cargo build --release
$(GENERATED) : main.zng
cd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name "crate"
clean :
- del /f /q generated.h generated.cpp src\generated.rs a.exe main.obj actual_output.txt 2>nul
================================================
FILE: examples/rustyline/README.md
================================================
# Example: Rustyline
Line by line port of the [`rustyline` example](https://github.com/kkawakam/rustyline#example) in C++:
```Rust
use rustyline::error::ReadlineError;
use rustyline::{DefaultEditor, Result};
fn main() -> Result<()> {
// `()` can be used when no completer is required
let mut rl = DefaultEditor::new()?;
#[cfg(feature = "with-file-history")]
if rl.load_history("history.txt").is_err() {
println!("No previous history.");
}
loop {
let readline = rl.readline(">> ");
match readline {
Ok(line) => {
rl.add_history_entry(line.as_str());
println!("Line: {}", line);
},
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
break
},
Err(ReadlineError::Eof) => {
println!("CTRL-D");
break
},
Err(err) => {
println!("Error: {:?}", err);
break
}
}
}
#[cfg(feature = "with-file-history")]
rl.save_history("history.txt");
Ok(())
}
```
To run this example:
```
make
./a.out
```
================================================
FILE: examples/rustyline/expected_output.txt
================================================
No previous history.
CTRL-D
================================================
FILE: examples/rustyline/main.cpp
================================================
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <vector>
#include "./generated.h"
int main() {
auto editor = rust::rustyline::DefaultEditor::new_().unwrap();
if (editor.load_history("history.txt"_rs).is_err()) {
std::cout << "No previous history." << std::endl;
}
while (true) {
auto r = editor.readline(">>> "_rs);
if (r.is_err()) {
auto e = r.unwrap_err();
if (e.matches_Eof()) {
std::cout << "CTRL-D" << std::endl;
}
if (e.matches_Interrupted()) {
std::cout << "CTRL-C" << std::endl;
}
break;
} else {
auto s = r.as_ref().unwrap().as_str();
std::string cpp_s((char *)s.as_ptr(), s.len());
std::cout << "Line: " << cpp_s << std::endl;
editor.add_history_entry(s);
}
}
editor.save_history("history.txt"_rs);
}
================================================
FILE: examples/rustyline/main.zng
================================================
// This example uses various layout policies to demonstrate them. See https://hkalbasi.github.io/zngur/call_rust_from_cpp/layout_policy.html
type str {
wellknown_traits(?Sized); // Unsized types don't need layout policy
fn as_ptr(&self) -> *const u8;
fn len(&self) -> usize;
}
type bool {
#layout(size = 1, align = 1); // primitives like bool have stable layout
wellknown_traits(Copy);
}
mod ::std {
type string::String {
#only_by_ref; // String has stable layout, but we don't use it by value, so we can use this policy.
fn as_str(&self) -> &str;
}
}
mod ::rustyline {
type DefaultEditor {
// DefaultEditor is a complex type defined by rustyline crate, so its layout may break
// when upgrading the compiler or the rustyline itself. We can easily manage this kind
// of breakage when we control the final binary build process, but when we don't control, it
// can break. Using `#heap_allocate` we don't need to know the layout information at compile time.
#heap_allocated;
fn new() -> Result<DefaultEditor>;
fn readline(&mut self, &str) -> Result<::std::string::String>;
fn load_history<str>(&mut self, &str) -> Result<()>;
fn add_history_entry<&str>(&mut self, &str) -> Result<bool>;
fn save_history<str>(&mut self, &str) -> Result<()>;
}
type error::ReadlineError {
#heap_allocated;
constructor Interrupted;
constructor Eof;
}
type Result<DefaultEditor> {
#heap_allocated;
fn unwrap(self) -> DefaultEditor;
}
type ::std::result::Result<&::std::string::String, &error::ReadlineError> {
#heap_allocated;
fn unwrap(self) -> &::std::string::String;
}
type Result<::std::string::String> {
#heap_allocated;
fn is_err(&self) -> bool;
fn as_ref(&self) -> ::std::result::Result<&::std::string::String, &error::ReadlineError>;
fn unwrap_err(self) -> error::ReadlineError;
}
type Result<()> {
#heap_allocated;
fn is_err(&self) -> bool;
}
type Result<bool> {
#heap_allocated;
fn is_err(&self) -> bool;
}
}
================================================
FILE: examples/rustyline/src/lib.rs
================================================
#[rustfmt::skip]
mod generated;
================================================
FILE: examples/simple/.gitignore
================================================
generated.h
generated.rs
generated.cpp
================================================
FILE: examples/simple/Cargo.toml
================================================
[package]
name = "example-simple"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["staticlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
================================================
FILE: examples/simple/Makefile
================================================
a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_simple.a
${CXX} -std=c++17 -Werror main.cpp generated.cpp -g -L ../../target/release/ -l example_simple
../../target/release/libexample_simple.a:
cargo build --release
generated.h generated.cpp ./src/generated.rs: main.zng
cd ../../zngur-cli && cargo run g -i ../examples/simple/main.zng --crate-name "crate"
.PHONY: ../../target/release/libexample_simple.a generated.h clean
clean:
rm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt
================================================
FILE: examples/simple/NMakefile
================================================
CXX = cl.exe
CXXFLAGS = /W4 /DEBUG /EHsc /std:c++20
WINLIBS = ntdll.lib
EXAMPLE_NAME = simple
GENERATED = generated.h src/generated.rs
RUSTLIB_PATH = ../../target/release/
RUSTLIB = example_$(EXAMPLE_NAME).lib
a.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)
$(CXX) $(CXXFLAGS) main.cpp generated.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)
$(RUSTLIB_PATH)/$(RUSTLIB) :
cargo build --release
$(GENERATED) : main.zng
cd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name "crate"
clean :
- del /f /q generated.h generated.cpp src\generated.rs a.exe main.obj generated.obj actual_output.txt 2>nul
================================================
FILE: examples/simple/README.md
================================================
# Example: Simple
A simple example, used as a demo in the main README file.
To run this example:
```
make
./a.out
```
================================================
FILE: examples/simple/expected_output.txt
================================================
17
s[2] = 7
thread panicked at examples/simple/src/generated.rs:370:40:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
s[4] = Rust panic happened
hello 2 2
hello 5 7
hello 7 14
hello 3 17
34 17
vector iterator has been destructed
[main.cpp:71] t = [
10,
20,
60,
]
================================================
FILE: examples/simple/main.cpp
================================================
#include <iostream>
#include <vector>
#include "./generated.h"
// Rust values are available in the `::rust` namespace from their absolute path
// in Rust
template <typename T> using Vec = rust::std::vec::Vec<T>;
template <typename T> using Option = rust::std::option::Option<T>;
template <typename T> using BoxDyn = rust::Box<rust::Dyn<T>>;
// You can implement Rust traits for your classes
template <typename T>
class VectorIterator : public rust::std::iter::Iterator<T> {
std::vector<T> vec;
size_t pos;
public:
VectorIterator(std::vector<T> &&v) : vec(v), pos(0) {}
~VectorIterator() {
std::cout << "vector iterator has been destructed" << std::endl;
}
Option<T> next() override {
if (pos >= vec.size()) {
return Option<T>::None();
}
T value = vec[pos++];
// You can construct Rust enum with fields in C++
return Option<T>::Some(value);
}
};
int main() {
// You can call Rust functions that return things by value, and store that
// value in your stack.
auto s = Vec<int32_t>::new_();
s.push(2);
Vec<int32_t>::push(s, 5);
s.push(7);
Vec<int32_t>::push(s, 3);
// You can call Rust functions just like normal Rust.
std::cout << s.clone().into_iter().sum() << std::endl;
// You can catch Rust panics as C++ exceptions
try {
std::cout << "s[2] = " << *s.get(2).unwrap() << std::endl;
std::cout << "s[4] = " << *s.get(4).unwrap() << std::endl;
} catch (rust::Panic e) {
std::cout << "Rust panic happened" << std::endl;
}
int state = 0;
// You can convert a C++ lambda into a `Box<dyn Fn>` and friends.
auto f = BoxDyn<rust::Fn<int32_t, int32_t>>::make_box([&](int32_t x) {
state += x;
std::cout << "hello " << x << " " << state << "\n";
return x * 2;
});
// And pass it to Rust functions that accept closures.
auto x = s.into_iter().map(std::move(f)).sum();
std::cout << x << " " << state << "\n";
std::vector<int32_t> vec{10, 20, 60};
// You can convert a C++ type that implements `Trait` to a `Box<dyn Trait>`.
// `make_box` is similar to the `make_unique`, it takes constructor arguments
// and construct it inside the `Box` (instead of `unique_ptr`).
auto vec_as_iter = BoxDyn<rust::std::iter::Iterator<int32_t>>::make_box<
VectorIterator<int32_t>>(std::move(vec));
// Then use it like a normal Rust value.
auto t = vec_as_iter.collect();
// Some utilities are also provided. For example, `zngur_dbg` is the
// equivalent of `dbg!` macro.
zngur_dbg(t);
}
================================================
FILE: examples/simple/main.zng
================================================
#convert_panic_to_exception
type Box<dyn Fn(i32) -> i32> {
#layout(size = 16, align = 8);
}
mod ::std {
type option::Option<i32> {
#layout(size = 8, align = 4);
wellknown_traits(Copy);
constructor None;
constructor Some(i32);
fn unwrap(self) -> i32;
}
type option::Option<&i32> {
#layout(size = 8, align = 8);
wellknown_traits(Copy);
fn unwrap(self) -> &i32;
}
type iter::Map<::std::vec::IntoIter<i32>, Box<dyn Fn(i32) -> i32>> {
#layout(size = 48, align = 8);
fn sum<i32>(self) -> i32;
}
mod vec {
type IntoIter<i32> {
#layout(size = 32, align = 8);
fn sum<i32>(self) -> i32;
fn map<i32, Box<dyn Fn(i32) -> i32>>(self, Box<dyn Fn(i32) -> i32>)
-> ::std::iter::Map<::std::vec::IntoIter<i32>, Box<dyn Fn(i32) -> i32>>;
}
type Vec<i32> {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
fn new() -> Vec<i32>;
fn push(&mut self, i32);
fn clone(&self) -> Vec<i32>;
fn get(&self, usize) -> ::std::option::Option<&i32> deref [i32];
fn into_iter(self) -> ::std::vec::IntoIter<i32>;
}
}
trait iter::Iterator::<Item = i32> {
fn next(&mut self) -> ::std::option::Option<i32>;
}
}
type Box<dyn ::std::iter::Iterator<Item = i32>> {
#layout(size = 16, align = 8);
fn collect<::std::vec::Vec<i32>>(self) -> ::std::vec::Vec<i32>;
}
================================================
FILE: examples/simple/src/lib.rs
================================================
#[rustfmt::skip]
mod generated;
================================================
FILE: examples/simple_import/.gitignore
================================================
generated.h
generated.rs
generated.cpp
================================================
FILE: examples/simple_import/Cargo.toml
================================================
[package]
name = "example-simple-import"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["staticlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
================================================
FILE: examples/simple_import/Makefile
================================================
.PHONY: ../../target/release/libexample_simple_import.a
a.out: main.cpp foo.cpp bar.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_simple_import.a
${CXX} -std=c++11 main.cpp foo.cpp bar.cpp -g -L ../../target/release/ -l example_simple_import
../../target/release/libexample_simple_import.a:
cargo build --release
generated.h ./src/generated.rs: main.zng primitives.zng foo.zng bar.zng
cd ../../zngur-cli && cargo run g -i ../examples/simple_import/main.zng --crate-name "crate"
clean:
rm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt
================================================
FILE: examples/simple_import/NMakefile
================================================
CXX = cl.exe
CXXFLAGS = /W4 /DEBUG /EHsc /std:c++20
WINLIBS = ntdll.lib
EXAMPLE_NAME = simple_import
GENERATED = generated.h src/generated.rs
RUSTLIB_PATH = ../../target/release/
RUSTLIB = example_$(EXAMPLE_NAME).lib
a.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)
$(CXX) $(CXXFLAGS) main.cpp foo.cpp bar.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)
$(RUSTLIB_PATH)/$(RUSTLIB) :
cargo build --release
$(GENERATED) : main.zng
cd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name "crate"
clean :
- del /f /q generated.h generated.cpp src\generated.rs a.exe main.obj foo.obj bar.obj actual_output.txt 2>nul
================================================
FILE: examples/simple_import/README.md
================================================
# Example: Import and Merge
A demonstration of Zngur's `import` and `merge` functionality using four focused modules.
## Structure
- **`primitives.zng`** - Defines basic primitive types (`bool`)
- **`foo.{zng,cpp}`** - Imports primitives, defines `Vec<i32>` APIs and returns a populated Vec
- **`bar.{zng,cpp}`** - Imports primitives, defines `Option<String>` APIs and returns an Option
- **`main.{zng,cpp}`** - Imports foo and bar (transitively gets primitives), extends both types with additional APIs, and demonstrates everything
## API Extensions in main.zng
The main module doesn't just import - it extends the imported types:
- **Vec<i32>**: Adds `is_empty()` and `clear()` methods beyond `foo.zng`'s `new()` and `push()`
- **Option<String>**: Adds `unwrap()` method beyond `bar.zng`'s constructors and `is_some()`/`is_none()`
## Running
```bash
make
./a.out
```
================================================
FILE: examples/simple_import/bar.cpp
================================================
#include "generated.h"
// Creates and returns a Rust Option<String> with Some(String)
rust::std::option::Option<rust::std::string::String> bar() {
// Create Some(String)
return rust::std::option::Option<rust::std::string::String>::Some(
rust::std::string::String::new_()
);
}
================================================
FILE: examples/simple_import/bar.zng
================================================
// Bar module - exports Option<String> APIs for C++ usage
merge "./primitives.zng";
mod ::std {
mod string {
type String {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
fn new() -> String;
}
}
type option::Option<::std::string::String> {
#layout(size = 24, align = 8);
constructor None;
constructor Some(::std::string::String);
fn is_some(&self) -> bool;
fn is_none(&self) -> bool;
}
}
================================================
FILE: examples/simple_import/expected_output.txt
================================================
foo(): Creating a Rust Vec<i32>
Vec contents: [main.cpp:13] numbers = [
10,
20,
30,
]
Vec is_empty(): 0
After clear(), is_empty(): 1
bar(): Creating Rust Option<String>
some_value.is_some(): 1
none_value.is_none(): 1
Unwrapped string: [main.cpp:33] unwrapped_string = ""
================================================
FILE: examples/simple_import/foo.cpp
================================================
#include "generated.h"
// Creates and returns a Rust Vec<i32> with sample data
rust::std::vec::Vec<int32_t> foo() {
// Create a new Rust Vec<i32>
auto numbers = rust::std::vec::Vec<int32_t>::new_();
// Add some numbers
numbers.push(10);
numbers.push(20);
numbers.push(30);
return numbers;
}
================================================
FILE: examples/simple_import/foo.zng
================================================
// Foo module - exports Vec<i32> APIs for C++ usage
merge "./primitives.zng";
mod ::std {
mod vec {
type Vec<i32> {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
fn new() -> Vec<i32>;
fn push(&mut self, i32);
}
}
}
================================================
FILE: examples/simple_import/main.cpp
================================================
#include <iostream>
#include "generated.h"
// External function declarations from foo.cpp and bar.cpp
extern rust::std::vec::Vec<int32_t> foo();
extern rust::std::option::Option<rust::std::string::String> bar();
int main() {
// Get Vec<i32> from foo() and demonstrate both imported and extended APIs
std::cout << "foo(): Creating a Rust Vec<i32>" << std::endl;
auto numbers = foo();
std::cout << " Vec contents: ";
zngur_dbg(numbers);
// Use extended APIs defined in main.zng
std::cout << " Vec is_empty(): " << numbers.is_empty() << std::endl;
numbers.clear(); // Clear the vector using main.zng API
std::cout << " After clear(), is_empty(): " << numbers.is_empty() << std::endl;
std::cout << std::endl;
// Get Option<String> from bar() and demonstrate both imported and extended APIs
std::cout << "bar(): Creating Rust Option<String>" << std::endl;
auto some_value = bar();
auto none_value = rust::std::option::Option<rust::std::string::String>::None();
// Use imported APIs from bar.zng
std::cout << " some_value.is_some(): " << some_value.is_some() << std::endl;
std::cout << " none_value.is_none(): " << none_value.is_none() << std::endl;
// Use extended API defined in main.zng
auto unwrapped_string = some_value.unwrap(); // Use main.zng API
std::cout << " Unwrapped string: ";
zngur_dbg(unwrapped_string);
return 0;
}
================================================
FILE: examples/simple_import/main.zng
================================================
// Main module - imports foo and bar modules to demonstrate import/merge
merge "./foo.zng";
merge "./bar.zng";
// Note: All APIs from foo.zng and bar.zng are now available
// Primitives from primitives.zng are also available transitively
// The std module definitions are automatically merged
// Main module extensions - adding additional APIs to imported types
mod ::std {
mod vec {
type Vec<i32> {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
// Inherited methods from foo.zng (automatically merged)
fn new() -> Vec<i32>;
fn push(&mut self, i32);
// Additional methods beyond what foo.zng provides
fn is_empty(&self) -> bool;
fn clear(&mut self);
}
}
type option::Option<::std::string::String> {
#layout(size = 24, align = 8);
// Inherited constructors and methods from bar.zng (automatically merged)
constructor None;
constructor Some(::std::string::String);
fn is_some(&self) -> bool;
fn is_none(&self) -> bool;
// Additional methods beyond what bar.zng provides
fn unwrap(self) -> ::std::string::String;
}
}
================================================
FILE: examples/simple_import/primitives.zng
================================================
// Primitive types used across the import/merge example
type bool {
#layout(size = 1, align = 1);
wellknown_traits(Copy);
}
================================================
FILE: examples/simple_import/src/lib.rs
================================================
// Minimal lib.rs - just includes the generated Zngur bindings
#[rustfmt::skip]
mod generated;
================================================
FILE: examples/tutorial/.gitignore
================================================
generated.h
generated.rs
================================================
FILE: examples/tutorial/Cargo.toml
================================================
[package]
name = "example-tutorial"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
[lib]
crate-type = ["staticlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
================================================
FILE: examples/tutorial/Makefile
================================================
a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_tutorial.a
${CXX} -std=c++11 -Werror main.cpp -g -L ../../target/release/ -l example_tutorial
../../target/release/libexample_tutorial.a:
cargo build --release
generated.h ./src/generated.rs: main.zng
cd ../../zngur-cli && cargo run g -i ../examples/tutorial/main.zng --crate-name "crate"
.PHONY: ../../target/release/libexample_tutorial.a generated.h clean
clean:
rm -f generated.h generated.cpp src/generated.rs a.out actual_output.txt
================================================
FILE: examples/tutorial/NMakefile
================================================
CXX = cl.exe
CXXFLAGS = /W4 /DEBUG /EHsc /std:c++20
WINLIBS = ntdll.lib
EXAMPLE_NAME = tutorial
GENERATED = generated.h src/generated.rs
RUSTLIB_PATH = ../../target/release/
RUSTLIB = example_$(EXAMPLE_NAME).lib
a.exe : main.cpp src/lib.rs $(GENERATED) $(RUSTLIB_PATH)/$(RUSTLIB)
$(CXX) $(CXXFLAGS) main.cpp /Fe:a.exe /link $(WINLIBS) $(RUSTLIB) /LIBPATH:$(RUSTLIB_PATH)
$(RUSTLIB_PATH)/$(RUSTLIB) :
cargo build --release
$(GENERATED) : main.zng
cd ../../zngur-cli && cargo run g -i ../examples/$(EXAMPLE_NAME)/main.zng --crate-name "crate"
clean :
- del /f /q generated.h generated.cpp src\generated.rs a.exe main.obj actual_output.txt 2>nul
================================================
FILE: examples/tutorial/README.md
================================================
# Example: Tutorial
Full code of the [Tutorial](https://hkalbasi.github.io/zngur/tutorial.html) part 1 (Calling Rust from C++) in the Zngur book.
To run this example:
```
make
./a.out
```
================================================
FILE: examples/tutorial/expected_output.txt
================================================
[main.cpp:7] inventory = Inventory {
items: [
Item {
name: "banana",
size: 7,
},
Item {
name: "banana",
size: 7,
},
Item {
name: "banana",
size: 7,
},
Item {
name: "apple",
size: 5,
},
],
remaining_space: 974,
}
[main.cpp:10] v = [
Item {
name: "banana",
size: 7,
},
Item {
name: "banana",
size: 7,
},
Item {
name: "banana",
size: 7,
},
Item {
name: "apple",
size: 5,
},
]
================================================
FILE: examples/tutorial/main.cpp
================================================
#include "./generated.h"
int main() {
auto inventory = rust::crate::Inventory::new_empty(1000);
inventory.add_banana(3);
inventory.add_item(rust::crate::Item("apple"_rs.to_owned(), 5));
zngur_dbg(inventory);
rust::std::vec::Vec<rust::crate::Item> v = inventory.into_items();
zngur_dbg(v);
}
================================================
FILE: examples/tutorial/main.zng
================================================
type ::std::vec::Vec<crate::Item> {
#layout(size = 24, align = 8);
wellknown_traits(Debug);
}
type str {
wellknown_traits(?Sized);
fn to_owned(&self) -> ::std::string::String;
}
type ::std::string::String {
#layout(size = 24, align = 8);
}
type crate::Item {
#layout(size = 32, align = 8);
constructor { name: ::std::string::String, size: u32 };
}
type crate::Inventory {
#layout(size = 32, align = 8);
wellknown_traits(Debug);
fn new_empty(u32) -> crate::Inventory;
fn add_banana(&mut self, u32);
fn add_item(&mut self, crate::Item);
fn into_items(self) -> ::std::vec::Vec<crate::Item>;
}
================================================
FILE: examples/tutorial/src/lib.rs
================================================
#![allow(dead_code)]
#[rustfmt::skip]
mod generated;
#[derive(Debug)]
struct Item {
name: String,
size: u32,
}
#[derive(Debug)]
struct Inventory {
items: Vec<Item>,
remaining_space: u32,
}
impl Inventory {
fn new_empty(space: u32) -> Self {
Self {
items: vec![],
remaining_space: space,
}
}
fn add_item(&mut self, item: Item) {
self.remaining_space -= item.size;
self.items.push(item);
}
fn add_banana(&mut self, count: u32) {
for _ in 0..count {
self.add_item(Item {
name: "banana".to_owned(),
size: 7,
});
}
}
fn into_items(self) -> Vec<Item> {
self.items
}
}
================================================
FILE: examples/tutorial-wasm32/.gitignore
================================================
generated.h
generated.rs
generated.cpp
generated.o
main.js
target/
a.out
example_tutorial_wasm32.wasm
# WASI SDK and dependencies
wasi-sdk-*
wasi-sdk-latest.tar.gz
wasi-sdk-installed
wasm32-wasip1-target
# Build artifacts
actual_output.txt
*.wasm
================================================
FILE: examples/tutorial-wasm32/Cargo.toml
================================================
[package]
name = "example-tutorial-wasm32"
version = "0.6.0"
edition = "2024"
rust-version = "1.85"
license = "MIT OR Apache-2.0"
publish = false
[lib]
crate-type = ["staticlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
================================================
FILE: examples/tutorial-wasm32/Makefile
================================================
# WASI build flags for C++ compilation with wasmtime
WASIFLAGS = -std=c++14 \
--target=wasm32-wasi \
--sysroot=$(WASI_SDK_PATH)/share/wasi-sysroot \
-D_WASI_EMULATED_SIGNAL \
-lwasi-emulated-signal \
-fno-exceptions
# Use the mise-installed WASI SDK C++ compiler
# Load mise environment if WASI_SDK_PATH is not set
ifeq ($(WASI_SDK_PATH),)
$(eval $(shell mise env))
endif
CXX = $(WASI_SDK_PATH)/bin/clang++
# Default target
all: run a.out
# Run the example with wasmtime (installs all deps automatically)
run: main.wasm
wasmtime run --allow-precompiled main.wasm
# CI expects a.out; we create it as a bash script that simply execs wasmtime
a.out: main.wasm
@printf '%s\n' '#!/usr/bin/env bash' 'exec wasmtime run --allow-precompiled "$$(dirname "$$0")/main.wasm" "$$@"' > $@
@chmod +x $@
main.wasm: main.cpp generated.h generated.cpp \
./target/wasm32-wasip1/release/libexample_tutorial_wasm32.a
$(CXX) $(WASIFLAGS) \
main.cpp generated.cpp \
./target/wasm32-wasip1/release/libexample_tutorial_wasm32.a \
-o $@
./target/wasm32-wasip1/release/libexample_tutorial_wasm32.a: wasm32-wasip1-target generated.h ./src/generated.rs ./src/lib.rs
cargo build --target=wasm32-wasip1 --release
generated.h ./src/generated.rs generated.cpp: main32.zng
cargo run --release --manifest-path ../../zngur-cli/Cargo.toml g -i main32.zng
# Ensure wasm32-wasip1 target is installed
wasm32-wasip1-target:
@rustup target list --installed | grep -q wasm32-wasip1 || { \
echo "Installing wasm32-wasip1 Rust target..."; \
rustup target add wasm32-wasip1; \
}
@touch wasm32-wasip1-target
clean:
cargo clean
rm -f generated.h ./src/generated.rs generated.cpp generated.o
rm -f main.wasm example_tutorial_wasm32.wasm a.out
rm -f wasm32-wasip1-target
FORCE: ;
================================================
FILE: examples/tutorial-wasm32/NMakefile
================================================
# can not eval mise after the fact in nmake, must preeval
WASIFLAGS = -std=c++17 \
--target=wasm32-wasi \
--sysroot=$(WASI_SDK_PATH)/share/wasi-sysroot \
-D_WASI_EMULATED_SIGNAL \
-lwasi-emulated-signal \
-fno-exceptions
CXX = $(WASI_SDK_PATH)\bin\clang++
# Default target
all: run a.bat
# Run the example with wasmtime (installs all deps automatically)
run: main.wasm
wasmtime run --allow-precompiled main.wasm
# CI expects a.bat; we create it as a batch script that simply execs wasmtime
a.bat: main.wasm
echo @echo off > $@
echo wasmtime run --allow-precompiled "%0\..\main.wasm" "$$@" >> $@
main.wasm: main.cpp generated.h generated.cpp \
./target/wasm32-wasip1/release/libexample_tutorial_wasm32.a
$(CXX) $(WASIFLAGS) \
main.cpp generated.cpp \
./target/wasm32-wasip1/release/libexample_tutorial_wasm32.a \
-o $@
./target/wasm32-wasip1/release/libexample_tutorial_wasm32.a: generated.h ./src/generated.rs ./src/lib.rs
cargo build --target=wasm32-wasip1 --release
generated.h ./src/generated.rs generated.cpp: main32.zng
cargo run --release --manifest-path ../../zngur-cli/Cargo.toml g -i main32.zng
clean:
cargo clean
- del /f generated.h .\src\generated.rs generated.cpp generated.o 2>nul
- del /f main.wasm example_tutorial_wasm32.wasm a.bat 2>nul
================================================
FILE: examples/tutorial-wasm32/README.md
================================================
# Wasm32 Example
This example builds a sample application for wasmtime to test zngur's support for basic WASM applications.
## To build and run
```
$ make run
```
This automatically installs all dependencies (wasmtime, WASI SDK, Rust targets) and runs the example.
## Alternative targets
```
$ make # Same as 'make run'
$ make main.wasm # Build without running
$ make a.out # Create executable wrapper script
$ make clean # Clean all build artifacts
```
================================================
FILE: examples/tutorial-wasm32/expected_output.txt
================================================
17
s[2] = 7
Rust panic would happen if we accessed invalid index, but we avoid it
hello 2 2
hello 5 7
hello 7 14
hello 3 17
34 17
vector iterator has been destructed
[main.cpp:70] t = [
10,
20,
60,
]
================================================
FILE: examples/tutorial-wasm32/main.cpp
================================================
#include <iostream>
#include <vector>
#include "./generated.h"
// Rust values are available in the `::rust` namespace from their absolute path
// in Rust
template <typename T> using Vec = rust::std::vec::Vec<T>;
template <typename T> using Option = rust::std::option::Option<T>;
template <typename T> using BoxDyn = rust::Box<rust::Dyn<T>>;
// You can implement Rust traits for your classes
template <typename T>
class VectorIterator : public rust::std::iter::Iterator<T> {
std::vector<T> vec;
size_t pos;
public:
VectorIterator(std::vector<T> &&v) : vec(v), pos(0) {}
~VectorIterator() {
std::cout << "vector iterator has been destructed" << std::endl;
}
Option<T> next() override {
if (pos >= vec.size()) {
return Option<T>::None();
}
T value = vec[pos++];
// You can construct Rust enum with fields in C++
return Option<T>::Some(value);
}
};
int main() {
// You can call Rust functions that return things by value, and store that
// value in your stack.
auto s = Vec<int32_t>::new_();
s.push(2);
Vec<int32_t>::push(s, 5);
s.push(7);
Vec<int32_t>::push(s, 3);
// You can call Rust functions just like normal Rust.
std::cout << s.clone().into_iter().sum() << std::endl;
// Access valid indices
std::cout << "s[2] = " << *s.get(2).unwrap() << std::endl;
// TODO: Uncomment this line after enabling wasmtime exceptions.
// std::cout << "s[4] = " << *s.get(4).unwrap() << std::endl;
std::cout << "Rust panic would happen if we accessed invalid index, but we avoid it" << std::endl;
int state = 0;
// You can convert a C++ lambda into a `Box<dyn Fn>` and friends.
auto f = BoxDyn<rust::Fn<int32_t, int32_t>>::make_box([&](int32_t x) {
state += x;
std::cout << "hello " << x << " " << state << "\n";
return x * 2;
});
// And pass it to Rust functions that accept closures.
auto x = s.into_iter().map(std::move(f)).sum();
std::cout << x << " " << state << "\n";
std::vector<int32_t> vec{10, 20, 60};
// You can convert a C++ type that implements `Trait` to a `Box<dyn Trait>`.
// `make_box` is similar to the `make_unique`, it takes constructor arguments
// and construct it inside the `Box` (instead of `unique_ptr`).
auto vec_as_iter = BoxDyn<rust::std::iter::Iterator<int32_t>>::make_box<
VectorIterator<int32_t>>(std::move(vec));
// Then use it like a normal Rust value.
auto t = vec_as_iter.collect();
// Some utilities are also provided. For example, `zngur_dbg` is the
// equivalent of `dbg!` macro.
zngur_dbg(t);
return 0;
}
================================================
FILE: examples/tutorial-wasm32/main32.zng
================================================
type Box<dyn Fn(i32) -> i32> {
#layout(size = 8, align = 4);
}
mod ::std {
type option::Option<i32> {
#layout(size = 8, align = 4);
wellknown_traits(Copy);
constructor None;
constructor Some(i32);
fn unwrap(self) -> i32;
}
type option::Option<&i32> {
#layout(size = 4, align = 4);
wellknown_traits(Copy);
fn unwrap(self) -> &i32;
}
type iter::Map<::std::vec::IntoIter<i32>, Box<dyn Fn(i32) -> i32>> {
#layout(size = 24, align = 4);
fn sum<i32>(self) -> i32;
}
mod vec {
type IntoIter<i32> {
#layout(size = 16, align = 4);
fn sum<i32>(self) -> i32;
fn map<i32, Box<dyn Fn(i32) -> i32>>(self, Box<dyn Fn(i32) -> i32>)
-> ::std::iter::Map<::std::vec::IntoIter<i32>, Box<dyn Fn(i32) -> i32>>;
}
type Vec<i32> {
#layout(size = 12, align = 4);
wellknown_traits(Debug);
fn new() -> Vec<i32>;
fn push(&mut self, i32);
fn clone(&self) -> Vec<i32>;
fn get(&self, usize) -> ::std::option::Option<&i32> deref [i32];
fn into_iter(self) -> ::std::vec::IntoIter<i32>;
}
}
trait iter::Iterator::<Item = i32> {
fn next(&mut self) -> ::std::option::Option<i32>;
}
}
type Box<dyn ::std::iter::Iterator<Item = i32>> {
#layout(size = 8, align = 4);
fn collect<::std::vec::Vec<i32>>(self) -> ::std::vec::Vec<i32>;
}
================================================
FILE: examples/tutorial-wasm32/src/lib.rs
================================================
#![allow(dead_code)]
#[rustfmt::skip]
mod generated;
pub fn add_one(x: usize) -> usize {
x + 1
}
#[derive(Debug)]
struct Item {
name: String,
size: u32,
}
#[derive(Debug)]
struct Inventory {
items: Vec<Item>,
remaining_space: u32,
}
impl Inventory {
fn new_empty(space: u32) -> Self {
Self {
items: vec![],
remaining_space: space,
}
}
fn add_item(&mut self, item: Item) {
self.remaining_space -= item.size;
self.items.push(item);
}
fn add_banana(&mut self, count: u32) {
for _ in 0..count {
self.add_item(Item {
name: "banana".to_owned(),
size: 7,
});
}
}
fn into_items(self) -> Vec<Item> {
self.items
}
}
================================================
FILE: examples/tutorial_cpp/Cargo.toml
================================================
[package]
name = "example-tutorial_cpp"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[build-dependencies]
cc = "1.0"
build-rs = "0.1.2"
zngur = { path = "../../zngur" }
================================================
FILE: examples/tutorial_cpp/README.md
================================================
# Example: Tutorial Cpp
Full code of the [Tutorial](https://hkalbasi.github.io/zngur/tutorial.html) part 2 (Calling C++ from Rust) in the Zngur book.
To run this example:
```
cargo run
```
================================================
FILE: examples/tutorial_cpp/build.rs
================================================
#[cfg(not(target_os = "windows"))]
use std::env;
use zngur::Zngur;
fn main() {
build::rerun_if_changed("main.zng");
build::rerun_if_changed("impls.cpp");
build::rerun_if_env_changed("CXX");
#[cfg(not(target_os = "windows"))]
let cxx = env::var("CXX").unwrap_or("c++".to_owned());
let crate_dir = build::cargo_manifest_dir();
let out_dir = build::out_dir();
// Force rerun if generated files don't exist
let generated_files = [
out_dir.join("generated.cpp"),
out_dir.join("generated.h"),
out_dir.join("generated.rs"),
];
for file in &generated_files {
if !file.exists() {
println!("cargo:rerun-if-changed=nonexistent_trigger_file");
break;
}
}
Zngur::from_zng_file(crate_dir.join("main.zng"))
.with_cpp_file(out_dir.join("generated.cpp"))
.with_h_file(out_dir.join("generated.h"))
.with_rs_file(out_dir.join("generated.rs"))
.with_crate_name("crate")
.with_zng_header_in_place()
.generate();
let my_build = &mut cc::Build::new();
let my_build = my_build.cpp(true).std("c++20");
#[cfg(not(target_os = "windows"))]
my_build.compiler(&cxx);
my_build.include(&crate_dir).include(&out_dir);
let my_build = || my_build.clone();
my_build()
.file(out_dir.join("generated.cpp"))
.compile("zngur_generated");
my_build().file("impls.cpp").compile("impls");
}
================================================
FILE: examples/tutorial_cpp/expected_output.txt
================================================
[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 }] }
================================================
FILE: examples/tutorial_cpp/impls.cpp
================================================
#include "generated.h"
#include <string>
using namespace rust::crate;
template <typename T> using Ref = rust::Ref<T>;
template <typename T> using RefMut = rust::RefMut<T>;
rust::Ref<rust::Str> rust_str_from_c_str(const char* input) {
return rust::std::ffi::CStr::from_ptr(reinterpret_cast<const int8_t*>(input)).to_str().expect("invalid_utf8"_rs);
}
Inventory rust::Impl<Inventory>::new_empty(uint32_t space) {
return Inventory(
rust::ZngurCppOpaqueOwnedObject::build<cpp_inventory::Inventory>(space));
}
rust::Unit rust::Impl<Inventory>::add_banana(RefMut<Inventory> self,
uint32_t count) {
self.cpp().add_banana(count);
return {};
}
rust::Unit rust::Impl<Inventory>::add_item(RefMut<Inventory> self, Item item) {
self.cpp().add_item(item.cpp());
return {};
}
Item rust::Impl<Item>::new_(Ref<rust::Str> name, uint32_t size) {
return Item(rust::ZngurCppOpaqueOwnedObject::build<cpp_inventory::Item>(
cpp_inventory::Item{
.name = ::std::string(reinterpret_cast<const char *>(name.as_ptr()),
name.len()),
.size = size}));
}
rust::std::fmt::Result rust::Impl<Inventory, rust::std::fmt::Debug>::fmt(
Ref<Inventory> self, RefMut<rust::std::fmt::Formatter> f) {
::std::string result = "Inventory { remaining_space: ";
result += ::std::to_string(self.cpp().remaining_space);
result += ", items: [";
bool is_first = true;
for (const auto &item : self.cpp().items) {
if (!is_first) {
result += ", ";
} else {
is_first = false;
}
result += "Item { name: \"";
result += item.name;
result += "\", size: ";
result += ::std::to_string(item.size);
result += " }";
}
result += "] }";
return f.write_str(rust_str_from_c_str(result.c_str()));
}
================================================
FILE: examples/tutorial_cpp/inventory.h
================================================
#include <cstdint>
#include <string>
#include <vector>
namespace cpp_inventory {
struct Item {
std::string name;
uint32_t size;
};
struct Inventory {
std::vector<Item> items;
uint32_t remaining_space;
Inventory(uint32_t space) : items(), remaining_space(space) {}
void add_item(Item item) {
remaining_space -= item.size;
items.push_back(std::move(item));
}
void add_banana(uint32_t count) {
for (uint32_t i = 0; i < count; i += 1) {
add_item(Item{
.name = "banana",
.size = 7,
});
}
}
};
} // namespace cpp_inventory
================================================
FILE: examples/tutorial_cpp/main.zng
================================================
#cpp_additional_includes "
#include <inventory.h>
"
type str {
wellknown_traits(?Sized);
fn as_ptr(&self) -> *const u8;
fn len(&self) -> usize;
}
type ::std::ffi::CStr {
wellknown_traits(?Sized);
fn from_ptr(*const i8) -> &::std::ffi::CStr;
fn to_str(&self) -> ::std::result::Result<&str, ::std::str::Utf8Error>;
}
type ::std::result::Result<&str, ::std::str::Utf8Error> {
#layout(size = 24, align = 8);
fn expect(self, &str) -> &str;
}
type crate::Inventory {
#layout(size = 16, align = 8);
constructor(ZngurCppOpaqueOwnedObject);
#cpp_value "0" "::cpp_inventory::Inventory";
}
type crate::Item {
#layout(size = 16, align = 8);
constructor(ZngurCppOpaqueOwnedObject);
#cpp_value "0" "::cpp_inventory::Item";
}
type ::std::fmt::Result {
#layout(size = 1, align = 1);
constructor Ok(());
}
type ::std::fmt::Formatter {
#only_by_ref;
fn write_str(&mut self, &str) -> ::std::fmt::Result;
}
extern "C++" {
impl crate::Inventory {
fn new_empty(u32) -> crate::Inventory;
fn add_banana(&mut self, u32);
fn add_item(&mut self, crate::Item);
}
impl crate::Item {
fn new(&str, u32) -> crate::Item;
}
impl std::fmt::Debug for crate::Inventory {
fn fmt(&self, &mut ::std::fmt::Formatter) -> ::std::fmt::Result;
}
}
================================================
FILE: examples/tutorial_cpp/src/main.rs
================================================
mod generated {
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
}
struct Inventory(generated::ZngurCppOpaqueOwnedObject);
struct Item(generated::ZngurCppOpaqueOwnedObject);
fn main() {
let mut inventory = Inventory::new_empty(1000);
inventory.add_banana(3);
inventory.add_item(Item::new("apple", 5));
dbg!(inventory);
}
================================================
FILE: mise.toml
================================================
[tools]
cspell = "9.4.0"
dprint = "0.50.2"
wasmtime = "36.0.2"
[tools."github:WebAssembly/wasi-sdk"]
version = "30"
version_prefix = "wasi-sdk-"
# don't export clang binaries
filter_bins = ""
[tools."http:emsdk"]
version = "5.0.2"
url = "https://github.com/emscripten-core/emsdk/archive/refs/tags/{{version}}.tar.gz"
[env]
WASI_SDK_PATH = { value = '{{ tools["github:WebAssembly/wasi-sdk"].path }}', tools = true }
EMSDK_PATH = { value = '{{ [tools["http:emsdk"].path] | concat(with= ["emsdk-", tools["http:emsdk"].version] | join ) | join_path }}', tools = true }
RUST_BACKTRACE = { value = "0" }
================================================
FILE: xtask/Cargo.toml
================================================
[package]
name = "xtask"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
xshell = "0.2.7"
anyhow = "1.0"
clap = { version = "4.3.12", features = ["derive"] }
================================================
FILE: xtask/src/ci.rs
================================================
use crate::format_book;
use anyhow::{Context, Result};
use xshell::{Shell, cmd};
fn check_crate(sh: &Shell) -> Result<()> {
cmd!(sh, "cargo check").run()?;
cmd!(sh, "cargo fmt --check")
.run()
.with_context(|| "Crate is not formatted. Run `cargo fmt`")?;
Ok(())
}
fn check_book_formatting() -> Result<()> {
format_book::main(false /* don't fix */)
.with_context(|| "Book markdown files are not formatted. Run `cargo xtask format-book`")
}
fn check_examples(sh: &Shell, fix: bool) -> Result<()> {
const CARGO_PROJECTS: &[&str] = &["cxx_demo", "tutorial_cpp"];
let examples_dir = sh.current_dir().join("examples");
sh.change_dir("examples");
let examples = sh.read_dir(".")?;
for example in examples {
let mut skip = false;
let example = example
.file_name()
.unwrap_or_default()
.to_str()
.ok_or(anyhow::anyhow!("Non utf8 example name?"))?;
println!("Building and testing {example}");
sh.change_dir(example);
println!("Working in {}", sh.current_dir().display());
if CARGO_PROJECTS.contains(&example) {
#[cfg(not(target_os = "windows"))]
{
// Clean generated files for Cargo projects
let _ = cmd!(
sh,
"rm -f generated.h generated.cpp src/generated.rs actual_output.txt"
)
.run();
cmd!(sh, "cargo build")
.run()
.with_context(|| format!("Building example `{example}` failed"))?;
let bash_cmd = format!(
"../../target/debug/example-{example} 2>&1 | sed -e s/thread.*\\(.*\\)/thread/g > actual_output.txt"
);
cmd!(sh, "bash -c {bash_cmd}")
.run()
.with_context(|| format!("Running example `{example}` failed"))?;
}
#[cfg(target_os = "windows")]
{
// Clean generated files for Cargo projects
let _ = cmd!(
sh,
"cmd /c 'del /f /q generated.h generated.cpp src\\generated.rs actual_output.txt 2>nul'"
)
.run();
cmd!(sh, "cmd /c 'cargo build'")
.run()
.with_context(|| format!("Building example `{example}` failed"))?;
let batch_cmd =
format!("..\\..\\target\\debug\\example-{example} > actual_output.txt 2>&1");
cmd!(sh, "cmd /c {batch_cmd}")
.run()
.with_context(|| format!("Running example `{example}` failed"))?;
cmd!(sh, "pwsh -Command '(Get-Content actual_output.txt) -replace \"thread.*\\(.*\\)\", \"thread\" -replace \"\\\\\", \"/\"| Out-File actual_output.txt'")
.run()
.with_context(|| format!("Filtering example `{example}` thread output failed"))?;
}
} else {
#[cfg(not(target_os = "windows"))]
if sh.path_exists("Makefile") {
// Clean generated files for Make projects
cmd!(sh, "make clean")
.run()
.with_context(|| format!("Cleaning example `{example}` failed"))?;
cmd!(sh, "make")
.run()
.with_context(|| format!("Building example `{example}` failed"))?;
cmd!(
sh,
"bash -c './a.out 2>&1 | sed -e s/thread.*\\(.*\\)/thread/g > actual_output.txt'"
)
.run()
.with_context(|| format!("Running example `{example}` failed"))?;
if sh.path_exists("b.out") {
cmd!(
sh,
"bash -c './b.out 2>&1 | sed -r s/thread.*\\(.*\\)/thread/g >> actual_output.txt'"
)
.run()
.with_context(|| format!("Running example `{example}` b.out failed"))?;
}
} else {
skip = true;
println!("Skipping {example}, no Makefile for this example");
}
#[cfg(target_os = "windows")]
if sh.path_exists("NMakefile") {
// Clean generated files for NMake projects
cmd!(sh, "nmake /f NMakefile clean")
.run()
.with_context(|| format!("Cleaning example `{example}` failed"))?;
cmd!(sh, "nmake /f NMakefile")
.run()
.with_context(|| format!("Building example `{example}` failed"))?;
if sh.path_exists("a.bat") {
cmd!(sh, "cmd /c '.\\a.bat > actual_output.txt 2>&1'")
.run()
.with_context(|| format!("Running example `{example}` failed"))?;
} else {
cmd!(sh, "cmd /c '.\\a.exe > actual_output.txt 2>&1'")
.run()
.with_context(|| format!("Running example `{example}` failed"))?;
}
if sh.path_exists("b.exe") {
cmd!(sh, "cmd /c '.\\b.exe >> actual_output.txt 2>&1'")
.run()
.with_context(|| format!("Running example `{example}` b.exe failed"))?;
}
cmd!(sh, "pwsh -Command '(Get-Content actual_output.txt) -replace \"thread.*\\(.*\\)\", \"thread\" -replace \"\\\\\", \"/\"| Out-File actual_output.txt'")
.run()
.with_context(|| format!("Filtering example `{example}` thread output failed"))?;
} else {
skip = true;
println!("Skipping {example}, no NMakefile for this example");
}
}
if fix {
sh.copy_file("./actual_output.txt", "./expected_output.txt")?;
}
if !skip {
#[cfg(not(target_os = "windows"))]
cmd!(sh, "diff actual_output.txt expected_output.txt")
.run()
.with_context(|| format!("Example `{example}` output differs from expected."))?;
#[cfg(target_os = "windows")]
cmd!(sh, "cmd /c 'fc actual_output.txt expected_output.txt'")
.run()
.with_context(|| format!("Example `{example}` output differs from expected."))?;
cmd!(sh, "cargo fmt --check").run().with_context(|| {
format!("Example `{example}` is not formatted. Run `cargo fmt`")
})?;
}
sh.change_dir(&examples_dir);
}
Ok(())
}
pub fn main(fix: bool) -> Result<()> {
let sh = &Shell::new()?;
println!("Cargo version = {}", cmd!(sh, "cargo --version").read()?);
#[cfg(not(target_os = "windows"))]
{
let cxx = sh.var("CXX")?;
println!("CXX version = {}", cmd!(sh, "{cxx} --version").read()?);
}
#[cfg(target_os = "windows")]
let msvc_ver: u32 = {
let msvc = String::from_utf8(cmd!(sh, "cl.exe /help").output()?.stderr)?;
let msvc = msvc
.lines()
.next()
.and_then(|line| line.split("Version ").nth(1))
.unwrap_or_default();
let mut parts = msvc.split(".");
let major = parts.next().unwrap_or("0");
let minor = parts.next().unwrap_or("0");
let msvc_ver: u32 = format!("{major}{minor}").parse()?;
println!("MSVC version = {msvc} ({msvc_ver})",);
msvc_ver
};
#[cfg(not(target_os = "windows"))]
sh.set_var("RUSTFLAGS", "-D warnings");
#[cfg(target_os = "windows")]
{
// Prevent link.exe error:1318
let link_debug = if msvc_ver > 1944 {
// sorry, msvc 2026 removed FASTLINK support so it can't prevent pdb
// corruption. best we can do is disable debug symbols
"/DEBUG:NONE"
} else {
"/DEBUG:FASTLINK"
};
sh.set_var(
"RUSTFLAGS",
format!("-D warnings -C link-arg={link_debug} -C link-arg=/INCREMENTAL:NO"),
);
}
if fix {
cmd!(sh, "cargo fmt --all").run()?;
if let Err(e) = format_book::main(true /* fix */) {
eprintln!("Warning: Failed to format book: {}", e);
}
}
#[cfg(not(target_os = "windows"))]
cmd!(sh, "cspell .")
.run()
.with_context(|| "Failed to check word spellings")?;
#[cfg(target_os = "windows")]
cmd!(sh, "cspell.cmd .")
.run()
.with_context(|| "Failed to check word spellings")?;
// Check book formatting
check_book_formatting().with_context(|| "Book formatting check failed")?;
for dir in sh.read_dir(".")? {
if sh.path_exists(dir.join("Cargo.toml")) {
let _crate_dir = sh.push_dir(dir.file_name().unwrap_or_default());
check_crate(sh).with_context(|| format!("Checking crate {dir:?} failed"))?;
}
}
check_examples(sh, fix).with_context(|| "Checking examples failed")?;
// it's nigh impossible to get this to run under MSVC
#[cfg(not(target_os = "windows"))]
cmd!(sh, "cargo test --all-features").run()?;
Ok(())
}
================================================
FILE: xtask/src/format_book.rs
================================================
use anyhow::{Context, Result, bail};
use xshell::{Shell, cmd};
pub fn main(fix: bool) -> Result<()> {
let sh = Shell::new()?;
// Check if dprint config exists
if !sh.path_exists("dprint.json") {
bail!("dprint.json config file not found. Please create it first.");
}
// Check if book source directory exists
if !sh.path_exists("book/src") {
bail!("Book source directory 'book/src' not found");
}
if fix {
println!("Formatting markdown files...");
cmd!(sh, "dprint fmt")
.run()
.with_context(|| "Failed to format markdown files")?;
println!("✓ Book formatting complete!");
Ok(())
} else {
println!("Checking markdown formatting...");
match cmd!(sh, "dprint check").run() {
Ok(_) => {
println!("✓ All markdown files are correctly formatted!");
Ok(())
}
Err(_) => {
eprintln!("✗ Some markdown files need formatting.");
eprintln!("Run `cargo xtask format-book --fix` to fix them.");
bail!("Book formatting check failed");
}
}
}
}
================================================
FILE: xtask/src/format_templates.rs
================================================
use anyhow::{Context, Result, bail};
use xshell::{Shell, cmd};
fn convert_sailfish_tags_to_comment(mut template: &str) -> Result<(String, Vec<&str>)> {
let mut result_text = String::with_capacity(template.len());
let mut result_dicts = vec![];
while let Some((before_start, rest)) = template.split_once("<%") {
result_text.push_str(before_start);
let comment = format!("/* SAILFISH_TEMPLATE{} */", result_dicts.len());
let (tag, rest) = rest
.split_once("%>")
.context("A <% without %> found in template")?;
result_dicts.push(tag);
template = rest;
result_text.push_str(&comment);
}
result_text.push_str(template);
Ok((result_text, result_dicts))
}
fn convert_comments_to_sailfish_tag(mut template: String, tags: Vec<&str>) -> String {
for (i, tag) in tags.into_iter().enumerate() {
let comment = format!("/* SAILFISH_TEMPLATE{i} */");
let tag_fixed = format!("<%{tag}%>");
template = template.replace(&comment, &tag_fixed);
}
template
}
pub fn main(fix: bool) -> Result<()> {
let sh = Shell::new()?;
let temp_dir = sh.create_temp_dir()?;
for cpp_template in [
"./zngur-generator/templates/cpp_header.sptl",
"./zngur-generator/templates/cpp_source.sptl",
] {
let text = std::fs::read_to_string(cpp_template).context("failed to open template file")?;
let (commented_text, tags) = convert_sailfish_tags_to_comment(&text)?;
let temp_file_path = temp_dir.path().join("template.cpp");
std::fs::write(&temp_file_path, commented_text)?;
cmd!(sh, "clang-format --style=webkit -i {temp_file_path}").run()?;
let fixed_text = std::fs::read_to_string(&temp_file_path)?;
let fixed_text = convert_comments_to_sailfish_tag(fixed_text, tags);
if fix {
std::fs::write(&cpp_template, fixed_text)?;
} else {
if fixed_text != text {
bail!("Diff detected in file {cpp_template}");
}
}
}
Ok(())
}
================================================
FILE: xtask/src/main.rs
================================================
use clap::Parser;
mod ci;
mod format_book;
mod format_templates;
#[derive(Parser)]
enum Command {
CI {
#[arg(long)]
fix: bool,
},
FormatBook {
#[arg(long)]
fix: bool,
},
FormatTemplates {
#[arg(long)]
fix: bool,
},
}
fn main() -> anyhow::Result<()> {
let cmd = Command::parse();
match cmd {
Command::CI { fix } => ci::main(fix),
Command::FormatBook { fix } => format_book::main(fix),
Command::FormatTemplates { fix } => format_templates::main(fix),
}
}
================================================
FILE: zngur/Cargo.toml
================================================
[package]
name = "zngur"
description = "A Rust/C++ interoperability tool"
readme = "../README.md"
version = "0.9.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
zngur-generator = { version = "=0.9.0", path = "../zngur-generator" }
================================================
FILE: zngur/src/lib.rs
================================================
//! This crate contains an API for using the Zngur code generator inside build scripts. For more information
//! about the Zngur itself, see [the documentation](https://hkalbasi.github.io/zngur).
use std::{
fs::File,
io::Write,
path::{Path, PathBuf},
};
use zngur_generator::{
ParsedZngFile, ZngHeaderGenerator, ZngurGenerator,
cfg::{InMemoryRustCfgProvider, NullCfg, RustCfgProvider},
};
#[must_use]
/// Builder for the Zngur generator.
///
/// Usage:
/// ```ignore
/// let crate_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
/// let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
gitextract_ukr27c6s/
├── .cargo/
│ └── config.toml
├── .github/
│ └── workflows/
│ ├── ci.yml
│ ├── publish.yml
│ └── site.yml
├── .gitignore
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── benchmark/
│ ├── .gitignore
│ ├── Cargo.toml
│ ├── benches/
│ │ └── simple.rs
│ ├── build.rs
│ ├── impls.cpp
│ ├── main.zng
│ └── src/
│ └── lib.rs
├── cspell-words.txt
├── cspell.json
├── dprint.json
├── examples/
│ ├── .gitignore
│ ├── char/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── conditional/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── cxx_demo/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ ├── blobstore.cpp
│ │ ├── build.rs
│ │ ├── expected_output.txt
│ │ ├── main.zng
│ │ └── src/
│ │ └── main.rs
│ ├── cxx_demo_split/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ ├── blobstore.cpp
│ │ ├── build.rs
│ │ ├── expected_output.txt
│ │ ├── main.zng
│ │ └── src/
│ │ └── main.rs
│ ├── impl_trait/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── memory_management/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── multiple_modules/
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── aggregation/
│ │ │ ├── Cargo.toml
│ │ │ ├── aggregation.zng
│ │ │ ├── impls.cpp
│ │ │ ├── src/
│ │ │ │ └── lib.rs
│ │ │ └── stats.h
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── packet/
│ │ │ ├── Cargo.toml
│ │ │ ├── packet.zng
│ │ │ └── src/
│ │ │ └── lib.rs
│ │ ├── processor/
│ │ │ ├── Cargo.toml
│ │ │ ├── processor.zng
│ │ │ └── src/
│ │ │ └── lib.rs
│ │ ├── receiver/
│ │ │ ├── Cargo.toml
│ │ │ ├── receiver.zng
│ │ │ └── src/
│ │ │ └── lib.rs
│ │ └── src/
│ │ └── lib.rs
│ ├── raw_pointer/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── rayon/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── rayon_split/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── regression_test1/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── rustyline/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── simple/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── simple_import/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── bar.cpp
│ │ ├── bar.zng
│ │ ├── expected_output.txt
│ │ ├── foo.cpp
│ │ ├── foo.zng
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ ├── primitives.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── tutorial/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main.zng
│ │ └── src/
│ │ └── lib.rs
│ ├── tutorial-wasm32/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── NMakefile
│ │ ├── README.md
│ │ ├── expected_output.txt
│ │ ├── main.cpp
│ │ ├── main32.zng
│ │ └── src/
│ │ └── lib.rs
│ └── tutorial_cpp/
│ ├── Cargo.toml
│ ├── README.md
│ ├── build.rs
│ ├── expected_output.txt
│ ├── impls.cpp
│ ├── inventory.h
│ ├── main.zng
│ └── src/
│ └── main.rs
├── mise.toml
├── xtask/
│ ├── Cargo.toml
│ └── src/
│ ├── ci.rs
│ ├── format_book.rs
│ ├── format_templates.rs
│ └── main.rs
├── zngur/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
├── zngur-autozng/
│ ├── Cargo.toml
│ └── src/
│ └── main.rs
├── zngur-cli/
│ ├── Cargo.toml
│ └── src/
│ ├── cfg_extractor.rs
│ └── main.rs
├── zngur-def/
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs
│ └── merge.rs
├── zngur-generator/
│ ├── Cargo.toml
│ ├── src/
│ │ ├── cpp.rs
│ │ ├── lib.rs
│ │ ├── rust.rs
│ │ └── template.rs
│ └── templates/
│ ├── cpp_header.sptl
│ ├── cpp_source.sptl
│ └── zng_header.sptl
└── zngur-parser/
├── Cargo.toml
└── src/
├── cfg.rs
├── conditional.rs
├── lib.rs
└── tests.rs
SYMBOL INDEX (617 symbols across 61 files)
FILE: benchmark/benches/simple.rs
function criterion_benchmark (line 4) | fn criterion_benchmark(c: &mut Criterion) {
FILE: benchmark/build.rs
function main (line 3) | fn main() {
FILE: benchmark/impls.cpp
type rust::exported_functions (line 7) | namespace rust::exported_functions {
function build_vec_by_push_cpp (line 8) | auto build_vec_by_push_cpp(u64 n) -> Vec<u64> {
FILE: benchmark/src/lib.rs
function build_vec_by_push_rust (line 5) | pub fn build_vec_by_push_rust(n: u64) -> Vec<u64> {
function build_vec_by_push_cpp (line 13) | pub fn build_vec_by_push_cpp(n: u64) -> Vec<u64> {
FILE: examples/char/main.cpp
function main (line 5) | int main() {
FILE: examples/char/src/lib.rs
type CharPrinter (line 4) | struct CharPrinter;
method print (line 7) | fn print(c: char) {
method is_alphabetic (line 11) | fn is_alphabetic(c: char) -> bool {
method to_uppercase (line 15) | fn to_uppercase(c: char) -> char {
FILE: examples/conditional/main.cpp
function main (line 24) | int main() {
FILE: examples/conditional/src/lib.rs
type KeyValuePair (line 10) | struct KeyValuePair {
method self_size (line 19) | fn self_size() -> usize {
method self_align (line 22) | fn self_align() -> usize {
method fmt (line 30) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 38) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 50) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 58) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: examples/cxx_demo/blobstore.cpp
class BlobStore (line 8) | class BlobStore : public rust::crate::BlobStoreTrait {
class Impl (line 9) | class Impl {
method put (line 20) | uint64_t put(rust::RefMut<rust::crate::MultiBuf> buf) override {
method tag (line 42) | rust::Unit tag(::uint64_t blob_id,
method metadata (line 48) | rust::crate::BlobMetadata metadata(::uint64_t blob_id) override {
FILE: examples/cxx_demo/build.rs
function main (line 6) | fn main() {
FILE: examples/cxx_demo/src/main.rs
type MultiBuf (line 10) | pub struct MultiBuf {
method next_chunk (line 16) | pub fn next_chunk(&mut self) -> &[u8] {
type BlobMetadata (line 24) | struct BlobMetadata {
method set_size (line 30) | fn set_size(&mut self, size: usize) {
method push_tag (line 34) | fn push_tag(&mut self, c: *const i8) {
type BlobStoreTrait (line 41) | trait BlobStoreTrait {
method put (line 42) | fn put(&self, buf: &mut MultiBuf) -> u64;
method tag (line 43) | fn tag(&self, blob_id: u64, tag: &str);
method metadata (line 44) | fn metadata(&self, blob_id: u64) -> BlobMetadata;
function main (line 47) | fn main() {
FILE: examples/cxx_demo_split/blobstore.cpp
class BlobStore (line 8) | class BlobStore : public rust::crate::BlobStoreTrait {
class Impl (line 9) | class Impl {
method put (line 20) | uint64_t put(rust::RefMut<rust::crate::MultiBuf> buf) override {
method tag (line 42) | rust::Unit tag(::uint64_t blob_id,
method metadata (line 48) | rust::crate::BlobMetadata metadata(::uint64_t blob_id) override {
FILE: examples/cxx_demo_split/build.rs
function main (line 6) | fn main() {
FILE: examples/cxx_demo_split/src/main.rs
type MultiBuf (line 10) | pub struct MultiBuf {
method next_chunk (line 16) | pub fn next_chunk(&mut self) -> &[u8] {
type BlobMetadata (line 24) | struct BlobMetadata {
method set_size (line 30) | fn set_size(&mut self, size: usize) {
method push_tag (line 34) | fn push_tag(&mut self, c: *const i8) {
type BlobStoreTrait (line 41) | trait BlobStoreTrait {
method put (line 42) | fn put(&self, buf: &mut MultiBuf) -> u64;
method tag (line 43) | fn tag(&self, blob_id: u64, tag: &str);
method metadata (line 44) | fn metadata(&self, blob_id: u64) -> BlobMetadata;
function main (line 47) | fn main() {
FILE: examples/impl_trait/main.cpp
function main (line 8) | int main() {
FILE: examples/impl_trait/src/lib.rs
function argument_position_impl_trait (line 9) | fn argument_position_impl_trait(arg: impl Debug) {
function return_position_impl_trait (line 13) | fn return_position_impl_trait() -> impl Debug {
function both_impl_trait (line 17) | fn both_impl_trait(input: impl Debug) -> impl Debug {
function async_func1 (line 21) | async fn async_func1() -> i32 {
function async_func2 (line 26) | async fn async_func2() -> i32 {
function impl_future (line 31) | fn impl_future() -> impl Future<Output = i32> {
function busy_wait_future (line 39) | fn busy_wait_future<T: Debug>(fut: Box<dyn Future<Output = T>>) -> T {
FILE: examples/memory_management/main.cpp
class CppPrintOnDropHolder (line 13) | class CppPrintOnDropHolder : public PrintOnDropConsumer {
method consume (line 14) | rust::Unit consume(PrintOnDrop p) override {
function main (line 22) | int main() {
FILE: examples/memory_management/src/lib.rs
type PrintOnDrop (line 5) | pub struct PrintOnDrop(&'static str);
type PrintOnDropPair (line 7) | pub struct PrintOnDropPair {
method drop (line 13) | fn drop(&mut self) {
type PrintOnDropConsumer (line 18) | trait PrintOnDropConsumer {
method consume (line 19) | fn consume(&mut self, p: PrintOnDrop);
function consume_n_times (line 22) | fn consume_n_times(consumer: &mut dyn PrintOnDropConsumer, name: &'stati...
function consume_and_panic (line 28) | fn consume_and_panic(p: PrintOnDrop, do_panic: bool) -> PrintOnDrop {
FILE: examples/multiple_modules/aggregation/impls.cpp
function StatsAccumulator (line 9) | StatsAccumulator rust::Impl<StatsAccumulator>::create() {
FILE: examples/multiple_modules/aggregation/src/lib.rs
type StatsAccumulator (line 7) | pub struct StatsAccumulator(pub generated::ZngurCppOpaqueOwnedObject);
FILE: examples/multiple_modules/aggregation/stats.h
function namespace (line 9) | namespace cpp_stats {
FILE: examples/multiple_modules/main.cpp
function main (line 8) | int main() {
FILE: examples/multiple_modules/packet/src/lib.rs
type Packet (line 1) | pub struct Packet(pub u64, pub u32);
method new (line 4) | pub fn new(timestamp: u64, size: u32) -> Self {
method timestamp (line 8) | pub fn timestamp(&self) -> u64 {
method size (line 12) | pub fn size(&self) -> u32 {
FILE: examples/multiple_modules/processor/src/lib.rs
type Processor (line 4) | pub struct Processor;
method new (line 7) | pub fn new() -> Self {
method run (line 11) | pub fn run(
FILE: examples/multiple_modules/receiver/src/lib.rs
type Receiver (line 3) | pub struct Receiver {
method new (line 8) | pub fn new() -> Self {
method next_packet (line 12) | pub fn next_packet(&mut self) -> Packet {
FILE: examples/raw_pointer/main.cpp
function main (line 8) | int main()
FILE: examples/rayon/main.cpp
function is_prime (line 17) | bool is_prime(uint64_t v) {
function main (line 28) | int main() {
FILE: examples/rayon_split/main.cpp
function is_prime (line 17) | bool is_prime(uint64_t v) {
function main (line 28) | int main() {
FILE: examples/regression_test1/main.cpp
function test_dbg_works_for_ref_and_refmut (line 6) | void test_dbg_works_for_ref_and_refmut() {
function test_fields_and_constructor (line 27) | void test_fields_and_constructor() {
function test_field_underlying_conversions (line 62) | void test_field_underlying_conversions() {
function test_floats (line 91) | void test_floats() {
function test_dyn_fn_with_multiple_arguments (line 113) | void test_dyn_fn_with_multiple_arguments() {
function test_refref (line 123) | void test_refref() {
function test_zero_sized_type (line 139) | void test_zero_sized_type() {
function test_nested_heap_refs_and_auto_field_offset (line 146) | void test_nested_heap_refs_and_auto_field_offset() {
function test_conservative_layout (line 202) | void test_conservative_layout() {
function main (line 229) | int main() {
FILE: examples/regression_test1/src/lib.rs
type Foo (line 6) | struct Foo {
type FieldTypeA (line 13) | struct FieldTypeA {
type FieldTypeB (line 20) | struct FieldTypeB {
type FieldTypeC (line 27) | struct FieldTypeC {
type TypeA (line 35) | struct TypeA {
type TypeB (line 44) | struct TypeB {
type ConservativeLayoutType (line 53) | struct ConservativeLayoutType {
method mem_size (line 61) | pub fn mem_size(&self) -> usize {
method mem_align (line 64) | pub fn mem_align(&self) -> usize {
type Scoped (line 69) | struct Scoped(&'static str);
method new (line 72) | fn new(message: &'static str) -> Self {
method drop (line 79) | fn drop(&mut self) {
function call_dyn_fn_multi_args (line 85) | fn call_dyn_fn_multi_args(func: Box<dyn Fn(i32, crate::Scoped, &str)>) {
type ZeroSizedType (line 92) | struct ZeroSizedType;
method new (line 95) | fn new() -> Self {
method method (line 99) | fn method(&self) {
FILE: examples/rustyline/main.cpp
function main (line 8) | int main() {
FILE: examples/simple/main.cpp
class VectorIterator (line 14) | class VectorIterator : public rust::std::iter::Iterator<T> {
method VectorIterator (line 19) | VectorIterator(std::vector<T> &&v) : vec(v), pos(0) {}
method next (line 24) | Option<T> next() override {
function main (line 34) | int main() {
FILE: examples/simple_import/bar.cpp
function bar (line 4) | rust::std::option::Option<rust::std::string::String> bar() {
FILE: examples/simple_import/foo.cpp
function foo (line 4) | rust::std::vec::Vec<int32_t> foo() {
FILE: examples/simple_import/main.cpp
function main (line 8) | int main() {
FILE: examples/tutorial-wasm32/main.cpp
class VectorIterator (line 14) | class VectorIterator : public rust::std::iter::Iterator<T> {
method VectorIterator (line 19) | VectorIterator(std::vector<T> &&v) : vec(v), pos(0) {}
method next (line 24) | Option<T> next() override {
function main (line 34) | int main() {
FILE: examples/tutorial-wasm32/src/lib.rs
function add_one (line 6) | pub fn add_one(x: usize) -> usize {
type Item (line 11) | struct Item {
type Inventory (line 17) | struct Inventory {
method new_empty (line 23) | fn new_empty(space: u32) -> Self {
method add_item (line 30) | fn add_item(&mut self, item: Item) {
method add_banana (line 35) | fn add_banana(&mut self, count: u32) {
method into_items (line 44) | fn into_items(self) -> Vec<Item> {
FILE: examples/tutorial/main.cpp
function main (line 3) | int main() {
FILE: examples/tutorial/src/lib.rs
type Item (line 7) | struct Item {
type Inventory (line 13) | struct Inventory {
method new_empty (line 19) | fn new_empty(space: u32) -> Self {
method add_item (line 26) | fn add_item(&mut self, item: Item) {
method add_banana (line 31) | fn add_banana(&mut self, count: u32) {
method into_items (line 40) | fn into_items(self) -> Vec<Item> {
FILE: examples/tutorial_cpp/build.rs
function main (line 6) | fn main() {
FILE: examples/tutorial_cpp/impls.cpp
function rust_str_from_c_str (line 9) | rust::Ref<rust::Str> rust_str_from_c_str(const char* input) {
function Inventory (line 13) | Inventory rust::Impl<Inventory>::new_empty(uint32_t space) {
function Item (line 29) | Item rust::Impl<Item>::new_(Ref<rust::Str> name, uint32_t size) {
FILE: examples/tutorial_cpp/inventory.h
function namespace (line 5) | namespace cpp_inventory {
FILE: examples/tutorial_cpp/src/main.rs
type Inventory (line 5) | struct Inventory(generated::ZngurCppOpaqueOwnedObject);
type Item (line 6) | struct Item(generated::ZngurCppOpaqueOwnedObject);
function main (line 8) | fn main() {
FILE: xtask/src/ci.rs
function check_crate (line 5) | fn check_crate(sh: &Shell) -> Result<()> {
function check_book_formatting (line 13) | fn check_book_formatting() -> Result<()> {
function check_examples (line 18) | fn check_examples(sh: &Shell, fix: bool) -> Result<()> {
function main (line 157) | pub fn main(fix: bool) -> Result<()> {
FILE: xtask/src/format_book.rs
function main (line 4) | pub fn main(fix: bool) -> Result<()> {
FILE: xtask/src/format_templates.rs
function convert_sailfish_tags_to_comment (line 4) | fn convert_sailfish_tags_to_comment(mut template: &str) -> Result<(Strin...
function convert_comments_to_sailfish_tag (line 21) | fn convert_comments_to_sailfish_tag(mut template: String, tags: Vec<&str...
function main (line 30) | pub fn main(fix: bool) -> Result<()> {
FILE: xtask/src/main.rs
type Command (line 8) | enum Command {
function main (line 23) | fn main() -> anyhow::Result<()> {
FILE: zngur-autozng/src/main.rs
type RustdocRustType (line 8) | enum RustdocRustType {
method render (line 30) | fn render(&self) -> String {
type RustdocFunctionDecl (line 52) | struct RustdocFunctionDecl {
type RustdocItemInner (line 61) | enum RustdocItemInner {
type RustdocItem (line 111) | struct RustdocItem {
type RustdocOutput (line 119) | struct RustdocOutput {
function main (line 123) | fn main() {
FILE: zngur-cli/src/cfg_extractor.rs
type CfgFromRustc (line 5) | pub struct CfgFromRustc {
function cfg_from_rustc (line 60) | pub fn cfg_from_rustc(
function parse_rustflags_env (line 132) | fn parse_rustflags_env() -> Vec<String> {
function parse_rustflags (line 137) | fn parse_rustflags(flags_str: &str) -> Vec<String> {
FILE: zngur-cli/src/main.rs
type CfgKey (line 11) | struct CfgKey {
method into_tuple (line 17) | fn into_tuple(self) -> (String, Vec<String>) {
method from (line 23) | fn from(s: &'a str) -> Self {
type Command (line 45) | enum Command {
function main (line 150) | fn main() {
FILE: zngur-def/src/lib.rs
type Mutability (line 10) | pub enum Mutability {
type ZngurMethodReceiver (line 16) | pub enum ZngurMethodReceiver {
type ZngurMethod (line 23) | pub struct ZngurMethod {
type ZngurFn (line 32) | pub struct ZngurFn {
type ZngurExternCppFn (line 39) | pub struct ZngurExternCppFn {
type ZngurExternCppImpl (line 46) | pub struct ZngurExternCppImpl {
type ZngurConstructor (line 53) | pub struct ZngurConstructor {
type ZngurField (line 59) | pub struct ZngurField {
type ZngurFieldData (line 66) | pub struct ZngurFieldData {
type ZngurFieldDataOffset (line 73) | pub enum ZngurFieldDataOffset {
method is_offset (line 79) | pub fn is_offset(&self) -> bool {
method as_offset (line 83) | pub fn as_offset(&self) -> Option<usize> {
method as_auto (line 90) | pub fn as_auto(&self) -> Option<&str> {
type ZngurWellknownTrait (line 99) | pub enum ZngurWellknownTrait {
type ZngurWellknownTraitData (line 107) | pub enum ZngurWellknownTraitData {
type LayoutPolicy (line 120) | pub enum LayoutPolicy {
constant ZERO_SIZED_TYPE (line 128) | pub const ZERO_SIZED_TYPE: Self = LayoutPolicy::StackAllocated { size:...
type ZngurMethodDetails (line 132) | pub struct ZngurMethodDetails {
type CppValue (line 139) | pub struct CppValue(pub String, pub String);
type CppRef (line 142) | pub struct CppRef(pub String);
method fmt (line 145) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type ZngurType (line 151) | pub struct ZngurType {
type ZngurTrait (line 163) | pub struct ZngurTrait {
type AdditionalIncludes (line 169) | pub struct AdditionalIncludes(pub String);
type ConvertPanicToException (line 172) | pub struct ConvertPanicToException(pub bool);
type Import (line 175) | pub struct Import(pub std::path::PathBuf);
type ModuleImport (line 178) | pub struct ModuleImport {
type ZngurSpec (line 183) | pub struct ZngurSpec {
type RustTrait (line 200) | pub enum RustTrait {
method take_assocs (line 210) | pub fn take_assocs(mut self) -> (Self, Vec<(String, RustType)>) {
type PrimitiveRustType (line 220) | pub enum PrimitiveRustType {
type RustPathAndGenerics (line 232) | pub struct RustPathAndGenerics {
type RustType (line 239) | pub enum RustType {
constant UNIT (line 252) | pub const UNIT: Self = RustType::Tuple(Vec::new());
method fmt (line 256) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 284) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 303) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: zngur-def/src/merge.rs
type Merge (line 22) | pub trait Merge<T = Self> {
method merge (line 28) | fn merge(self, into: &mut T) -> MergeResult;
method merge (line 77) | fn merge(self, into: &mut Self) -> MergeResult {
method merge (line 126) | fn merge(self, into: &mut Self) -> MergeResult {
method merge (line 167) | fn merge(self, into: &mut Self) -> MergeResult {
method merge (line 186) | fn merge(self, into: &mut Self) -> MergeResult {
method merge (line 199) | fn merge(self, into: &mut Self) -> MergeResult {
method merge (line 220) | fn merge(self, into: &mut Self) -> MergeResult {
method merge (line 229) | fn merge(self, into: &mut Self) -> MergeResult {
method merge (line 238) | fn merge(self, into: &mut Self) -> MergeResult {
type MergeResult (line 32) | pub type MergeResult = Result<(), MergeFailure>;
type MergeFailure (line 35) | pub enum MergeFailure {
function push_unique (line 41) | fn push_unique<T: Eq>(item: T, smallvec: &mut std::vec::Vec<T>) {
function inplace_union (line 48) | fn inplace_union<T: Eq>(other: Vec<T>, smallvec: &mut std::vec::Vec<T>) {
function merge_by_identity (line 57) | fn merge_by_identity<T: Merge>(
method merge (line 104) | fn merge(self, into: &mut indexmap::IndexMap<K, V>) -> MergeResult {
method merge (line 209) | fn merge(self, into: &mut ZngurSpec) -> MergeResult {
method merge (line 248) | fn merge(self, into: &mut ZngurSpec) -> MergeResult {
method merge (line 255) | fn merge(self, into: &mut ZngurSpec) -> MergeResult {
method merge (line 263) | fn merge(self, into: &mut ZngurSpec) -> MergeResult {
method merge (line 271) | fn merge(self, into: &mut ZngurSpec) -> MergeResult {
method merge (line 279) | fn merge(self, into: &mut ZngurSpec) -> MergeResult {
method merge (line 287) | fn merge(self, into: &mut ZngurSpec) -> MergeResult {
FILE: zngur-generator/src/cpp.rs
type CppPath (line 17) | pub struct CppPath(pub Vec<String>);
method namespace (line 20) | fn namespace(&self) -> &[String] {
method open_namespace (line 24) | pub(crate) fn open_namespace(&self) -> String {
method close_namespace (line 32) | pub(crate) fn close_namespace(&self) -> String {
method name (line 40) | pub(crate) fn name(&self) -> &str {
method need_header (line 48) | fn need_header(&self) -> bool {
method from_rust_path (line 60) | pub(crate) fn from_rust_path(path: &[String], ns: &str, crate_name: &s...
method from (line 75) | fn from(value: [&str; N]) -> Self {
method from (line 81) | fn from(value: &str) -> Self {
method fmt (line 88) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type CppType (line 94) | pub struct CppType {
method into_ref (line 100) | pub fn into_ref(self) -> CppType {
method top_level_ns (line 107) | fn top_level_ns(&self) -> &String {
method specialization_decl (line 111) | pub(crate) fn specialization_decl(&self) -> String {
method header_helper (line 125) | fn header_helper(&self, state: &mut impl Write) -> std::fmt::Result {
method header (line 152) | pub(crate) fn header(&self) -> String {
method from (line 204) | fn from(value: &str) -> Self {
method fmt (line 162) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
function split_string (line 171) | fn split_string(input: &str) -> impl Iterator<Item = String> {
type State (line 223) | pub(crate) struct State {
method remove_no_except_in_panic (line 229) | fn remove_no_except_in_panic(&mut self) {
method write_str (line 237) | fn write_str(&mut self, s: &str) -> std::fmt::Result {
type CppTraitMethod (line 244) | pub struct CppTraitMethod {
method render_inputs (line 252) | pub fn render_inputs(&self, namespace: &str) -> String {
type CppFnSig (line 267) | pub struct CppFnSig {
method render_inputs (line 274) | pub fn render_inputs(&self, namespace: &str) -> String {
type CppFnDefinition (line 288) | pub struct CppFnDefinition {
type CppExportedFnDefinition (line 293) | pub struct CppExportedFnDefinition {
type CppExportedImplDefinition (line 298) | pub struct CppExportedImplDefinition {
method render_tr (line 305) | pub fn render_tr(&self, namespace: &str) -> String {
type CppMethod (line 314) | pub struct CppMethod {
method is_valid_field_method (line 321) | pub fn is_valid_field_method(&self, field_kind: &str) -> bool {
method is_ref_not_mut (line 329) | pub fn is_ref_not_mut(&self) -> bool {
method fn_name (line 336) | pub fn fn_name(&self, type_name: &str) -> String {
method render_sig_inputs_skip_one (line 340) | pub fn render_sig_inputs_skip_one(&self) -> String {
type CppTraitDefinition (line 353) | pub enum CppTraitDefinition {
method is_normal (line 366) | pub fn is_normal(&self) -> bool {
method as_normal (line 370) | pub fn as_normal(&self) -> Option<(&CppType, &[CppTraitMethod], &str, ...
method as_fn (line 384) | pub fn as_fn(&self) -> Option<&CppFnSig> {
type CppLayoutPolicy (line 394) | pub enum CppLayoutPolicy {
method is_only_by_ref (line 408) | pub fn is_only_by_ref(&self) -> bool {
method is_stack_allocated (line 412) | pub fn is_stack_allocated(&self) -> bool {
method stack_size (line 416) | pub fn stack_size(&self) -> usize {
method stack_align (line 424) | pub fn stack_align(&self) -> usize {
method alloc_heap (line 432) | pub fn alloc_heap(&self) -> String {
method free_heap (line 440) | pub fn free_heap(&self) -> String {
method copy_data (line 448) | pub fn copy_data(&self) -> String {
method size_fn (line 459) | pub fn size_fn(&self) -> String {
method alloc_fn (line 467) | pub fn alloc_fn(&self) -> String {
method free_fn (line 475) | pub fn free_fn(&self) -> String {
type CppTypeDefinition (line 485) | pub struct CppTypeDefinition {
method has_unsized (line 499) | pub fn has_unsized(&self) -> bool {
method has_copy (line 505) | pub fn has_copy(&self) -> bool {
method drop_in_place (line 511) | pub fn drop_in_place(&self) -> String {
method render_make_box (line 524) | pub fn render_make_box(&self, name: &str, namespace: &str, crate_name:...
method render_make_box_ref (line 549) | pub fn render_make_box_ref(&self, name: &str, namespace: &str, crate_n...
method render_make_box_ref_only (line 574) | pub fn render_make_box_ref_only(
method default (line 603) | fn default() -> Self {
type CppFile (line 620) | pub struct CppFile {
method emit_h_file (line 634) | fn emit_h_file(
method emit_cpp_file (line 657) | fn emit_cpp_file(
method render (line 679) | pub fn render(self, namespace: &str, crate_name: &str) -> (String, Opt...
function cpp_handle_keyword (line 699) | pub fn cpp_handle_keyword(name: &str) -> &str {
function cpp_handle_field_name (line 707) | pub fn cpp_handle_field_name(name: &str) -> String {
type CountCharMatchesExt (line 714) | trait CountCharMatchesExt {
method count_start_matches (line 715) | fn count_start_matches(&self, pred: impl Fn(char) -> bool) -> usize;
method count_matches (line 716) | fn count_matches(&self, pred: impl Fn(char) -> bool) -> usize;
method count_start_matches (line 720) | fn count_start_matches(&self, pred: impl Fn(char) -> bool) -> usize {
method count_matches (line 731) | fn count_matches(&self, pred: impl Fn(char) -> bool) -> usize {
function normalize_whitespace (line 746) | pub fn normalize_whitespace(cpp: &str) -> String {
FILE: zngur-generator/src/lib.rs
type ZngurGenerator (line 28) | pub struct ZngurGenerator(pub ZngurSpec, pub String);
method build_from_zng (line 31) | pub fn build_from_zng(zng: ZngurSpec, crate_name: String) -> Self {
method render (line 35) | pub fn render(self, zng_header_in_place: bool) -> (String, String, Opt...
type ZngHeaderGenerator (line 332) | pub struct ZngHeaderGenerator {
method render (line 339) | pub fn render(&self) -> String {
function real_inputs_of_method (line 348) | fn real_inputs_of_method(method: &ZngurMethod, ty: &RustType) -> Vec<Rus...
FILE: zngur-generator/src/rust.rs
type IntoCpp (line 13) | pub trait IntoCpp {
method into_cpp (line 14) | fn into_cpp(&self, namespace: &str, crate_name: &str) -> CppType;
method into_cpp (line 18) | fn into_cpp(&self, namespace: &str, crate_name: &str) -> CppType {
method into_cpp (line 37) | fn into_cpp(&self, namespace: &str, crate_name: &str) -> CppType {
method into_cpp (line 57) | fn into_cpp(&self, namespace: &str, crate_name: &str) -> CppType {
type RustFile (line 153) | pub struct RustFile {
method new (line 160) | pub fn new(mangling_base: &str) -> Self {
method mangle_name (line 469) | fn mangle_name(&self, name: &str) -> String {
method call_cpp_function (line 473) | fn call_cpp_function(&mut self, name: &str, inputs: usize) {
method add_static_is_copy_assert (line 486) | pub fn add_static_is_copy_assert(&mut self, ty: &RustType) {
method add_static_size_assert (line 490) | pub fn add_static_size_assert(&mut self, ty: &RustType, size: usize) {
method add_static_align_assert (line 494) | pub fn add_static_align_assert(&mut self, ty: &RustType, align: usize) {
method add_static_size_upper_bound_assert (line 498) | pub fn add_static_size_upper_bound_assert(&mut self, ty: &RustType, si...
method add_static_align_upper_bound_assert (line 502) | pub fn add_static_align_upper_bound_assert(&mut self, ty: &RustType, a...
method add_builder_for_dyn_trait (line 509) | pub(crate) fn add_builder_for_dyn_trait(
method add_builder_for_dyn_trait_owned (line 564) | fn add_builder_for_dyn_trait_owned(
method add_builder_for_dyn_trait_borrowed (line 625) | fn add_builder_for_dyn_trait_borrowed(
method add_builder_for_dyn_fn (line 684) | pub fn add_builder_for_dyn_fn(
method add_tuple_constructor (line 730) | pub fn add_tuple_constructor(&mut self, fields: &[RustType]) -> String {
method add_constructor (line 754) | pub fn add_constructor(
method add_field_assertions (line 795) | pub(crate) fn add_field_assertions(
method add_extern_cpp_impl (line 822) | pub fn add_extern_cpp_impl(
method add_extern_cpp_function (line 889) | pub fn add_extern_cpp_function(
method add_cpp_value_bridge (line 919) | pub fn add_cpp_value_bridge(&mut self, ty: &RustType, field: &str) -> ...
method add_function (line 933) | pub fn add_function(
method add_wellknown_trait (line 1006) | pub(crate) fn add_wellknown_trait(
method wrap_in_catch_unwind (line 1062) | fn wrap_in_catch_unwind(&mut self, f: impl FnOnce(&mut RustFile)) {
method add_layout_policy_shim (line 1079) | pub(crate) fn add_layout_policy_shim(
method write_str (line 404) | fn write_str(&mut self, s: &str) -> std::fmt::Result {
function hash_of_sig (line 421) | pub fn hash_of_sig(sig: &[RustType]) -> String {
function mangle_name (line 431) | fn mangle_name(name: &str, mangling_base: &str) -> String {
type ConstructorMangledNames (line 463) | pub struct ConstructorMangledNames {
FILE: zngur-generator/src/template.rs
type CppHeaderTemplate (line 48) | pub(crate) struct CppHeaderTemplate<'a> {
function cpp_handle_field_name (line 63) | pub fn cpp_handle_field_name(&self, name: &str) -> String {
type ZngHeaderTemplate (line 70) | pub(crate) struct ZngHeaderTemplate {
method is_ref_kind_ref (line 507) | pub fn is_ref_kind_ref(&self, ref_kind: &str) -> bool {
method is_size_t (line 510) | pub fn is_size_t(&self, ty: &str) -> bool {
method is_printable (line 514) | pub fn is_printable(&self, ty: &str) -> bool {
method builtin_types (line 522) | fn builtin_types(&self) -> Vec<String> {
function panic_handler (line 76) | fn panic_handler(&self) -> String {
function render_type_methods (line 90) | pub fn render_type_methods(&self, td: &crate::cpp::CppTypeDefinition) ->...
function render_from_trait (line 263) | pub fn render_from_trait(&self, td: &crate::cpp::CppTypeDefinition) -> S...
function render_from_trait_ref (line 352) | pub fn render_from_trait_ref(&self, td: &crate::cpp::CppTypeDefinition) ...
function render_fn_deps (line 393) | pub fn render_fn_deps(&self) -> String {
function render_exported_impls (line 457) | pub fn render_exported_impls(&self) -> String {
function render_zng_header (line 497) | fn render_zng_header(&self) -> String {
type CppSourceTemplate (line 545) | pub(crate) struct CppSourceTemplate<'a> {
FILE: zngur-parser/src/cfg.rs
type RustCfgProvider (line 11) | pub trait RustCfgProvider: CloneableCfg {
method get_cfg (line 13) | fn get_cfg(&self, key: &str) -> Option<Vec<String>>;
method get_features (line 15) | fn get_features(&self) -> Vec<String>;
method get_cfg_pairs (line 20) | fn get_cfg_pairs(&self) -> Vec<(String, Option<String>)>;
method get_cfg (line 40) | fn get_cfg(&self, _key: &str) -> Option<Vec<String>> {
method get_features (line 43) | fn get_features(&self) -> Vec<String> {
method get_cfg_pairs (line 46) | fn get_cfg_pairs(&self) -> Vec<(String, Option<String>)> {
method get_cfg (line 128) | fn get_cfg(&self, key: &str) -> Option<Vec<String>> {
method get_features (line 131) | fn get_features(&self) -> Vec<String> {
method get_cfg_pairs (line 134) | fn get_cfg_pairs(&self) -> Vec<(String, Option<String>)> {
type CloneableCfg (line 23) | pub trait CloneableCfg {
method clone_box (line 24) | fn clone_box(&self) -> Box<dyn RustCfgProvider>;
method clone_box (line 31) | fn clone_box(&self) -> Box<dyn RustCfgProvider> {
type NullCfg (line 37) | pub struct NullCfg;
type InMemoryRustCfgProvider (line 52) | pub struct InMemoryRustCfgProvider {
method new (line 60) | pub fn new() -> Self {
method with_values (line 66) | pub fn with_values<'a, CfgPairs, CfgKey, CfgValues>(mut self, cfg_valu...
method load_from_cargo_env (line 86) | pub fn load_from_cargo_env(mut self) -> Self {
constant CARGO_FEATURE_PREFIX (line 56) | const CARGO_FEATURE_PREFIX: &str = "CARGO_FEATURE_";
constant CARGO_CFG_PREFIX (line 57) | const CARGO_CFG_PREFIX: &str = "CARGO_CFG_";
method default (line 122) | fn default() -> Self {
type CfgScrutinee (line 152) | pub(crate) enum CfgScrutinee<'src> {
type ProcessedCfgScrutinee (line 160) | pub(crate) enum ProcessedCfgScrutinee {
type ProcessedCfgConditional (line 166) | pub(crate) enum ProcessedCfgConditional {
type CfgConditional (line 173) | pub(crate) enum CfgConditional<'src> {
type CfgPatternItem (line 179) | pub(crate) enum CfgPatternItem<'src> {
type CfgPattern (line 188) | pub(crate) enum CfgPattern<'src> {
method default_some (line 198) | fn default_some(span: Span) -> Self {
function parser (line 203) | fn parser() -> impl ZngParser<'src, Self> {
type Pattern (line 263) | type Pattern = CfgPattern<'src>;
method eval (line 265) | fn eval(&self, pattern: &Self::Pattern, ctx: &mut ParseContext) -> bool {
function parser (line 312) | fn parser() -> impl ZngParser<'src, Self> {
function parser (line 333) | fn parser() -> impl ZngParser<'src, Self> {
function combined (line 350) | fn combined() -> Option<
function matches (line 396) | fn matches(&self, scrutinee: &ProcessedCfgConditional, ctx: &mut ParseCo...
function matches (line 461) | fn matches(&self, scrutinee: &ProcessedCfgScrutinee) -> bool {
FILE: zngur-parser/src/conditional.rs
type Matchable (line 5) | pub trait Matchable: core::fmt::Debug + Clone + PartialEq + Eq {
method eval (line 9) | fn eval(&self, pattern: &Self::Pattern, ctx: &mut ParseContext) -> bool;
type MatchableParse (line 13) | pub(crate) trait MatchableParse<'src>: Matchable {
method parser (line 15) | fn parser() -> impl ZngParser<'src, Self>;
method combined (line 19) | fn combined()
type MatchPattern (line 25) | pub trait MatchPattern: core::fmt::Debug + Clone + PartialEq + Eq {
method default_some (line 27) | fn default_some(span: crate::Span) -> Self;
type MatchPatternParse (line 31) | pub(crate) trait MatchPatternParse<'src>: MatchPattern {
method parser (line 33) | fn parser() -> impl ZngParser<'src, Self>;
type BodyItem (line 36) | pub trait BodyItem: core::fmt::Debug + Clone + PartialEq + Eq {
method process (line 41) | fn process(self, ctx: &mut ParseContext) -> Self::Processed;
type ConditionBody (line 45) | pub trait ConditionBody<Pattern: MatchPattern, Item: BodyItem>: core::fm...
method pattern (line 47) | fn pattern(&self) -> &Pattern;
type ConditionBodyCardinality (line 51) | pub trait ConditionBodyCardinality<Item: BodyItem>:
method single_to_block (line 61) | fn single_to_block(item: Spanned<Item>) -> Self::Block;
method empty_block (line 63) | fn empty_block() -> Self::Block;
method new_body (line 65) | fn new_body<Pattern: MatchPattern>(
method pass_block (line 70) | fn pass_block(block: &Self::Block, ctx: &mut ParseContext) -> Self::Ev...
method pass_body (line 72) | fn pass_body<Pattern: MatchPattern>(
type ConditionalItem (line 79) | pub trait ConditionalItem<Item: BodyItem, Cardinality: ConditionBodyCard...
method eval (line 81) | fn eval(&self, ctx: &mut ParseContext) -> Option<Cardinality::EvalResu...
type ConditionBodyMany (line 86) | pub struct ConditionBodyMany<Pattern: MatchPattern, Item: BodyItem> {
type ConditionBodySingle (line 93) | pub struct ConditionBodySingle<Pattern: MatchPattern, Item: BodyItem> {
function pattern (line 101) | fn pattern(&self) -> &Pattern {
function pattern (line 109) | fn pattern(&self) -> &Pattern {
type SingleItem (line 116) | pub struct SingleItem;
type Body (line 119) | type Body<Pattern: MatchPattern> = ConditionBodySingle<Pattern, Item>;
type Block (line 120) | type Block = Option<Spanned<Item>>;
type EvalResult (line 121) | type EvalResult = Option<Spanned<<Item as BodyItem>::Processed>>;
method single_to_block (line 123) | fn single_to_block(item: Spanned<Item>) -> Self::Block {
method empty_block (line 127) | fn empty_block() -> Self::Block {
method new_body (line 131) | fn new_body<Pattern: MatchPattern>(
method pass_block (line 138) | fn pass_block(block: &Self::Block, ctx: &mut ParseContext) -> Self::Ev...
method pass_body (line 148) | fn pass_body<Pattern: MatchPattern>(
type NItems (line 158) | pub struct NItems;
type Body (line 161) | type Body<Pattern: MatchPattern> = ConditionBodyMany<Pattern, Item>;
type Block (line 162) | type Block = Vec<Spanned<Item>>;
type EvalResult (line 163) | type EvalResult = Vec<Spanned<<Item as BodyItem>::Processed>>;
method single_to_block (line 165) | fn single_to_block(item: Spanned<Item>) -> Self::Block {
method empty_block (line 169) | fn empty_block() -> Self::Block {
method new_body (line 173) | fn new_body<Pattern: MatchPattern>(
method pass_block (line 180) | fn pass_block(block: &Self::Block, ctx: &mut ParseContext) -> Self::Ev...
method pass_body (line 194) | fn pass_body<Pattern: MatchPattern>(
type ConditionGuard (line 204) | pub enum ConditionGuard<Scrutinee: Matchable> {
function eval (line 217) | fn eval(&self, ctx: &mut ParseContext) -> bool {
type ConditionBranch (line 232) | pub struct ConditionBranch<
type ConditionIf (line 243) | pub struct ConditionIf<
type ConditionMatch (line 254) | pub struct ConditionMatch<
function eval (line 272) | fn eval(
function eval (line 289) | fn eval(
function eval (line 308) | fn eval(
type Condition (line 328) | pub enum Condition<
function eval (line 340) | fn eval(
type Conditional (line 352) | pub trait Conditional<'src, Item: BodyItem, Cardinality: ConditionBodyCa...
method if_parser (line 354) | fn if_parser(
method match_parser (line 357) | fn match_parser(
function block_for_single (line 363) | pub fn block_for_single<'src, Item: BodyItem>(
function block_for_many (line 377) | pub fn block_for_many<'src, Item: BodyItem>(
function guarded_block (line 384) | pub fn guarded_block<
function if_stmnt (line 466) | pub fn if_stmnt<
function match_arm (line 503) | fn match_arm<
function match_stmt (line 534) | fn match_stmt<
function conditional_item (line 560) | pub fn conditional_item<
type Scrutinee (line 593) | type Scrutinee = Scrutinee;
method if_parser (line 594) | fn if_parser(
method match_parser (line 605) | fn match_parser(
type Scrutinee (line 620) | type Scrutinee = Scrutinee;
method if_parser (line 621) | fn if_parser(
method match_parser (line 632) | fn match_parser(
FILE: zngur-parser/src/lib.rs
type Span (line 18) | pub type Span = SimpleSpan<usize>;
type ParseResult (line 22) | pub struct ParseResult {
type Spanned (line 41) | pub struct Spanned<T> {
type ParserInput (line 46) | type ParserInput<'a> = chumsky::input::MappedInput<
type UnstableFeatures (line 58) | pub struct UnstableFeatures {
type ZngParserState (line 64) | pub struct ZngParserState {
type ZngParserExtra (line 68) | type ZngParserExtra<'a> =
type BoxedZngParser (line 71) | type BoxedZngParser<'a, Item> = chumsky::Boxed<'a, 'a, ParserInput<'a>, ...
type ZngParser (line 74) | pub(crate) trait ZngParser<'a, Item>:
type ParsedZngFile (line 84) | pub struct ParsedZngFile<'a>(Vec<ParsedItem<'a>>);
type ProcessedZngFile (line 87) | pub struct ProcessedZngFile<'a> {
type ParsedPathStart (line 93) | enum ParsedPathStart {
type ParsedPath (line 100) | struct ParsedPath<'a> {
type Scope (line 107) | struct Scope<'a> {
function new_root (line 114) | fn new_root(aliases: Vec<ParsedAlias<'a>>) -> Scope<'a> {
function resolve_path (line 122) | fn resolve_path(&self, path: ParsedPath<'a>) -> Vec<String> {
function simple_relative_path (line 136) | fn simple_relative_path(&self, relative_item_name: &str) -> Vec<String> {
function sub_scope (line 144) | fn sub_scope(&self, new_aliases: &[ParsedAlias<'a>], nested_path: Parsed...
function to_zngur (line 157) | fn to_zngur(self, base: &[String]) -> Vec<String> {
function matches_alias (line 174) | fn matches_alias(&self, alias: &ParsedAlias<'_>) -> bool {
type ParsedAlias (line 186) | pub struct ParsedAlias<'a> {
function expand (line 193) | fn expand(&self, path: &ParsedPath<'_>, base: &[String]) -> Option<Vec<S...
type ParsedImportPath (line 228) | struct ParsedImportPath {
type ParsedItem (line 234) | enum ParsedItem<'a> {
type ProcessedItem (line 262) | enum ProcessedItem<'a> {
type ParsedExternCppItem (line 288) | enum ParsedExternCppItem<'a> {
type ParsedConstructorArgs (line 298) | enum ParsedConstructorArgs<'a> {
type ParsedLayoutPolicy (line 305) | enum ParsedLayoutPolicy<'a> {
type ParsedTypeItem (line 313) | enum ParsedTypeItem<'a> {
type ParsedMethod (line 341) | struct ParsedMethod<'a> {
function to_zngur (line 350) | fn to_zngur(self, scope: &Scope<'_>) -> ZngurMethod {
function checked_merge (line 365) | fn checked_merge<T, U>(src: T, dst: &mut U, span: Span, ctx: &mut ParseC...
function add_to_zngur_spec (line 380) | fn add_to_zngur_spec(self, r: &mut ZngurSpec, scope: &Scope<'_>, ctx: &m...
type ParsedRustType (line 717) | enum ParsedRustType<'a> {
function to_zngur (line 730) | fn to_zngur(self, scope: &Scope<'_>) -> RustType {
type ParsedRustTrait (line 754) | enum ParsedRustTrait<'a> {
function to_zngur (line 764) | fn to_zngur(self, scope: &Scope<'_>) -> RustTrait {
type ParsedRustPathAndGenerics (line 781) | struct ParsedRustPathAndGenerics<'a> {
function to_zngur (line 788) | fn to_zngur(self, scope: &Scope<'_>) -> RustPathAndGenerics {
type ParseContext (line 805) | struct ParseContext<'a, 'b> {
function new (line 817) | fn new(path: std::path::PathBuf, text: &'a str, cfg: Box<dyn RustCfgProv...
function with_depth (line 830) | fn with_depth(
function filename (line 848) | fn filename(&self) -> &str {
function add_report (line 852) | fn add_report(&mut self, report: Report<'b, (String, std::ops::Range<usi...
function add_errors (line 855) | fn add_errors<'err_src>(&mut self, errs: impl Iterator<Item = Rich<'err_...
function add_error_str (line 874) | fn add_error_str(&mut self, error: &str, span: Span) {
function consume_from (line 878) | fn consume_from(&mut self, mut other: ParseContext<'_, 'b>) {
function has_errors (line 888) | fn has_errors(&self) -> bool {
function emit_ariadne_errors (line 893) | fn emit_ariadne_errors(&self) -> ! {
function emit_ariadne_errors (line 923) | fn emit_ariadne_errors(&self) -> ! {
function get_config_provider (line 946) | fn get_config_provider(&self) -> &dyn RustCfgProvider {
type ImportResolver (line 952) | pub trait ImportResolver {
method resolve_import (line 953) | fn resolve_import(
method resolve_import (line 964) | fn resolve_import(
type DefaultImportResolver (line 961) | struct DefaultImportResolver;
function parse_into (line 978) | fn parse_into(zngur: &mut ZngurSpec, ctx: &mut ParseContext, resolver: &...
function parse (line 1037) | pub fn parse(path: std::path::PathBuf, cfg: Box<dyn RustCfgProvider>) ->...
function parse_str (line 1072) | pub fn parse_str(text: &str, cfg: impl RustCfgProvider + 'static) -> Par...
function parse_str_with_resolver (line 1086) | pub(crate) fn parse_str_with_resolver(
type ProcessedItemOrAlias (line 1104) | pub(crate) enum ProcessedItemOrAlias<'a> {
function process_parsed_item (line 1111) | fn process_parsed_item<'a>(
function partition_parsed_items (line 1157) | fn partition_parsed_items<'a>(
function new (line 1178) | fn new(aliases: Vec<ParsedAlias<'a>>, items: Vec<ProcessedItem<'a>>) -> ...
function into_zngur_spec (line 1182) | fn into_zngur_spec(self, zngur: &mut ZngurSpec, ctx: &mut ParseContext) {
type Token (line 1192) | enum Token<'a> {
function ident_or_kw (line 1242) | fn ident_or_kw(ident: &'a str) -> Self {
method fmt (line 1269) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
function lexer (line 1321) | fn lexer<'src>()
function alias (line 1369) | fn alias<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngPa...
function file_parser (line 1387) | fn file_parser<'a>()
function rust_type (line 1392) | fn rust_type<'a>() -> Boxed<'a, 'a, ParserInput<'a>, ParsedRustType<'a>,...
function rust_generics (line 1473) | fn rust_generics<'a>(
function rust_path_and_generics (line 1497) | fn rust_path_and_generics<'a>(
function fn_args (line 1514) | fn fn_args<'a>(
function spanned (line 1532) | fn spanned<'a, T>(
function rust_trait (line 1541) | fn rust_trait<'a>(
function method (line 1558) | fn method<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedMethod<'a>, Zn...
function inner_type_item (line 1615) | fn inner_type_item<'a>()
function type_item (line 1762) | fn type_item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, Z...
function trait_item (line 1775) | fn trait_item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ...
function fn_item (line 1790) | fn fn_item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, Zng...
function additional_include_item (line 1796) | fn additional_include_item<'a>()
function extern_cpp_item (line 1809) | fn extern_cpp_item<'a>()
function unstable_feature (line 1844) | fn unstable_feature<'a>()
function item (line 1868) | fn item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngPar...
function import_item (line 1895) | fn import_item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>,...
function module_import_item (line 1911) | fn module_import_item<'a>()
function path (line 1923) | fn path<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedPath<'a>, ZngPar...
type Processed (line 1951) | type Processed = Self;
function process (line 1953) | fn process(self, _ctx: &mut ParseContext) -> Self::Processed {
type Processed (line 1959) | type Processed = ProcessedItemOrAlias<'a>;
function process (line 1961) | fn process(self, ctx: &mut ParseContext) -> Self::Processed {
FILE: zngur-parser/src/tests.rs
function check_success (line 11) | fn check_success(zng: &str) {
type ErrorText (line 15) | pub struct ErrorText(pub String);
function check_fail (line 17) | fn check_fail(zng: &str, error: Expect) {
function check_fail_with_cfg (line 30) | fn check_fail_with_cfg(
function check_import_fail (line 47) | fn check_import_fail(zng: &str, error: Expect, resolver: &MockFilesystem) {
function catch_parse_fail (line 62) | fn catch_parse_fail(
function parse_unit (line 84) | fn parse_unit() {
function parse_tuple (line 105) | fn parse_tuple() {
function typo_in_wellknown_trait (line 116) | fn typo_in_wellknown_trait() {
function multiple_layout_policies (line 137) | fn multiple_layout_policies() {
function cpp_ref_should_not_need_layout_info (line 158) | fn cpp_ref_should_not_need_layout_info() {
function alias_expands_correctly (line 196) | fn alias_expands_correctly() {
function alias_expands_nearest_scope_first (line 214) | fn alias_expands_nearest_scope_first() {
type MockFilesystem (line 234) | struct MockFilesystem {
method new (line 239) | fn new(
method resolve_import (line 252) | fn resolve_import(
function import_parser_test (line 266) | fn import_parser_test() {
function module_import_prohibited (line 286) | fn module_import_prohibited() {
function import_has_conflict (line 307) | fn import_has_conflict() {
function import_not_found (line 339) | fn import_not_found() {
function import_has_mismatched_method_signature (line 353) | fn import_has_mismatched_method_signature() {
function import_has_mismatched_field (line 381) | fn import_has_mismatched_field() {
function convert_panic_to_exception_in_imported_file_fails (line 412) | fn convert_panic_to_exception_in_imported_file_fails() {
function convert_panic_to_exception_in_main_file_succeeds (line 444) | fn convert_panic_to_exception_in_main_file_succeeds() {
function processed_files_single_file (line 458) | fn processed_files_single_file() {
function processed_files_with_import (line 480) | fn processed_files_with_import() {
function processed_files_with_nested_imports (line 508) | fn processed_files_with_nested_imports() {
function assert_layout (line 544) | fn assert_layout(wanted_size: usize, wanted_align: usize, layout: &Layou...
function test_if_conditional_type_item (line 557) | fn test_if_conditional_type_item() {
function test_match_conditional_type_item (line 591) | fn test_match_conditional_type_item() {
type CfgPathPairs (line 645) | type CfgPathPairs<'a> = &'a [(&'a [(&'a str, &'a [&'a str])], &'a [&'a s...
function conditional_if_spec_item (line 648) | fn conditional_if_spec_item() {
function conditional_match_spec_item (line 671) | fn conditional_match_spec_item() {
function match_pattern_single_cfg (line 694) | fn match_pattern_single_cfg() {
function if_pattern_multi_cfg (line 728) | fn if_pattern_multi_cfg() {
function match_pattern_multi_cfg (line 774) | fn match_pattern_multi_cfg() {
function match_pattern_multi_cfg_bad_pattern (line 809) | fn match_pattern_multi_cfg_bad_pattern() {
function match_pattern_multi_cfg_bad_pattern2 (line 845) | fn match_pattern_multi_cfg_bad_pattern2() {
function cfg_match_unstable (line 885) | fn cfg_match_unstable() {
function module_import_parser_test (line 916) | fn module_import_parser_test() {
FILE: zngur/src/lib.rs
type Zngur (line 29) | pub struct Zngur {
method from_zng_file (line 44) | pub fn from_zng_file(zng_file_path: impl AsRef<Path>) -> Self {
method with_zng_header (line 60) | pub fn with_zng_header(mut self, zng_header: impl AsRef<Path>) -> Self {
method with_h_file (line 65) | pub fn with_h_file(mut self, path: impl AsRef<Path>) -> Self {
method with_cpp_file (line 70) | pub fn with_cpp_file(mut self, path: impl AsRef<Path>) -> Self {
method with_rs_file (line 75) | pub fn with_rs_file(mut self, path: impl AsRef<Path>) -> Self {
method with_depfile (line 84) | pub fn with_depfile(mut self, path: impl AsRef<Path>) -> Self {
method with_mangling_base (line 89) | pub fn with_mangling_base(mut self, mangling_base: &str) -> Self {
method with_cpp_namespace (line 94) | pub fn with_cpp_namespace(mut self, cpp_namespace: &str) -> Self {
method with_crate_name (line 99) | pub fn with_crate_name(mut self, crate_name: &str) -> Self {
method with_rust_cargo_cfg (line 104) | pub fn with_rust_cargo_cfg(mut self) -> Self {
method with_zng_header_in_place_as (line 111) | pub fn with_zng_header_in_place_as(mut self, value: bool) -> Self {
method with_zng_header_in_place (line 116) | pub fn with_zng_header_in_place(self) -> Self {
method with_rust_in_memory_cfg (line 120) | pub fn with_rust_in_memory_cfg<'a, CfgPairs, CfgKey, CfgValues>(
method generate (line 136) | pub fn generate(self) {
type ZngurHdr (line 225) | pub struct ZngurHdr {
method new (line 232) | pub const fn new() -> Self {
method with_panic_to_exception (line 240) | pub fn with_panic_to_exception(self) -> Self {
method without_panic_to_exception (line 244) | pub fn without_panic_to_exception(self) -> Self {
method with_panic_to_exception_as (line 248) | pub fn with_panic_to_exception_as(mut self, panic_to_exception: bool) ...
method with_zng_header (line 253) | pub fn with_zng_header(mut self, zng_header: impl Into<PathBuf>) -> Se...
method with_cpp_namespace (line 258) | pub fn with_cpp_namespace(mut self, cpp_namespace: &str) -> Self {
method generate (line 263) | pub fn generate(self) {
Condensed preview — 213 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (555K chars).
[
{
"path": ".cargo/config.toml",
"chars": 41,
"preview": "[alias]\nxtask = \"run --package xtask --\"\n"
},
{
"path": ".github/workflows/ci.yml",
"chars": 2494,
"preview": "name: CI\n\non:\n push:\n branches: [\"main\"]\n pull_request:\n branches: [\"main\"]\n\nenv:\n CARGO_TERM_COLOR: always\n\njo"
},
{
"path": ".github/workflows/publish.yml",
"chars": 1741,
"preview": "name: Publish\non:\n workflow_dispatch:\njobs:\n publish:\n name: Publish\n runs-on: ubuntu-latest\n\n steps:\n -"
},
{
"path": ".github/workflows/site.yml",
"chars": 612,
"preview": "name: Deploy\n\non:\n push:\n branches:\n - main\n paths:\n - book/**\n - .github/workflows/site.yml\n wor"
},
{
"path": ".gitignore",
"chars": 174,
"preview": "/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.d"
},
{
"path": "Cargo.toml",
"chars": 488,
"preview": "[workspace]\nmembers = [\n \"zngur\",\n \"zngur-cli\",\n \"zngur-def\",\n \"zngur-generator\",\n \"zngur-parser\",\n \"z"
},
{
"path": "LICENSE-APACHE",
"chars": 9639,
"preview": " Apache License\n Version 2.0, January 2004\n http"
},
{
"path": "LICENSE-MIT",
"chars": 1023,
"preview": "Permission is hereby granted, free of charge, to any\nperson obtaining a copy of this software and associated\ndocumentati"
},
{
"path": "README.md",
"chars": 5557,
"preview": "# Zngur\n\n[<img alt=\"github\" src=\"https://img.shields.io/badge/github-hkalbasi/zngur-8da0cb?style=for-the-badge&labelColo"
},
{
"path": "benchmark/.gitignore",
"chars": 8,
"preview": "/target\n"
},
{
"path": "benchmark/Cargo.toml",
"chars": 365,
"preview": "[package]\nname = \"benchmark\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace "
},
{
"path": "benchmark/benches/simple.rs",
"chars": 487,
"preview": "use criterion::{Criterion, criterion_group, criterion_main};\nuse std::hint::black_box;\n\nfn criterion_benchmark(c: &mut C"
},
{
"path": "benchmark/build.rs",
"chars": 1397,
"preview": "use zngur::Zngur;\n\nfn main() {\n build::rerun_if_changed(\"main.zng\");\n build::rerun_if_changed(\"impls.cpp\");\n\n #"
},
{
"path": "benchmark/impls.cpp",
"chars": 325,
"preview": "#include <generated.h>\n\ntemplate <typename T>\nusing Vec = rust::std::vec::Vec<T>;\nusing u64 = uint64_t;\n\nnamespace rust:"
},
{
"path": "benchmark/main.zng",
"chars": 239,
"preview": "type ::std::vec::Vec<u64> {\n #layout(size = 24, align = 8);\n wellknown_traits(Debug);\n\n fn new() -> ::std::vec:"
},
{
"path": "benchmark/src/lib.rs",
"chars": 303,
"preview": "mod generated {\n include!(concat!(env!(\"OUT_DIR\"), \"/generated.rs\"));\n}\n\npub fn build_vec_by_push_rust(n: u64) -> Vec"
},
{
"path": "cspell-words.txt",
"chars": 817,
"preview": "alignas\nalignof\nassocs\nautozng\nbarbaz\nbarbazxxx\nblobstore\ncerr\nchumsky\ncloneable\nConds\nconstexpr\ncout\ncplusplus\nCPTE\nCru"
},
{
"path": "cspell.json",
"chars": 575,
"preview": "{\n \"$schema\": \"https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json\",\n \"version\": \""
},
{
"path": "dprint.json",
"chars": 477,
"preview": "{\n \"markdown\": {\n \"lineWidth\": 100,\n \"emphasisKind\": \"asterisks\",\n \"strongKind\": \"asterisks\",\n \"textWrap\": "
},
{
"path": "examples/.gitignore",
"chars": 16,
"preview": "zngur.h\n*.zng.*\n"
},
{
"path": "examples/char/.gitignore",
"chars": 24,
"preview": "generated.h\ngenerated.rs"
},
{
"path": "examples/char/Cargo.toml",
"chars": 294,
"preview": "[package]\nname = \"example-char\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspa"
},
{
"path": "examples/char/Makefile",
"chars": 518,
"preview": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_char.a\n\t${CXX} -std=c++11 -Werro"
},
{
"path": "examples/char/NMakefile",
"chars": 718,
"preview": "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"
},
{
"path": "examples/char/expected_output.txt",
"chars": 132,
"preview": "Rust received char: 'A' (U+0041)\nRust received char: 'é' (U+00E9)\nRust received char: 'Z' (U+005A)\nRust received char: '"
},
{
"path": "examples/char/main.cpp",
"chars": 669,
"preview": "#include \"./generated.h\"\n\nusing ::operator\"\"_rs;\n\nint main() {\n // Pass a char literal directly using the _rs suffix\n"
},
{
"path": "examples/char/main.zng",
"chars": 292,
"preview": "type char {\n #layout(size = 4, align = 4);\n wellknown_traits(Copy);\n}\n\ntype bool {\n #layout(size = 1, align = 1);\n w"
},
{
"path": "examples/char/src/lib.rs",
"chars": 339,
"preview": "#[rustfmt::skip]\nmod generated;\n\nstruct CharPrinter;\n\nimpl CharPrinter {\n fn print(c: char) {\n println!(\"Rust "
},
{
"path": "examples/conditional/.gitignore",
"chars": 77,
"preview": "generated.h\r\ngenerated.rs\r\ngenerated*.rs\r\ngenerated.cpp\r\nhistory.txt\r\nb.out\r\n"
},
{
"path": "examples/conditional/Cargo.toml",
"chars": 361,
"preview": "[package]\r\nname = \"example-conditional\"\r\nversion = \"0.9.0\"\r\nedition.workspace = true\r\nrust-version.workspace = true\r\nlic"
},
{
"path": "examples/conditional/Makefile",
"chars": 1669,
"preview": "both:: a.out b.out\r\n\r\na.out: main.cpp include/float/generated.h src/lib.rs ../../target/release/libexample_conditional.a"
},
{
"path": "examples/conditional/NMakefile",
"chars": 1962,
"preview": "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 = cond"
},
{
"path": "examples/conditional/README.md",
"chars": 123,
"preview": "# Example: Conditional\n\nA example, used to demonstrate conditional compilation\n\nTo run this example:\n\n```\nmake\n./a.out\n`"
},
{
"path": "examples/conditional/expected_output.txt",
"chars": 952,
"preview": "KVPair(size = 32, align = 8){foo : 1.000000}\n[main.cpp:44] pair = KeyValuePair[f64] { key: \"foo\", value: 1.0, }\nKVPair(s"
},
{
"path": "examples/conditional/main.cpp",
"chars": 1436,
"preview": "\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"
},
{
"path": "examples/conditional/main.zng",
"chars": 2887,
"preview": "#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(&sel"
},
{
"path": "examples/conditional/src/lib.rs",
"chars": 1827,
"preview": "/// 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\nmo"
},
{
"path": "examples/cxx_demo/.gitignore",
"chars": 51,
"preview": "generated.h\ngenerated.rs\ngenerated.cpp\nhistory.txt\n"
},
{
"path": "examples/cxx_demo/Cargo.toml",
"chars": 349,
"preview": "[package]\nname = \"example-cxx_demo\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.wor"
},
{
"path": "examples/cxx_demo/README.md",
"chars": 436,
"preview": "# Example: CXX demo\n\nThis example tries to replicate [the CXX demo](https://github.com/dtolnay/cxx/tree/master/demo) usi"
},
{
"path": "examples/cxx_demo/blobstore.cpp",
"chars": 1958,
"preview": "#include <algorithm>\n#include <cstdint>\n#include <set>\n#include <unordered_map>\n\n#include \"./generated.h\"\n\nclass BlobSto"
},
{
"path": "examples/cxx_demo/build.rs",
"chars": 1039,
"preview": "#[cfg(not(target_os = \"windows\"))]\nuse std::env;\n\nuse zngur::Zngur;\n\nfn main() {\n build::rerun_if_changed(\"main.zng\")"
},
{
"path": "examples/cxx_demo/expected_output.txt",
"chars": 53,
"preview": "metadata = BlobMetadata { size: 19, tags: [\"rust\"] }\n"
},
{
"path": "examples/cxx_demo/main.zng",
"chars": 1063,
"preview": "type [u8] {\n wellknown_traits(?Sized);\n\n fn as_ptr(&self) -> *const u8;\n fn len(&self) -> usize;\n}\n\ntype str {\n"
},
{
"path": "examples/cxx_demo/src/main.rs",
"chars": 1525,
"preview": "#[rustfmt::skip]\nmod generated;\n\nuse generated::new_blob_store_client;\n\n// An iterator over contiguous chunks of a disco"
},
{
"path": "examples/cxx_demo_split/.gitignore",
"chars": 51,
"preview": "generated.h\ngenerated.rs\ngenerated.cpp\nhistory.txt\n"
},
{
"path": "examples/cxx_demo_split/Cargo.toml",
"chars": 355,
"preview": "[package]\nname = \"example-cxx_demo_split\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicen"
},
{
"path": "examples/cxx_demo_split/README.md",
"chars": 436,
"preview": "# Example: CXX demo\n\nThis example tries to replicate [the CXX demo](https://github.com/dtolnay/cxx/tree/master/demo) usi"
},
{
"path": "examples/cxx_demo_split/blobstore.cpp",
"chars": 1958,
"preview": "#include <algorithm>\n#include <cstdint>\n#include <set>\n#include <unordered_map>\n\n#include \"./generated.h\"\n\nclass BlobSto"
},
{
"path": "examples/cxx_demo_split/build.rs",
"chars": 1092,
"preview": "#[cfg(not(target_os = \"windows\"))]\nuse std::env;\n\nuse zngur::Zngur;\n\nfn main() {\n build::rerun_if_changed(\"main.zng\")"
},
{
"path": "examples/cxx_demo_split/expected_output.txt",
"chars": 53,
"preview": "metadata = BlobMetadata { size: 19, tags: [\"rust\"] }\n"
},
{
"path": "examples/cxx_demo_split/main.zng",
"chars": 1063,
"preview": "type [u8] {\n wellknown_traits(?Sized);\n\n fn as_ptr(&self) -> *const u8;\n fn len(&self) -> usize;\n}\n\ntype str {\n"
},
{
"path": "examples/cxx_demo_split/src/main.rs",
"chars": 1525,
"preview": "#[rustfmt::skip]\nmod generated;\n\nuse generated::new_blob_store_client;\n\n// An iterator over contiguous chunks of a disco"
},
{
"path": "examples/impl_trait/.gitignore",
"chars": 39,
"preview": "generated.h\ngenerated.rs\ngenerated.cpp\n"
},
{
"path": "examples/impl_trait/Cargo.toml",
"chars": 300,
"preview": "[package]\nname = \"example-impl-trait\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.w"
},
{
"path": "examples/impl_trait/Makefile",
"chars": 544,
"preview": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_impl_trait.a\n\t${CXX} -std=c++20 "
},
{
"path": "examples/impl_trait/NMakefile",
"chars": 681,
"preview": "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 = g"
},
{
"path": "examples/impl_trait/README.md",
"chars": 130,
"preview": "# Example: Regression test 1\n\nA example, used to check previous Zngur problems in CI.\n\nTo run this example:\n\n```\nmake\n./"
},
{
"path": "examples/impl_trait/expected_output.txt",
"chars": 371,
"preview": "Print debug -- 5\nPrint debug -- \"hello\"\nPrint debug -- 4\nPrint debug -- \"foo\"\nPrint debug -- \"foo\"\nPrint debug -- \"Rust "
},
{
"path": "examples/impl_trait/main.cpp",
"chars": 1066,
"preview": "#include <iostream>\n#include <vector>\n\n#include \"./generated.h\"\n\nusing DynDebug = rust::Dyn<rust::std::fmt::Debug>;\n\nint"
},
{
"path": "examples/impl_trait/main.zng",
"chars": 1275,
"preview": "#convert_panic_to_exception\n\ntype str {\n wellknown_traits(?Sized, Debug);\n\n fn as_ptr(&self) -> *const u8;\n fn "
},
{
"path": "examples/impl_trait/src/lib.rs",
"chars": 1053,
"preview": "use std::{\n fmt::Debug,\n task::{Context, Waker},\n};\n\n#[rustfmt::skip]\nmod generated;\n\nfn argument_position_impl_tr"
},
{
"path": "examples/memory_management/.gitignore",
"chars": 39,
"preview": "generated.h\ngenerated.rs\ngenerated.cpp\n"
},
{
"path": "examples/memory_management/Cargo.toml",
"chars": 307,
"preview": "[package]\nname = \"example-memory_management\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nli"
},
{
"path": "examples/memory_management/Makefile",
"chars": 607,
"preview": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_memory_management.a\n\t${CXX} -std"
},
{
"path": "examples/memory_management/NMakefile",
"chars": 716,
"preview": "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\nGENERA"
},
{
"path": "examples/memory_management/README.md",
"chars": 130,
"preview": "# Example: Memory management\n\nExplains the corner cases of memory management by code.\n\nTo run this example:\n\n```\nmake\n./"
},
{
"path": "examples/memory_management/expected_output.txt",
"chars": 2288,
"preview": "Checkpoint 1\nPrintOnDrop(B) has been dropped\nCheckpoint 2\nCheckpoint 3\nCheckpoint 4\nPrintOnDrop(A) has been dropped\nChec"
},
{
"path": "examples/memory_management/main.cpp",
"chars": 5205,
"preview": "#include <cstdint>\n#include <iostream>\n#include <vector>\n\n#include \"./generated.h\"\n\ntemplate <typename T> using Vec = ru"
},
{
"path": "examples/memory_management/main.zng",
"chars": 2756,
"preview": "#convert_panic_to_exception\n\ntype (crate::PrintOnDrop, i32, crate::PrintOnDrop) {\n #layout(size = 40, align = 8);\n}\n\n"
},
{
"path": "examples/memory_management/src/lib.rs",
"chars": 723,
"preview": "#[rustfmt::skip]\nmod generated;\n\n#[derive(Debug, Clone)]\npub struct PrintOnDrop(&'static str);\n\npub struct PrintOnDropPa"
},
{
"path": "examples/multiple_modules/Cargo.toml",
"chars": 344,
"preview": "[package]\nname = \"example-multiple-modules\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlic"
},
{
"path": "examples/multiple_modules/Makefile",
"chars": 2373,
"preview": "ZNGUR_CLI = cd ../../zngur-cli && cargo run\n\na.out: main.cpp aggregation.a packet.zng.h receiver.zng.h aggregation.zng.h"
},
{
"path": "examples/multiple_modules/aggregation/Cargo.toml",
"chars": 222,
"preview": "[package]\nname = \"aggregation\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspac"
},
{
"path": "examples/multiple_modules/aggregation/aggregation.zng",
"chars": 424,
"preview": "import \"packet.zng\";\n\n#cpp_additional_includes \"\n#include <stats.h>\n\"\n\ntype crate::StatsAccumulator {\n #layout(size ="
},
{
"path": "examples/multiple_modules/aggregation/impls.cpp",
"chars": 695,
"preview": "#include <aggregation.zng.h>\n#include <packet.zng.h>\n#include <stats.h>\n\nusing rust::aggregation::StatsAccumulator;\nusin"
},
{
"path": "examples/multiple_modules/aggregation/src/lib.rs",
"chars": 160,
"preview": "#[rustfmt::skip]\n#[path = \"aggregation.zng.rs\"]\nmod generated;\n\npub use packet::Packet;\n\npub struct StatsAccumulator(pub"
},
{
"path": "examples/multiple_modules/aggregation/stats.h",
"chars": 1072,
"preview": "#pragma once\n#include <iostream>\n#include <numeric>\n#include <vector>\n\n// We include packet.zng.h to use Packet methods\n"
},
{
"path": "examples/multiple_modules/expected_output.txt",
"chars": 118,
"preview": "Starting LatencyAnalysis simulation...\nLatencyAnalysis Report:\nTotal Packets: 5\nTotal Bytes: 150\nAverage Latency: 100\n"
},
{
"path": "examples/multiple_modules/main.cpp",
"chars": 716,
"preview": "#include <iostream>\n\n#include <aggregation.zng.h>\n#include <packet.zng.h>\n#include <processor.zng.h>\n#include <receiver."
},
{
"path": "examples/multiple_modules/packet/Cargo.toml",
"chars": 185,
"preview": "[package]\nname = \"packet\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = t"
},
{
"path": "examples/multiple_modules/packet/packet.zng",
"chars": 183,
"preview": "type crate::Packet {\n #layout(size = 16, align = 8); // u64 timestamp, u32 size\n fn new(u64, u32) -> crate::Packet"
},
{
"path": "examples/multiple_modules/packet/src/lib.rs",
"chars": 316,
"preview": "pub struct Packet(pub u64, pub u32);\n\nimpl Packet {\n pub fn new(timestamp: u64, size: u32) -> Self {\n Packet(t"
},
{
"path": "examples/multiple_modules/processor/Cargo.toml",
"chars": 266,
"preview": "[package]\nname = \"processor\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace "
},
{
"path": "examples/multiple_modules/processor/processor.zng",
"chars": 569,
"preview": "import \"receiver.zng\";\nimport \"aggregation.zng\";\n\ntype crate::Processor {\n #layout(size = 0, align = 1);\n fn new()"
},
{
"path": "examples/multiple_modules/processor/src/lib.rs",
"chars": 508,
"preview": "pub use aggregation::StatsAccumulator;\npub use receiver::Receiver;\n\npub struct Processor;\n\nimpl Processor {\n pub fn n"
},
{
"path": "examples/multiple_modules/receiver/Cargo.toml",
"chars": 219,
"preview": "[package]\nname = \"receiver\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace ="
},
{
"path": "examples/multiple_modules/receiver/receiver.zng",
"chars": 516,
"preview": "import \"packet.zng\";\n\ntype crate::Receiver {\n #layout(size = 8, align = 8); // count: u64\n fn new() -> crate::Rece"
},
{
"path": "examples/multiple_modules/receiver/src/lib.rs",
"chars": 421,
"preview": "pub use packet::Packet;\n\npub struct Receiver {\n count: u64,\n}\n\nimpl Receiver {\n pub fn new() -> Self {\n Rec"
},
{
"path": "examples/multiple_modules/src/lib.rs",
"chars": 194,
"preview": "// Re-export everything from child crates to ensure symbols are included in the staticlib\n#![allow(unused)]\npub use aggr"
},
{
"path": "examples/raw_pointer/.gitignore",
"chars": 39,
"preview": "generated.h\ngenerated.rs\ngenerated.cpp\n"
},
{
"path": "examples/raw_pointer/Cargo.toml",
"chars": 301,
"preview": "[package]\nname = \"example-raw-pointer\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense."
},
{
"path": "examples/raw_pointer/Makefile",
"chars": 550,
"preview": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_raw_pointer.a\n\t${CXX} --std=c++1"
},
{
"path": "examples/raw_pointer/NMakefile",
"chars": 723,
"preview": "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\nE"
},
{
"path": "examples/raw_pointer/README.md",
"chars": 121,
"preview": "# 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```"
},
{
"path": "examples/raw_pointer/expected_output.txt",
"chars": 1355,
"preview": "[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 ["
},
{
"path": "examples/raw_pointer/main.cpp",
"chars": 1596,
"preview": "#include <vector>\n\n#include \"./generated.h\"\n\ntemplate <typename T>\nusing Vec = rust::std::vec::Vec<T>;\n\nint main()\n{\n "
},
{
"path": "examples/raw_pointer/main.zng",
"chars": 1459,
"preview": "#convert_panic_to_exception\n\ntype str {\n wellknown_traits(?Sized);\n\n fn to_owned(&self) -> ::std::string::String;\n"
},
{
"path": "examples/raw_pointer/src/lib.rs",
"chars": 32,
"preview": "#[rustfmt::skip]\nmod generated;\n"
},
{
"path": "examples/rayon/.gitignore",
"chars": 51,
"preview": "generated.h\ngenerated.rs\ngenerated.cpp\nhistory.txt\n"
},
{
"path": "examples/rayon/Cargo.toml",
"chars": 311,
"preview": "[package]\nname = \"example-rayon\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.worksp"
},
{
"path": "examples/rayon/Makefile",
"chars": 519,
"preview": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_rayon.a\n\t${CXX} -std=c++11 -Werr"
},
{
"path": "examples/rayon/NMakefile",
"chars": 706,
"preview": "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"
},
{
"path": "examples/rayon/README.md",
"chars": 200,
"preview": "# Example: Rayon\n\nCalculates the sum and the number of prime numbers in `1..10000000` with multiple cores using [rayon]("
},
{
"path": "examples/rayon/expected_output.txt",
"chars": 46,
"preview": "Sum = 50000005000000\nCount of primes = 664579\n"
},
{
"path": "examples/rayon/main.cpp",
"chars": 1012,
"preview": "#include <cstddef>\n#include <cstdint>\n#include <iostream>\n#include <numeric>\n#include <vector>\n\n#include \"./generated.h\""
},
{
"path": "examples/rayon/main.zng",
"chars": 1434,
"preview": "type bool {\n #layout(size = 1, align = 1);\n wellknown_traits(Copy);\n}\n\ntype ::std::option::Option<&u64> {\n #lay"
},
{
"path": "examples/rayon/src/lib.rs",
"chars": 32,
"preview": "#[rustfmt::skip]\nmod generated;\n"
},
{
"path": "examples/rayon_split/.gitignore",
"chars": 51,
"preview": "generated.h\ngenerated.rs\ngenerated.cpp\nhistory.txt\n"
},
{
"path": "examples/rayon_split/Cargo.toml",
"chars": 317,
"preview": "[package]\nname = \"example-rayon_split\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense."
},
{
"path": "examples/rayon_split/Makefile",
"chars": 645,
"preview": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_rayon_split.a\n\t${CXX} -std=c++11"
},
{
"path": "examples/rayon_split/NMakefile",
"chars": 829,
"preview": "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 "
},
{
"path": "examples/rayon_split/README.md",
"chars": 200,
"preview": "# Example: Rayon\n\nCalculates the sum and the number of prime numbers in `1..10000000` with multiple cores using [rayon]("
},
{
"path": "examples/rayon_split/expected_output.txt",
"chars": 46,
"preview": "Sum = 50000005000000\nCount of primes = 664579\n"
},
{
"path": "examples/rayon_split/main.cpp",
"chars": 1012,
"preview": "#include <cstddef>\n#include <cstdint>\n#include <iostream>\n#include <numeric>\n#include <vector>\n\n#include \"./generated.h\""
},
{
"path": "examples/rayon_split/main.zng",
"chars": 1434,
"preview": "type bool {\n #layout(size = 1, align = 1);\n wellknown_traits(Copy);\n}\n\ntype ::std::option::Option<&u64> {\n #lay"
},
{
"path": "examples/rayon_split/src/lib.rs",
"chars": 32,
"preview": "#[rustfmt::skip]\nmod generated;\n"
},
{
"path": "examples/regression_test1/.gitignore",
"chars": 39,
"preview": "generated.h\ngenerated.rs\ngenerated.cpp\n"
},
{
"path": "examples/regression_test1/Cargo.toml",
"chars": 306,
"preview": "[package]\nname = \"example-regression-test1\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlic"
},
{
"path": "examples/regression_test1/Makefile",
"chars": 574,
"preview": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_regression_test1.a\n\t${CXX} -std="
},
{
"path": "examples/regression_test1/NMakefile",
"chars": 687,
"preview": "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\nGENERAT"
},
{
"path": "examples/regression_test1/README.md",
"chars": 130,
"preview": "# Example: Regression test 1\n\nA example, used to check previous Zngur problems in CI.\n\nTo run this example:\n\n```\nmake\n./"
},
{
"path": "examples/regression_test1/expected_output.txt",
"chars": 5680,
"preview": "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"
},
{
"path": "examples/regression_test1/main.cpp",
"chars": 7567,
"preview": "#include <iostream>\n#include <vector>\n\n#include \"./generated.h\"\n\nvoid test_dbg_works_for_ref_and_refmut() {\n auto scope"
},
{
"path": "examples/regression_test1/main.zng",
"chars": 5815,
"preview": "#convert_panic_to_exception\n\ntype bool {\n\t#layout(size = 1, align = 1);\n\twellknown_traits(Copy);\n}\n\ntype str {\n wellk"
},
{
"path": "examples/regression_test1/src/lib.rs",
"chars": 1823,
"preview": "#[rustfmt::skip]\nmod generated;\n\n#[allow(unused)]\n#[derive(Debug)]\nstruct Foo {\n field1: i32,\n field2: String,\n}\n\n"
},
{
"path": "examples/rustyline/.gitignore",
"chars": 37,
"preview": "generated.h\ngenerated.rs\nhistory.txt\n"
},
{
"path": "examples/rustyline/Cargo.toml",
"chars": 320,
"preview": "[package]\nname = \"example-rustyline\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.wo"
},
{
"path": "examples/rustyline/Makefile",
"chars": 539,
"preview": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_rustyline.a\n\t${CXX} -std=c++11 -"
},
{
"path": "examples/rustyline/NMakefile",
"chars": 691,
"preview": "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\nGEN"
},
{
"path": "examples/rustyline/README.md",
"chars": 1186,
"preview": "# Example: Rustyline\n\nLine by line port of the [`rustyline` example](https://github.com/kkawakam/rustyline#example) in C"
},
{
"path": "examples/rustyline/expected_output.txt",
"chars": 28,
"preview": "No previous history.\nCTRL-D\n"
},
{
"path": "examples/rustyline/main.cpp",
"chars": 840,
"preview": "#include <cstddef>\n#include <cstdint>\n#include <iostream>\n#include <vector>\n\n#include \"./generated.h\"\n\nint main() {\n au"
},
{
"path": "examples/rustyline/main.zng",
"chars": 2230,
"preview": "// This example uses various layout policies to demonstrate them. See https://hkalbasi.github.io/zngur/call_rust_from_cp"
},
{
"path": "examples/rustyline/src/lib.rs",
"chars": 32,
"preview": "#[rustfmt::skip]\nmod generated;\n"
},
{
"path": "examples/simple/.gitignore",
"chars": 39,
"preview": "generated.h\ngenerated.rs\ngenerated.cpp\n"
},
{
"path": "examples/simple/Cargo.toml",
"chars": 296,
"preview": "[package]\nname = \"example-simple\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.works"
},
{
"path": "examples/simple/Makefile",
"chars": 552,
"preview": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_simple.a\n\t${CXX} -std=c++17 -Wer"
},
{
"path": "examples/simple/NMakefile",
"chars": 705,
"preview": "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 = gener"
},
{
"path": "examples/simple/README.md",
"chars": 121,
"preview": "# 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```"
},
{
"path": "examples/simple/expected_output.txt",
"chars": 352,
"preview": "17\ns[2] = 7\n\nthread panicked at examples/simple/src/generated.rs:370:40:\ncalled `Option::unwrap()` on a `None` value\nnot"
},
{
"path": "examples/simple/main.cpp",
"chars": 2497,
"preview": "#include <iostream>\n#include <vector>\n\n#include \"./generated.h\"\n\n// Rust values are available in the `::rust` namespace "
},
{
"path": "examples/simple/main.zng",
"chars": 1551,
"preview": "#convert_panic_to_exception\n\ntype Box<dyn Fn(i32) -> i32> {\n #layout(size = 16, align = 8);\n}\n\nmod ::std {\n type o"
},
{
"path": "examples/simple/src/lib.rs",
"chars": 32,
"preview": "#[rustfmt::skip]\nmod generated;\n"
},
{
"path": "examples/simple_import/.gitignore",
"chars": 39,
"preview": "generated.h\ngenerated.rs\ngenerated.cpp\n"
},
{
"path": "examples/simple_import/Cargo.toml",
"chars": 303,
"preview": "[package]\nname = \"example-simple-import\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicens"
},
{
"path": "examples/simple_import/Makefile",
"chars": 596,
"preview": ".PHONY: ../../target/release/libexample_simple_import.a\n\na.out: main.cpp foo.cpp bar.cpp generated.h src/generated.rs sr"
},
{
"path": "examples/simple_import/NMakefile",
"chars": 716,
"preview": "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 "
},
{
"path": "examples/simple_import/README.md",
"chars": 877,
"preview": "# Example: Import and Merge\n\nA demonstration of Zngur's `import` and `merge` functionality using four focused modules.\n\n"
},
{
"path": "examples/simple_import/bar.cpp",
"chars": 297,
"preview": "#include \"generated.h\"\n\n// Creates and returns a Rust Option<String> with Some(String)\nrust::std::option::Option<rust::s"
},
{
"path": "examples/simple_import/bar.zng",
"chars": 510,
"preview": "// Bar module - exports Option<String> APIs for C++ usage\n\nmerge \"./primitives.zng\";\n\nmod ::std {\n mod string {\n "
},
{
"path": "examples/simple_import/expected_output.txt",
"chars": 296,
"preview": "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"
},
{
"path": "examples/simple_import/foo.cpp",
"chars": 322,
"preview": "#include \"generated.h\"\n\n// Creates and returns a Rust Vec<i32> with sample data\nrust::std::vec::Vec<int32_t> foo() {\n "
},
{
"path": "examples/simple_import/foo.zng",
"chars": 300,
"preview": "// Foo module - exports Vec<i32> APIs for C++ usage\n\nmerge \"./primitives.zng\";\n\nmod ::std {\n mod vec {\n type V"
},
{
"path": "examples/simple_import/main.cpp",
"chars": 1428,
"preview": "#include <iostream>\n#include \"generated.h\"\n\n// External function declarations from foo.cpp and bar.cpp\nextern rust::std:"
},
{
"path": "examples/simple_import/main.zng",
"chars": 1224,
"preview": "// Main module - imports foo and bar modules to demonstrate import/merge\n\nmerge \"./foo.zng\";\nmerge \"./bar.zng\";\n\n// Note"
},
{
"path": "examples/simple_import/primitives.zng",
"chars": 133,
"preview": "// Primitive types used across the import/merge example\n\ntype bool {\n #layout(size = 1, align = 1);\n wellknown_tra"
},
{
"path": "examples/simple_import/src/lib.rs",
"chars": 96,
"preview": "// Minimal lib.rs - just includes the generated Zngur bindings\n\n#[rustfmt::skip]\nmod generated;\n"
},
{
"path": "examples/tutorial/.gitignore",
"chars": 25,
"preview": "generated.h\ngenerated.rs\n"
},
{
"path": "examples/tutorial/Cargo.toml",
"chars": 298,
"preview": "[package]\nname = \"example-tutorial\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.wor"
},
{
"path": "examples/tutorial/Makefile",
"chars": 534,
"preview": "a.out: main.cpp generated.h src/generated.rs src/lib.rs ../../target/release/libexample_tutorial.a\n\t${CXX} -std=c++11 -W"
},
{
"path": "examples/tutorial/NMakefile",
"chars": 679,
"preview": "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 = gen"
},
{
"path": "examples/tutorial/README.md",
"chars": 191,
"preview": "# Example: Tutorial\n\nFull code of the [Tutorial](https://hkalbasi.github.io/zngur/tutorial.html) part 1 (Calling Rust fr"
},
{
"path": "examples/tutorial/expected_output.txt",
"chars": 641,
"preview": "[main.cpp:7] inventory = Inventory {\n items: [\n Item {\n name: \"banana\",\n size: 7,\n "
},
{
"path": "examples/tutorial/main.cpp",
"chars": 305,
"preview": "#include \"./generated.h\"\n\nint main() {\n auto inventory = rust::crate::Inventory::new_empty(1000);\n inventory.add_banan"
},
{
"path": "examples/tutorial/main.zng",
"chars": 649,
"preview": "type ::std::vec::Vec<crate::Item> {\n #layout(size = 24, align = 8);\n wellknown_traits(Debug);\n}\n\ntype str {\n we"
},
{
"path": "examples/tutorial/src/lib.rs",
"chars": 753,
"preview": "#![allow(dead_code)]\n\n#[rustfmt::skip]\nmod generated;\n\n#[derive(Debug)]\nstruct Item {\n name: String,\n size: u32,\n}"
},
{
"path": "examples/tutorial-wasm32/.gitignore",
"chars": 249,
"preview": "generated.h\ngenerated.rs\ngenerated.cpp\ngenerated.o\nmain.js\ntarget/\na.out\nexample_tutorial_wasm32.wasm\n\n# WASI SDK and de"
},
{
"path": "examples/tutorial-wasm32/Cargo.toml",
"chars": 294,
"preview": "[package]\nname = \"example-tutorial-wasm32\"\nversion = \"0.6.0\"\nedition = \"2024\"\nrust-version = \"1.85\"\nlicense = \"MIT OR Ap"
},
{
"path": "examples/tutorial-wasm32/Makefile",
"chars": 1842,
"preview": "# WASI build flags for C++ compilation with wasmtime\nWASIFLAGS = -std=c++14 \\\n --target=wasm32-wasi \\\n "
},
{
"path": "examples/tutorial-wasm32/NMakefile",
"chars": 1396,
"preview": "# can not eval mise after the fact in nmake, must preeval\r\nWASIFLAGS = -std=c++17 \\\r\n --target=wasm32-wasi \\\r\n"
},
{
"path": "examples/tutorial-wasm32/README.md",
"chars": 482,
"preview": "# Wasm32 Example\n\nThis example builds a sample application for wasmtime to test zngur's support for basic WASM applicati"
},
{
"path": "examples/tutorial-wasm32/expected_output.txt",
"chars": 212,
"preview": "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"
},
{
"path": "examples/tutorial-wasm32/main.cpp",
"chars": 2561,
"preview": "#include <iostream>\n#include <vector>\n\n#include \"./generated.h\"\n\n// Rust values are available in the `::rust` namespace "
},
{
"path": "examples/tutorial-wasm32/main32.zng",
"chars": 1516,
"preview": "type Box<dyn Fn(i32) -> i32> {\n #layout(size = 8, align = 4);\n}\n\nmod ::std {\n type option::Option<i32> {\n #"
},
{
"path": "examples/tutorial-wasm32/src/lib.rs",
"chars": 802,
"preview": "#![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)]"
},
{
"path": "examples/tutorial_cpp/Cargo.toml",
"chars": 353,
"preview": "[package]\nname = \"example-tutorial_cpp\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense"
},
{
"path": "examples/tutorial_cpp/README.md",
"chars": 192,
"preview": "# Example: Tutorial Cpp\n\nFull code of the [Tutorial](https://hkalbasi.github.io/zngur/tutorial.html) part 2 (Calling C++"
},
{
"path": "examples/tutorial_cpp/build.rs",
"chars": 1470,
"preview": "#[cfg(not(target_os = \"windows\"))]\nuse std::env;\n\nuse zngur::Zngur;\n\nfn main() {\n build::rerun_if_changed(\"main.zng\")"
},
{
"path": "examples/tutorial_cpp/expected_output.txt",
"chars": 232,
"preview": "[examples/tutorial_cpp/src/main.rs:12:5] inventory = Inventory { remaining_space: 974, items: [Item { name: \"banana\", si"
},
{
"path": "examples/tutorial_cpp/impls.cpp",
"chars": 1822,
"preview": "#include \"generated.h\"\n#include <string>\n\nusing namespace rust::crate;\n\ntemplate <typename T> using Ref = rust::Ref<T>;\n"
},
{
"path": "examples/tutorial_cpp/inventory.h",
"chars": 588,
"preview": "#include <cstdint>\n#include <string>\n#include <vector>\n\nnamespace cpp_inventory {\nstruct Item {\n std::string name;\n ui"
},
{
"path": "examples/tutorial_cpp/main.zng",
"chars": 1362,
"preview": "#cpp_additional_includes \"\n #include <inventory.h>\n\"\n\ntype str {\n wellknown_traits(?Sized);\n\n fn as_ptr(&self) "
},
{
"path": "examples/tutorial_cpp/src/main.rs",
"chars": 347,
"preview": "mod generated {\n include!(concat!(env!(\"OUT_DIR\"), \"/generated.rs\"));\n}\n\nstruct Inventory(generated::ZngurCppOpaqueOw"
},
{
"path": "mise.toml",
"chars": 601,
"preview": "[tools]\ncspell = \"9.4.0\"\ndprint = \"0.50.2\"\nwasmtime = \"36.0.2\"\n\n[tools.\"github:WebAssembly/wasi-sdk\"]\nversion = \"30\"\nver"
},
{
"path": "xtask/Cargo.toml",
"chars": 338,
"preview": "[package]\nname = \"xtask\"\nversion = \"0.9.0\"\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = tr"
},
{
"path": "xtask/src/ci.rs",
"chars": 9402,
"preview": "use crate::format_book;\nuse anyhow::{Context, Result};\nuse xshell::{Shell, cmd};\n\nfn check_crate(sh: &Shell) -> Result<("
},
{
"path": "xtask/src/format_book.rs",
"chars": 1193,
"preview": "use anyhow::{Context, Result, bail};\nuse xshell::{Shell, cmd};\n\npub fn main(fix: bool) -> Result<()> {\n let sh = Shel"
},
{
"path": "xtask/src/format_templates.rs",
"chars": 2090,
"preview": "use anyhow::{Context, Result, bail};\nuse xshell::{Shell, cmd};\n\nfn convert_sailfish_tags_to_comment(mut template: &str) "
},
{
"path": "xtask/src/main.rs",
"chars": 564,
"preview": "use clap::Parser;\n\nmod ci;\nmod format_book;\nmod format_templates;\n\n#[derive(Parser)]\nenum Command {\n CI {\n #[a"
},
{
"path": "zngur/Cargo.toml",
"chars": 380,
"preview": "[package]\nname = \"zngur\"\ndescription = \"A Rust/C++ interoperability tool\"\nreadme = \"../README.md\"\nversion = \"0.9.0\"\nedit"
},
{
"path": "zngur/src/lib.rs",
"chars": 8982,
"preview": "//! This crate contains an API for using the Zngur code generator inside build scripts. For more information\n//! about t"
},
{
"path": "zngur-autozng/Cargo.toml",
"chars": 299,
"preview": "[package]\nname = \"zngur-autozng\"\ndescription = \"Generating Zngur zng files automatically for a Rust crate\"\nversion = \"0."
},
{
"path": "zngur-autozng/src/main.rs",
"chars": 5005,
"preview": "use std::collections::HashMap;\n\nuse serde::{Deserialize, Serialize};\nuse serde_json::Value;\n\n#[derive(Debug, Serialize, "
},
{
"path": "zngur-cli/Cargo.toml",
"chars": 494,
"preview": "[package]\nname = \"zngur-cli\"\ndescription = \"CLI of the Zngur, a Rust/C++ interoperability tool\"\nreadme = \"../README.md\"\n"
},
{
"path": "zngur-cli/src/cfg_extractor.rs",
"chars": 6485,
"preview": "use clap::Args;\nuse std::collections::HashMap;\n\n#[derive(Args)]\npub struct CfgFromRustc {\n /// Load rust cfg values u"
},
{
"path": "zngur-cli/src/main.rs",
"chars": 7427,
"preview": "use std::{collections::HashMap, path::PathBuf};\n\nuse clap::Parser;\nuse zngur::{Zngur, ZngurHdr};\n\nuse crate::cfg_extract"
},
{
"path": "zngur-def/Cargo.toml",
"chars": 371,
"preview": "[package]\nname = \"zngur-def\"\ndescription = \"Data types that define the structure of a zng file\"\nreadme = \"../README.md\"\n"
},
{
"path": "zngur-def/src/lib.rs",
"chars": 8935,
"preview": "use std::fmt::Display;\n\nuse indexmap::IndexMap;\nuse itertools::Itertools;\n\nmod merge;\npub use merge::{Merge, MergeFailur"
},
{
"path": "zngur-def/src/merge.rs",
"chars": 9888,
"preview": "use crate::{\n AdditionalIncludes, ConvertPanicToException, CppRef, CppValue, LayoutPolicy, ZngurConstructor,\n Zngu"
}
]
// ... and 13 more files (download for full content)
About this extraction
This page contains the full source code of the HKalbasi/zngur GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 213 files (508.1 KB), approximately 138.3k tokens, and a symbol index with 617 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.