Vendor dependencies
Let's see how I like this workflow.
This commit is contained in:
parent
34d1830413
commit
9c435dc440
7500 changed files with 1665121 additions and 99 deletions
1
vendor/cxx/.cargo-checksum.json
vendored
Normal file
1
vendor/cxx/.cargo-checksum.json
vendored
Normal file
File diff suppressed because one or more lines are too long
92
vendor/cxx/BUCK
vendored
Normal file
92
vendor/cxx/BUCK
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
rust_library(
|
||||
name = "cxx",
|
||||
srcs = glob(["src/**/*.rs"]),
|
||||
edition = "2018",
|
||||
features = [
|
||||
"alloc",
|
||||
"std",
|
||||
],
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
":core",
|
||||
":macro",
|
||||
],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "codegen",
|
||||
srcs = glob(["gen/cmd/src/**/*.rs"]) + [
|
||||
"gen/cmd/src/gen",
|
||||
"gen/cmd/src/syntax",
|
||||
],
|
||||
crate = "cxxbridge",
|
||||
edition = "2018",
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
"//third-party:clap",
|
||||
"//third-party:codespan-reporting",
|
||||
"//third-party:proc-macro2",
|
||||
"//third-party:quote",
|
||||
"//third-party:syn",
|
||||
],
|
||||
)
|
||||
|
||||
cxx_library(
|
||||
name = "core",
|
||||
srcs = ["src/cxx.cc"],
|
||||
exported_headers = {
|
||||
"cxx.h": "include/cxx.h",
|
||||
},
|
||||
exported_linker_flags = ["-lstdc++"],
|
||||
header_namespace = "rust",
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "macro",
|
||||
srcs = glob(["macro/src/**/*.rs"]) + ["macro/src/syntax"],
|
||||
crate = "cxxbridge_macro",
|
||||
edition = "2018",
|
||||
proc_macro = True,
|
||||
deps = [
|
||||
"//third-party:proc-macro2",
|
||||
"//third-party:quote",
|
||||
"//third-party:syn",
|
||||
],
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "build",
|
||||
srcs = glob(["gen/build/src/**/*.rs"]) + [
|
||||
"gen/build/src/gen",
|
||||
"gen/build/src/syntax",
|
||||
],
|
||||
edition = "2018",
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
"//third-party:cc",
|
||||
"//third-party:codespan-reporting",
|
||||
"//third-party:once_cell",
|
||||
"//third-party:proc-macro2",
|
||||
"//third-party:quote",
|
||||
"//third-party:scratch",
|
||||
"//third-party:syn",
|
||||
],
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "lib",
|
||||
srcs = glob(["gen/lib/src/**/*.rs"]) + [
|
||||
"gen/lib/src/gen",
|
||||
"gen/lib/src/syntax",
|
||||
],
|
||||
edition = "2018",
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
"//third-party:cc",
|
||||
"//third-party:codespan-reporting",
|
||||
"//third-party:proc-macro2",
|
||||
"//third-party:quote",
|
||||
"//third-party:syn",
|
||||
],
|
||||
)
|
||||
89
vendor/cxx/BUILD
vendored
Normal file
89
vendor/cxx/BUILD
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
load("@rules_cc//cc:defs.bzl", "cc_library")
|
||||
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_proc_macro")
|
||||
|
||||
rust_library(
|
||||
name = "cxx",
|
||||
srcs = glob(["src/**/*.rs"]),
|
||||
crate_features = [
|
||||
"alloc",
|
||||
"std",
|
||||
],
|
||||
edition = "2018",
|
||||
proc_macro_deps = [
|
||||
":cxxbridge-macro",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":core-lib"],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "codegen",
|
||||
srcs = glob(["gen/cmd/src/**/*.rs"]),
|
||||
data = ["gen/cmd/src/gen/include/cxx.h"],
|
||||
edition = "2018",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//third-party:clap",
|
||||
"//third-party:codespan-reporting",
|
||||
"//third-party:proc-macro2",
|
||||
"//third-party:quote",
|
||||
"//third-party:syn",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "core",
|
||||
hdrs = ["include/cxx.h"],
|
||||
include_prefix = "rust",
|
||||
strip_include_prefix = "include",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "core-lib",
|
||||
srcs = ["src/cxx.cc"],
|
||||
hdrs = ["include/cxx.h"],
|
||||
)
|
||||
|
||||
rust_proc_macro(
|
||||
name = "cxxbridge-macro",
|
||||
srcs = glob(["macro/src/**/*.rs"]),
|
||||
edition = "2018",
|
||||
deps = [
|
||||
"//third-party:proc-macro2",
|
||||
"//third-party:quote",
|
||||
"//third-party:syn",
|
||||
],
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "build",
|
||||
srcs = glob(["gen/build/src/**/*.rs"]),
|
||||
data = ["gen/build/src/gen/include/cxx.h"],
|
||||
edition = "2018",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//third-party:cc",
|
||||
"//third-party:codespan-reporting",
|
||||
"//third-party:once_cell",
|
||||
"//third-party:proc-macro2",
|
||||
"//third-party:quote",
|
||||
"//third-party:scratch",
|
||||
"//third-party:syn",
|
||||
],
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "lib",
|
||||
srcs = glob(["gen/lib/src/**/*.rs"]),
|
||||
data = ["gen/lib/src/gen/include/cxx.h"],
|
||||
edition = "2018",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//third-party:cc",
|
||||
"//third-party:codespan-reporting",
|
||||
"//third-party:proc-macro2",
|
||||
"//third-party:quote",
|
||||
"//third-party:syn",
|
||||
],
|
||||
)
|
||||
89
vendor/cxx/Cargo.toml
vendored
Normal file
89
vendor/cxx/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
rust-version = "1.48"
|
||||
name = "cxx"
|
||||
version = "1.0.85"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
links = "cxxbridge1"
|
||||
exclude = [
|
||||
"/demo",
|
||||
"/gen",
|
||||
"/syntax",
|
||||
"/third-party",
|
||||
]
|
||||
description = "Safe interop between Rust and C++"
|
||||
homepage = "https://cxx.rs"
|
||||
documentation = "https://docs.rs/cxx"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"ffi",
|
||||
"c++",
|
||||
]
|
||||
categories = [
|
||||
"development-tools::ffi",
|
||||
"api-bindings",
|
||||
"no-std",
|
||||
]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/dtolnay/cxx"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
rustdoc-args = [
|
||||
"--cfg",
|
||||
"doc_cfg",
|
||||
]
|
||||
|
||||
[lib]
|
||||
doc-scrape-examples = false
|
||||
|
||||
[dependencies.cxxbridge-macro]
|
||||
version = "=1.0.85"
|
||||
|
||||
[dependencies.link-cplusplus]
|
||||
version = "1.0"
|
||||
|
||||
[dev-dependencies.cxx-build]
|
||||
version = "=1.0.85"
|
||||
|
||||
[dev-dependencies.cxx-gen]
|
||||
version = "0.7"
|
||||
|
||||
[dev-dependencies.cxx-test-suite]
|
||||
version = "0"
|
||||
|
||||
[dev-dependencies.rustversion]
|
||||
version = "1.0"
|
||||
|
||||
[dev-dependencies.trybuild]
|
||||
version = "1.0.66"
|
||||
features = ["diff"]
|
||||
|
||||
[build-dependencies.cc]
|
||||
version = "1.0.49"
|
||||
|
||||
[build-dependencies.cxxbridge-flags]
|
||||
version = "=1.0.85"
|
||||
default-features = false
|
||||
|
||||
[features]
|
||||
alloc = []
|
||||
"c++14" = ["cxxbridge-flags/c++14"]
|
||||
"c++17" = ["cxxbridge-flags/c++17"]
|
||||
"c++20" = ["cxxbridge-flags/c++20"]
|
||||
default = [
|
||||
"std",
|
||||
"cxxbridge-flags/default",
|
||||
]
|
||||
std = ["alloc"]
|
||||
201
vendor/cxx/LICENSE-APACHE
vendored
Normal file
201
vendor/cxx/LICENSE-APACHE
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
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
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
23
vendor/cxx/LICENSE-MIT
vendored
Normal file
23
vendor/cxx/LICENSE-MIT
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
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.
|
||||
388
vendor/cxx/README.md
vendored
Normal file
388
vendor/cxx/README.md
vendored
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
CXX — safe FFI between Rust and C++
|
||||
=========================================
|
||||
|
||||
[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/cxx-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/cxx)
|
||||
[<img alt="crates.io" src="https://img.shields.io/crates/v/cxx.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/cxx)
|
||||
[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-cxx-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/cxx)
|
||||
[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/cxx/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/cxx/actions?query=branch%3Amaster)
|
||||
|
||||
This library provides a **safe** mechanism for calling C++ code from Rust and
|
||||
Rust code from C++, not subject to the many ways that things can go wrong when
|
||||
using bindgen or cbindgen to generate unsafe C-style bindings.
|
||||
|
||||
This doesn't change the fact that 100% of C++ code is unsafe. When auditing a
|
||||
project, you would be on the hook for auditing all the unsafe Rust code and
|
||||
*all* the C++ code. The core safety claim under this new model is that auditing
|
||||
just the C++ side would be sufficient to catch all problems, i.e. the Rust side
|
||||
can be 100% safe.
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
cxx = "1.0"
|
||||
|
||||
[build-dependencies]
|
||||
cxx-build = "1.0"
|
||||
```
|
||||
|
||||
*Compiler support: requires rustc 1.48+ and c++11 or newer*<br>
|
||||
*[Release notes](https://github.com/dtolnay/cxx/releases)*
|
||||
|
||||
<br>
|
||||
|
||||
## Guide
|
||||
|
||||
Please see **<https://cxx.rs>** for a tutorial, reference material, and example
|
||||
code.
|
||||
|
||||
<br>
|
||||
|
||||
## Overview
|
||||
|
||||
The idea is that we define the signatures of both sides of our FFI boundary
|
||||
embedded together in one Rust module (the next section shows an example). From
|
||||
this, CXX receives a complete picture of the boundary to perform static analyses
|
||||
against the types and function signatures to uphold both Rust's and C++'s
|
||||
invariants and requirements.
|
||||
|
||||
If everything checks out statically, then CXX uses a pair of code generators to
|
||||
emit the relevant `extern "C"` signatures on both sides together with any
|
||||
necessary static assertions for later in the build process to verify
|
||||
correctness. On the Rust side this code generator is simply an attribute
|
||||
procedural macro. On the C++ side it can be a small Cargo build script if your
|
||||
build is managed by Cargo, or for other build systems like Bazel or Buck we
|
||||
provide a command line tool which generates the header and source file and
|
||||
should be easy to integrate.
|
||||
|
||||
The resulting FFI bridge operates at zero or negligible overhead, i.e. no
|
||||
copying, no serialization, no memory allocation, no runtime checks needed.
|
||||
|
||||
The FFI signatures are able to use native types from whichever side they please,
|
||||
such as Rust's `String` or C++'s `std::string`, Rust's `Box` or C++'s
|
||||
`std::unique_ptr`, Rust's `Vec` or C++'s `std::vector`, etc in any combination.
|
||||
CXX guarantees an ABI-compatible signature that both sides understand, based on
|
||||
builtin bindings for key standard library types to expose an idiomatic API on
|
||||
those types to the other language. For example when manipulating a C++ string
|
||||
from Rust, its `len()` method becomes a call of the `size()` member function
|
||||
defined by C++; when manipulating a Rust string from C++, its `size()` member
|
||||
function calls Rust's `len()`.
|
||||
|
||||
<br>
|
||||
|
||||
## Example
|
||||
|
||||
In this example we are writing a Rust application that wishes to take advantage
|
||||
of an existing C++ client for a large-file blobstore service. The blobstore
|
||||
supports a `put` operation for a discontiguous buffer upload. For example we
|
||||
might be uploading snapshots of a circular buffer which would tend to consist of
|
||||
2 chunks, or fragments of a file spread across memory for some other reason.
|
||||
|
||||
A runnable version of this example is provided under the *demo* directory of
|
||||
this repo. To try it out, run `cargo run` from that directory.
|
||||
|
||||
```rust
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
// Any shared structs, whose fields will be visible to both languages.
|
||||
struct BlobMetadata {
|
||||
size: usize,
|
||||
tags: Vec<String>,
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
// Zero or more opaque types which both languages can pass around but
|
||||
// only Rust can see the fields.
|
||||
type MultiBuf;
|
||||
|
||||
// Functions implemented in Rust.
|
||||
fn next_chunk(buf: &mut MultiBuf) -> &[u8];
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
// One or more headers with the matching C++ declarations. Our code
|
||||
// generators don't read it but it gets #include'd and used in static
|
||||
// assertions to ensure our picture of the FFI boundary is accurate.
|
||||
include!("demo/include/blobstore.h");
|
||||
|
||||
// Zero or more opaque types which both languages can pass around but
|
||||
// only C++ can see the fields.
|
||||
type BlobstoreClient;
|
||||
|
||||
// Functions implemented in C++.
|
||||
fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
|
||||
fn put(&self, parts: &mut MultiBuf) -> u64;
|
||||
fn tag(&self, blobid: u64, tag: &str);
|
||||
fn metadata(&self, blobid: u64) -> BlobMetadata;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now we simply provide Rust definitions of all the things in the `extern "Rust"`
|
||||
block and C++ definitions of all the things in the `extern "C++"` block, and get
|
||||
to call back and forth safely.
|
||||
|
||||
Here are links to the complete set of source files involved in the demo:
|
||||
|
||||
- [demo/src/main.rs](demo/src/main.rs)
|
||||
- [demo/build.rs](demo/build.rs)
|
||||
- [demo/include/blobstore.h](demo/include/blobstore.h)
|
||||
- [demo/src/blobstore.cc](demo/src/blobstore.cc)
|
||||
|
||||
To look at the code generated in both languages for the example by the CXX code
|
||||
generators:
|
||||
|
||||
```console
|
||||
# run Rust code generator and print to stdout
|
||||
# (requires https://github.com/dtolnay/cargo-expand)
|
||||
$ cargo expand --manifest-path demo/Cargo.toml
|
||||
|
||||
# run C++ code generator and print to stdout
|
||||
$ cargo run --manifest-path gen/cmd/Cargo.toml -- demo/src/main.rs
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
## Details
|
||||
|
||||
As seen in the example, the language of the FFI boundary involves 3 kinds of
|
||||
items:
|
||||
|
||||
- **Shared structs** — their fields are made visible to both languages.
|
||||
The definition written within cxx::bridge is the single source of truth.
|
||||
|
||||
- **Opaque types** — their fields are secret from the other language.
|
||||
These cannot be passed across the FFI by value but only behind an indirection,
|
||||
such as a reference `&`, a Rust `Box`, or a `UniquePtr`. Can be a type alias
|
||||
for an arbitrarily complicated generic language-specific type depending on
|
||||
your use case.
|
||||
|
||||
- **Functions** — implemented in either language, callable from the other
|
||||
language.
|
||||
|
||||
Within the `extern "Rust"` part of the CXX bridge we list the types and
|
||||
functions for which Rust is the source of truth. These all implicitly refer to
|
||||
the `super` module, the parent module of the CXX bridge. You can think of the
|
||||
two items listed in the example above as being like `use super::MultiBuf` and
|
||||
`use super::next_chunk` except re-exported to C++. The parent module will either
|
||||
contain the definitions directly for simple things, or contain the relevant
|
||||
`use` statements to bring them into scope from elsewhere.
|
||||
|
||||
Within the `extern "C++"` part, we list types and functions for which C++ is the
|
||||
source of truth, as well as the header(s) that declare those APIs. In the future
|
||||
it's possible that this section could be generated bindgen-style from the
|
||||
headers but for now we need the signatures written out; static assertions will
|
||||
verify that they are accurate.
|
||||
|
||||
Your function implementations themselves, whether in C++ or Rust, *do not* need
|
||||
to be defined as `extern "C"` ABI or no\_mangle. CXX will put in the right shims
|
||||
where necessary to make it all work.
|
||||
|
||||
<br>
|
||||
|
||||
## Comparison vs bindgen and cbindgen
|
||||
|
||||
Notice that with CXX there is repetition of all the function signatures: they
|
||||
are typed out once where the implementation is defined (in C++ or Rust) and
|
||||
again inside the cxx::bridge module, though compile-time assertions guarantee
|
||||
these are kept in sync. This is different from [bindgen] and [cbindgen] where
|
||||
function signatures are typed by a human once and the tool consumes them in one
|
||||
language and emits them in the other language.
|
||||
|
||||
[bindgen]: https://github.com/rust-lang/rust-bindgen
|
||||
[cbindgen]: https://github.com/eqrion/cbindgen/
|
||||
|
||||
This is because CXX fills a somewhat different role. It is a lower level tool
|
||||
than bindgen or cbindgen in a sense; you can think of it as being a replacement
|
||||
for the concept of `extern "C"` signatures as we know them, rather than a
|
||||
replacement for a bindgen. It would be reasonable to build a higher level
|
||||
bindgen-like tool on top of CXX which consumes a C++ header and/or Rust module
|
||||
(and/or IDL like Thrift) as source of truth and generates the cxx::bridge,
|
||||
eliminating the repetition while leveraging the static analysis safety
|
||||
guarantees of CXX.
|
||||
|
||||
But note in other ways CXX is higher level than the bindgens, with rich support
|
||||
for common standard library types. Frequently with bindgen when we are dealing
|
||||
with an idiomatic C++ API we would end up manually wrapping that API in C-style
|
||||
raw pointer functions, applying bindgen to get unsafe raw pointer Rust
|
||||
functions, and replicating the API again to expose those idiomatically in Rust.
|
||||
That's a much worse form of repetition because it is unsafe all the way through.
|
||||
|
||||
By using a CXX bridge as the shared understanding between the languages, rather
|
||||
than `extern "C"` C-style signatures as the shared understanding, common FFI use
|
||||
cases become expressible using 100% safe code.
|
||||
|
||||
It would also be reasonable to mix and match, using CXX bridge for the 95% of
|
||||
your FFI that is straightforward and doing the remaining few oddball signatures
|
||||
the old fashioned way with bindgen and cbindgen, if for some reason CXX's static
|
||||
restrictions get in the way. Please file an issue if you end up taking this
|
||||
approach so that we know what ways it would be worthwhile to make the tool more
|
||||
expressive.
|
||||
|
||||
<br>
|
||||
|
||||
## Cargo-based setup
|
||||
|
||||
For builds that are orchestrated by Cargo, you will use a build script that runs
|
||||
CXX's C++ code generator and compiles the resulting C++ code along with any
|
||||
other C++ code for your crate.
|
||||
|
||||
The canonical build script is as follows. The indicated line returns a
|
||||
[`cc::Build`] instance (from the usual widely used `cc` crate) on which you can
|
||||
set up any additional source files and compiler flags as normal.
|
||||
|
||||
[`cc::Build`]: https://docs.rs/cc/1.0/cc/struct.Build.html
|
||||
|
||||
```toml
|
||||
# Cargo.toml
|
||||
|
||||
[build-dependencies]
|
||||
cxx-build = "1.0"
|
||||
```
|
||||
|
||||
```rust
|
||||
// build.rs
|
||||
|
||||
fn main() {
|
||||
cxx_build::bridge("src/main.rs") // returns a cc::Build
|
||||
.file("src/demo.cc")
|
||||
.flag_if_supported("-std=c++11")
|
||||
.compile("cxxbridge-demo");
|
||||
|
||||
println!("cargo:rerun-if-changed=src/main.rs");
|
||||
println!("cargo:rerun-if-changed=src/demo.cc");
|
||||
println!("cargo:rerun-if-changed=include/demo.h");
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
## Non-Cargo setup
|
||||
|
||||
For use in non-Cargo builds like Bazel or Buck, CXX provides an alternate way of
|
||||
invoking the C++ code generator as a standalone command line tool. The tool is
|
||||
packaged as the `cxxbridge-cmd` crate on crates.io or can be built from the
|
||||
*gen/cmd* directory of this repo.
|
||||
|
||||
```bash
|
||||
$ cargo install cxxbridge-cmd
|
||||
|
||||
$ cxxbridge src/main.rs --header > path/to/mybridge.h
|
||||
$ cxxbridge src/main.rs > path/to/mybridge.cc
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
## Safety
|
||||
|
||||
Be aware that the design of this library is intentionally restrictive and
|
||||
opinionated! It isn't a goal to be powerful enough to handle arbitrary
|
||||
signatures in either language. Instead this project is about carving out a
|
||||
reasonably expressive set of functionality about which we can make useful safety
|
||||
guarantees today and maybe extend over time. You may find that it takes some
|
||||
practice to use CXX bridge effectively as it won't work in all the ways that you
|
||||
are used to.
|
||||
|
||||
Some of the considerations that go into ensuring safety are:
|
||||
|
||||
- By design, our paired code generators work together to control both sides of
|
||||
the FFI boundary. Ordinarily in Rust writing your own `extern "C"` blocks is
|
||||
unsafe because the Rust compiler has no way to know whether the signatures
|
||||
you've written actually match the signatures implemented in the other
|
||||
language. With CXX we achieve that visibility and know what's on the other
|
||||
side.
|
||||
|
||||
- Our static analysis detects and prevents passing types by value that shouldn't
|
||||
be passed by value from C++ to Rust, for example because they may contain
|
||||
internal pointers that would be screwed up by Rust's move behavior.
|
||||
|
||||
- To many people's surprise, it is possible to have a struct in Rust and a
|
||||
struct in C++ with exactly the same layout / fields / alignment / everything,
|
||||
and still not the same ABI when passed by value. This is a longstanding
|
||||
bindgen bug that leads to segfaults in absolutely correct-looking code
|
||||
([rust-lang/rust-bindgen#778]). CXX knows about this and can insert the
|
||||
necessary zero-cost workaround transparently where needed, so go ahead and
|
||||
pass your structs by value without worries. This is made possible by owning
|
||||
both sides of the boundary rather than just one.
|
||||
|
||||
- Template instantiations: for example in order to expose a UniquePtr\<T\> type
|
||||
in Rust backed by a real C++ unique\_ptr, we have a way of using a Rust trait
|
||||
to connect the behavior back to the template instantiations performed by the
|
||||
other language.
|
||||
|
||||
[rust-lang/rust-bindgen#778]: https://github.com/rust-lang/rust-bindgen/issues/778
|
||||
|
||||
<br>
|
||||
|
||||
## Builtin types
|
||||
|
||||
In addition to all the primitive types (i32 <=> int32_t), the following
|
||||
common types may be used in the fields of shared structs and the arguments and
|
||||
returns of functions.
|
||||
|
||||
<table>
|
||||
<tr><th>name in Rust</th><th>name in C++</th><th>restrictions</th></tr>
|
||||
<tr><td>String</td><td>rust::String</td><td></td></tr>
|
||||
<tr><td>&str</td><td>rust::Str</td><td></td></tr>
|
||||
<tr><td>&[T]</td><td>rust::Slice<const T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
<tr><td>&mut [T]</td><td>rust::Slice<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
<tr><td><a href="https://docs.rs/cxx/1.0/cxx/struct.CxxString.html">CxxString</a></td><td>std::string</td><td><sup><i>cannot be passed by value</i></sup></td></tr>
|
||||
<tr><td>Box<T></td><td>rust::Box<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
<tr><td><a href="https://docs.rs/cxx/1.0/cxx/struct.UniquePtr.html">UniquePtr<T></a></td><td>std::unique_ptr<T></td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr>
|
||||
<tr><td><a href="https://docs.rs/cxx/1.0/cxx/struct.SharedPtr.html">SharedPtr<T></a></td><td>std::shared_ptr<T></td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr>
|
||||
<tr><td>[T; N]</td><td>std::array<T, N></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
<tr><td>Vec<T></td><td>rust::Vec<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
<tr><td><a href="https://docs.rs/cxx/1.0/cxx/struct.CxxVector.html">CxxVector<T></a></td><td>std::vector<T></td><td><sup><i>cannot be passed by value, cannot hold opaque Rust type</i></sup></td></tr>
|
||||
<tr><td>*mut T, *const T</td><td>T*, const T*</td><td><sup><i>fn with a raw pointer argument must be declared unsafe to call</i></sup></td></tr>
|
||||
<tr><td>fn(T, U) -> V</td><td>rust::Fn<V(T, U)></td><td><sup><i>only passing from Rust to C++ is implemented so far</i></sup></td></tr>
|
||||
<tr><td>Result<T></td><td>throw/catch</td><td><sup><i>allowed as return type only</i></sup></td></tr>
|
||||
</table>
|
||||
|
||||
The C++ API of the `rust` namespace is defined by the *include/cxx.h* file in
|
||||
this repo. You will need to include this header in your C++ code when working
|
||||
with those types.
|
||||
|
||||
The following types are intended to be supported "soon" but are just not
|
||||
implemented yet. I don't expect any of these to be hard to make work but it's a
|
||||
matter of designing a nice API for each in its non-native language.
|
||||
|
||||
<table>
|
||||
<tr><th>name in Rust</th><th>name in C++</th></tr>
|
||||
<tr><td>BTreeMap<K, V></td><td><sup><i>tbd</i></sup></td></tr>
|
||||
<tr><td>HashMap<K, V></td><td><sup><i>tbd</i></sup></td></tr>
|
||||
<tr><td>Arc<T></td><td><sup><i>tbd</i></sup></td></tr>
|
||||
<tr><td>Option<T></td><td><sup><i>tbd</i></sup></td></tr>
|
||||
<tr><td><sup><i>tbd</i></sup></td><td>std::map<K, V></td></tr>
|
||||
<tr><td><sup><i>tbd</i></sup></td><td>std::unordered_map<K, V></td></tr>
|
||||
</table>
|
||||
|
||||
<br>
|
||||
|
||||
## Remaining work
|
||||
|
||||
This is still early days for CXX; I am releasing it as a minimum viable product
|
||||
to collect feedback on the direction and invite collaborators. Please check the
|
||||
open issues.
|
||||
|
||||
Especially please report issues if you run into trouble building or linking any
|
||||
of this stuff. I'm sure there are ways to make the build aspects friendlier or
|
||||
more robust.
|
||||
|
||||
Finally, I know more about Rust library design than C++ library design so I
|
||||
would appreciate help making the C++ APIs in this project more idiomatic where
|
||||
anyone has suggestions.
|
||||
|
||||
<br>
|
||||
|
||||
#### 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>
|
||||
31
vendor/cxx/WORKSPACE
vendored
Normal file
31
vendor/cxx/WORKSPACE
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
workspace(name = "cxx.rs")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "rules_rust",
|
||||
sha256 = "617082067629939c0a22f587811a3e822a50a203119a90380e21f5aec3373da9",
|
||||
strip_prefix = "rules_rust-e07881fa22a5f0d16230d8b23bbff2bf358823b8",
|
||||
urls = [
|
||||
# Main branch as of 2022-04-27
|
||||
"https://github.com/bazelbuild/rules_rust/archive/e07881fa22a5f0d16230d8b23bbff2bf358823b8.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
load("@rules_rust//rust:repositories.bzl", "rules_rust_dependencies", "rust_register_toolchains")
|
||||
|
||||
RUST_VERSION = "1.65.0"
|
||||
|
||||
rules_rust_dependencies()
|
||||
|
||||
rust_register_toolchains(
|
||||
version = RUST_VERSION,
|
||||
)
|
||||
|
||||
load("//tools/bazel:vendor.bzl", "vendor")
|
||||
|
||||
vendor(
|
||||
name = "third-party",
|
||||
cargo_version = RUST_VERSION,
|
||||
lockfile = "//third-party:Cargo.lock",
|
||||
)
|
||||
9
vendor/cxx/book/README.md
vendored
Normal file
9
vendor/cxx/book/README.md
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Published automatically to https://cxx.rs from master branch.
|
||||
|
||||
To build and view locally:
|
||||
|
||||
- Install [mdBook]: `cargo install mdbook`.
|
||||
- Run `mdbook build` in this directory.
|
||||
- Open the generated *build/index.html*.
|
||||
|
||||
[mdBook]: https://github.com/rust-lang/mdBook
|
||||
22
vendor/cxx/book/book.toml
vendored
Normal file
22
vendor/cxx/book/book.toml
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[book]
|
||||
#title = "Rust ♡ C++"
|
||||
authors = ["David Tolnay"]
|
||||
description = "CXX — safe interop between Rust and C++"
|
||||
|
||||
[rust]
|
||||
edition = "2018"
|
||||
|
||||
[build]
|
||||
build-dir = "build"
|
||||
create-missing = false
|
||||
|
||||
[output.html]
|
||||
additional-css = ["css/cxx.css"]
|
||||
cname = "cxx.rs"
|
||||
git-repository-url = "https://github.com/dtolnay/cxx"
|
||||
playground = { copyable = false }
|
||||
print = { enable = false }
|
||||
|
||||
[output.html.redirect]
|
||||
"binding/index.html" = "../bindings.html"
|
||||
"build/index.html" = "../building.html"
|
||||
104
vendor/cxx/book/build.js
vendored
Normal file
104
vendor/cxx/book/build.js
vendored
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const cheerio = require('cheerio');
|
||||
const hljs = require('./build/highlight.js');
|
||||
const Entities = require('html-entities').AllHtmlEntities;
|
||||
const entities = new Entities();
|
||||
|
||||
const githublink = `\
|
||||
<li class="part-title">\
|
||||
<a href="https://github.com/dtolnay/cxx">\
|
||||
<i class="fa fa-github"></i>\
|
||||
https://github.com/dtolnay/cxx\
|
||||
</a>\
|
||||
</li>`;
|
||||
|
||||
const opengraph = `\
|
||||
<meta property="og:image" content="https://cxx.rs/cxx.png" />\
|
||||
<meta property="og:site_name" content="CXX" />\
|
||||
<meta property="og:title" content="CXX — safe interop between Rust and C++" />\
|
||||
<meta name="twitter:image:src" content="https://cxx.rs/cxx.png" />\
|
||||
<meta name="twitter:site" content="@davidtolnay" />\
|
||||
<meta name="twitter:card" content="summary" />\
|
||||
<meta name="twitter:title" content="CXX — safe interop between Rust and C++" />`;
|
||||
|
||||
const htmljs = `\
|
||||
var html = document.querySelector('html');
|
||||
html.classList.remove('no-js');
|
||||
html.classList.add('js');`;
|
||||
|
||||
const dirs = ['build'];
|
||||
while (dirs.length) {
|
||||
const dir = dirs.pop();
|
||||
fs.readdirSync(dir).forEach((entry) => {
|
||||
path = dir + '/' + entry;
|
||||
const stat = fs.statSync(path);
|
||||
if (stat.isDirectory()) {
|
||||
dirs.push(path);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!path.endsWith('.html')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = fs.readFileSync(path, 'utf8');
|
||||
const $ = cheerio.load(index, { decodeEntities: false });
|
||||
|
||||
$('head').append(opengraph);
|
||||
$('script:nth-of-type(3)').text(htmljs);
|
||||
$('nav#sidebar ol.chapter').append(githublink);
|
||||
$('head link[href="tomorrow-night.css"]').attr('disabled', true);
|
||||
$('head link[href="ayu-highlight.css"]').attr('disabled', true);
|
||||
$('button#theme-toggle').attr('style', 'display:none');
|
||||
$('pre code').each(function () {
|
||||
const node = $(this);
|
||||
const langClass = node.attr('class').split(' ', 2)[0];
|
||||
if (!langClass.startsWith('language-')) {
|
||||
return;
|
||||
}
|
||||
const lang = langClass.replace('language-', '');
|
||||
const lines = node.html().split('\n');
|
||||
const boring = lines.map((line) =>
|
||||
line.includes('<span class="boring">')
|
||||
);
|
||||
const ellipsis = lines.map((line) => line.includes('// ...'));
|
||||
const target = entities.decode(node.text());
|
||||
const highlighted = hljs.highlight(lang, target).value;
|
||||
const result = highlighted
|
||||
.split('\n')
|
||||
.map(function (line, i) {
|
||||
if (boring[i]) {
|
||||
line = '<span class="boring">' + line;
|
||||
} else if (ellipsis[i]) {
|
||||
line = '<span class="ellipsis">' + line;
|
||||
}
|
||||
if (i > 0 && (boring[i - 1] || ellipsis[i - 1])) {
|
||||
line = '</span>' + line;
|
||||
}
|
||||
return line;
|
||||
})
|
||||
.join('\n');
|
||||
node.text(result);
|
||||
node.removeClass(langClass);
|
||||
if (!node.hasClass('focuscomment')) {
|
||||
node.addClass('hidelines');
|
||||
node.addClass('hide-boring');
|
||||
}
|
||||
});
|
||||
$('code').each(function () {
|
||||
$(this).addClass('hljs');
|
||||
});
|
||||
|
||||
const out = $.html();
|
||||
fs.writeFileSync(path, out);
|
||||
});
|
||||
}
|
||||
|
||||
fs.copyFileSync('build/highlight.css', 'build/tomorrow-night.css');
|
||||
fs.copyFileSync('build/highlight.css', 'build/ayu-highlight.css');
|
||||
|
||||
var bookjs = fs.readFileSync('build/book.js', 'utf8');
|
||||
bookjs = bookjs.replace('set_theme(theme, false);', '');
|
||||
fs.writeFileSync('build/book.js', bookjs);
|
||||
17
vendor/cxx/book/build.sh
vendored
Normal file
17
vendor/cxx/book/build.sh
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
if [ -f ./mdbook ]; then
|
||||
./mdbook build
|
||||
else
|
||||
mdbook build
|
||||
fi
|
||||
|
||||
if [ ! -d node_modules ]; then
|
||||
npm install
|
||||
fi
|
||||
|
||||
./build.js
|
||||
44
vendor/cxx/book/css/cxx.css
vendored
Normal file
44
vendor/cxx/book/css/cxx.css
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
:root {
|
||||
--sidebar-width: 310px;
|
||||
}
|
||||
|
||||
.badges img {
|
||||
margin: 0 7px 7px 0;
|
||||
}
|
||||
|
||||
.badges {
|
||||
margin: 16px 0 120px;
|
||||
}
|
||||
|
||||
.boring {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.no-js code:not(.focuscomment) .boring {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.js code:not(.hide-boring) .ellipsis {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.focuscomment .hljs-comment {
|
||||
font-weight: bold;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.focuscomment .boring {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
nav.sidebar li.part-title i.fa-github {
|
||||
font-size: 20px;
|
||||
padding-right: 5px;
|
||||
padding-top: 12px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
.sidebar .sidebar-scrollbox {
|
||||
padding: 10px 0 10px 10px;
|
||||
}
|
||||
8
vendor/cxx/book/diagram/Makefile
vendored
Normal file
8
vendor/cxx/book/diagram/Makefile
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
overview.svg: overview.pdf
|
||||
pdf2svg $< $@
|
||||
|
||||
overview.pdf: overview.tex
|
||||
latexmk $<
|
||||
|
||||
overview.png: overview.svg
|
||||
svgexport $< $@ 3x
|
||||
45
vendor/cxx/book/diagram/overview.tex
vendored
Normal file
45
vendor/cxx/book/diagram/overview.tex
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
\documentclass{standalone}
|
||||
\usepackage{makecell}
|
||||
\usepackage{pgfplots}
|
||||
\usepackage{sansmath}
|
||||
\usetikzlibrary{arrows.meta}
|
||||
\pgfplotsset{compat=1.16}
|
||||
\begin{document}
|
||||
\pagecolor{white}
|
||||
\begin{tikzpicture}[
|
||||
x=1cm,
|
||||
y=-.6cm,
|
||||
every node/.append style={
|
||||
line width=1.5pt,
|
||||
font=\Large\sansmath\sffamily,
|
||||
},
|
||||
every path/.append style={
|
||||
>={Latex[length=10pt,width=8pt]},
|
||||
line width=1.5pt,
|
||||
},
|
||||
execute at end node={\vphantom{bg}},
|
||||
]
|
||||
\node[draw, rounded corners=5, inner xsep=30pt, inner ysep=2pt]
|
||||
(bridge) at (0, .25) {\makecell{\texttt{\#\hspace{-1pt}[}cxx::bridge\texttt{]} mod\\[-4pt]description of boundary}};
|
||||
\node[draw, rounded corners, inner xsep=10pt, inner ysep=6pt, text depth=1pt]
|
||||
(rust-bindings) at (-3.5, 6.5) {Rust bindings};
|
||||
\node[draw, rounded corners, inner xsep=10pt, inner ysep=6pt, text depth=1pt]
|
||||
(cpp-bindings) at (3.5, 6.5) {C\texttt{++} bindings};
|
||||
\node[inner xsep=4pt, inner ysep=-0pt]
|
||||
(rust-code) at (-9, 6.5) {\makecell[r]{\\[-8pt]Rust\\[-4pt]code}};
|
||||
\node[inner xsep=4pt, inner ysep=-0pt]
|
||||
(cpp-code) at (9, 6.5) {\makecell[l]{\\[-8pt]C\texttt{++}\\[-4pt]code}};
|
||||
\draw (bridge) -- (0, 4);
|
||||
\draw[<->] (rust-bindings) |- (0, 4) -| (cpp-bindings);
|
||||
\draw[<->] (rust-code) -- (rust-bindings);
|
||||
\draw[<->, dash pattern=on 8pt off 6pt] (rust-bindings) -- (cpp-bindings);
|
||||
\draw[<->] (cpp-bindings) -- (cpp-code);
|
||||
\draw (-.75, 4) node[anchor=south east] {Macro expansion};
|
||||
\draw (.75, 4) node[anchor=south west] {Code generation};
|
||||
\draw (0, 6.5) node[anchor=south, inner ysep=4pt] {Hidden C ABI};
|
||||
\draw (-6.75, 6.5) node[anchor=south, inner ysep=1pt] {\makecell{Safe\\[-4pt]straightforward\\[-4pt]Rust APIs}};
|
||||
\draw (6.75, 6.5) node[anchor=south, inner ysep=1pt] {\makecell{Straightforward\\[-4pt]C\texttt{++} APIs}};
|
||||
\pgfresetboundingbox\path
|
||||
(-9.5, 0) -- (rust-bindings.south)+(0, .3) -- (9.5, 0) -- (bridge.north);
|
||||
\end{tikzpicture}
|
||||
\end{document}
|
||||
207
vendor/cxx/book/package-lock.json
generated
vendored
Normal file
207
vendor/cxx/book/package-lock.json
generated
vendored
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
{
|
||||
"name": "cxx-book-build",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
|
||||
},
|
||||
"cheerio": {
|
||||
"version": "0.22.0",
|
||||
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz",
|
||||
"integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=",
|
||||
"requires": {
|
||||
"css-select": "~1.2.0",
|
||||
"dom-serializer": "~0.1.0",
|
||||
"entities": "~1.1.1",
|
||||
"htmlparser2": "^3.9.1",
|
||||
"lodash.assignin": "^4.0.9",
|
||||
"lodash.bind": "^4.1.4",
|
||||
"lodash.defaults": "^4.0.1",
|
||||
"lodash.filter": "^4.4.0",
|
||||
"lodash.flatten": "^4.2.0",
|
||||
"lodash.foreach": "^4.3.0",
|
||||
"lodash.map": "^4.4.0",
|
||||
"lodash.merge": "^4.4.0",
|
||||
"lodash.pick": "^4.2.1",
|
||||
"lodash.reduce": "^4.4.0",
|
||||
"lodash.reject": "^4.4.0",
|
||||
"lodash.some": "^4.4.0"
|
||||
}
|
||||
},
|
||||
"css-select": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
|
||||
"integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
|
||||
"requires": {
|
||||
"boolbase": "~1.0.0",
|
||||
"css-what": "2.1",
|
||||
"domutils": "1.5.1",
|
||||
"nth-check": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"css-what": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
|
||||
"integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg=="
|
||||
},
|
||||
"dom-serializer": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
|
||||
"integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==",
|
||||
"requires": {
|
||||
"domelementtype": "^1.3.0",
|
||||
"entities": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"domelementtype": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
|
||||
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
|
||||
},
|
||||
"domhandler": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
|
||||
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
|
||||
"requires": {
|
||||
"domelementtype": "1"
|
||||
}
|
||||
},
|
||||
"domutils": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
|
||||
"integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
|
||||
"requires": {
|
||||
"dom-serializer": "0",
|
||||
"domelementtype": "1"
|
||||
}
|
||||
},
|
||||
"entities": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
|
||||
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
|
||||
},
|
||||
"html-entities": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz",
|
||||
"integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA=="
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
|
||||
"integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
|
||||
"requires": {
|
||||
"domelementtype": "^1.3.1",
|
||||
"domhandler": "^2.3.0",
|
||||
"domutils": "^1.5.1",
|
||||
"entities": "^1.1.1",
|
||||
"inherits": "^2.0.1",
|
||||
"readable-stream": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"lodash.assignin": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz",
|
||||
"integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI="
|
||||
},
|
||||
"lodash.bind": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz",
|
||||
"integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU="
|
||||
},
|
||||
"lodash.defaults": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||
"integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw="
|
||||
},
|
||||
"lodash.filter": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz",
|
||||
"integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4="
|
||||
},
|
||||
"lodash.flatten": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
|
||||
"integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8="
|
||||
},
|
||||
"lodash.foreach": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
|
||||
"integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM="
|
||||
},
|
||||
"lodash.map": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz",
|
||||
"integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM="
|
||||
},
|
||||
"lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
|
||||
},
|
||||
"lodash.pick": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
|
||||
"integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM="
|
||||
},
|
||||
"lodash.reduce": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz",
|
||||
"integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs="
|
||||
},
|
||||
"lodash.reject": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz",
|
||||
"integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU="
|
||||
},
|
||||
"lodash.some": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz",
|
||||
"integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0="
|
||||
},
|
||||
"nth-check": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
|
||||
"integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
|
||||
"requires": {
|
||||
"boolbase": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
}
|
||||
}
|
||||
}
|
||||
12
vendor/cxx/book/package.json
vendored
Normal file
12
vendor/cxx/book/package.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "cxx-book-build",
|
||||
"version": "0.0.0",
|
||||
"main": "build.js",
|
||||
"dependencies": {
|
||||
"cheerio": "^0.22.0",
|
||||
"html-entities": "^1.3.1"
|
||||
},
|
||||
"prettier": {
|
||||
"singleQuote": true
|
||||
}
|
||||
}
|
||||
5
vendor/cxx/book/src/404.md
vendored
Normal file
5
vendor/cxx/book/src/404.md
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
### Whoops, this page doesn’t exist :-(
|
||||
|
||||
<br>
|
||||
|
||||
<img src="https://www.rust-lang.org/static/images/ferris-error.png" alt="ferris" width="325">
|
||||
37
vendor/cxx/book/src/SUMMARY.md
vendored
Normal file
37
vendor/cxx/book/src/SUMMARY.md
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# Summary
|
||||
|
||||
- [Rust ❤️ C++](index.md)
|
||||
|
||||
- [Core concepts](concepts.md)
|
||||
|
||||
- [Tutorial](tutorial.md)
|
||||
|
||||
- [Other Rust–C++ interop tools](context.md)
|
||||
|
||||
- [Multi-language build system options](building.md)
|
||||
- [Cargo](build/cargo.md)
|
||||
- [Bazel](build/bazel.md)
|
||||
- [CMake](build/cmake.md)
|
||||
- [More...](build/other.md)
|
||||
|
||||
- [Reference: the bridge module](reference.md)
|
||||
- [extern "Rust"](extern-rust.md)
|
||||
- [extern "C++"](extern-c++.md)
|
||||
- [Shared types](shared.md)
|
||||
- [Attributes](attributes.md)
|
||||
- [Async functions](async.md)
|
||||
- [Error handling](binding/result.md)
|
||||
|
||||
- [Reference: built-in bindings](bindings.md)
|
||||
- [String — rust::String](binding/string.md)
|
||||
- [&str — rust::Str](binding/str.md)
|
||||
- [&[T], &mut [T] — rust::Slice\<T\>](binding/slice.md)
|
||||
- [CxxString — std::string](binding/cxxstring.md)
|
||||
- [Box\<T\> — rust::Box\<T\>](binding/box.md)
|
||||
- [UniquePtr\<T\> — std::unique\_ptr\<T\>](binding/uniqueptr.md)
|
||||
- [SharedPtr\<T\> — std::shared\_ptr\<T\>](binding/sharedptr.md)
|
||||
- [Vec\<T\> — rust::Vec\<T\>](binding/vec.md)
|
||||
- [CxxVector\<T\> — std::vector\<T\>](binding/cxxvector.md)
|
||||
- [*mut T, *const T raw pointers](binding/rawptr.md)
|
||||
- [Function pointers](binding/fn.md)
|
||||
- [Result\<T\>](binding/result.md)
|
||||
86
vendor/cxx/book/src/async.md
vendored
Normal file
86
vendor/cxx/book/src/async.md
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
{{#title Async functions — Rust ♡ C++}}
|
||||
# Async functions
|
||||
|
||||
Direct FFI of async functions is absolutely in scope for CXX (on C++20 and up)
|
||||
but is not implemented yet in the current release. We are aiming for an
|
||||
implementation that is as easy as:
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
unsafe extern "C++" {
|
||||
async fn doThing(arg: Arg) -> Ret;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```cpp,hidelines
|
||||
rust::Future<Ret> doThing(Arg arg) {
|
||||
auto v1 = co_await f();
|
||||
auto v2 = co_await g(arg);
|
||||
co_return v1 + v2;
|
||||
}
|
||||
```
|
||||
|
||||
## Workaround
|
||||
|
||||
For now the recommended approach is to handle the return codepath over a oneshot
|
||||
channel (such as [`futures::channel::oneshot`]) represented in an opaque Rust
|
||||
type on the FFI.
|
||||
|
||||
[`futures::channel::oneshot`]: https://docs.rs/futures/0.3.8/futures/channel/oneshot/index.html
|
||||
|
||||
```rust,noplayground
|
||||
// bridge.rs
|
||||
|
||||
use futures::channel::oneshot;
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
type DoThingContext;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("path/to/bridge_shim.h");
|
||||
|
||||
fn shim_doThing(
|
||||
arg: Arg,
|
||||
done: fn(Box<DoThingContext>, ret: Ret),
|
||||
ctx: Box<DoThingContext>,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
struct DoThingContext(oneshot::Sender<Ret>);
|
||||
|
||||
pub async fn do_thing(arg: Arg) -> Ret {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let context = Box::new(DoThingContext(tx));
|
||||
|
||||
ffi::shim_doThing(
|
||||
arg,
|
||||
|context, ret| { let _ = context.0.send(ret); },
|
||||
context,
|
||||
);
|
||||
|
||||
rx.await.unwrap()
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// bridge_shim.cc
|
||||
|
||||
#include "path/to/bridge.rs.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
void shim_doThing(
|
||||
Arg arg,
|
||||
rust::Fn<void(rust::Box<DoThingContext> ctx, Ret ret)> done,
|
||||
rust::Box<DoThingContext> ctx) noexcept {
|
||||
doThing(arg)
|
||||
.then([done, ctx(std::move(ctx))](auto &&res) mutable {
|
||||
(*done)(std::move(ctx), std::move(res));
|
||||
});
|
||||
}
|
||||
```
|
||||
75
vendor/cxx/book/src/attributes.md
vendored
Normal file
75
vendor/cxx/book/src/attributes.md
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
{{#title Attributes — Rust ♡ C++}}
|
||||
# Attributes
|
||||
|
||||
## namespace
|
||||
|
||||
The top-level cxx::bridge attribute macro takes an optional `namespace` argument
|
||||
to control the C++ namespace into which to emit extern Rust items and the
|
||||
namespace in which to expect to find the extern C++ items.
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge(namespace = "path::of::my::company")]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
type MyType; // emitted to path::of::my::company::MyType
|
||||
}
|
||||
|
||||
extern "C++" {
|
||||
type TheirType; // refers to path::of::my::company::TheirType
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Additionally, a `#[namespace = "..."]` attribute may be used inside the bridge
|
||||
module on any extern block or individual item. An item will inherit the
|
||||
namespace specified on its surrounding extern block if any, otherwise the
|
||||
namespace specified with the top level cxx::bridge attribute if any, otherwise
|
||||
the global namespace.
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge(namespace = "third_priority")]
|
||||
mod ffi {
|
||||
#[namespace = "second_priority"]
|
||||
extern "Rust" {
|
||||
fn f();
|
||||
|
||||
#[namespace = "first_priority"]
|
||||
fn g();
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
fn h();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The above would result in functions `::second_priority::f`,
|
||||
`::first_priority::g`, `::third_priority::h`.
|
||||
|
||||
## rust\_name, cxx\_name
|
||||
|
||||
Sometimes you want the Rust name of a function or type to differ from its C++
|
||||
name. Importantly, this enables binding multiple overloads of the same C++
|
||||
function name using distinct Rust names.
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
unsafe extern "C++" {
|
||||
#[rust_name = "i32_overloaded_function"]
|
||||
fn cOverloadedFunction(x: i32) -> String;
|
||||
#[rust_name = "str_overloaded_function"]
|
||||
fn cOverloadedFunction(x: &str) -> String;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `#[rust_name = "..."]` attribute replaces the name that Rust should use for
|
||||
this function, and an analogous `#[cxx_name = "..."]` attribute replaces the
|
||||
name that C++ should use.
|
||||
|
||||
Either of the two attributes may be used on extern "Rust" as well as extern
|
||||
"C++" functions, according to which one you find clearer in context.
|
||||
|
||||
The same attribute works for renaming functions, opaque types, shared
|
||||
structs and enums, and enum variants.
|
||||
120
vendor/cxx/book/src/binding/box.md
vendored
Normal file
120
vendor/cxx/book/src/binding/box.md
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
{{#title rust::Box<T> — Rust ♡ C++}}
|
||||
# rust::Box\<T\>
|
||||
|
||||
### Public API:
|
||||
|
||||
```cpp,hidelines
|
||||
// rust/cxx.h
|
||||
#
|
||||
# #include <type_traits>
|
||||
#
|
||||
# namespace rust {
|
||||
|
||||
template <typename T>
|
||||
class Box final {
|
||||
public:
|
||||
using element_type = T;
|
||||
using const_pointer =
|
||||
typename std::add_pointer<typename std::add_const<T>::type>::type;
|
||||
using pointer = typename std::add_pointer<T>::type;
|
||||
|
||||
Box(Box &&) noexcept;
|
||||
~Box() noexcept;
|
||||
|
||||
explicit Box(const T &);
|
||||
explicit Box(T &&);
|
||||
|
||||
Box &operator=(Box &&) noexcept;
|
||||
|
||||
const T *operator->() const noexcept;
|
||||
const T &operator*() const noexcept;
|
||||
T *operator->() noexcept;
|
||||
T &operator*() noexcept;
|
||||
|
||||
template <typename... Fields>
|
||||
static Box in_place(Fields &&...);
|
||||
|
||||
void swap(Box &) noexcept;
|
||||
|
||||
// Important: requires that `raw` came from an into_raw call. Do not
|
||||
// pass a pointer from `new` or any other source.
|
||||
static Box from_raw(T *) noexcept;
|
||||
|
||||
T *into_raw() noexcept;
|
||||
};
|
||||
#
|
||||
# } // namespace rust
|
||||
```
|
||||
|
||||
### Restrictions:
|
||||
|
||||
Box\<T\> does not support T being an opaque C++ type. You should use
|
||||
[UniquePtr\<T\>](uniqueptr.md) or [SharedPtr\<T\>](sharedptr.md) instead for
|
||||
transferring ownership of opaque C++ types on the language boundary.
|
||||
|
||||
If T is an opaque Rust type, the Rust type is required to be [Sized] i.e. size
|
||||
known at compile time. In the future we may introduce support for dynamically
|
||||
sized opaque Rust types.
|
||||
|
||||
[Sized]: https://doc.rust-lang.org/std/marker/trait.Sized.html
|
||||
|
||||
## Example
|
||||
|
||||
This program uses a Box to pass ownership of some opaque piece of Rust state
|
||||
over to C++ and then back to a Rust callback, which is a useful pattern for
|
||||
implementing [async functions over FFI](../async.md).
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
type File;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("example/include/example.h");
|
||||
|
||||
fn f(
|
||||
callback: fn(Box<File>, fst: &str, snd: &str),
|
||||
out: Box<File>,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct File(std::fs::File);
|
||||
|
||||
fn main() {
|
||||
let out = std::fs::File::create("example.log").unwrap();
|
||||
|
||||
ffi::f(
|
||||
|mut out, fst, snd| { let _ = write!(out.0, "{}{}\n", fst, snd); },
|
||||
Box::new(File(out)),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// include/example.h
|
||||
|
||||
#pragma once
|
||||
#include "example/src/main.rs.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
void f(rust::Fn<void(rust::Box<File>, rust::Str, rust::Str)> callback,
|
||||
rust::Box<File> out);
|
||||
```
|
||||
|
||||
```cpp
|
||||
// include/example.cc
|
||||
|
||||
#include "example/include/example.h"
|
||||
|
||||
void f(rust::Fn<void(rust::Box<File>, rust::Str, rust::Str)> callback,
|
||||
rust::Box<File> out) {
|
||||
callback(std::move(out), "fearless", "concurrency");
|
||||
}
|
||||
```
|
||||
140
vendor/cxx/book/src/binding/cxxstring.md
vendored
Normal file
140
vendor/cxx/book/src/binding/cxxstring.md
vendored
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
{{#title std::string — Rust ♡ C++}}
|
||||
# std::string
|
||||
|
||||
The Rust binding of std::string is called **[`CxxString`]**. See the link for
|
||||
documentation of the Rust API.
|
||||
|
||||
[`CxxString`]: https://docs.rs/cxx/*/cxx/struct.CxxString.html
|
||||
|
||||
### Restrictions:
|
||||
|
||||
Rust code can never obtain a CxxString by value. C++'s string requires a move
|
||||
constructor and may hold internal pointers, which is not compatible with Rust's
|
||||
move behavior. Instead in Rust code we will only ever look at a CxxString
|
||||
through a reference or smart pointer, as in &CxxString or Pin\<&mut CxxString\>
|
||||
or UniquePtr\<CxxString\>.
|
||||
|
||||
In order to construct a CxxString on the stack from Rust, you must use the
|
||||
[`let_cxx_string!`] macro which will pin the string properly. The code below
|
||||
uses this in one place, and the link covers the syntax.
|
||||
|
||||
[`let_cxx_string!`]: https://docs.rs/cxx/*/cxx/macro.let_cxx_string.html
|
||||
|
||||
## Example
|
||||
|
||||
This example uses C++17's std::variant to build a toy JSON type. JSON can hold
|
||||
various types including strings, and JSON's object type is a map with string
|
||||
keys. The example demonstrates Rust indexing into one of those maps.
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
|
||||
use cxx::let_cxx_string;
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
unsafe extern "C++" {
|
||||
include!("example/include/json.h");
|
||||
|
||||
#[cxx_name = "json"]
|
||||
type Json;
|
||||
#[cxx_name = "object"]
|
||||
type Object;
|
||||
|
||||
fn isNull(self: &Json) -> bool;
|
||||
fn isNumber(self: &Json) -> bool;
|
||||
fn isString(self: &Json) -> bool;
|
||||
fn isArray(self: &Json) -> bool;
|
||||
fn isObject(self: &Json) -> bool;
|
||||
|
||||
fn getNumber(self: &Json) -> f64;
|
||||
fn getString(self: &Json) -> &CxxString;
|
||||
fn getArray(self: &Json) -> &CxxVector<Json>;
|
||||
fn getObject(self: &Json) -> &Object;
|
||||
|
||||
#[cxx_name = "at"]
|
||||
fn get<'a>(self: &'a Object, key: &CxxString) -> &'a Json;
|
||||
|
||||
fn load_config() -> UniquePtr<Json>;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let config = ffi::load_config();
|
||||
|
||||
let_cxx_string!(key = "name");
|
||||
println!("{}", config.getObject().get(&key).getString());
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// include/json.h
|
||||
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
class json final {
|
||||
public:
|
||||
static const json null;
|
||||
using number = double;
|
||||
using string = std::string;
|
||||
using array = std::vector<json>;
|
||||
using object = std::map<string, json>;
|
||||
|
||||
json() noexcept = default;
|
||||
json(const json &) = default;
|
||||
json(json &&) = default;
|
||||
template <typename... T>
|
||||
json(T &&...value) : value(std::forward<T>(value)...) {}
|
||||
|
||||
bool isNull() const;
|
||||
bool isNumber() const;
|
||||
bool isString() const;
|
||||
bool isArray() const;
|
||||
bool isObject() const;
|
||||
|
||||
number getNumber() const;
|
||||
const string &getString() const;
|
||||
const array &getArray() const;
|
||||
const object &getObject() const;
|
||||
|
||||
private:
|
||||
std::variant<std::monostate, number, string, array, object> value;
|
||||
};
|
||||
|
||||
using object = json::object;
|
||||
|
||||
std::unique_ptr<json> load_config();
|
||||
```
|
||||
|
||||
```cpp
|
||||
// include/json.cc
|
||||
|
||||
#include "example/include/json.h"
|
||||
#include <initializer_list>
|
||||
#include <utility>
|
||||
|
||||
const json json::null{};
|
||||
bool json::isNull() const { return std::holds_alternative<std::monostate>(value); }
|
||||
bool json::isNumber() const { return std::holds_alternative<number>(value); }
|
||||
bool json::isString() const { return std::holds_alternative<string>(value); }
|
||||
bool json::isArray() const { return std::holds_alternative<array>(value); }
|
||||
bool json::isObject() const { return std::holds_alternative<object>(value); }
|
||||
json::number json::getNumber() const { return std::get<number>(value); }
|
||||
const json::string &json::getString() const { return std::get<string>(value); }
|
||||
const json::array &json::getArray() const { return std::get<array>(value); }
|
||||
const json::object &json::getObject() const { return std::get<object>(value); }
|
||||
|
||||
std::unique_ptr<json> load_config() {
|
||||
return std::make_unique<json>(
|
||||
std::in_place_type<json::object>,
|
||||
std::initializer_list<std::pair<const std::string, json>>{
|
||||
{"name", "cxx-example"},
|
||||
{"edition", 2018.},
|
||||
{"repository", json::null}});
|
||||
}
|
||||
```
|
||||
62
vendor/cxx/book/src/binding/cxxvector.md
vendored
Normal file
62
vendor/cxx/book/src/binding/cxxvector.md
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
{{#title std::vector<T> — Rust ♡ C++}}
|
||||
# std::vector\<T\>
|
||||
|
||||
The Rust binding of std::vector\<T\> is called **[`CxxVector<T>`]**. See the
|
||||
link for documentation of the Rust API.
|
||||
|
||||
[`CxxVector<T>`]: https://docs.rs/cxx/*/cxx/struct.CxxVector.html
|
||||
|
||||
### Restrictions:
|
||||
|
||||
Rust code can never obtain a CxxVector by value. Instead in Rust code we will
|
||||
only ever look at a vector behind a reference or smart pointer, as in
|
||||
&CxxVector\<T\> or UniquePtr\<CxxVector\<T\>\>.
|
||||
|
||||
CxxVector\<T\> does not support T being an opaque Rust type. You should use a
|
||||
Vec\<T\> (C++ rust::Vec\<T\>) instead for collections of opaque Rust types on
|
||||
the language boundary.
|
||||
|
||||
## Example
|
||||
|
||||
This program involves Rust code converting a `CxxVector<CxxString>` (i.e.
|
||||
`std::vector<std::string>`) into a Rust `Vec<String>`.
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
|
||||
#![no_main] // main defined in C++ by main.cc
|
||||
|
||||
use cxx::{CxxString, CxxVector};
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
fn f(vec: &CxxVector<CxxString>);
|
||||
}
|
||||
}
|
||||
|
||||
fn f(vec: &CxxVector<CxxString>) {
|
||||
let vec: Vec<String> = vec
|
||||
.iter()
|
||||
.map(|s| s.to_string_lossy().into_owned())
|
||||
.collect();
|
||||
g(&vec);
|
||||
}
|
||||
|
||||
fn g(vec: &[String]) {
|
||||
println!("{:?}", vec);
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// src/main.cc
|
||||
|
||||
#include "example/src/main.rs.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
int main() {
|
||||
std::vector<std::string> vec{"fearless", "concurrency"};
|
||||
f(vec);
|
||||
}
|
||||
```
|
||||
34
vendor/cxx/book/src/binding/fn.md
vendored
Normal file
34
vendor/cxx/book/src/binding/fn.md
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
{{#title Function pointers — Rust ♡ C++}}
|
||||
# Function pointers
|
||||
|
||||
### Public API:
|
||||
|
||||
```cpp,hidelines
|
||||
// rust/cxx.h
|
||||
#
|
||||
# namespace rust {
|
||||
|
||||
template <typename Signature>
|
||||
class Fn;
|
||||
|
||||
template <typename Ret, typename... Args>
|
||||
class Fn<Ret(Args...)> final {
|
||||
public:
|
||||
Ret operator()(Args... args) const noexcept;
|
||||
Fn operator*() const noexcept;
|
||||
};
|
||||
#
|
||||
# } // namespace rust
|
||||
```
|
||||
|
||||
### Restrictions:
|
||||
|
||||
Function pointers with a Result return type are not implemented yet.
|
||||
|
||||
Passing a function pointer from C++ to Rust is not implemented yet, only from
|
||||
Rust to an `extern "C++"` function is implemented.
|
||||
|
||||
## Example
|
||||
|
||||
Function pointers are commonly useful for implementing [async functions over
|
||||
FFI](../async.md). See the example code on that page.
|
||||
100
vendor/cxx/book/src/binding/rawptr.md
vendored
Normal file
100
vendor/cxx/book/src/binding/rawptr.md
vendored
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
{{#title *mut T, *const T — Rust ♡ C++}}
|
||||
# *mut T, *const T
|
||||
|
||||
Generally you should use references (`&mut T`, `&T`) or [std::unique_ptr\<T\>]
|
||||
where possible over raw pointers, but raw pointers are available too as an
|
||||
unsafe fallback option.
|
||||
|
||||
[std::unique_ptr\<T\>]: uniqueptr.md
|
||||
|
||||
### Restrictions:
|
||||
|
||||
Extern functions and function pointers taking a raw pointer as an argument must
|
||||
be declared `unsafe fn` i.e. unsafe to call. The same does not apply to
|
||||
functions which only *return* a raw pointer, though presumably doing anything
|
||||
useful with the returned pointer is going to involve unsafe code elsewhere
|
||||
anyway.
|
||||
|
||||
## Example
|
||||
|
||||
This example illustrates making a Rust call to a canonical C-style `main`
|
||||
signature involving `char *argv[]`.
|
||||
|
||||
```cpp
|
||||
// include/args.h
|
||||
|
||||
#pragma once
|
||||
|
||||
void parseArgs(int argc, char *argv[]);
|
||||
```
|
||||
|
||||
```cpp
|
||||
// src/args.cc
|
||||
|
||||
#include "example/include/args.h"
|
||||
#include <iostream>
|
||||
|
||||
void parseArgs(int argc, char *argv[]) {
|
||||
std::cout << argc << std::endl;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
std::cout << '"' << argv[i] << '"' << std::endl;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
|
||||
use std::env;
|
||||
use std::ffi::CString;
|
||||
use std::os::raw::c_char;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::ptr;
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "C++" {
|
||||
include!("example/include/args.h");
|
||||
|
||||
unsafe fn parseArgs(argc: i32, argv: *mut *mut c_char);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Convert from OsString to nul-terminated CString, truncating each argument
|
||||
// at the first inner nul byte if present.
|
||||
let args: Vec<CString> = env::args_os()
|
||||
.map(|os_str| {
|
||||
let bytes = os_str.as_bytes();
|
||||
CString::new(bytes).unwrap_or_else(|nul_error| {
|
||||
let nul_position = nul_error.nul_position();
|
||||
let mut bytes = nul_error.into_vec();
|
||||
bytes.truncate(nul_position);
|
||||
CString::new(bytes).unwrap()
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Convert from Vec<CString> of owned strings to Vec<*mut c_char> of
|
||||
// borrowed string pointers.
|
||||
//
|
||||
// Once extern type stabilizes (https://github.com/rust-lang/rust/issues/43467)
|
||||
// and https://internals.rust-lang.org/t/pre-rfc-make-cstr-a-thin-pointer/6258
|
||||
// is implemented, and CStr pointers become thin, we can sidestep this step
|
||||
// by accumulating the args as Vec<Box<CStr>> up front, then simply casting
|
||||
// from *mut [Box<CStr>] to *mut [*mut CStr] to *mut *mut c_char.
|
||||
let argc = args.len();
|
||||
let mut argv: Vec<*mut c_char> = Vec::with_capacity(argc + 1);
|
||||
for arg in &args {
|
||||
argv.push(arg.as_ptr() as *mut c_char);
|
||||
}
|
||||
argv.push(ptr::null_mut()); // Nul terminator.
|
||||
|
||||
unsafe {
|
||||
ffi::parseArgs(argc as i32, argv.as_mut_ptr());
|
||||
}
|
||||
|
||||
// The CStrings go out of scope here. C function must not have held on to
|
||||
// the pointers beyond this point.
|
||||
}
|
||||
```
|
||||
148
vendor/cxx/book/src/binding/result.md
vendored
Normal file
148
vendor/cxx/book/src/binding/result.md
vendored
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
{{#title Result<T> — Rust ♡ C++}}
|
||||
# Result\<T\>
|
||||
|
||||
Result\<T\> is allowed as the return type of an extern function in either
|
||||
direction. Its behavior is to translate to/from C++ exceptions. If your codebase
|
||||
does not use C++ exceptions, or prefers to represent fallibility using something
|
||||
like outcome\<T\>, leaf::result\<T\>, StatusOr\<T\>, etc then you'll need to
|
||||
handle the translation of those to Rust Result\<T\> using your own shims for
|
||||
now. Better support for this is planned.
|
||||
|
||||
If an exception is thrown from an `extern "C++"` function that is *not* declared
|
||||
by the CXX bridge to return Result, the program calls C++'s `std::terminate`.
|
||||
The behavior is equivalent to the same exception being thrown through a
|
||||
`noexcept` C++ function.
|
||||
|
||||
If a panic occurs in *any* `extern "Rust"` function, regardless of whether it is
|
||||
declared by the CXX bridge to return Result, a message is logged and the program
|
||||
calls Rust's `std::process::abort`.
|
||||
|
||||
## Returning Result from Rust to C++
|
||||
|
||||
An `extern "Rust"` function returning a Result turns into a `throw` in C++ if
|
||||
the Rust side produces an error.
|
||||
|
||||
Note that the return type written inside of cxx::bridge must be written without
|
||||
a second type parameter. Only the Ok type is specified for the purpose of the
|
||||
FFI. The Rust *implementation* (outside of the bridge module) may pick any error
|
||||
type as long as it has a std::fmt::Display impl.
|
||||
|
||||
```rust,noplayground
|
||||
# use std::io;
|
||||
#
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
fn fallible1(depth: usize) -> Result<String>;
|
||||
fn fallible2() -> Result<()>;
|
||||
}
|
||||
}
|
||||
|
||||
fn fallible1(depth: usize) -> anyhow::Result<String> {
|
||||
if depth == 0 {
|
||||
return Err(anyhow::Error::msg("fallible1 requires depth > 0"));
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
fn fallible2() -> Result<(), io::Error> {
|
||||
...
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
The exception that gets thrown by CXX on the C++ side is always of type
|
||||
`rust::Error` and has the following C++ public API. The `what()` member function
|
||||
gives the error message according to the Rust error's std::fmt::Display impl.
|
||||
|
||||
```cpp,hidelines
|
||||
// rust/cxx.h
|
||||
#
|
||||
# namespace rust {
|
||||
|
||||
class Error final : public std::exception {
|
||||
public:
|
||||
Error(const Error &);
|
||||
Error(Error &&) noexcept;
|
||||
~Error() noexcept;
|
||||
|
||||
Error &operator=(const Error &);
|
||||
Error &operator=(Error &&) noexcept;
|
||||
|
||||
const char *what() const noexcept override;
|
||||
};
|
||||
#
|
||||
# } // namespace rust
|
||||
```
|
||||
|
||||
## Returning Result from C++ to Rust
|
||||
|
||||
An `extern "C++"` function returning a Result turns into a `catch` in C++ that
|
||||
converts the exception into an Err for Rust.
|
||||
|
||||
Note that the return type written inside of cxx::bridge must be written without
|
||||
a second type parameter. Only the Ok type is specified for the purpose of the
|
||||
FFI. The resulting error type created by CXX when an `extern "C++"` function
|
||||
throws will always be of type **[`cxx::Exception`]**.
|
||||
|
||||
[`cxx::Exception`]: https://docs.rs/cxx/*/cxx/struct.Exception.html
|
||||
|
||||
```rust,noplayground
|
||||
# use std::process;
|
||||
#
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
unsafe extern "C++" {
|
||||
include!("example/include/example.h");
|
||||
fn fallible1(depth: usize) -> Result<String>;
|
||||
fn fallible2() -> Result<()>;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if let Err(err) = ffi::fallible1(99) {
|
||||
eprintln!("Error: {}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The specific set of caught exceptions and the conversion to error message are
|
||||
both customizable. The way you do this is by defining a template function
|
||||
`rust::behavior::trycatch` with a suitable signature inside any one of the
|
||||
headers `include!`'d by your cxx::bridge.
|
||||
|
||||
The template signature is required to be:
|
||||
|
||||
```cpp,hidelines
|
||||
namespace rust {
|
||||
namespace behavior {
|
||||
|
||||
template <typename Try, typename Fail>
|
||||
static void trycatch(Try &&func, Fail &&fail) noexcept;
|
||||
|
||||
} // namespace behavior
|
||||
} // namespace rust
|
||||
```
|
||||
|
||||
The default `trycatch` used by CXX if you have not provided your own is the
|
||||
following. You must follow the same pattern: invoke `func` with no arguments,
|
||||
catch whatever exception(s) you want, and invoke `fail` with the error message
|
||||
you'd like for the Rust error to have.
|
||||
|
||||
```cpp,hidelines
|
||||
# #include <exception>
|
||||
#
|
||||
# namespace rust {
|
||||
# namespace behavior {
|
||||
#
|
||||
template <typename Try, typename Fail>
|
||||
static void trycatch(Try &&func, Fail &&fail) noexcept try {
|
||||
func();
|
||||
} catch (const std::exception &e) {
|
||||
fail(e.what());
|
||||
}
|
||||
#
|
||||
# } // namespace behavior
|
||||
# } // namespace rust
|
||||
```
|
||||
80
vendor/cxx/book/src/binding/sharedptr.md
vendored
Normal file
80
vendor/cxx/book/src/binding/sharedptr.md
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
{{#title std::shared_ptr<T> — Rust ♡ C++}}
|
||||
# std::shared\_ptr\<T\>
|
||||
|
||||
The Rust binding of std::shared\_ptr\<T\> is called **[`SharedPtr<T>`]**. See
|
||||
the link for documentation of the Rust API.
|
||||
|
||||
[`SharedPtr<T>`]: https://docs.rs/cxx/*/cxx/struct.SharedPtr.html
|
||||
|
||||
### Restrictions:
|
||||
|
||||
SharedPtr\<T\> does not support T being an opaque Rust type. You should use a
|
||||
Box\<T\> (C++ [rust::Box\<T\>](box.md)) instead for transferring ownership of
|
||||
opaque Rust types on the language boundary.
|
||||
|
||||
## Example
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
unsafe extern "C++" {
|
||||
include!("example/include/example.h");
|
||||
|
||||
type Object;
|
||||
|
||||
fn create_shared_ptr() -> SharedPtr<Object>;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let ptr1 = ffi::create_shared_ptr();
|
||||
|
||||
{
|
||||
// Create a second shared_ptr holding shared ownership of the same
|
||||
// object. There is still only one Object but two SharedPtr<Object>.
|
||||
// Both pointers point to the same object on the heap.
|
||||
let ptr2 = ptr1.clone();
|
||||
assert!(ptr::eq(ptr1.deref(), ptr2.deref()));
|
||||
|
||||
// ptr2 goes out of scope, but Object is not destroyed yet.
|
||||
}
|
||||
|
||||
println!("say goodbye to Object");
|
||||
|
||||
// ptr1 goes out of scope and Object is destroyed.
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// include/example.h
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
|
||||
class Object {
|
||||
public:
|
||||
Object();
|
||||
~Object();
|
||||
};
|
||||
|
||||
std::shared_ptr<Object> create_shared_ptr();
|
||||
```
|
||||
|
||||
```cpp
|
||||
// src/example.cc
|
||||
|
||||
#include "example/include/example.h"
|
||||
#include <iostream>
|
||||
|
||||
Object::Object() { std::cout << "construct Object" << std::endl; }
|
||||
Object::~Object() { std::cout << "~Object" << std::endl; }
|
||||
|
||||
std::shared_ptr<Object> create_shared_ptr() {
|
||||
return std::make_shared<Object>();
|
||||
}
|
||||
```
|
||||
171
vendor/cxx/book/src/binding/slice.md
vendored
Normal file
171
vendor/cxx/book/src/binding/slice.md
vendored
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
{{#title rust::Slice<T> — Rust ♡ C++}}
|
||||
# rust::Slice\<const T\>, rust::Slice\<T\>
|
||||
|
||||
- Rust `&[T]` is written `rust::Slice<const T>` in C++
|
||||
- Rust `&mut [T]` is written `rust::Slice<T>` in C++
|
||||
|
||||
### Public API:
|
||||
|
||||
```cpp,hidelines
|
||||
// rust/cxx.h
|
||||
#
|
||||
# #include <iterator>
|
||||
# #include <type_traits>
|
||||
#
|
||||
# namespace rust {
|
||||
|
||||
template <typename T>
|
||||
class Slice final {
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
Slice() noexcept;
|
||||
Slice(const Slice<T> &) noexcept;
|
||||
Slice(T *, size_t count) noexcept;
|
||||
|
||||
Slice &operator=(Slice<T> &&) noexcept;
|
||||
Slice &operator=(const Slice<T> &) noexcept
|
||||
requires std::is_const_v<T>;
|
||||
|
||||
T *data() const noexcept;
|
||||
size_t size() const noexcept;
|
||||
size_t length() const noexcept;
|
||||
bool empty() const noexcept;
|
||||
|
||||
T &operator[](size_t n) const noexcept;
|
||||
T &at(size_t n) const;
|
||||
T &front() const noexcept;
|
||||
T &back() const noexcept;
|
||||
|
||||
class iterator;
|
||||
iterator begin() const noexcept;
|
||||
iterator end() const noexcept;
|
||||
|
||||
void swap(Slice &) noexcept;
|
||||
};
|
||||
#
|
||||
# template <typename T>
|
||||
# class Slice<T>::iterator final {
|
||||
# public:
|
||||
# using iterator_category = std::random_access_iterator_tag;
|
||||
# using value_type = T;
|
||||
# using pointer = T *;
|
||||
# using reference = T &;
|
||||
#
|
||||
# T &operator*() const noexcept;
|
||||
# T *operator->() const noexcept;
|
||||
# T &operator[](ptrdiff_t) const noexcept;
|
||||
#
|
||||
# iterator &operator++() noexcept;
|
||||
# iterator operator++(int) noexcept;
|
||||
# iterator &operator--() noexcept;
|
||||
# iterator operator--(int) noexcept;
|
||||
#
|
||||
# iterator &operator+=(ptrdiff_t) noexcept;
|
||||
# iterator &operator-=(ptrdiff_t) noexcept;
|
||||
# iterator operator+(ptrdiff_t) const noexcept;
|
||||
# iterator operator-(ptrdiff_t) const noexcept;
|
||||
# ptrdiff_t operator-(const iterator &) const noexcept;
|
||||
#
|
||||
# bool operator==(const iterator &) const noexcept;
|
||||
# bool operator!=(const iterator &) const noexcept;
|
||||
# bool operator<(const iterator &) const noexcept;
|
||||
# bool operator>(const iterator &) const noexcept;
|
||||
# bool operator<=(const iterator &) const noexcept;
|
||||
# bool operator>=(const iterator &) const noexcept;
|
||||
# };
|
||||
#
|
||||
# } // namespace rust
|
||||
```
|
||||
|
||||
### Restrictions:
|
||||
|
||||
T must not be an opaque Rust type or opaque C++ type. Support for opaque Rust
|
||||
types in slices is coming.
|
||||
|
||||
Allowed as function argument or return value. Not supported in shared structs.
|
||||
|
||||
Only rust::Slice\<const T\> is copy-assignable, not rust::Slice\<T\>. (Both are
|
||||
move-assignable.) You'll need to write std::move occasionally as a reminder that
|
||||
accidentally exposing overlapping &mut \[T\] to Rust is UB.
|
||||
|
||||
## Example
|
||||
|
||||
This example is a C++ program that constructs a slice containing JSON data (by
|
||||
reading from stdin, but it could be from anywhere), then calls into Rust to
|
||||
pretty-print that JSON data into a std::string via the [serde_json] and
|
||||
[serde_transcode] crates.
|
||||
|
||||
[serde_json]: https://github.com/serde-rs/json
|
||||
[serde_transcode]: https://github.com/sfackler/serde-transcode
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
|
||||
#![no_main] // main defined in C++ by main.cc
|
||||
|
||||
use cxx::CxxString;
|
||||
use std::io::{self, Write};
|
||||
use std::pin::Pin;
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
fn prettify_json(input: &[u8], output: Pin<&mut CxxString>) -> Result<()>;
|
||||
}
|
||||
}
|
||||
|
||||
struct WriteToCxxString<'a>(Pin<&'a mut CxxString>);
|
||||
|
||||
impl<'a> Write for WriteToCxxString<'a> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.as_mut().push_bytes(buf);
|
||||
Ok(buf.len())
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn prettify_json(input: &[u8], output: Pin<&mut CxxString>) -> serde_json::Result<()> {
|
||||
let writer = WriteToCxxString(output);
|
||||
let mut deserializer = serde_json::Deserializer::from_slice(input);
|
||||
let mut serializer = serde_json::Serializer::pretty(writer);
|
||||
serde_transcode::transcode(&mut deserializer, &mut serializer)
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// src/main.cc
|
||||
|
||||
#include "example/src/main.rs.h"
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
int main() {
|
||||
// Read json from stdin.
|
||||
std::istreambuf_iterator<char> begin{std::cin}, end;
|
||||
std::vector<unsigned char> input{begin, end};
|
||||
rust::Slice<const uint8_t> slice{input.data(), input.size()};
|
||||
|
||||
// Prettify using serde_json and serde_transcode.
|
||||
std::string output;
|
||||
prettify_json(slice, output);
|
||||
|
||||
// Write to stdout.
|
||||
std::cout << output << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
Testing the example:
|
||||
|
||||
```console
|
||||
$ echo '{"fearless":"concurrency"}' | cargo run
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.02s
|
||||
Running `target/debug/example`
|
||||
{
|
||||
"fearless": "concurrency"
|
||||
}
|
||||
```
|
||||
118
vendor/cxx/book/src/binding/str.md
vendored
Normal file
118
vendor/cxx/book/src/binding/str.md
vendored
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
{{#title rust::Str — Rust ♡ C++}}
|
||||
# rust::Str
|
||||
|
||||
### Public API:
|
||||
|
||||
```cpp,hidelines
|
||||
// rust/cxx.h
|
||||
#
|
||||
# #include <iosfwd>
|
||||
# #include <string>
|
||||
#
|
||||
# namespace rust {
|
||||
|
||||
class Str final {
|
||||
public:
|
||||
Str() noexcept;
|
||||
Str(const Str &) noexcept;
|
||||
Str(const String &) noexcept;
|
||||
|
||||
// Throws std::invalid_argument if not utf-8.
|
||||
Str(const std::string &);
|
||||
Str(const char *);
|
||||
Str(const char *, size_t);
|
||||
|
||||
Str &operator=(const Str &) noexcept;
|
||||
|
||||
explicit operator std::string() const;
|
||||
|
||||
// Note: no null terminator.
|
||||
const char *data() const noexcept;
|
||||
size_t size() const noexcept;
|
||||
size_t length() const noexcept;
|
||||
bool empty() const noexcept;
|
||||
|
||||
using iterator = const char *;
|
||||
using const_iterator = const char *;
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
const_iterator cbegin() const noexcept;
|
||||
const_iterator cend() const noexcept;
|
||||
|
||||
bool operator==(const Str &) const noexcept;
|
||||
bool operator!=(const Str &) const noexcept;
|
||||
bool operator<(const Str &) const noexcept;
|
||||
bool operator<=(const Str &) const noexcept;
|
||||
bool operator>(const Str &) const noexcept;
|
||||
bool operator>=(const Str &) const noexcept;
|
||||
|
||||
void swap(Str &) noexcept;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &, const Str &);
|
||||
#
|
||||
# } // namespace rust
|
||||
```
|
||||
|
||||
### Notes:
|
||||
|
||||
**Be aware that rust::Str behaves like &str i.e. it is a borrow!** C++
|
||||
needs to be mindful of the lifetimes at play.
|
||||
|
||||
Just to reiterate: &str is rust::Str. Do not try to write &str as `const
|
||||
rust::Str &`. A language-level C++ reference is not able to capture the fat
|
||||
pointer nature of &str.
|
||||
|
||||
### Restrictions:
|
||||
|
||||
Allowed as function argument or return value. Not supported in shared structs
|
||||
yet. `&mut str` is not supported yet, but is also extremely obscure so this is
|
||||
fine.
|
||||
|
||||
## Example
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
fn r(greeting: &str);
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("example/include/greeting.h");
|
||||
fn c(greeting: &str);
|
||||
}
|
||||
}
|
||||
|
||||
fn r(greeting: &str) {
|
||||
println!("{}", greeting);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
ffi::c("hello from Rust");
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// include/greeting.h
|
||||
|
||||
#pragma once
|
||||
#include "example/src/main.rs.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
void c(rust::Str greeting);
|
||||
```
|
||||
|
||||
```cpp
|
||||
// src/greeting.cc
|
||||
|
||||
#include "example/include/greeting.h"
|
||||
#include <iostream>
|
||||
|
||||
void c(rust::Str greeting) {
|
||||
std::cout << greeting << std::endl;
|
||||
r("hello from C++");
|
||||
}
|
||||
```
|
||||
132
vendor/cxx/book/src/binding/string.md
vendored
Normal file
132
vendor/cxx/book/src/binding/string.md
vendored
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
{{#title rust::String — Rust ♡ C++}}
|
||||
# rust::String
|
||||
|
||||
### Public API:
|
||||
|
||||
```cpp,hidelines
|
||||
// rust/cxx.h
|
||||
#
|
||||
# #include <iosfwd>
|
||||
# #include <string>
|
||||
#
|
||||
# namespace rust {
|
||||
|
||||
class String final {
|
||||
public:
|
||||
String() noexcept;
|
||||
String(const String &) noexcept;
|
||||
String(String &&) noexcept;
|
||||
~String() noexcept;
|
||||
|
||||
// Throws std::invalid_argument if not UTF-8.
|
||||
String(const std::string &);
|
||||
String(const char *);
|
||||
String(const char *, size_t);
|
||||
|
||||
// Replaces invalid UTF-8 data with the replacement character (U+FFFD).
|
||||
static String lossy(const std::string &) noexcept;
|
||||
static String lossy(const char *) noexcept;
|
||||
static String lossy(const char *, size_t) noexcept;
|
||||
|
||||
// Throws std::invalid_argument if not UTF-16.
|
||||
String(const char16_t *);
|
||||
String(const char16_t *, size_t);
|
||||
|
||||
// Replaces invalid UTF-16 data with the replacement character (U+FFFD).
|
||||
static String lossy(const char16_t *) noexcept;
|
||||
static String lossy(const char16_t *, size_t) noexcept;
|
||||
|
||||
String &operator=(const String &) noexcept;
|
||||
String &operator=(String &&) noexcept;
|
||||
|
||||
explicit operator std::string() const;
|
||||
|
||||
// Note: no null terminator.
|
||||
const char *data() const noexcept;
|
||||
size_t size() const noexcept;
|
||||
size_t length() const noexcept;
|
||||
bool empty() const noexcept;
|
||||
|
||||
const char *c_str() noexcept;
|
||||
|
||||
size_t capacity() const noexcept;
|
||||
void reserve(size_t new_cap) noexcept;
|
||||
|
||||
using iterator = char *;
|
||||
iterator begin() noexcept;
|
||||
iterator end() noexcept;
|
||||
|
||||
using const_iterator = const char *;
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
const_iterator cbegin() const noexcept;
|
||||
const_iterator cend() const noexcept;
|
||||
|
||||
bool operator==(const String &) const noexcept;
|
||||
bool operator!=(const String &) const noexcept;
|
||||
bool operator<(const String &) const noexcept;
|
||||
bool operator<=(const String &) const noexcept;
|
||||
bool operator>(const String &) const noexcept;
|
||||
bool operator>=(const String &) const noexcept;
|
||||
|
||||
void swap(String &) noexcept;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &, const String &);
|
||||
#
|
||||
# } // namespace rust
|
||||
```
|
||||
|
||||
### Restrictions:
|
||||
|
||||
None. Strings may be used as function arguments and function return values, by
|
||||
value or by reference, as well as fields of shared structs.
|
||||
|
||||
## Example
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
struct ConcatRequest {
|
||||
fst: String,
|
||||
snd: String,
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("example/include/concat.h");
|
||||
fn concat(r: ConcatRequest) -> String;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let concatenated = ffi::concat(ffi::ConcatRequest {
|
||||
fst: "fearless".to_owned(),
|
||||
snd: "concurrency".to_owned(),
|
||||
});
|
||||
println!("concatenated: {:?}", concatenated);
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// include/concat.h
|
||||
|
||||
#pragma once
|
||||
#include "example/src/main.rs.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
rust::String concat(ConcatRequest r);
|
||||
```
|
||||
|
||||
```cpp
|
||||
// src/concat.cc
|
||||
|
||||
#include "example/include/concat.h"
|
||||
|
||||
rust::String concat(ConcatRequest r) {
|
||||
// The full suite of operator overloads hasn't been added
|
||||
// yet on rust::String, but we can get it done like this:
|
||||
return std::string(r.fst) + std::string(r.snd);
|
||||
}
|
||||
```
|
||||
63
vendor/cxx/book/src/binding/uniqueptr.md
vendored
Normal file
63
vendor/cxx/book/src/binding/uniqueptr.md
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
{{#title std::unique_ptr<T> — Rust ♡ C++}}
|
||||
# std::unique\_ptr\<T\>
|
||||
|
||||
The Rust binding of std::unique\_ptr\<T\> is called **[`UniquePtr<T>`]**. See
|
||||
the link for documentation of the Rust API.
|
||||
|
||||
[`UniquePtr<T>`]: https://docs.rs/cxx/*/cxx/struct.UniquePtr.html
|
||||
|
||||
### Restrictions:
|
||||
|
||||
Only `std::unique_ptr<T, std::default_delete<T>>` is currently supported. Custom
|
||||
deleters may be supported in the future.
|
||||
|
||||
UniquePtr\<T\> does not support T being an opaque Rust type. You should use a
|
||||
Box\<T\> (C++ [rust::Box\<T\>](box.md)) instead for transferring ownership of
|
||||
opaque Rust types on the language boundary.
|
||||
|
||||
## Example
|
||||
|
||||
UniquePtr is commonly useful for returning opaque C++ objects to Rust. This use
|
||||
case was featured in the [*blobstore tutorial*](../tutorial.md).
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
unsafe extern "C++" {
|
||||
include!("example/include/blobstore.h");
|
||||
|
||||
type BlobstoreClient;
|
||||
|
||||
fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let client = ffi::new_blobstore_client();
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// include/blobstore.h
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
|
||||
class BlobstoreClient;
|
||||
|
||||
std::unique_ptr<BlobstoreClient> new_blobstore_client();
|
||||
```
|
||||
|
||||
```cpp
|
||||
// src/blobstore.cc
|
||||
|
||||
#include "example/include/blobstore.h"
|
||||
|
||||
std::unique_ptr<BlobstoreClient> new_blobstore_client() {
|
||||
return std::make_unique<BlobstoreClient>();
|
||||
}
|
||||
```
|
||||
192
vendor/cxx/book/src/binding/vec.md
vendored
Normal file
192
vendor/cxx/book/src/binding/vec.md
vendored
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
{{#title rust::Vec<T> — Rust ♡ C++}}
|
||||
# rust::Vec\<T\>
|
||||
|
||||
### Public API:
|
||||
|
||||
```cpp,hidelines
|
||||
// rust/cxx.h
|
||||
#
|
||||
# #include <initializer_list>
|
||||
# #include <iterator>
|
||||
# #include <type_traits>
|
||||
#
|
||||
# namespace rust {
|
||||
|
||||
template <typename T>
|
||||
class Vec final {
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
Vec() noexcept;
|
||||
Vec(std::initializer_list<T>);
|
||||
Vec(const Vec &);
|
||||
Vec(Vec &&) noexcept;
|
||||
~Vec() noexcept;
|
||||
|
||||
Vec &operator=(Vec &&) noexcept;
|
||||
Vec &operator=(const Vec &);
|
||||
|
||||
size_t size() const noexcept;
|
||||
bool empty() const noexcept;
|
||||
const T *data() const noexcept;
|
||||
T *data() noexcept;
|
||||
size_t capacity() const noexcept;
|
||||
|
||||
const T &operator[](size_t n) const noexcept;
|
||||
const T &at(size_t n) const;
|
||||
const T &front() const;
|
||||
const T &back() const;
|
||||
|
||||
T &operator[](size_t n) noexcept;
|
||||
T &at(size_t n);
|
||||
T &front();
|
||||
T &back();
|
||||
|
||||
void reserve(size_t new_cap);
|
||||
void push_back(const T &value);
|
||||
void push_back(T &&value);
|
||||
template <typename... Args>
|
||||
void emplace_back(Args &&...args);
|
||||
void truncate(size_t len);
|
||||
void clear();
|
||||
|
||||
class iterator;
|
||||
iterator begin() noexcept;
|
||||
iterator end() noexcept;
|
||||
|
||||
class const_iterator;
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
const_iterator cbegin() const noexcept;
|
||||
const_iterator cend() const noexcept;
|
||||
|
||||
void swap(Vec &) noexcept;
|
||||
};
|
||||
#
|
||||
# template <typename T>
|
||||
# class Vec<T>::iterator final {
|
||||
# public:
|
||||
# using iterator_category = std::random_access_iterator_tag;
|
||||
# using value_type = T;
|
||||
# using pointer = T *;
|
||||
# using reference = T &;
|
||||
#
|
||||
# T &operator*() const noexcept;
|
||||
# T *operator->() const noexcept;
|
||||
# T &operator[](ptrdiff_t) const noexcept;
|
||||
#
|
||||
# iterator &operator++() noexcept;
|
||||
# iterator operator++(int) noexcept;
|
||||
# iterator &operator--() noexcept;
|
||||
# iterator operator--(int) noexcept;
|
||||
#
|
||||
# iterator &operator+=(ptrdiff_t) noexcept;
|
||||
# iterator &operator-=(ptrdiff_t) noexcept;
|
||||
# iterator operator+(ptrdiff_t) const noexcept;
|
||||
# iterator operator-(ptrdiff_t) const noexcept;
|
||||
# ptrdiff_t operator-(const iterator &) const noexcept;
|
||||
#
|
||||
# bool operator==(const iterator &) const noexcept;
|
||||
# bool operator!=(const iterator &) const noexcept;
|
||||
# bool operator<(const iterator &) const noexcept;
|
||||
# bool operator<=(const iterator &) const noexcept;
|
||||
# bool operator>(const iterator &) const noexcept;
|
||||
# bool operator>=(const iterator &) const noexcept;
|
||||
# };
|
||||
#
|
||||
# template <typename T>
|
||||
# class Vec<T>::const_iterator final {
|
||||
# public:
|
||||
# using iterator_category = std::random_access_iterator_tag;
|
||||
# using value_type = const T;
|
||||
# using pointer = const T *;
|
||||
# using reference = const T &;
|
||||
#
|
||||
# const T &operator*() const noexcept;
|
||||
# const T *operator->() const noexcept;
|
||||
# const T &operator[](ptrdiff_t) const noexcept;
|
||||
#
|
||||
# const_iterator &operator++() noexcept;
|
||||
# const_iterator operator++(int) noexcept;
|
||||
# const_iterator &operator--() noexcept;
|
||||
# const_iterator operator--(int) noexcept;
|
||||
#
|
||||
# const_iterator &operator+=(ptrdiff_t) noexcept;
|
||||
# const_iterator &operator-=(ptrdiff_t) noexcept;
|
||||
# const_iterator operator+(ptrdiff_t) const noexcept;
|
||||
# const_iterator operator-(ptrdiff_t) const noexcept;
|
||||
# ptrdiff_t operator-(const const_iterator &) const noexcept;
|
||||
#
|
||||
# bool operator==(const const_iterator &) const noexcept;
|
||||
# bool operator!=(const const_iterator &) const noexcept;
|
||||
# bool operator<(const const_iterator &) const noexcept;
|
||||
# bool operator<=(const const_iterator &) const noexcept;
|
||||
# bool operator>(const const_iterator &) const noexcept;
|
||||
# bool operator>=(const const_iterator &) const noexcept;
|
||||
# };
|
||||
#
|
||||
# } // namespace rust
|
||||
```
|
||||
|
||||
### Restrictions:
|
||||
|
||||
Vec\<T\> does not support T being an opaque C++ type. You should use
|
||||
CxxVector\<T\> (C++ std::vector\<T\>) instead for collections of opaque C++
|
||||
types on the language boundary.
|
||||
|
||||
## Example
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
struct Shared {
|
||||
v: u32,
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("example/include/example.h");
|
||||
|
||||
fn f(elements: Vec<Shared>);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let shared = |v| ffi::Shared { v };
|
||||
let elements = vec![shared(3), shared(2), shared(1)];
|
||||
ffi::f(elements);
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// include/example.h
|
||||
|
||||
#pragma once
|
||||
#include "example/src/main.rs.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
void f(rust::Vec<Shared> elements);
|
||||
```
|
||||
|
||||
```cpp
|
||||
// src/example.cc
|
||||
|
||||
#include "example/include/example.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
void f(rust::Vec<Shared> v) {
|
||||
for (auto shared : v) {
|
||||
std::cout << shared.v << std::endl;
|
||||
}
|
||||
|
||||
// Copy the elements to a C++ std::vector using STL algorithm.
|
||||
std::vector<Shared> stdv;
|
||||
std::copy(v.begin(), v.end(), std::back_inserter(stdv));
|
||||
assert(v.size() == stdv.size());
|
||||
}
|
||||
```
|
||||
56
vendor/cxx/book/src/bindings.md
vendored
Normal file
56
vendor/cxx/book/src/bindings.md
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
{{#title Built-in bindings — Rust ♡ C++}}
|
||||
# Built-in bindings reference
|
||||
|
||||
In addition to all the primitive types (i32 <=> int32_t), the following
|
||||
common types may be used in the fields of shared structs and the arguments and
|
||||
returns of extern functions.
|
||||
|
||||
<br>
|
||||
|
||||
<table>
|
||||
<tr><th>name in Rust</th><th>name in C++</th><th>restrictions</th></tr>
|
||||
<tr><td style="padding:3px 6px">String</td><td style="padding:3px 6px"><b><a href="binding/string.md">rust::String</a></b></td><td style="padding:3px 6px"></td></tr>
|
||||
<tr><td style="padding:3px 6px">&str</td><td style="padding:3px 6px"><b><a href="binding/str.md">rust::Str</a></b></td><td style="padding:3px 6px"></td></tr>
|
||||
<tr><td style="padding:3px 6px">&[T]</td><td style="padding:3px 6px"><b><a href="binding/slice.md">rust::Slice<const T></a></b></td><td style="padding:3px 6px"><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
<tr><td style="padding:3px 6px">&mut [T]</td><td style="padding:3px 6px"><b><a href="binding/slice.md">rust::Slice<T></a></b></td><td style="padding:3px 6px"><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
<tr><td style="padding:3px 6px"><b><a href="binding/cxxstring.md">CxxString</a></b></td><td style="padding:3px 6px">std::string</td><td style="padding:3px 6px"><sup><i>cannot be passed by value</i></sup></td></tr>
|
||||
<tr><td style="padding:3px 6px">Box<T></td><td style="padding:3px 6px"><b><a href="binding/box.md">rust::Box<T></a></b></td><td style="padding:3px 6px"><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
<tr><td style="padding:3px 6px"><b><a href="binding/uniqueptr.md">UniquePtr<T></a></b></td><td style="padding:3px 6px">std::unique_ptr<T></td><td style="padding:3px 6px"><sup><i>cannot hold opaque Rust type</i></sup></td></tr>
|
||||
<tr><td style="padding:3px 6px"><b><a href="binding/sharedptr.md">SharedPtr<T></a></b></td><td style="padding:3px 6px">std::shared_ptr<T></td><td style="padding:3px 6px"><sup><i>cannot hold opaque Rust type</i></sup></td></tr>
|
||||
<tr><td style="padding:3px 6px">[T; N]</td><td style="padding:3px 6px">std::array<T, N></td><td style="padding:3px 6px"><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
<tr><td style="padding:3px 6px">Vec<T></td><td style="padding:3px 6px"><b><a href="binding/vec.md">rust::Vec<T></a></b></td><td style="padding:3px 6px"><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
<tr><td style="padding:3px 6px"><b><a href="binding/cxxvector.md">CxxVector<T></a></b></td><td style="padding:3px 6px">std::vector<T></td><td style="padding:3px 6px"><sup><i>cannot be passed by value, cannot hold opaque Rust type</i></sup></td></tr>
|
||||
<tr><td style="padding:3px 6px"><b><a href="binding/rawptr.md">*mut T, *const T</a></b></td><td style="padding:3px 6px">T*, const T*</td><td style="padding:3px 6px"><sup><i>fn with a raw pointer argument must be declared unsafe to call</i></sup></td></tr>
|
||||
<tr><td style="padding:3px 6px">fn(T, U) -> V</td><td style="padding:3px 6px"><b><a href="binding/fn.md">rust::Fn<V(T, U)></a></b></td><td style="padding:3px 6px"><sup><i>only passing from Rust to C++ is implemented so far</i></sup></td></tr>
|
||||
<tr><td style="padding:3px 6px"><b><a href="binding/result.md">Result<T></a></b></td><td style="padding:3px 6px">throw/catch</td><td style="padding:3px 6px"><sup><i>allowed as return type only</i></sup></td></tr>
|
||||
</table>
|
||||
|
||||
<br>
|
||||
|
||||
The C++ API of the `rust` namespace is defined by the *include/cxx.h* file in
|
||||
the CXX GitHub repo. You will need to include this header in your C++ code when
|
||||
working with those types. **When using Cargo and the cxx-build crate, the header
|
||||
is made available to you at `#include "rust/cxx.h"`.**
|
||||
|
||||
The `rust` namespace additionally provides lowercase type aliases of all the
|
||||
types mentioned in the table, for use in codebases preferring that style. For
|
||||
example `rust::String`, `rust::Vec` may alternatively be written `rust::string`,
|
||||
`rust::vec` etc.
|
||||
|
||||
## Pending bindings
|
||||
|
||||
The following types are intended to be supported "soon" but are just not
|
||||
implemented yet. I don't expect any of these to be hard to make work but it's a
|
||||
matter of designing a nice API for each in its non-native language.
|
||||
|
||||
<br>
|
||||
|
||||
<table>
|
||||
<tr><th>name in Rust</th><th>name in C++</th></tr>
|
||||
<tr><td>BTreeMap<K, V></td><td><sup><i>tbd</i></sup></td></tr>
|
||||
<tr><td>HashMap<K, V></td><td><sup><i>tbd</i></sup></td></tr>
|
||||
<tr><td>Arc<T></td><td><sup><i>tbd</i></sup></td></tr>
|
||||
<tr><td>Option<T></td><td><sup><i>tbd</i></sup></td></tr>
|
||||
<tr><td><sup><i>tbd</i></sup></td><td>std::map<K, V></td></tr>
|
||||
<tr><td><sup><i>tbd</i></sup></td><td>std::unordered_map<K, V></td></tr>
|
||||
</table>
|
||||
106
vendor/cxx/book/src/build/bazel.md
vendored
Normal file
106
vendor/cxx/book/src/build/bazel.md
vendored
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
{{#title Bazel, Buck — Rust ♡ C++}}
|
||||
## Bazel, Buck, potentially other similar environments
|
||||
|
||||
Starlark-based build systems with the ability to compile a code generator and
|
||||
invoke it as a `genrule` will run CXX's C++ code generator via its `cxxbridge`
|
||||
command line interface.
|
||||
|
||||
The tool is packaged as the `cxxbridge-cmd` crate on crates.io or can be built
|
||||
from the *gen/cmd/* directory of the CXX GitHub repo.
|
||||
|
||||
```console
|
||||
$ cargo install cxxbridge-cmd
|
||||
|
||||
$ cxxbridge src/bridge.rs --header > path/to/bridge.rs.h
|
||||
$ cxxbridge src/bridge.rs > path/to/bridge.rs.cc
|
||||
```
|
||||
|
||||
The CXX repo maintains working Bazel `BUILD` and Buck `BUCK` targets for the
|
||||
complete blobstore tutorial (chapter 3) for your reference, tested in CI. These
|
||||
aren't meant to be directly what you use in your codebase, but serve as an
|
||||
illustration of one possible working pattern.
|
||||
|
||||
```python
|
||||
# tools/bazel/rust_cxx_bridge.bzl
|
||||
|
||||
load("@bazel_skylib//rules:run_binary.bzl", "run_binary")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library")
|
||||
|
||||
def rust_cxx_bridge(name, src, deps = []):
|
||||
native.alias(
|
||||
name = "%s/header" % name,
|
||||
actual = src + ".h",
|
||||
)
|
||||
|
||||
native.alias(
|
||||
name = "%s/source" % name,
|
||||
actual = src + ".cc",
|
||||
)
|
||||
|
||||
run_binary(
|
||||
name = "%s/generated" % name,
|
||||
srcs = [src],
|
||||
outs = [
|
||||
src + ".h",
|
||||
src + ".cc",
|
||||
],
|
||||
args = [
|
||||
"$(location %s)" % src,
|
||||
"-o",
|
||||
"$(location %s.h)" % src,
|
||||
"-o",
|
||||
"$(location %s.cc)" % src,
|
||||
],
|
||||
tool = "//:codegen",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = name,
|
||||
srcs = [src + ".cc"],
|
||||
deps = deps + [":%s/include" % name],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "%s/include" % name,
|
||||
hdrs = [src + ".h"],
|
||||
)
|
||||
```
|
||||
|
||||
```python
|
||||
# demo/BUILD
|
||||
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library")
|
||||
load("@rules_rust//rust:defs.bzl", "rust_binary")
|
||||
load("//tools/bazel:rust_cxx_bridge.bzl", "rust_cxx_bridge")
|
||||
|
||||
rust_binary(
|
||||
name = "demo",
|
||||
srcs = glob(["src/**/*.rs"]),
|
||||
deps = [
|
||||
":blobstore-sys",
|
||||
":bridge",
|
||||
"//:cxx",
|
||||
],
|
||||
)
|
||||
|
||||
rust_cxx_bridge(
|
||||
name = "bridge",
|
||||
src = "src/main.rs",
|
||||
deps = [":blobstore-include"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "blobstore-sys",
|
||||
srcs = ["src/blobstore.cc"],
|
||||
deps = [
|
||||
":blobstore-include",
|
||||
":bridge/include",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "blobstore-include",
|
||||
hdrs = ["include/blobstore.h"],
|
||||
deps = ["//:core"],
|
||||
)
|
||||
```
|
||||
306
vendor/cxx/book/src/build/cargo.md
vendored
Normal file
306
vendor/cxx/book/src/build/cargo.md
vendored
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
{{#title Cargo-based setup — Rust ♡ C++}}
|
||||
# Cargo-based builds
|
||||
|
||||
As one aspect of delivering a good Rust–C++ interop experience, CXX turns
|
||||
Cargo into a quite usable build system for C++ projects published as a
|
||||
collection of crates.io packages, including a consistent and frictionless
|
||||
experience `#include`-ing C++ headers across dependencies.
|
||||
|
||||
## Canonical setup
|
||||
|
||||
CXX's integration with Cargo is handled through the [cxx-build] crate.
|
||||
|
||||
[cxx-build]: https://docs.rs/cxx-build
|
||||
|
||||
```toml,hidelines
|
||||
## Cargo.toml
|
||||
# [package]
|
||||
# name = "..."
|
||||
# version = "..."
|
||||
# edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cxx = "1.0"
|
||||
|
||||
[build-dependencies]
|
||||
cxx-build = "1.0"
|
||||
```
|
||||
|
||||
The canonical build script is as follows. The indicated line returns a
|
||||
[`cc::Build`] instance (from the usual widely used `cc` crate) on which you can
|
||||
set up any additional source files and compiler flags as normal.
|
||||
|
||||
[`cc::Build`]: https://docs.rs/cc/1.0/cc/struct.Build.html
|
||||
|
||||
```rust,noplayground
|
||||
// build.rs
|
||||
|
||||
fn main() {
|
||||
cxx_build::bridge("src/main.rs") // returns a cc::Build
|
||||
.file("src/demo.cc")
|
||||
.flag_if_supported("-std=c++11")
|
||||
.compile("cxxbridge-demo");
|
||||
|
||||
println!("cargo:rerun-if-changed=src/main.rs");
|
||||
println!("cargo:rerun-if-changed=src/demo.cc");
|
||||
println!("cargo:rerun-if-changed=include/demo.h");
|
||||
}
|
||||
```
|
||||
|
||||
The `rerun-if-changed` lines are optional but make it so that Cargo does not
|
||||
spend time recompiling your C++ code when only non-C++ code has changed since
|
||||
the previous Cargo build. By default without any `rerun-if-changed`, Cargo will
|
||||
re-execute the build script after *any* file changed in the project.
|
||||
|
||||
If stuck, try comparing what you have against the *demo/* directory of the CXX
|
||||
GitHub repo, which maintains a working Cargo-based setup for the blobstore
|
||||
tutorial (chapter 3).
|
||||
|
||||
## Header include paths
|
||||
|
||||
With cxx-build, by default your include paths always start with the crate name.
|
||||
This applies to both `#include` within your C++ code, and `include!` in the
|
||||
`extern "C++"` section of your Rust cxx::bridge.
|
||||
|
||||
Your crate name is determined by the `name` entry in Cargo.toml.
|
||||
|
||||
For example if your crate is named `yourcratename` and contains a C++ header
|
||||
file `path/to/header.h` relative to Cargo.toml, that file will be includable as:
|
||||
|
||||
```cpp
|
||||
#include "yourcratename/path/to/header.h"
|
||||
```
|
||||
|
||||
A crate can choose a prefix for its headers that is different from the crate
|
||||
name by modifying **[`CFG.include_prefix`][CFG]** from build.rs:
|
||||
|
||||
[CFG]: https://docs.rs/cxx-build/*/cxx_build/static.CFG.html
|
||||
|
||||
```rust,noplayground
|
||||
// build.rs
|
||||
|
||||
use cxx_build::CFG;
|
||||
|
||||
fn main() {
|
||||
CFG.include_prefix = "my/project";
|
||||
|
||||
cxx_build::bridge(...)...
|
||||
}
|
||||
```
|
||||
|
||||
Subsequently the header located at `path/to/header.h` would now be includable
|
||||
as:
|
||||
|
||||
```cpp
|
||||
#include "my/project/path/to/header.h"
|
||||
```
|
||||
|
||||
The empty string `""` is a valid include prefix and will make it possible to
|
||||
have `#include "path/to/header.h"`. However, if your crate is a library, be
|
||||
considerate of possible name collisions that may occur in downstream crates. If
|
||||
using an empty include prefix, you'll want to make sure your headers' local path
|
||||
within the crate is sufficiently namespaced or unique.
|
||||
|
||||
## Including generated code
|
||||
|
||||
If your `#[cxx::bridge]` module contains an `extern "Rust"` block i.e. types or
|
||||
functions exposed from Rust to C++, or any shared data structures, the
|
||||
CXX-generated C++ header declaring those things is available using a `.rs.h`
|
||||
extension on the Rust source file's name.
|
||||
|
||||
```cpp
|
||||
// the header generated from path/to/lib.rs
|
||||
#include "yourcratename/path/to/lib.rs.h"
|
||||
```
|
||||
|
||||
For giggles, it's also available using just a plain `.rs` extension as if you
|
||||
were including the Rust file directly. Use whichever you find more palatable.
|
||||
|
||||
```cpp
|
||||
#include "yourcratename/path/to/lib.rs"
|
||||
```
|
||||
|
||||
## Including headers from dependencies
|
||||
|
||||
You get to include headers from your dependencies, both handwritten ones
|
||||
contained as `.h` files in their Cargo package, as well as CXX-generated ones.
|
||||
|
||||
It works the same as an include of a local header: use the crate name (or their
|
||||
include\_prefix if their crate changed it) followed by the relative path of the
|
||||
header within the crate.
|
||||
|
||||
```cpp
|
||||
#include "dependencycratename/path/to/their/header.h`
|
||||
```
|
||||
|
||||
Note that cross-crate imports are only made available between **direct
|
||||
dependencies**. You must directly depend on the other crate in order to #include
|
||||
its headers; a transitive dependency is not sufficient.
|
||||
|
||||
Additionally, headers from a direct dependency are only importable if the
|
||||
dependency's Cargo.toml manifest contains a `links` key. If not, its headers
|
||||
will not be importable from outside of the same crate. See *[the `links`
|
||||
manifest key][links]* in the Cargo reference.
|
||||
|
||||
[links]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key
|
||||
|
||||
<br><br><br>
|
||||
|
||||
# Advanced features
|
||||
|
||||
The following CFG settings are only relevant to you if you are writing a library
|
||||
that needs to support downstream crates `#include`-ing its C++ public headers.
|
||||
|
||||
## Publicly exporting header directories
|
||||
|
||||
**[`CFG.exported_header_dirs`][CFG]** (vector of absolute paths) defines a set
|
||||
of additional directories from which the current crate, directly dependent
|
||||
crates, and further crates to which this crate's headers are exported (more
|
||||
below) will be able to `#include` headers.
|
||||
|
||||
Adding a directory to `exported_header_dirs` is similar to adding it to the
|
||||
current build via the `cc` crate's [`Build::include`], but *also* makes the
|
||||
directory available to downstream crates that want to `#include` one of the
|
||||
headers from your crate. If the dir were added only using `Build::include`, the
|
||||
downstream crate including your header would need to manually add the same
|
||||
directory to their own build as well.
|
||||
|
||||
[`Build::include`]: https://docs.rs/cc/1/cc/struct.Build.html#method.include
|
||||
|
||||
When using `exported_header_dirs`, your crate must also set a `links` key for
|
||||
itself in Cargo.toml. See [*the `links` manifest key*][links]. The reason is
|
||||
that Cargo imposes no ordering on the execution of build scripts without a
|
||||
`links` key, which means the downstream crate's build script might otherwise
|
||||
execute before yours decides what to put into `exported_header_dirs`.
|
||||
|
||||
### Example
|
||||
|
||||
One of your crate's headers wants to include a system library, such as `#include
|
||||
"Python.h"`.
|
||||
|
||||
```rust,noplayground
|
||||
// build.rs
|
||||
|
||||
use cxx_build::CFG;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
let python3 = pkg_config::probe_library("python3").unwrap();
|
||||
let python_include_paths = python3.include_paths.iter().map(PathBuf::as_path);
|
||||
CFG.exported_header_dirs.extend(python_include_paths);
|
||||
|
||||
cxx_build::bridge("src/bridge.rs").compile("demo");
|
||||
}
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
Your crate wants to rearrange the headers that it exports vs how they're laid
|
||||
out locally inside the crate's source directory.
|
||||
|
||||
Suppose the crate as published contains a file at `./include/myheader.h` but
|
||||
wants it available to downstream crates as `#include "foo/v1/public.h"`.
|
||||
|
||||
```rust,noplayground
|
||||
// build.rs
|
||||
|
||||
use cxx_build::CFG;
|
||||
use std::path::Path;
|
||||
use std::{env, fs};
|
||||
|
||||
fn main() {
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let headers = Path::new(&out_dir).join("headers");
|
||||
CFG.exported_header_dirs.push(&headers);
|
||||
|
||||
// We contain `include/myheader.h` locally, but
|
||||
// downstream will use `#include "foo/v1/public.h"`
|
||||
let foo = headers.join("foo").join("v1");
|
||||
fs::create_dir_all(&foo).unwrap();
|
||||
fs::copy("include/myheader.h", foo.join("public.h")).unwrap();
|
||||
|
||||
cxx_build::bridge("src/bridge.rs").compile("demo");
|
||||
}
|
||||
```
|
||||
|
||||
## Publicly exporting dependencies
|
||||
|
||||
**[`CFG.exported_header_prefixes`][CFG]** (vector of strings) each refer to the
|
||||
`include_prefix` of one of your direct dependencies, or a prefix thereof. They
|
||||
describe which of your dependencies participate in your crate's C++ public API,
|
||||
as opposed to private use by your crate's implementation.
|
||||
|
||||
As a general rule, if one of your headers `#include`s something from one of your
|
||||
dependencies, you need to put that dependency's `include_prefix` into
|
||||
`CFG.exported_header_prefixes` (*or* their `links` key into
|
||||
`CFG.exported_header_links`; see below). On the other hand if only your C++
|
||||
implementation files and *not* your headers are importing from the dependency,
|
||||
you do not export that dependency.
|
||||
|
||||
The significance of exported headers is that if downstream code (crate **𝒜**)
|
||||
contains an `#include` of a header from your crate (**ℬ**) and your header
|
||||
contains an `#include` of something from your dependency (**𝒞**), the exported
|
||||
dependency **𝒞** becomes available during the downstream crate **𝒜**'s build.
|
||||
Otherwise the downstream crate **𝒜** doesn't know about **𝒞** and wouldn't be
|
||||
able to find what header your header is referring to, and would fail to build.
|
||||
|
||||
When using `exported_header_prefixes`, your crate must also set a `links` key
|
||||
for itself in Cargo.toml.
|
||||
|
||||
### Example
|
||||
|
||||
Suppose you have a crate with 5 direct dependencies and the `include_prefix` for
|
||||
each one are:
|
||||
|
||||
- "crate0"
|
||||
- "group/api/crate1"
|
||||
- "group/api/crate2"
|
||||
- "group/api/contrib/crate3"
|
||||
- "detail/crate4"
|
||||
|
||||
Your header involves types from the first four so we re-export those as part of
|
||||
your public API, while crate4 is only used internally by your cc file not your
|
||||
header, so we do not export:
|
||||
|
||||
```rust,noplayground
|
||||
// build.rs
|
||||
|
||||
use cxx_build::CFG;
|
||||
|
||||
fn main() {
|
||||
CFG.exported_header_prefixes = vec!["crate0", "group/api"];
|
||||
|
||||
cxx_build::bridge("src/bridge.rs")
|
||||
.file("src/impl.cc")
|
||||
.compile("demo");
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
For more fine grained control, there is **[`CFG.exported_header_links`][CFG]**
|
||||
(vector of strings) which each refer to the `links` attribute ([*the `links`
|
||||
manifest key*][links]) of one of your crate's direct dependencies.
|
||||
|
||||
This achieves an equivalent result to `CFG.exported_header_prefixes` by
|
||||
re-exporting a C++ dependency as part of your crate's public API, except with
|
||||
finer control for cases when multiple crates might be sharing the same
|
||||
`include_prefix` and you'd like to export some but not others. Links attributes
|
||||
are guaranteed to be unique identifiers by Cargo.
|
||||
|
||||
When using `exported_header_links`, your crate must also set a `links` key for
|
||||
itself in Cargo.toml.
|
||||
|
||||
### Example
|
||||
|
||||
```rust,noplayground
|
||||
// build.rs
|
||||
|
||||
use cxx_build::CFG;
|
||||
|
||||
fn main() {
|
||||
CFG.exported_header_links.push("git2");
|
||||
|
||||
cxx_build::bridge("src/bridge.rs").compile("demo");
|
||||
}
|
||||
```
|
||||
47
vendor/cxx/book/src/build/cmake.md
vendored
Normal file
47
vendor/cxx/book/src/build/cmake.md
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
{{#title CMake — Rust ♡ C++}}
|
||||
# CMake
|
||||
|
||||
There is not an officially endorsed CMake setup for CXX, but a few developers
|
||||
have shared one that they got working. You can try one of these as a starting
|
||||
point. If you feel that you have arrived at a CMake setup that is superior to
|
||||
what is available in these links, feel free to make a PR adding it to this list.
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
- **<https://github.com/XiangpengHao/cxx-cmake-example>**
|
||||
|
||||
- Supports cross-language link time optimization (LTO)
|
||||
|
||||
---
|
||||
|
||||
- **<https://github.com/david-cattermole/cxx-demo-example>**
|
||||
|
||||
- Includes a cbindgen component
|
||||
- Tested on Windows 10 with MSVC, and on Linux
|
||||
|
||||
---
|
||||
|
||||
- **<https://github.com/trondhe/rusty_cmake>**
|
||||
|
||||
- Alias target that can be linked into a C++ project
|
||||
- Tested on Windows 10 with GNU target, and on Linux
|
||||
|
||||
---
|
||||
|
||||
- **<https://github.com/geekbrother/cxx-corrosion-cmake>**
|
||||
|
||||
- Improved rusty_cmake CMake file to use modern C++
|
||||
- Rich examples of using different primitive types and Rust's Result return to C++
|
||||
- MacOS and Linux only
|
||||
|
||||
---
|
||||
|
||||
- **<https://github.com/paandahl/cpp-with-rust>**
|
||||
|
||||
- Same blobstore example as the official demo, but inverted languages
|
||||
- Minimal CMake configuration
|
||||
- Tested on Linux, macOS, and Windows
|
||||
|
||||
---
|
||||
75
vendor/cxx/book/src/build/other.md
vendored
Normal file
75
vendor/cxx/book/src/build/other.md
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
{{#title Other build systems — Rust ♡ C++}}
|
||||
# Some other build system
|
||||
|
||||
You will need to achieve at least these three things:
|
||||
|
||||
- Produce the CXX-generated C++ bindings code.
|
||||
- Compile the generated C++ code.
|
||||
- Link the resulting objects together with your other C++ and Rust objects.
|
||||
|
||||
### Producing the generated code
|
||||
|
||||
CXX's Rust code generation automatically happens when the `#[cxx::bridge]`
|
||||
procedural macro is expanded during the normal Rust compilation process, so no
|
||||
special build steps are required there.
|
||||
|
||||
But the C++ side of the bindings needs to be generated. Your options are:
|
||||
|
||||
- Use the `cxxbridge` command, which is a standalone command line interface to
|
||||
the CXX C++ code generator. Wire up your build system to compile and invoke
|
||||
this tool.
|
||||
|
||||
```console
|
||||
$ cxxbridge src/bridge.rs --header > path/to/bridge.rs.h
|
||||
$ cxxbridge src/bridge.rs > path/to/bridge.rs.cc
|
||||
```
|
||||
|
||||
It's packaged as the `cxxbridge-cmd` crate on crates.io or can be built from
|
||||
the *gen/cmd/* directory of the CXX GitHub repo.
|
||||
|
||||
- Or, build your own code generator frontend on top of the [cxx-gen] crate. This
|
||||
is currently unofficial and unsupported.
|
||||
|
||||
[cxx-gen]: https://docs.rs/cxx-gen
|
||||
|
||||
### Compiling C++
|
||||
|
||||
However you like. We can provide no guidance.
|
||||
|
||||
### Linking the C++ and Rust together
|
||||
|
||||
When linking a binary which contains mixed Rust and C++ code, you will have to
|
||||
choose between using the Rust toolchain (`rustc`) or the C++ toolchain which you
|
||||
may already have extensively tuned.
|
||||
|
||||
Rust does not generate simple standalone `.o` files, so you can't just throw the
|
||||
Rust-generated code into your existing C++ toolchain linker. Instead you need to
|
||||
choose one of these options:
|
||||
|
||||
* Use `rustc` as the final linker. Pass any non-Rust libraries using `-L
|
||||
<directory>` and `-l<library>` rustc arguments, and/or `#[link]` directives in
|
||||
your Rust code. If you need to link against C/C++ `.o` files you can use
|
||||
`-Clink-arg=file.o`.
|
||||
|
||||
* Use your C++ linker. In this case, you first need to use `rustc` and/or
|
||||
`cargo` to generate a _single_ Rust `staticlib` target and pass that into your
|
||||
foreign linker invocation.
|
||||
|
||||
* If you need to link multiple Rust subsystems, you will need to generate a
|
||||
_single_ `staticlib` perhaps using lots of `extern crate` statements to
|
||||
include multiple Rust `rlib`s. Multiple Rust `staticlib` files are likely
|
||||
to conflict.
|
||||
|
||||
Passing Rust `rlib`s directly into your non-Rust linker is not supported (but
|
||||
apparently sometimes works).
|
||||
|
||||
See the [Rust reference's *Linkage*][linkage] page for some general information
|
||||
here.
|
||||
|
||||
[linkage]: https://doc.rust-lang.org/reference/linkage.html
|
||||
|
||||
The following open rust-lang issues might hold more recent guidance or
|
||||
inspiration: [rust-lang/rust#73632], [rust-lang/rust#73295].
|
||||
|
||||
[rust-lang/rust#73632]: https://github.com/rust-lang/rust/issues/73632
|
||||
[rust-lang/rust#73295]: https://github.com/rust-lang/rust/issues/73295
|
||||
20
vendor/cxx/book/src/building.md
vendored
Normal file
20
vendor/cxx/book/src/building.md
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{{#title Multi-language build system options — Rust ♡ C++}}
|
||||
# Multi-language build system options
|
||||
|
||||
CXX is designed to be convenient to integrate into a variety of build systems.
|
||||
|
||||
If you are working in a project that does not already have a preferred build
|
||||
system for its C++ code *or* which will be relying heavily on open source
|
||||
libraries from the Rust package registry, you're likely to have the easiest
|
||||
experience with Cargo which is the build system commonly used by open source
|
||||
Rust projects. Refer to the ***[Cargo](build/cargo.md)*** chapter about CXX's
|
||||
Cargo support.
|
||||
|
||||
Among build systems designed for first class multi-language support, Bazel is a
|
||||
solid choice. Refer to the ***[Bazel](build/bazel.md)*** chapter.
|
||||
|
||||
If your codebase is already invested in CMake, refer to the
|
||||
***[CMake](build/cmake.md)*** chapter.
|
||||
|
||||
If you have some other build system that you'd like to try to make work with
|
||||
CXX, see [this page](build/other.md) for notes.
|
||||
85
vendor/cxx/book/src/concepts.md
vendored
Normal file
85
vendor/cxx/book/src/concepts.md
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
{{#title Core concepts — Rust ♡ C++}}
|
||||
# Core concepts
|
||||
|
||||
This page is a brief overview of the major concepts of CXX, enough so that you
|
||||
recognize the shape of things as you read the tutorial and following chapters.
|
||||
|
||||
In CXX, the language of the FFI boundary involves 3 kinds of items:
|
||||
|
||||
- **Shared structs** — data structures whose fields are made visible to
|
||||
both languages. The definition written within cxx::bridge in Rust is usually
|
||||
the single source of truth, though there are ways to do sharing based on a
|
||||
bindgen-generated definition with C++ as source of truth.
|
||||
|
||||
- **Opaque types** — their fields are secret from the other language.
|
||||
These cannot be passed across the FFI by value but only behind an indirection,
|
||||
such as a reference `&`, a Rust `Box`, or a C++ `unique_ptr`. Can be a type
|
||||
alias for an arbitrarily complicated generic language-specific type depending
|
||||
on your use case.
|
||||
|
||||
- **Functions** — implemented in either language, callable from the other
|
||||
language.
|
||||
|
||||
```rust,noplayground,focuscomment
|
||||
# #[cxx::bridge]
|
||||
# mod ffi {
|
||||
// Any shared structs, whose fields will be visible to both languages.
|
||||
# struct BlobMetadata {
|
||||
# size: usize,
|
||||
# tags: Vec<String>,
|
||||
# }
|
||||
#
|
||||
# extern "Rust" {
|
||||
// Zero or more opaque types which both languages can pass around
|
||||
// but only Rust can see the fields.
|
||||
# type MultiBuf;
|
||||
#
|
||||
// Functions implemented in Rust.
|
||||
# fn next_chunk(buf: &mut MultiBuf) -> &[u8];
|
||||
# }
|
||||
#
|
||||
# unsafe extern "C++" {
|
||||
// One or more headers with the matching C++ declarations for the
|
||||
// enclosing extern "C++" block. Our code generators don't read it
|
||||
// but it gets #include'd and used in static assertions to ensure
|
||||
// our picture of the FFI boundary is accurate.
|
||||
# include!("demo/include/blobstore.h");
|
||||
#
|
||||
// Zero or more opaque types which both languages can pass around
|
||||
// but only C++ can see the fields.
|
||||
# type BlobstoreClient;
|
||||
#
|
||||
// Functions implemented in C++.
|
||||
# fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
|
||||
# fn put(&self, parts: &mut MultiBuf) -> u64;
|
||||
# fn tag(&self, blobid: u64, tag: &str);
|
||||
# fn metadata(&self, blobid: u64) -> BlobMetadata;
|
||||
# }
|
||||
# }
|
||||
```
|
||||
|
||||
Within the `extern "Rust"` part of the CXX bridge we list the types and
|
||||
functions for which Rust is the source of truth. These all implicitly refer to
|
||||
the `super` module, the parent module of the CXX bridge. You can think of the
|
||||
two items listed in the example above as being like `use super::MultiBuf` and
|
||||
`use super::next_chunk` except re-exported to C++. The parent module will either
|
||||
contain the definitions directly for simple things, or contain the relevant
|
||||
`use` statements to bring them into scope from elsewhere.
|
||||
|
||||
Within the `extern "C++"` part, we list types and functions for which C++ is the
|
||||
source of truth, as well as the header(s) that declare those APIs. In the future
|
||||
it's possible that this section could be generated bindgen-style from the
|
||||
headers but for now we need the signatures written out; static assertions verify
|
||||
that they are accurate.
|
||||
|
||||
<br><br>
|
||||
|
||||
Be aware that the design of this library is intentionally restrictive and
|
||||
opinionated! It isn't a goal to be flexible enough to handle an arbitrary
|
||||
signature in either language. Instead this project is about carving out a highly
|
||||
expressive set of functionality about which we can make powerful safety
|
||||
guarantees today and extend over time. You may find that it takes some practice
|
||||
to use CXX bridge effectively as it won't work in all the ways that you may be
|
||||
used to.
|
||||
|
||||
<br>
|
||||
118
vendor/cxx/book/src/context.md
vendored
Normal file
118
vendor/cxx/book/src/context.md
vendored
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
{{#title Other Rust–C++ interop tools — Rust ♡ C++}}
|
||||
# Context: other Rust–C++ interop tools
|
||||
|
||||
When it comes to interacting with an idiomatic Rust API or idiomatic C++ API
|
||||
from the other language, the generally applicable approaches outside of the CXX
|
||||
crate are:
|
||||
|
||||
- Build a C-compatible wrapper around the code (expressed using `extern "C"`
|
||||
signatures, primitives, C-compatible structs, raw pointers). Translate that
|
||||
manually to equivalent `extern "C"` declarations in the other language and
|
||||
keep them in sync. Preferably, build a safe/idiomatic wrapper around the
|
||||
translated `extern "C"` signatures for callers to use.
|
||||
|
||||
- Build a C wrapper around the C++ code and use **[bindgen]** to translate that
|
||||
programmatically to `extern "C"` Rust signatures. Preferably, build a
|
||||
safe/idiomatic Rust wrapper on top.
|
||||
|
||||
- Build a C-compatible Rust wrapper around the Rust code and use **[cbindgen]**
|
||||
to translate that programmatically to an `extern "C"` C++ header. Preferably,
|
||||
build an idiomatic C++ wrapper.
|
||||
|
||||
**If the code you are binding is already *"effectively C"*, the above has you
|
||||
covered.** You should use bindgen or cbindgen, or manually translated C
|
||||
signatures if there aren't too many and they seldom change.
|
||||
|
||||
[bindgen]: https://github.com/rust-lang/rust-bindgen
|
||||
[cbindgen]: https://github.com/eqrion/cbindgen
|
||||
|
||||
## C++ vs C
|
||||
|
||||
Bindgen has some basic support for C++. It can reason about classes, member
|
||||
functions, and the layout of templated types. However, everything it does
|
||||
related to C++ is best-effort only. Bindgen starts from a point of wanting to
|
||||
generate declarations for everything, so any C++ detail that it hasn't
|
||||
implemented will cause a crash if you are lucky ([bindgen#388]) or more likely
|
||||
silently emit an incompatible signature ([bindgen#380], [bindgen#607],
|
||||
[bindgen#652], [bindgen#778], [bindgen#1194]) which will do arbitrary
|
||||
memory-unsafe things at runtime whenever called.
|
||||
|
||||
[bindgen#388]: https://github.com/rust-lang/rust-bindgen/issues/388
|
||||
[bindgen#380]: https://github.com/rust-lang/rust-bindgen/issues/380
|
||||
[bindgen#607]: https://github.com/rust-lang/rust-bindgen/issues/607
|
||||
[bindgen#652]: https://github.com/rust-lang/rust-bindgen/issues/652
|
||||
[bindgen#778]: https://github.com/rust-lang/rust-bindgen/issues/778
|
||||
[bindgen#1194]: https://github.com/rust-lang/rust-bindgen/issues/1194
|
||||
|
||||
Thus using bindgen correctly requires not just juggling all your pointers
|
||||
correctly at the language boundary, but also understanding ABI details and their
|
||||
workarounds and reliably applying them. For example, the programmer will
|
||||
discover that their program sometimes segfaults if they call a function that
|
||||
returns std::unique\_ptr\<T\> through bindgen. Why? Because unique\_ptr, despite
|
||||
being "just a pointer", has a different ABI than a pointer or a C struct
|
||||
containing a pointer ([bindgen#778]) and is not directly expressible in Rust.
|
||||
Bindgen emitted something that *looks* reasonable and you will have a hell of a
|
||||
time in gdb working out what went wrong. Eventually people learn to avoid
|
||||
anything involving a non-trivial copy constructor, destructor, or inheritance,
|
||||
and instead stick to raw pointers and primitives and trivial structs only
|
||||
— in other words C.
|
||||
|
||||
## Geometric intuition for why there is so much opportunity for improvement
|
||||
|
||||
The CXX project attempts a different approach to C++ FFI.
|
||||
|
||||
Imagine Rust and C and C++ as three vertices of a scalene triangle, with length
|
||||
of the edges being related to similarity of the languages when it comes to
|
||||
library design.
|
||||
|
||||
The most similar pair (the shortest edge) is Rust–C++. These languages
|
||||
have largely compatible concepts of things like ownership, vectors, strings,
|
||||
fallibility, etc that translate clearly from signatures in either language to
|
||||
signatures in the other language.
|
||||
|
||||
When we make a binding for an idiomatic C++ API using bindgen, and we fall down
|
||||
to raw pointers and primitives and trivial structs as described above, what we
|
||||
are really doing is coding the two longest edges of the triangle: getting from
|
||||
C++ down to C, and C back up to Rust. The Rust–C edge always involves a
|
||||
great deal of `unsafe` code, and the C++–C edge similarly requires care
|
||||
just for basic memory safety. Something as basic as "how do I pass ownership of
|
||||
a string to the other language?" becomes a strap-yourself-in moment,
|
||||
particularly for someone not already an expert in one or both sides.
|
||||
|
||||
You should think of the `cxx` crate as being the midpoint of the Rust–C++
|
||||
edge. Rather than coding the two long edges, you will code half the short edge
|
||||
in Rust and half the short edge in C++, in both cases with the library playing
|
||||
to the strengths of the Rust type system *and* the C++ type system to help
|
||||
assure correctness.
|
||||
|
||||
If you've already been through the tutorial in the previous chapter, take a
|
||||
moment to appreciate that the C++ side *really* looks like we are just writing
|
||||
C++ and the Rust side *really* looks like we are just writing Rust. Anything you
|
||||
could do wrong in Rust, and almost anything you could reasonably do wrong in
|
||||
C++, will be caught by the compiler. This highlights that we are on the "short
|
||||
edge of the triangle".
|
||||
|
||||
But it all still boils down to the same things: it's still FFI from one piece of
|
||||
native code to another, nothing is getting serialized or allocated or
|
||||
runtime-checked in between.
|
||||
|
||||
## Role of CXX
|
||||
|
||||
The role of CXX is to capture the language boundary with more fidelity than what
|
||||
`extern "C"` is able to represent. You can think of CXX as being a replacement
|
||||
for `extern "C"` in a sense.
|
||||
|
||||
From this perspective, CXX is a lower level tool than the bindgens. Just as
|
||||
bindgen and cbindgen are built on top of `extern "C"`, it makes sense to think
|
||||
about higher level tools built on top of CXX. Such a tool might consume a C++
|
||||
header and/or Rust module (and/or IDL like Thrift) and emit the corresponding
|
||||
safe cxx::bridge language boundary, leveraging CXX's static analysis and
|
||||
underlying implementation of that boundary. We are beginning to see this space
|
||||
explored by the [autocxx] tool, though nothing yet ready for broad use in the
|
||||
way that CXX on its own is.
|
||||
|
||||
[autocxx]: https://github.com/google/autocxx
|
||||
|
||||
But note in other ways CXX is higher level than the bindgens, with rich support
|
||||
for common standard library types. CXX's types serve as an intuitive vocabulary
|
||||
for designing a good boundary between components in different languages.
|
||||
BIN
vendor/cxx/book/src/cxx.png
vendored
Normal file
BIN
vendor/cxx/book/src/cxx.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
352
vendor/cxx/book/src/extern-c++.md
vendored
Normal file
352
vendor/cxx/book/src/extern-c++.md
vendored
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
{{#title extern "C++" — Rust ♡ C++}}
|
||||
# extern "C++"
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "C++" {
|
||||
include!("path/to/header.h");
|
||||
include!("path/to/another.h");
|
||||
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `extern "C++"` section of a CXX bridge declares C++ types and signatures to
|
||||
be made available to Rust, and gives the paths of the header(s) which contain
|
||||
the corresponding C++ declarations.
|
||||
|
||||
A bridge module may contain zero or more extern "C++" blocks.
|
||||
|
||||
## Opaque C++ types
|
||||
|
||||
Type defined in C++ that are made available to Rust, but only behind an
|
||||
indirection.
|
||||
|
||||
```rust,noplayground
|
||||
# #[cxx::bridge]
|
||||
# mod ffi {
|
||||
extern "C++" {
|
||||
# include!("path/to/header.h");
|
||||
#
|
||||
type MyType;
|
||||
type MyOtherType;
|
||||
}
|
||||
# }
|
||||
```
|
||||
|
||||
For example in the ***[Tutorial](tutorial.md)*** we saw `BlobstoreClient`
|
||||
implemented as an opaque C++ type. The blobstore client was created in C++ and
|
||||
returned to Rust by way of a UniquePtr.
|
||||
|
||||
**Mutability:** Unlike extern Rust types and shared types, an extern C++ type is
|
||||
not permitted to be passed by plain mutable reference `&mut MyType` across the
|
||||
FFI bridge. For mutation support, the bridge is required to use `Pin<&mut
|
||||
MyType>`. This is to safeguard against things like mem::swap-ing the contents of
|
||||
two mutable references, given that Rust doesn't have information about the size
|
||||
of the underlying object and couldn't invoke an appropriate C++ move constructor
|
||||
anyway.
|
||||
|
||||
**Thread safety:** Be aware that CXX does not assume anything about the thread
|
||||
safety of your extern C++ types. In other words the `MyType` etc bindings which
|
||||
CXX produces for you in Rust *do not* come with `Send` and `Sync` impls. If you
|
||||
are sure that your C++ type satisfies the requirements of `Send` and/or `Sync`
|
||||
and need to leverage that fact from Rust, you must provide your own unsafe
|
||||
marker trait impls.
|
||||
|
||||
```rust,noplayground
|
||||
# #[cxx::bridge]
|
||||
# mod ffi {
|
||||
# extern "C++" {
|
||||
# include!("path/to/header.h");
|
||||
#
|
||||
# type MyType;
|
||||
# }
|
||||
# }
|
||||
#
|
||||
/// The C++ implementation of MyType is thread safe.
|
||||
unsafe impl Send for ffi::MyType {}
|
||||
unsafe impl Sync for ffi::MyType {}
|
||||
```
|
||||
|
||||
Take care in doing this because thread safety in C++ can be extremely tricky to
|
||||
assess if you are coming from a Rust background. For example the
|
||||
`BlobstoreClient` type in the tutorial is *not thread safe* despite doing only
|
||||
completely innocuous things in its implementation. Concurrent calls to the `tag`
|
||||
member function trigger a data race on the `blobs` map.
|
||||
|
||||
## Functions and member functions
|
||||
|
||||
This largely follows the same principles as ***[extern
|
||||
"Rust"](extern-rust.md)*** functions and methods. In particular, any signature
|
||||
with a `self` parameter is interpreted as a C++ non-static member function and
|
||||
exposed to Rust as a method.
|
||||
|
||||
The programmer **does not** need to promise that the signatures they have typed
|
||||
in are accurate; that would be unreasonable. CXX performs static assertions that
|
||||
the signatures exactly correspond with what is declared in C++. Rather, the
|
||||
programmer is only on the hook for things that C++'s static information is not
|
||||
precise enough to capture, i.e. things that would only be represented at most by
|
||||
comments in the C++ code unintelligible to a static assertion: namely whether
|
||||
the C++ function is safe or unsafe to be called from Rust.
|
||||
|
||||
**Safety:** the extern "C++" block is responsible for deciding whether to expose
|
||||
each signature inside as safe-to-call or unsafe-to-call. If an extern block
|
||||
contains at least one safe-to-call signature, it must be written as an `unsafe
|
||||
extern` block, which serves as an item level unsafe block to indicate that an
|
||||
unchecked safety claim is being made about the contents of the block.
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
unsafe extern "C++" {
|
||||
# include!("path/to/header.h");
|
||||
#
|
||||
fn f(); // safe to call
|
||||
}
|
||||
|
||||
extern "C++" {
|
||||
unsafe fn g(); // unsafe to call
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Lifetimes
|
||||
|
||||
C++ types holding borrowed data may be described naturally in Rust by an extern
|
||||
type with a generic lifetime parameter. For example in the case of the following
|
||||
pair of types:
|
||||
|
||||
```cpp
|
||||
// header.h
|
||||
|
||||
class Resource;
|
||||
|
||||
class TypeContainingBorrow {
|
||||
TypeContainingBorrow(const Resource &res) : res(res) {}
|
||||
const Resource &res;
|
||||
};
|
||||
|
||||
std::shared_ptr<TypeContainingBorrow> create(const Resource &res);
|
||||
```
|
||||
|
||||
we'd want to expose this to Rust as:
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
unsafe extern "C++" {
|
||||
# include!("path/to/header.h");
|
||||
#
|
||||
type Resource;
|
||||
type TypeContainingBorrow<'a>;
|
||||
|
||||
fn create<'a>(res: &'a Resource) -> SharedPtr<TypeContainingBorrow<'a>>;
|
||||
|
||||
// or with lifetime elision:
|
||||
fn create(res: &Resource) -> SharedPtr<TypeContainingBorrow>;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Reusing existing binding types
|
||||
|
||||
Extern C++ types support a syntax for declaring that a Rust binding of the
|
||||
correct C++ type already exists outside of the current bridge module. This
|
||||
avoids generating a fresh new binding which Rust's type system would consider
|
||||
non-interchangeable with the first.
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge(namespace = "path::to")]
|
||||
mod ffi {
|
||||
extern "C++" {
|
||||
type MyType = crate::existing::MyType;
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
fn f(x: &MyType) -> usize;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this case rather than producing a unique new Rust type `ffi::MyType` for the
|
||||
Rust binding of C++'s `::path::to::MyType`, CXX will reuse the already existing
|
||||
binding at `crate::existing::MyType` in expressing the signature of `f` and any
|
||||
other uses of `MyType` within the bridge module.
|
||||
|
||||
CXX safely validates that `crate::existing::MyType` is in fact a binding for the
|
||||
right C++ type `::path::to::MyType` by generating a static assertion based on
|
||||
`crate::existing::MyType`'s implementation of [`ExternType`], which is a trait
|
||||
automatically implemented by CXX for bindings that it generates but can also be
|
||||
manually implemented as described below.
|
||||
|
||||
[`ExternType`]: https://docs.rs/cxx/*/cxx/trait.ExternType.html
|
||||
|
||||
`ExternType` serves the following two related use cases.
|
||||
|
||||
#### Safely unifying occurrences of an extern type across bridges
|
||||
|
||||
In the following snippet, two #\[cxx::bridge\] invocations in different files
|
||||
(possibly different crates) both contain function signatures involving the same
|
||||
C++ type `example::Demo`. If both were written just containing `type Demo;`,
|
||||
then both macro expansions would produce their own separate Rust type called
|
||||
`Demo` and thus the compiler wouldn't allow us to take the `Demo` returned by
|
||||
`file1::ffi::create_demo` and pass it as the `Demo` argument accepted by
|
||||
`file2::ffi::take_ref_demo`. Instead, one of the two `Demo`s has been defined as
|
||||
an extern type alias of the other, making them the same type in Rust.
|
||||
|
||||
```rust,noplayground
|
||||
// file1.rs
|
||||
#[cxx::bridge(namespace = "example")]
|
||||
pub mod ffi {
|
||||
unsafe extern "C++" {
|
||||
type Demo;
|
||||
|
||||
fn create_demo() -> UniquePtr<Demo>;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```rust,noplayground
|
||||
// file2.rs
|
||||
#[cxx::bridge(namespace = "example")]
|
||||
pub mod ffi {
|
||||
unsafe extern "C++" {
|
||||
type Demo = crate::file1::ffi::Demo;
|
||||
|
||||
fn take_ref_demo(demo: &Demo);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Integrating with bindgen-generated or handwritten unsafe bindings
|
||||
|
||||
Handwritten `ExternType` impls make it possible to plug in a data structure
|
||||
emitted by bindgen as the definition of a C++ type emitted by CXX.
|
||||
|
||||
By writing the unsafe `ExternType` impl, the programmer asserts that the C++
|
||||
namespace and type name given in the type id refers to a C++ type that is
|
||||
equivalent to Rust type that is the `Self` type of the impl.
|
||||
|
||||
```rust,noplayground
|
||||
mod folly_sys; // the bindgen-generated bindings
|
||||
|
||||
use cxx::{type_id, ExternType};
|
||||
|
||||
unsafe impl ExternType for folly_sys::StringPiece {
|
||||
type Id = type_id!("folly::StringPiece");
|
||||
type Kind = cxx::kind::Opaque;
|
||||
}
|
||||
|
||||
#[cxx::bridge(namespace = "folly")]
|
||||
pub mod ffi {
|
||||
unsafe extern "C++" {
|
||||
include!("rust_cxx_bindings.h");
|
||||
|
||||
type StringPiece = crate::folly_sys::StringPiece;
|
||||
|
||||
fn print_string_piece(s: &StringPiece);
|
||||
}
|
||||
}
|
||||
|
||||
// Now if we construct a StringPiece or obtain one through one
|
||||
// of the bindgen-generated signatures, we are able to pass it
|
||||
// along to ffi::print_string_piece.
|
||||
```
|
||||
|
||||
The `ExternType::Id` associated type encodes a type-level representation of the
|
||||
type's C++ namespace and type name. It will always be defined using the
|
||||
`type_id!` macro exposed in the cxx crate.
|
||||
|
||||
The `ExternType::Kind` associated type will always be either
|
||||
[`cxx::kind::Opaque`] or [`cxx::kind::Trivial`] identifying whether a C++ type
|
||||
is soundly relocatable by Rust's move semantics. A C++ type is only okay to hold
|
||||
and pass around by value in Rust if its [move constructor is trivial] and it has
|
||||
no destructor. In CXX, these are called Trivial extern C++ types, while types
|
||||
with nontrivial move behavior or a destructor must be considered Opaque and
|
||||
handled by Rust only behind an indirection, such as a reference or UniquePtr.
|
||||
|
||||
[`cxx::kind::Opaque`]: https://docs.rs/cxx/*/cxx/kind/enum.Opaque.html
|
||||
[`cxx::kind::Trivial`]: https://docs.rs/cxx/*/cxx/kind/enum.Trivial.html
|
||||
[move constructor is trivial]: https://en.cppreference.com/w/cpp/types/is_move_constructible
|
||||
|
||||
If you believe your C++ type reflected by the ExternType impl is indeed fine to
|
||||
hold by value and move in Rust, you can specify:
|
||||
|
||||
```rust,noplayground
|
||||
# unsafe impl cxx::ExternType for TypeName {
|
||||
# type Id = cxx::type_id!("name::space::of::TypeName");
|
||||
type Kind = cxx::kind::Trivial;
|
||||
# }
|
||||
```
|
||||
|
||||
which will enable you to pass it into C++ functions by value, return it by
|
||||
value, and include it in `struct`s that you have declared to `cxx::bridge`. Your
|
||||
claim about the triviality of the C++ type will be checked by a `static_assert`
|
||||
in the generated C++ side of the binding.
|
||||
|
||||
## Explicit shim trait impls
|
||||
|
||||
This is a somewhat niche feature, but important when you need it.
|
||||
|
||||
CXX's support for C++'s std::unique\_ptr and std::vector is built on a set of
|
||||
internal trait impls connecting the Rust API of UniquePtr and CxxVector to
|
||||
underlying template instantiations performed by the C++ compiler.
|
||||
|
||||
When reusing a binding type across multiple bridge modules as described in the
|
||||
previous section, you may find that your code needs some trait impls which CXX
|
||||
hasn't decided to generate.
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi1 {
|
||||
extern "C++" {
|
||||
include!("path/to/header.h");
|
||||
|
||||
type A;
|
||||
type B;
|
||||
|
||||
// Okay: CXX sees UniquePtr<B> using a type B defined within the same
|
||||
// bridge, and automatically emits the right template instantiations
|
||||
// corresponding to std::unique_ptr<B>.
|
||||
fn get_b() -> UniquePtr<B>;
|
||||
}
|
||||
}
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi2 {
|
||||
extern "C++" {
|
||||
type A = crate::ffi1::A;
|
||||
|
||||
// Rust trait error: CXX processing this module has no visibility into
|
||||
// whether template instantiations corresponding to std::unique_ptr<A>
|
||||
// have already been emitted by the upstream library, so it does not
|
||||
// emit them here. If the upstream library does not have any signatures
|
||||
// involving UniquePtr<A>, an explicit instantiation of the template
|
||||
// needs to be requested in one module or the other.
|
||||
fn get_a() -> UniquePtr<A>;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can request a specific template instantiation at a particular location in
|
||||
the Rust crate hierarchy by writing `impl UniquePtr<A> {}` inside of the bridge
|
||||
module which defines `A` but does not otherwise contain any use of
|
||||
`UniquePtr<A>`.
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi1 {
|
||||
extern "C++" {
|
||||
include!("path/to/header.h");
|
||||
|
||||
type A;
|
||||
type B;
|
||||
|
||||
fn get_b() -> UniquePtr<B>;
|
||||
}
|
||||
|
||||
impl UniquePtr<A> {} // explicit instantiation
|
||||
}
|
||||
```
|
||||
165
vendor/cxx/book/src/extern-rust.md
vendored
Normal file
165
vendor/cxx/book/src/extern-rust.md
vendored
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
{{#title extern "Rust" — Rust ♡ C++}}
|
||||
# extern "Rust"
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `extern "Rust"` section of a CXX bridge declares Rust types and signatures
|
||||
to be made available to C++.
|
||||
|
||||
The CXX code generator uses your extern "Rust" section(s) to produce a C++
|
||||
header file containing the corresponding C++ declarations. The generated header
|
||||
has the same path as the Rust source file containing the bridge, except with a
|
||||
`.rs.h` file extension.
|
||||
|
||||
A bridge module may contain zero or more extern "Rust" blocks.
|
||||
|
||||
## Opaque Rust types
|
||||
|
||||
Types defined in Rust that are made available to C++, but only behind an
|
||||
indirection.
|
||||
|
||||
```rust,noplayground
|
||||
# #[cxx::bridge]
|
||||
# mod ffi {
|
||||
extern "Rust" {
|
||||
type MyType;
|
||||
type MyOtherType;
|
||||
type OneMoreType<'a>;
|
||||
}
|
||||
# }
|
||||
```
|
||||
|
||||
For example in the ***[Tutorial](tutorial.md)*** we saw `MultiBuf` used in this
|
||||
way. Rust code created the `MultiBuf`, passed a `&mut MultiBuf` to C++, and C++
|
||||
later passed a `&mut MultiBuf` back across the bridge to Rust.
|
||||
|
||||
Another example is the one on the ***[Box\<T\>](binding/box.md)*** page, which
|
||||
exposes the Rust standard library's `std::fs::File` to C++ as an opaque type in
|
||||
a similar way but with Box as the indirection rather than &mut.
|
||||
|
||||
The types named as opaque types (`MyType` etc) refer to types in the `super`
|
||||
module, the parent module of the CXX bridge. You can think of an opaque type `T`
|
||||
as being like a re-export `use super::T` made available to C++ via the generated
|
||||
header.
|
||||
|
||||
Opaque types are currently required to be [`Sized`] and [`Unpin`]. In
|
||||
particular, a trait object `dyn MyTrait` or slice `[T]` may not be used for an
|
||||
opaque Rust type. These restrictions may be lifted in the future.
|
||||
|
||||
[`Sized`]: https://doc.rust-lang.org/std/marker/trait.Sized.html
|
||||
[`Unpin`]: https://doc.rust-lang.org/std/marker/trait.Unpin.html
|
||||
|
||||
For now, types used as extern Rust types are required to be defined by the same
|
||||
crate that contains the bridge using them. This restriction may be lifted in the
|
||||
future.
|
||||
|
||||
The bridge's parent module will contain the appropriate imports or definitions
|
||||
for these types.
|
||||
|
||||
```rust,noplayground
|
||||
use path::to::MyType;
|
||||
|
||||
pub struct MyOtherType {
|
||||
...
|
||||
}
|
||||
#
|
||||
# #[cxx::bridge]
|
||||
# mod ffi {
|
||||
# extern "Rust" {
|
||||
# type MyType;
|
||||
# type MyOtherType;
|
||||
# }
|
||||
# }
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
Rust functions made callable to C++.
|
||||
|
||||
Just like for opaque types, these functions refer implicitly to something in
|
||||
scope in the `super` module, whether defined there or imported by some `use`
|
||||
statement.
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
struct MyType;
|
||||
fn f() -> Box<MyType>;
|
||||
}
|
||||
}
|
||||
|
||||
struct MyType(i32);
|
||||
|
||||
fn f() -> Box<MyType> {
|
||||
return Box::new(MyType(1));
|
||||
}
|
||||
```
|
||||
|
||||
Extern Rust function signature may consist of types defined in the bridge,
|
||||
primitives, and [any of these additional bindings](bindings.md).
|
||||
|
||||
## Methods
|
||||
|
||||
Any signature with a `self` parameter is interpreted as a Rust method and
|
||||
exposed to C++ as a non-static member function.
|
||||
|
||||
```rust,noplayground
|
||||
# #[cxx::bridge]
|
||||
# mod ffi {
|
||||
extern "Rust" {
|
||||
type MyType;
|
||||
fn f(&self) -> usize;
|
||||
}
|
||||
# }
|
||||
```
|
||||
|
||||
The `self` parameter may be a shared reference `&self`, an exclusive reference
|
||||
`&mut self`, or a pinned reference `self: Pin<&mut Self>`. A by-value `self` is
|
||||
not currently supported.
|
||||
|
||||
If the surrounding `extern "Rust"` block contains exactly one extern type, that
|
||||
type is implicitly the receiver for a `&self` or `&mut self` method. If the
|
||||
surrounding block contains *more than one* extern type, a receiver type must be
|
||||
provided explicitly for the self parameter, or you can consider splitting into
|
||||
multiple extern blocks.
|
||||
|
||||
```rust,noplayground
|
||||
# #[cxx::bridge]
|
||||
# mod ffi {
|
||||
extern "Rust" {
|
||||
type First;
|
||||
type Second;
|
||||
fn bar(self: &First);
|
||||
fn foo(self: &mut Second);
|
||||
}
|
||||
# }
|
||||
```
|
||||
|
||||
## Functions with explicit lifetimes
|
||||
|
||||
An extern Rust function signature is allowed to contain explicit lifetimes but
|
||||
in this case the function must be declared unsafe-to-call. This is pretty
|
||||
meaningless given we're talking about calls from C++, but at least it draws some
|
||||
extra attention from the caller that they may be responsible for upholding some
|
||||
atypical lifetime relationship.
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
type MyType;
|
||||
unsafe fn f<'a>(&'a self, s: &str) -> &'a str;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Bounds on a lifetime (like `<'a, 'b: 'a>`) are not currently supported. Nor are
|
||||
type parameters or where-clauses.
|
||||
83
vendor/cxx/book/src/index.md
vendored
Normal file
83
vendor/cxx/book/src/index.md
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<div class="badges">
|
||||
<a href="https://github.com/dtolnay/cxx"><img src="https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github" alt="github" height="28" class="badge"></a><a href="https://crates.io/crates/cxx"><img src="https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust" alt="crates-io" height="28" class="badge"></a><a href="https://docs.rs/cxx"><img src="https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" alt="docs-rs" height="28" class="badge"></a>
|
||||
</div>
|
||||
|
||||
# CXX — safe interop between Rust and C++
|
||||
|
||||
This library provides a safe mechanism for calling C++ code from Rust and Rust
|
||||
code from C++. It carves out a regime of commonality where Rust and C++ are
|
||||
semantically very similar and guides the programmer to express their language
|
||||
boundary effectively within this regime. CXX fills in the low level stuff so
|
||||
that you get a safe binding, preventing the pitfalls of doing a foreign function
|
||||
interface over unsafe C-style signatures.
|
||||
|
||||
<div style="height:190px;width=718px;padding:44px 0 44px">
|
||||
<object type="image/svg+xml" data="overview.svg"></object>
|
||||
</div>
|
||||
|
||||
From a high level description of the language boundary, CXX uses static analysis
|
||||
of the types and function signatures to protect both Rust's and C++'s
|
||||
invariants. Then it uses a pair of code generators to implement the boundary
|
||||
efficiently on both sides together with any necessary static assertions for
|
||||
later in the build process to verify correctness.
|
||||
|
||||
The resulting FFI bridge operates at zero or negligible overhead, i.e. no
|
||||
copying, no serialization, no memory allocation, no runtime checks needed.
|
||||
|
||||
The FFI signatures are able to use native data structures from whichever side
|
||||
they please. In addition, CXX provides builtin bindings for key standard library
|
||||
types like strings, vectors, Box, unique\_ptr, etc to expose an idiomatic API on
|
||||
those types to the other language.
|
||||
|
||||
## Example
|
||||
|
||||
In this example we are writing a Rust application that calls a C++ client of a
|
||||
large-file blobstore service. The blobstore supports a `put` operation for a
|
||||
discontiguous buffer upload. For example we might be uploading snapshots of a
|
||||
circular buffer which would tend to consist of 2 pieces, or fragments of a file
|
||||
spread across memory for some other reason (like a rope data structure).
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
type MultiBuf;
|
||||
|
||||
fn next_chunk(buf: &mut MultiBuf) -> &[u8];
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("example/include/blobstore.h");
|
||||
|
||||
type BlobstoreClient;
|
||||
|
||||
fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
|
||||
fn put(self: &BlobstoreClient, buf: &mut MultiBuf) -> Result<u64>;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now we simply provide Rust definitions of all the things in the `extern "Rust"`
|
||||
block and C++ definitions of all the things in the `extern "C++"` block, and get
|
||||
to call back and forth safely.
|
||||
|
||||
The [***Tutorial***](tutorial.md) chapter walks through a fleshed out version of
|
||||
this blobstore example in full detail, including all of the Rust code and all of
|
||||
the C++ code. The code is also provided in runnable form in the *demo* directory
|
||||
of <https://github.com/dtolnay/cxx>. To try it out, run `cargo run` from that
|
||||
directory.
|
||||
|
||||
- [demo/src/main.rs](https://github.com/dtolnay/cxx/blob/master/demo/src/main.rs)
|
||||
- [demo/include/blobstore.h](https://github.com/dtolnay/cxx/blob/master/demo/include/blobstore.h)
|
||||
- [demo/src/blobstore.cc](https://github.com/dtolnay/cxx/blob/master/demo/src/blobstore.cc)
|
||||
|
||||
The key takeaway, which is enabled by the CXX library, is that the Rust code in
|
||||
main.rs is 100% ordinary safe Rust code working idiomatically with Rust types
|
||||
while the C++ code in blobstore.cc is 100% ordinary C++ code working
|
||||
idiomatically with C++ types. The Rust code feels like Rust and the C++ code
|
||||
feels like C++, not like C-style "FFI glue".
|
||||
|
||||
<br>
|
||||
|
||||
***Chapter outline:** See the hamburger menu in the top left if you are on a
|
||||
small screen and it didn't open with a sidebar by default.*
|
||||
444
vendor/cxx/book/src/overview.svg
vendored
Normal file
444
vendor/cxx/book/src/overview.svg
vendored
Normal file
|
|
@ -0,0 +1,444 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="541.903pt" height="142.287pt" viewBox="0 0 541.903 142.287" version="1.1">
|
||||
<defs>
|
||||
<g>
|
||||
<symbol overflow="visible" id="glyph0-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-1">
|
||||
<path style="stroke:none;" d="M 5.140625 -2.359375 L 6.234375 -2.359375 C 6.421875 -2.359375 6.890625 -2.359375 6.890625 -2.828125 C 6.890625 -3.296875 6.4375 -3.296875 6.234375 -3.296875 L 5.265625 -3.296875 L 5.515625 -5.46875 L 6.234375 -5.46875 C 6.421875 -5.46875 6.890625 -5.46875 6.890625 -5.921875 C 6.890625 -6.390625 6.4375 -6.390625 6.234375 -6.390625 L 5.65625 -6.390625 L 5.875 -8.125 C 5.9375 -8.59375 5.6875 -8.765625 5.421875 -8.765625 C 5.015625 -8.765625 4.984375 -8.390625 4.953125 -8.203125 L 4.71875 -6.390625 L 3.171875 -6.390625 L 3.40625 -8.125 C 3.453125 -8.59375 3.203125 -8.765625 2.9375 -8.765625 C 2.53125 -8.765625 2.5 -8.390625 2.46875 -8.203125 L 2.234375 -6.390625 L 1.140625 -6.390625 C 0.953125 -6.390625 0.484375 -6.390625 0.484375 -5.9375 C 0.484375 -5.46875 0.9375 -5.46875 1.140625 -5.46875 L 2.109375 -5.46875 L 1.84375 -3.296875 L 1.140625 -3.296875 C 0.953125 -3.296875 0.484375 -3.296875 0.484375 -2.84375 C 0.484375 -2.359375 0.9375 -2.359375 1.140625 -2.359375 L 1.71875 -2.359375 L 1.484375 -0.640625 C 1.40625 0 1.90625 0 1.953125 0 C 2.359375 0 2.390625 -0.375 2.421875 -0.5625 L 2.65625 -2.359375 L 4.203125 -2.359375 L 3.96875 -0.640625 C 3.890625 0 4.390625 0 4.4375 0 C 4.828125 0 4.875 -0.375 4.90625 -0.5625 Z M 3.046875 -5.46875 L 4.59375 -5.46875 L 4.328125 -3.296875 L 2.78125 -3.296875 Z M 3.046875 -5.46875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-2">
|
||||
<path style="stroke:none;" d="M 6.21875 -9.125 C 6.421875 -9.125 6.796875 -9.125 6.796875 -9.53125 C 6.796875 -9.953125 6.421875 -9.953125 6.21875 -9.953125 L 3.734375 -9.953125 C 3.25 -9.953125 3.15625 -9.828125 3.15625 -9.359375 L 3.15625 0.609375 C 3.15625 1.046875 3.234375 1.1875 3.734375 1.1875 L 6.21875 1.1875 C 6.421875 1.1875 6.796875 1.1875 6.796875 0.78125 C 6.796875 0.359375 6.421875 0.359375 6.21875 0.359375 L 4.09375 0.359375 L 4.09375 -9.125 Z M 6.21875 -9.125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-3">
|
||||
<path style="stroke:none;" d="M 4.21875 -9.359375 C 4.21875 -9.8125 4.125 -9.953125 3.640625 -9.953125 L 1.140625 -9.953125 C 0.953125 -9.953125 0.578125 -9.953125 0.578125 -9.53125 C 0.578125 -9.125 0.953125 -9.125 1.140625 -9.125 L 3.28125 -9.125 L 3.28125 0.359375 L 1.140625 0.359375 C 0.953125 0.359375 0.578125 0.359375 0.578125 0.78125 C 0.578125 1.1875 0.953125 1.1875 1.140625 1.1875 L 3.640625 1.1875 C 4.109375 1.1875 4.21875 1.0625 4.21875 0.609375 Z M 4.21875 -9.359375 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-4">
|
||||
<path style="stroke:none;" d="M 4.15625 -3.921875 L 6.203125 -3.921875 C 6.390625 -3.921875 6.84375 -3.921875 6.84375 -4.375 C 6.84375 -4.84375 6.390625 -4.84375 6.203125 -4.84375 L 4.15625 -4.84375 L 4.15625 -6.90625 C 4.15625 -7.078125 4.15625 -7.546875 3.703125 -7.546875 C 3.234375 -7.546875 3.234375 -7.09375 3.234375 -6.90625 L 3.234375 -4.84375 L 1.171875 -4.84375 C 0.984375 -4.84375 0.53125 -4.84375 0.53125 -4.390625 C 0.53125 -3.921875 0.96875 -3.921875 1.171875 -3.921875 L 3.234375 -3.921875 L 3.234375 -1.859375 C 3.234375 -1.671875 3.234375 -1.21875 3.6875 -1.21875 C 4.15625 -1.21875 4.15625 -1.65625 4.15625 -1.859375 Z M 4.15625 -3.921875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-1">
|
||||
<path style="stroke:none;" d="M 5.75 -1.546875 C 5.09375 -1.015625 4.359375 -0.75 3.5625 -0.75 C 2.359375 -0.75 1.59375 -1.8125 1.59375 -3.203125 C 1.59375 -4.390625 2.171875 -5.6875 3.59375 -5.6875 C 4.5625 -5.6875 4.96875 -5.46875 5.578125 -5.046875 L 5.75 -5.984375 C 4.921875 -6.46875 4.453125 -6.578125 3.59375 -6.578125 C 1.625 -6.578125 0.5 -4.828125 0.5 -3.203125 C 0.5 -1.359375 1.828125 0.140625 3.546875 0.140625 C 4.25 0.140625 5.046875 -0.03125 5.84375 -0.609375 C 5.84375 -0.640625 5.796875 -1.09375 5.78125 -1.140625 Z M 5.75 -1.546875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-2">
|
||||
<path style="stroke:none;" d="M 3.640625 -3.28125 L 6.1875 -6.375 L 4.984375 -6.375 L 3.171875 -4.046875 L 1.296875 -6.375 L 0.078125 -6.375 L 2.6875 -3.28125 L 0 0 L 1.1875 0 L 3.171875 -2.671875 L 5.203125 0 L 6.40625 0 Z M 3.640625 -3.28125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-3">
|
||||
<path style="stroke:none;" d="M 2.53125 -6.375 L 1.359375 -6.375 L 1.359375 -5.203125 L 2.53125 -5.203125 Z M 1.359375 -1.15625 L 1.359375 0 L 2.53125 0 L 2.53125 -1.15625 Z M 1.359375 -1.15625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-4">
|
||||
<path style="stroke:none;" d="M 2.1875 -9.953125 L 1.125 -9.953125 L 1.125 0 L 2.203125 0 L 2.203125 -0.640625 C 2.875 -0.015625 3.578125 0.140625 4.078125 0.140625 C 5.4375 0.140625 6.6875 -1.25 6.6875 -3.203125 C 6.6875 -4.96875 5.734375 -6.515625 4.40625 -6.515625 C 3.984375 -6.515625 3.0625 -6.421875 2.1875 -5.703125 Z M 2.203125 -4.828125 C 2.46875 -5.234375 2.984375 -5.65625 3.6875 -5.65625 C 4.5625 -5.65625 5.59375 -4.984375 5.59375 -3.203125 C 5.59375 -1.328125 4.421875 -0.71875 3.546875 -0.71875 C 3.140625 -0.71875 2.875 -0.859375 2.609375 -1.0625 C 2.265625 -1.359375 2.203125 -1.625 2.203125 -1.859375 Z M 2.203125 -4.828125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-5">
|
||||
<path style="stroke:none;" d="M 2.1875 -3.140625 C 2.1875 -4.59375 3.265625 -5.53125 4.5625 -5.546875 L 4.5625 -6.515625 C 3.25 -6.5 2.5 -5.734375 2.109375 -5.171875 L 2.109375 -6.4375 L 1.125 -6.4375 L 1.125 0 L 2.1875 0 Z M 2.1875 -3.140625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-6">
|
||||
<path style="stroke:none;" d="M 2.265625 -9.734375 L 1.03125 -9.734375 L 1.03125 -8.5 L 2.265625 -8.5 Z M 2.1875 -6.375 L 1.125 -6.375 L 1.125 0 L 2.1875 0 Z M 2.1875 -6.375 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-7">
|
||||
<path style="stroke:none;" d="M 6.0625 -9.953125 L 5 -9.953125 L 5 -5.765625 C 4.34375 -6.3125 3.59375 -6.515625 2.984375 -6.515625 C 1.625 -6.515625 0.5 -5.046875 0.5 -3.1875 C 0.5 -1.328125 1.5625 0.140625 2.921875 0.140625 C 3.453125 0.140625 4.265625 -0.03125 4.984375 -0.734375 L 4.984375 0 L 6.0625 0 Z M 4.984375 -1.6875 C 4.640625 -1.078125 4.125 -0.71875 3.5 -0.71875 C 2.625 -0.71875 1.59375 -1.390625 1.59375 -3.171875 C 1.59375 -5.078125 2.8125 -5.65625 3.640625 -5.65625 C 4.203125 -5.65625 4.65625 -5.359375 4.984375 -4.890625 Z M 4.984375 -1.6875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-8">
|
||||
<path style="stroke:none;" d="M 4.890625 -5.65625 C 4.890625 -5.65625 4.921875 -5.625 4.9375 -5.59375 C 5.234375 -5.625 5.546875 -5.671875 6.078125 -5.671875 C 6.125 -5.671875 6.453125 -5.671875 6.8125 -5.640625 L 6.65625 -6.515625 C 6.390625 -6.515625 5.40625 -6.5 4.453125 -6.03125 C 3.984375 -6.4375 3.40625 -6.515625 3.125 -6.515625 C 1.875 -6.515625 0.875 -5.46875 0.875 -4.203125 C 0.875 -3.6875 1.03125 -3.21875 1.34375 -2.78125 C 1.015625 -2.328125 0.9375 -1.890625 0.9375 -1.546875 C 0.9375 -1.015625 1.140625 -0.65625 1.296875 -0.46875 C 0.5625 0 0.390625 0.609375 0.390625 1.015625 C 0.390625 2.0625 1.75 2.9375 3.5 2.9375 C 5.25 2.9375 6.625 2.09375 6.625 1 C 6.625 -1 4.296875 -1 3.71875 -1 L 2.5 -1 C 2.296875 -1 1.671875 -1 1.671875 -1.765625 C 1.671875 -2.078125 1.734375 -2.171875 1.828125 -2.296875 C 2.0625 -2.125 2.53125 -1.875 3.109375 -1.875 C 4.34375 -1.875 5.359375 -2.890625 5.359375 -4.203125 C 5.359375 -4.71875 5.171875 -5.25 4.875 -5.640625 Z M 3.125 -2.671875 C 2.5 -2.671875 1.859375 -3.09375 1.859375 -4.1875 C 1.859375 -5.46875 2.671875 -5.71875 3.109375 -5.71875 C 3.75 -5.71875 4.375 -5.296875 4.375 -4.203125 C 4.375 -2.921875 3.578125 -2.671875 3.125 -2.671875 Z M 3.734375 0.03125 C 4.046875 0.03125 5.625 0.03125 5.625 1.015625 C 5.625 1.671875 4.640625 2.15625 3.515625 2.15625 C 2.390625 2.15625 1.390625 1.703125 1.390625 1 C 1.390625 0.96875 1.390625 0.03125 2.484375 0.03125 Z M 3.734375 0.03125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-9">
|
||||
<path style="stroke:none;" d="M 5.84375 -3.234375 C 5.84375 -3.84375 5.78125 -4.71875 5.328125 -5.484375 C 4.734375 -6.46875 3.734375 -6.578125 3.3125 -6.578125 C 1.765625 -6.578125 0.46875 -5.09375 0.46875 -3.234375 C 0.46875 -1.328125 1.84375 0.140625 3.515625 0.140625 C 4.171875 0.140625 4.96875 -0.046875 5.75 -0.609375 C 5.75 -0.671875 5.703125 -1.125 5.703125 -1.140625 C 5.6875 -1.15625 5.671875 -1.484375 5.671875 -1.53125 C 4.8125 -0.8125 3.96875 -0.71875 3.546875 -0.71875 C 2.4375 -0.71875 1.484375 -1.703125 1.46875 -3.234375 Z M 1.546875 -4 C 1.796875 -4.96875 2.46875 -5.71875 3.3125 -5.71875 C 3.765625 -5.71875 4.75 -5.515625 4.984375 -4 Z M 1.546875 -4 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-10">
|
||||
<path style="stroke:none;" d="M 10 -4.3125 C 10 -5.3125 9.734375 -6.515625 8.0625 -6.515625 C 6.84375 -6.515625 6.171875 -5.671875 5.953125 -5.34375 C 5.6875 -6.25 4.90625 -6.515625 4.15625 -6.515625 C 2.984375 -6.515625 2.359375 -5.75 2.125 -5.453125 L 2.125 -6.4375 L 1.109375 -6.4375 L 1.109375 0 L 2.1875 0 L 2.1875 -3.578125 C 2.1875 -4.515625 2.5625 -5.65625 3.609375 -5.65625 C 4.9375 -5.65625 5 -4.75 5 -4.21875 L 5 0 L 6.09375 0 L 6.09375 -3.578125 C 6.09375 -4.515625 6.46875 -5.65625 7.515625 -5.65625 C 8.828125 -5.65625 8.90625 -4.75 8.90625 -4.21875 L 8.90625 0 L 10 0 Z M 10 -4.3125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-11">
|
||||
<path style="stroke:none;" d="M 6.578125 -3.15625 C 6.578125 -5.09375 5.15625 -6.578125 3.515625 -6.578125 C 1.828125 -6.578125 0.4375 -5.0625 0.4375 -3.15625 C 0.4375 -1.28125 1.859375 0.140625 3.5 0.140625 C 5.1875 0.140625 6.578125 -1.3125 6.578125 -3.15625 Z M 3.515625 -0.75 C 2.484375 -0.75 1.515625 -1.609375 1.515625 -3.296875 C 1.515625 -5.03125 2.59375 -5.71875 3.5 -5.71875 C 4.484375 -5.71875 5.5 -4.984375 5.5 -3.296875 C 5.5 -1.53125 4.46875 -0.75 3.515625 -0.75 Z M 3.515625 -0.75 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-12">
|
||||
<path style="stroke:none;" d="M 4.8125 -6.140625 C 3.90625 -6.5625 3.125 -6.578125 2.796875 -6.578125 C 2.46875 -6.578125 0.46875 -6.578125 0.46875 -4.71875 C 0.46875 -4.09375 0.8125 -3.65625 1.03125 -3.453125 C 1.546875 -3.015625 1.90625 -2.9375 2.75 -2.765625 C 3.234375 -2.671875 4.0625 -2.5 4.0625 -1.734375 C 4.0625 -0.75 2.9375 -0.75 2.734375 -0.75 C 2.171875 -0.75 1.328125 -0.90625 0.5625 -1.46875 L 0.390625 -0.484375 C 0.453125 -0.4375 1.4375 0.140625 2.75 0.140625 C 4.609375 0.140625 5.046875 -0.96875 5.046875 -1.828125 C 5.046875 -2.546875 4.609375 -3.015625 4.546875 -3.078125 C 4.015625 -3.625 3.578125 -3.71875 2.71875 -3.890625 C 2.1875 -3.984375 1.46875 -4.125 1.46875 -4.84375 C 1.46875 -5.734375 2.46875 -5.734375 2.65625 -5.734375 C 3.40625 -5.734375 4.015625 -5.5625 4.640625 -5.203125 Z M 4.8125 -6.140625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-13">
|
||||
<path style="stroke:none;" d="M 2.203125 -0.640625 C 2.703125 -0.203125 3.296875 0.140625 4.078125 0.140625 C 5.453125 0.140625 6.6875 -1.25 6.6875 -3.203125 C 6.6875 -4.9375 5.765625 -6.515625 4.4375 -6.515625 C 3.84375 -6.515625 2.921875 -6.328125 2.1875 -5.6875 L 2.1875 -6.375 L 1.125 -6.375 L 1.125 2.78125 L 2.203125 2.78125 Z M 2.203125 -4.8125 C 2.53125 -5.3125 3.078125 -5.625 3.671875 -5.625 C 4.734375 -5.625 5.59375 -4.546875 5.59375 -3.1875 C 5.59375 -1.75 4.609375 -0.71875 3.546875 -0.71875 C 3.140625 -0.71875 2.875 -0.859375 2.609375 -1.0625 C 2.25 -1.375 2.203125 -1.640625 2.203125 -1.859375 Z M 2.203125 -4.8125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-14">
|
||||
<path style="stroke:none;" d="M 2.453125 -5.53125 L 4.4375 -5.53125 L 4.4375 -6.375 L 2.453125 -6.375 L 2.453125 -8.1875 L 1.46875 -8.1875 L 1.46875 -6.375 L 0.265625 -6.375 L 0.265625 -5.53125 L 1.4375 -5.53125 L 1.4375 -1.671875 C 1.4375 -0.84375 1.625 0.140625 2.609375 0.140625 C 3.578125 0.140625 4.234375 -0.1875 4.671875 -0.421875 L 4.453125 -1.25 C 3.953125 -0.796875 3.421875 -0.75 3.171875 -0.75 C 2.53125 -0.75 2.453125 -1.421875 2.453125 -1.921875 Z M 2.453125 -5.53125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-15">
|
||||
<path style="stroke:none;" d="M 6.078125 -4.3125 C 6.078125 -5.1875 5.890625 -6.515625 4.15625 -6.515625 C 3.359375 -6.515625 2.671875 -6.15625 2.125 -5.46875 L 2.125 -6.4375 L 1.109375 -6.4375 L 1.109375 0 L 2.1875 0 L 2.1875 -3.578125 C 2.1875 -4.453125 2.53125 -5.65625 3.609375 -5.65625 C 4.953125 -5.65625 4.984375 -4.71875 4.984375 -4.21875 L 4.984375 0 L 6.078125 0 Z M 6.078125 -4.3125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-16">
|
||||
<path style="stroke:none;" d="M 2.484375 -5.53125 L 4.015625 -5.53125 L 4.015625 -6.375 L 2.453125 -6.375 L 2.453125 -8.09375 C 2.453125 -9.0625 3.265625 -9.234375 3.75 -9.234375 C 4.25 -9.234375 4.6875 -9.078125 4.859375 -9.015625 L 4.859375 -9.953125 C 4.765625 -9.984375 4.28125 -10.09375 3.765625 -10.09375 C 2.390625 -10.09375 1.421875 -9.046875 1.421875 -7.65625 L 1.421875 -6.375 L 0.375 -6.375 L 0.375 -5.53125 L 1.421875 -5.53125 L 1.421875 0 L 2.484375 0 Z M 2.484375 -5.53125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-17">
|
||||
<path style="stroke:none;" d="M 6.078125 -6.375 L 4.984375 -6.375 L 4.984375 -2.265625 C 4.984375 -1.171875 4.234375 -0.640625 3.296875 -0.640625 C 2.296875 -0.640625 2.1875 -1.015625 2.1875 -1.65625 L 2.1875 -6.375 L 1.109375 -6.375 L 1.109375 -1.59375 C 1.109375 -0.5625 1.4375 0.140625 2.609375 0.140625 C 3.015625 0.140625 4.140625 0.078125 5.015625 -0.71875 L 5.015625 0 L 6.078125 0 Z M 6.078125 -6.375 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-18">
|
||||
<path style="stroke:none;" d="M 5.609375 -4.203125 C 5.609375 -5.578125 4.625 -6.578125 3.28125 -6.578125 C 2.421875 -6.578125 1.78125 -6.390625 1.078125 -5.984375 L 1.15625 -5.03125 C 1.796875 -5.5 2.453125 -5.75 3.28125 -5.75 C 3.9375 -5.75 4.515625 -5.21875 4.515625 -4.171875 L 4.515625 -3.578125 C 3.875 -3.5625 3.015625 -3.515625 2.15625 -3.234375 C 1.1875 -2.890625 0.625 -2.359375 0.625 -1.65625 C 0.625 -1.015625 1 0.140625 2.21875 0.140625 C 3.015625 0.140625 4.015625 -0.09375 4.546875 -0.53125 L 4.546875 0 L 5.609375 0 Z M 4.515625 -1.921875 C 4.515625 -1.640625 4.515625 -1.296875 4.046875 -1 C 3.65625 -0.765625 3.171875 -0.71875 2.953125 -0.71875 C 2.1875 -0.71875 1.65625 -1.140625 1.65625 -1.65625 C 1.65625 -2.640625 3.640625 -2.859375 4.515625 -2.859375 Z M 4.515625 -1.921875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-19">
|
||||
<path style="stroke:none;" d="M 6.203125 -6.375 L 5.140625 -6.375 C 4.46875 -4.671875 3.375 -1.859375 3.3125 -0.828125 L 3.296875 -0.828125 C 3.234375 -1.671875 2.46875 -3.578125 2.359375 -3.859375 L 1.328125 -6.375 L 0.203125 -6.375 L 2.875 0 L 2.359375 1.3125 C 2.046875 2.015625 1.84375 2.09375 1.578125 2.09375 C 1.375 2.09375 0.921875 2.046875 0.46875 1.875 L 0.5625 2.8125 C 0.640625 2.828125 1.125 2.921875 1.578125 2.921875 C 1.921875 2.921875 2.59375 2.921875 3.21875 1.34375 Z M 6.203125 -6.375 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-20">
|
||||
<path style="stroke:none;" d="M 5.84375 -4.671875 C 7.40625 -5.125 8.25 -6.203125 8.25 -7.265625 C 8.25 -8.703125 6.71875 -9.953125 4.6875 -9.953125 L 1.3125 -9.953125 L 1.3125 0 L 2.515625 0 L 2.515625 -4.546875 L 4.75 -4.546875 L 7.40625 0 L 8.640625 0 Z M 2.515625 -5.40625 L 2.515625 -9.15625 L 4.53125 -9.15625 C 6.265625 -9.15625 7.109375 -8.234375 7.109375 -7.265625 C 7.109375 -6.390625 6.34375 -5.40625 4.53125 -5.40625 Z M 2.515625 -5.40625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-21">
|
||||
<path style="stroke:none;" d="M 8.171875 -1.65625 C 7.296875 -1 6.703125 -0.765625 5.453125 -0.765625 C 3.578125 -0.765625 2.171875 -2.703125 2.171875 -5 C 2.171875 -6.9375 3.328125 -9.21875 5.515625 -9.21875 C 6.453125 -9.21875 7.171875 -8.9375 7.890625 -8.453125 L 8.109375 -9.625 C 7.171875 -9.984375 6.46875 -10.109375 5.484375 -10.109375 C 3.046875 -10.109375 0.953125 -7.953125 0.953125 -4.984375 C 0.953125 -1.84375 3.25 0.125 5.34375 0.125 C 6.78125 0.125 7.09375 0.046875 8.265625 -0.65625 Z M 8.171875 -1.65625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-22">
|
||||
<path style="stroke:none;" d="M 3 -9.953125 L 1.359375 -9.953125 L 1.359375 0 L 2.46875 0 L 2.46875 -8.84375 L 2.484375 -8.84375 C 2.6875 -7.875 5 -1.734375 5.546875 -0.296875 L 6.59375 -0.296875 C 7.078125 -1.53125 9.4375 -7.78125 9.703125 -8.859375 L 9.703125 0 L 10.8125 0 L 10.8125 -9.953125 L 9.1875 -9.953125 L 7.546875 -5.53125 C 6.796875 -3.53125 6.234375 -2.015625 6.09375 -1.359375 L 6.078125 -1.359375 C 6.03125 -1.609375 5.859375 -2.140625 5.671875 -2.703125 C 5.40625 -3.46875 5.40625 -3.5 5.171875 -4.09375 Z M 3 -9.953125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-23">
|
||||
<path style="stroke:none;" d="M 8.53125 -9.953125 L 7.296875 -9.953125 L 7.296875 -5.609375 L 2.53125 -5.609375 L 2.53125 -9.953125 L 1.296875 -9.953125 L 1.296875 0 L 2.53125 0 L 2.53125 -4.75 L 7.296875 -4.75 L 7.296875 0 L 8.53125 0 Z M 8.53125 -9.953125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-24">
|
||||
<path style="stroke:none;" d="M 5.265625 -9.953125 L 4 -9.953125 L 0.390625 0 L 1.453125 0 L 2.5 -2.90625 L 6.546875 -2.90625 L 7.609375 0 L 8.875 0 Z M 4.515625 -8.921875 L 6.234375 -3.71875 L 2.8125 -3.71875 Z M 4.515625 -8.921875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-25">
|
||||
<path style="stroke:none;" d="M 1.328125 -9.953125 L 1.328125 0 L 5.03125 0 C 7.0625 0 8.53125 -1.296875 8.53125 -2.703125 C 8.53125 -3.953125 7.28125 -4.984375 5.8125 -5.203125 C 7.484375 -5.671875 8.140625 -6.625 8.140625 -7.453125 C 8.140625 -8.75 6.671875 -9.953125 4.640625 -9.953125 Z M 2.5 -5.609375 L 2.5 -9.15625 L 4.265625 -9.15625 C 5.796875 -9.15625 7.03125 -8.390625 7.03125 -7.4375 C 7.03125 -6.4375 5.796875 -5.609375 4.28125 -5.609375 Z M 2.5 -0.796875 L 2.5 -4.75 L 4.40625 -4.75 C 6.25 -4.75 7.40625 -3.71875 7.40625 -2.71875 C 7.40625 -1.703125 6.234375 -0.796875 4.640625 -0.796875 Z M 2.5 -0.796875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-26">
|
||||
<path style="stroke:none;" d="M 2.53125 -9.953125 L 1.296875 -9.953125 L 1.296875 0 L 2.53125 0 Z M 2.53125 -9.953125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-27">
|
||||
<path style="stroke:none;" d="M 6.53125 -9.546875 C 5.9375 -9.875 5.21875 -10.25 3.9375 -10.25 C 2.015625 -10.25 0.78125 -8.875 0.78125 -7.4375 C 0.78125 -6.421875 1.390625 -5.765625 1.46875 -5.6875 C 2.171875 -4.984375 2.65625 -4.84375 3.578125 -4.625 C 4.796875 -4.3125 4.984375 -4.265625 5.453125 -3.78125 C 5.6875 -3.53125 5.90625 -3.0625 5.90625 -2.5625 C 5.90625 -1.578125 5.09375 -0.65625 3.859375 -0.65625 C 2.8125 -0.65625 1.6875 -1.078125 0.84375 -1.84375 L 0.625 -0.6875 C 1.9375 0.171875 3.203125 0.296875 3.859375 0.296875 C 5.703125 0.296875 7.015625 -1.125 7.015625 -2.71875 C 7.015625 -3.625 6.5625 -4.3125 6.25 -4.671875 C 5.59375 -5.375 5.0625 -5.515625 4.109375 -5.765625 C 3.125 -6.015625 2.765625 -6.09375 2.453125 -6.390625 C 2.265625 -6.59375 1.875 -6.953125 1.875 -7.609375 C 1.875 -8.484375 2.671875 -9.328125 3.9375 -9.328125 C 5.15625 -9.328125 5.796875 -8.84375 6.3125 -8.390625 Z M 6.53125 -9.546875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-28">
|
||||
<path style="stroke:none;" d="M 6.078125 -4.3125 C 6.078125 -5.1875 5.890625 -6.515625 4.15625 -6.515625 C 3.171875 -6.515625 2.515625 -5.953125 2.171875 -5.515625 L 2.171875 -9.953125 L 1.109375 -9.953125 L 1.109375 0 L 2.1875 0 L 2.1875 -3.578125 C 2.1875 -4.453125 2.53125 -5.65625 3.609375 -5.65625 C 4.953125 -5.65625 4.984375 -4.71875 4.984375 -4.21875 L 4.984375 0 L 6.078125 0 Z M 6.078125 -4.3125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-29">
|
||||
<path style="stroke:none;" d="M 9.328125 -6.375 L 8.28125 -6.375 L 7.421875 -3.453125 C 7.21875 -2.765625 6.8125 -1.421875 6.75 -0.796875 L 6.734375 -0.796875 C 6.703125 -1.140625 6.46875 -2.109375 6.171875 -3.125 L 5.21875 -6.375 L 4.234375 -6.375 L 3.40625 -3.5625 C 3.15625 -2.671875 2.8125 -1.4375 2.765625 -0.828125 L 2.75 -0.828125 C 2.734375 -1.109375 2.578125 -1.859375 2.3125 -2.828125 L 1.296875 -6.375 L 0.203125 -6.375 L 2.125 0 L 3.234375 0 C 3.765625 -1.8125 4.609375 -4.53125 4.6875 -5.53125 L 4.703125 -5.53125 C 4.734375 -4.953125 5.015625 -3.921875 5.125 -3.578125 L 6.140625 0 L 7.40625 0 Z M 9.328125 -6.375 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-30">
|
||||
<path style="stroke:none;" d="M 4.8125 -4.140625 C 6.78125 -4.140625 8.140625 -5.5625 8.140625 -7.0625 C 8.140625 -8.578125 6.75 -9.953125 4.8125 -9.953125 L 1.3125 -9.953125 L 1.3125 0 L 2.53125 0 L 2.53125 -4.140625 Z M 4.5 -9.15625 C 6.1875 -9.15625 7.015625 -8.140625 7.015625 -7.078125 C 7.015625 -5.9375 6.140625 -4.984375 4.5 -4.984375 L 2.515625 -4.984375 L 2.515625 -9.15625 Z M 4.5 -9.15625 "/>
|
||||
</symbol>
|
||||
</g>
|
||||
<clipPath id="clip1">
|
||||
<path d="M 0 0 L 541.902344 0 L 541.902344 142.285156 L 0 142.285156 Z M 0 0 "/>
|
||||
</clipPath>
|
||||
<clipPath id="clip2">
|
||||
<path d="M 102 92 L 245 92 L 245 142.285156 L 102 142.285156 Z M 102 92 "/>
|
||||
</clipPath>
|
||||
<clipPath id="clip3">
|
||||
<path d="M 302 92 L 442 92 L 442 142.285156 L 302 142.285156 Z M 302 92 "/>
|
||||
</clipPath>
|
||||
<clipPath id="clip4">
|
||||
<path d="M 17 101 L 67 101 L 67 142.285156 L 17 142.285156 Z M 17 101 "/>
|
||||
</clipPath>
|
||||
<clipPath id="clip5">
|
||||
<path d="M 92 101 L 142 101 L 142 142.285156 L 92 142.285156 Z M 92 101 "/>
|
||||
</clipPath>
|
||||
<clipPath id="clip6">
|
||||
<path d="M 205 101 L 255 101 L 255 142.285156 L 205 142.285156 Z M 205 101 "/>
|
||||
</clipPath>
|
||||
<clipPath id="clip7">
|
||||
<path d="M 292 101 L 342 101 L 342 142.285156 L 292 142.285156 Z M 292 101 "/>
|
||||
</clipPath>
|
||||
<clipPath id="clip8">
|
||||
<path d="M 402 101 L 452 101 L 452 142.285156 L 402 142.285156 Z M 402 101 "/>
|
||||
</clipPath>
|
||||
<clipPath id="clip9">
|
||||
<path d="M 479 101 L 528 101 L 528 142.285156 L 479 142.285156 Z M 479 101 "/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="surface1">
|
||||
<g clip-path="url(#clip1)" clip-rule="nonzero">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 0 142.285156 L 543.933594 142.285156 L 543.933594 -0.535156 L 0 -0.535156 Z M 0 142.285156 "/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 93.618469 13.681906 L -93.619813 13.681906 C -96.369813 13.681906 -98.600281 11.451438 -98.600281 8.701438 L -98.600281 -17.204812 C -98.600281 -19.954812 -96.369813 -22.185281 -93.619813 -22.185281 L 93.618469 -22.185281 C 96.368469 -22.185281 98.598937 -19.954812 98.598937 -17.204812 L 98.598937 8.701438 C 98.598937 11.451438 96.368469 13.681906 93.618469 13.681906 Z M 93.618469 13.681906 " transform="matrix(1,0,0,-1,272.612,14.428)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="215.699" y="15.293"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-2" x="222.091667" y="15.293"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="229.467" y="15.293"/>
|
||||
<use xlink:href="#glyph1-2" x="235.710466" y="15.293"/>
|
||||
<use xlink:href="#glyph1-2" x="242.136129" y="15.293"/>
|
||||
<use xlink:href="#glyph1-3" x="248.561792" y="15.293"/>
|
||||
<use xlink:href="#glyph1-3" x="252.463959" y="15.293"/>
|
||||
<use xlink:href="#glyph1-4" x="256.366125" y="15.293"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-5" x="263.184874" y="15.293"/>
|
||||
<use xlink:href="#glyph1-6" x="267.959289" y="15.293"/>
|
||||
<use xlink:href="#glyph1-7" x="271.263219" y="15.293"/>
|
||||
<use xlink:href="#glyph1-8" x="278.469315" y="15.293"/>
|
||||
<use xlink:href="#glyph1-9" x="285.493215" y="15.293"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-3" x="291.733" y="15.293"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-10" x="303.797" y="15.293"/>
|
||||
<use xlink:href="#glyph1-11" x="314.905263" y="15.293"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-7" x="322.31651" y="15.293"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-7" x="203.901" y="29.24"/>
|
||||
<use xlink:href="#glyph1-9" x="211.107096" y="29.24"/>
|
||||
<use xlink:href="#glyph1-12" x="217.350563" y="29.24"/>
|
||||
<use xlink:href="#glyph1-1" x="222.734691" y="29.24"/>
|
||||
<use xlink:href="#glyph1-5" x="228.978158" y="29.24"/>
|
||||
<use xlink:href="#glyph1-6" x="233.752573" y="29.24"/>
|
||||
<use xlink:href="#glyph1-13" x="237.056503" y="29.24"/>
|
||||
<use xlink:href="#glyph1-14" x="244.262599" y="29.24"/>
|
||||
<use xlink:href="#glyph1-6" x="249.335415" y="29.24"/>
|
||||
<use xlink:href="#glyph1-11" x="252.639345" y="29.24"/>
|
||||
<use xlink:href="#glyph1-15" x="259.663245" y="29.24"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-11" x="271.546202" y="29.24"/>
|
||||
<use xlink:href="#glyph1-16" x="278.570102" y="29.24"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-4" x="287.553692" y="29.24"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-11" x="295.147136" y="29.24"/>
|
||||
<use xlink:href="#glyph1-17" x="302.171035" y="29.24"/>
|
||||
<use xlink:href="#glyph1-15" x="309.377132" y="29.24"/>
|
||||
<use xlink:href="#glyph1-7" x="316.583228" y="29.24"/>
|
||||
<use xlink:href="#glyph1-18" x="323.789324" y="29.24"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-5" x="330.126041" y="29.24"/>
|
||||
<use xlink:href="#glyph1-19" x="334.900456" y="29.24"/>
|
||||
</g>
|
||||
<g clip-path="url(#clip2)" clip-rule="nonzero">
|
||||
<path style="fill:none;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -53.619813 -99.095437 L -144.807313 -99.095437 C -147.006531 -99.095437 -148.791688 -100.880594 -148.791688 -103.079812 L -148.791688 -118.025125 C -148.791688 -120.22825 -147.006531 -122.0095 -144.807313 -122.0095 L -53.619813 -122.0095 C -51.420594 -122.0095 -49.635438 -120.22825 -49.635438 -118.025125 L -49.635438 -103.079812 C -49.635438 -100.880594 -51.420594 -99.095437 -53.619813 -99.095437 Z M -53.619813 -99.095437 " transform="matrix(1,0,0,-1,272.612,14.428)"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-20" x="133.785" y="129.463"/>
|
||||
<use xlink:href="#glyph1-17" x="142.825975" y="129.463"/>
|
||||
<use xlink:href="#glyph1-12" x="150.032072" y="129.463"/>
|
||||
<use xlink:href="#glyph1-14" x="155.4162" y="129.463"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-4" x="165.165878" y="129.463"/>
|
||||
<use xlink:href="#glyph1-6" x="172.371974" y="129.463"/>
|
||||
<use xlink:href="#glyph1-15" x="175.675904" y="129.463"/>
|
||||
<use xlink:href="#glyph1-7" x="182.882" y="129.463"/>
|
||||
<use xlink:href="#glyph1-6" x="190.088097" y="129.463"/>
|
||||
<use xlink:href="#glyph1-15" x="193.392026" y="129.463"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-8" x="200.612469" y="129.463"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-12" x="207.622022" y="129.463"/>
|
||||
</g>
|
||||
<g clip-path="url(#clip3)" clip-rule="nonzero">
|
||||
<path style="fill:none;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 143.3255 -99.095437 L 55.102844 -99.095437 C 52.903625 -99.095437 51.118469 -100.880594 51.118469 -103.079812 L 51.118469 -118.025125 C 51.118469 -120.22825 52.903625 -122.0095 55.102844 -122.0095 L 143.3255 -122.0095 C 145.524719 -122.0095 147.309875 -120.22825 147.309875 -118.025125 L 147.309875 -103.079812 C 147.309875 -100.880594 145.524719 -99.095437 143.3255 -99.095437 Z M 143.3255 -99.095437 " transform="matrix(1,0,0,-1,272.612,14.428)"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-21" x="333.693" y="129.463"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-4" x="342.668" y="129.463"/>
|
||||
<use xlink:href="#glyph0-4" x="350.050555" y="129.463"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-4" x="362.115" y="129.463"/>
|
||||
<use xlink:href="#glyph1-6" x="369.321096" y="129.463"/>
|
||||
<use xlink:href="#glyph1-15" x="372.625026" y="129.463"/>
|
||||
<use xlink:href="#glyph1-7" x="379.831122" y="129.463"/>
|
||||
<use xlink:href="#glyph1-6" x="387.037219" y="129.463"/>
|
||||
<use xlink:href="#glyph1-15" x="390.341148" y="129.463"/>
|
||||
<use xlink:href="#glyph1-8" x="397.547245" y="129.463"/>
|
||||
<use xlink:href="#glyph1-12" x="404.571144" y="129.463"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-20" x="4.343" y="126.574"/>
|
||||
<use xlink:href="#glyph1-17" x="13.383975" y="126.574"/>
|
||||
<use xlink:href="#glyph1-12" x="20.590072" y="126.574"/>
|
||||
<use xlink:href="#glyph1-14" x="25.9742" y="126.574"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="3.941" y="140.522"/>
|
||||
<use xlink:href="#glyph1-11" x="10.184466" y="140.522"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-7" x="17.595713" y="140.522"/>
|
||||
<use xlink:href="#glyph1-9" x="24.801809" y="140.522"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-21" x="514.177" y="126.574"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-4" x="523.151" y="126.574"/>
|
||||
<use xlink:href="#glyph0-4" x="530.533555" y="126.574"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="514.177" y="140.522"/>
|
||||
<use xlink:href="#glyph1-11" x="520.420466" y="140.522"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-7" x="527.831713" y="140.522"/>
|
||||
<use xlink:href="#glyph1-9" x="535.037809" y="140.522"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0.00128125 -22.931375 L 0.00128125 -68.032937 " transform="matrix(1,0,0,-1,272.612,14.428)"/>
|
||||
<path style="fill:none;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -99.213563 -89.1345 L -99.213563 -68.032937 L 99.212219 -68.032937 L 99.212219 -89.1345 " transform="matrix(1,0,0,-1,272.612,14.428)"/>
|
||||
<path style="fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 6.317146 0.0002575 C 5.539802 0.207289 2.129646 1.371351 0.00074 2.640882 L 0.00074 -2.640368 C 2.129646 -1.370836 5.539802 -0.206774 6.317146 0.0002575 Z M 6.317146 0.0002575 " transform="matrix(0,1,1,0,173.39818,103.56176)"/>
|
||||
<path style="fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 6.317146 -0.00160125 C 5.539802 0.20543 2.129646 1.373399 0.00074 2.639024 L 0.00074 -2.63832 C 2.129646 -1.372695 5.539802 -0.204726 6.317146 -0.00160125 Z M 6.317146 -0.00160125 " transform="matrix(0,1,1,0,371.82582,103.56176)"/>
|
||||
<path style="fill:none;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -227.619813 -110.552469 L -158.752625 -110.552469 " transform="matrix(1,0,0,-1,272.612,14.428)"/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 38.675781 124.980469 C 39.453125 125.1875 42.859375 126.351562 44.992188 127.621094 L 44.992188 122.339844 C 42.859375 123.609375 39.453125 124.777344 38.675781 124.980469 Z M 38.675781 124.980469 "/>
|
||||
<g clip-path="url(#clip4)" clip-rule="nonzero">
|
||||
<path style="fill:none;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 6.316149 -0.00123125 C 5.538805 0.2058 2.132555 1.369862 -0.0002575 2.639394 L -0.0002575 -2.641856 C 2.132555 -1.372325 5.538805 -0.204356 6.316149 -0.00123125 Z M 6.316149 -0.00123125 " transform="matrix(-1,0,0,1,44.99193,124.9817)"/>
|
||||
</g>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 120.171875 124.980469 C 119.398438 124.777344 115.988281 123.609375 113.859375 122.339844 L 113.859375 127.621094 C 115.988281 126.351562 119.398438 125.1875 120.171875 124.980469 Z M 120.171875 124.980469 "/>
|
||||
<g clip-path="url(#clip5)" clip-rule="nonzero">
|
||||
<path style="fill:none;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 6.313975 0.00123125 C 5.540537 0.204356 2.130381 1.372325 0.001475 2.641856 L 0.001475 -2.639394 C 2.130381 -1.369862 5.540537 -0.2058 6.313975 0.00123125 Z M 6.313975 0.00123125 " transform="matrix(1,0,0,-1,113.8579,124.9817)"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:7.97021,5.97766;stroke-miterlimit:10;" d="M -39.6745 -110.552469 L 41.157531 -110.552469 " transform="matrix(1,0,0,-1,272.612,14.428)"/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 226.621094 124.980469 C 227.398438 125.1875 230.808594 126.351562 232.9375 127.621094 L 232.9375 122.339844 C 230.808594 123.609375 227.398438 124.777344 226.621094 124.980469 Z M 226.621094 124.980469 "/>
|
||||
<g clip-path="url(#clip6)" clip-rule="nonzero">
|
||||
<path style="fill:none;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 6.317366 -0.00123125 C 5.540023 0.2058 2.129866 1.369862 0.00096 2.639394 L 0.00096 -2.641856 C 2.129866 -1.372325 5.540023 -0.204356 6.317366 -0.00123125 Z M 6.317366 -0.00123125 " transform="matrix(-1,0,0,1,232.93846,124.9817)"/>
|
||||
</g>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 320.082031 124.980469 C 319.308594 124.777344 315.898438 123.609375 313.769531 122.339844 L 313.769531 127.621094 C 315.898438 126.351562 319.308594 125.1875 320.082031 124.980469 Z M 320.082031 124.980469 "/>
|
||||
<g clip-path="url(#clip7)" clip-rule="nonzero">
|
||||
<path style="fill:none;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 6.313811 0.00123125 C 5.540374 0.204356 2.130217 1.372325 0.00131125 2.641856 L 0.00131125 -2.639394 C 2.130217 -1.369862 5.540374 -0.2058 6.313811 0.00123125 Z M 6.313811 0.00123125 " transform="matrix(1,0,0,-1,313.76822,124.9817)"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 157.270812 -110.552469 L 227.618469 -110.552469 " transform="matrix(1,0,0,-1,272.612,14.428)"/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 423.566406 124.980469 C 424.34375 125.1875 427.753906 126.351562 429.882812 127.621094 L 429.882812 122.339844 C 427.753906 123.609375 424.34375 124.777344 423.566406 124.980469 Z M 423.566406 124.980469 "/>
|
||||
<g clip-path="url(#clip8)" clip-rule="nonzero">
|
||||
<path style="fill:none;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 6.317014 -0.00123125 C 5.53967 0.2058 2.129514 1.369862 0.0006075 2.639394 L 0.0006075 -2.641856 C 2.129514 -1.372325 5.53967 -0.204356 6.317014 -0.00123125 Z M 6.317014 -0.00123125 " transform="matrix(-1,0,0,1,429.88342,124.9817)"/>
|
||||
</g>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 506.546875 124.980469 C 505.773438 124.777344 502.363281 123.609375 500.230469 122.339844 L 500.230469 127.621094 C 502.363281 126.351562 505.773438 125.1875 506.546875 124.980469 Z M 506.546875 124.980469 "/>
|
||||
<g clip-path="url(#clip9)" clip-rule="nonzero">
|
||||
<path style="fill:none;stroke-width:1.49442;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 6.314805 0.00123125 C 5.541367 0.204356 2.131211 1.372325 -0.00160125 2.641856 L -0.00160125 -2.639394 C 2.131211 -1.369862 5.541367 -0.2058 6.314805 0.00123125 Z M 6.314805 0.00123125 " transform="matrix(1,0,0,-1,500.23207,124.9817)"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-22" x="148.925" y="75.603"/>
|
||||
<use xlink:href="#glyph1-18" x="161.112097" y="75.603"/>
|
||||
<use xlink:href="#glyph1-1" x="167.836161" y="75.603"/>
|
||||
<use xlink:href="#glyph1-5" x="174.079627" y="75.603"/>
|
||||
<use xlink:href="#glyph1-11" x="178.854042" y="75.603"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-9" x="190.554803" y="75.603"/>
|
||||
<use xlink:href="#glyph1-2" x="196.798269" y="75.603"/>
|
||||
<use xlink:href="#glyph1-13" x="203.223932" y="75.603"/>
|
||||
<use xlink:href="#glyph1-18" x="210.430029" y="75.603"/>
|
||||
<use xlink:href="#glyph1-15" x="217.154093" y="75.603"/>
|
||||
<use xlink:href="#glyph1-12" x="224.360189" y="75.603"/>
|
||||
<use xlink:href="#glyph1-6" x="229.744318" y="75.603"/>
|
||||
<use xlink:href="#glyph1-11" x="233.048248" y="75.603"/>
|
||||
<use xlink:href="#glyph1-15" x="240.072147" y="75.603"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-21" x="297.94" y="75.603"/>
|
||||
<use xlink:href="#glyph1-11" x="306.914983" y="75.603"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-7" x="314.32623" y="75.603"/>
|
||||
<use xlink:href="#glyph1-9" x="321.532326" y="75.603"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-8" x="332.452653" y="75.603"/>
|
||||
<use xlink:href="#glyph1-9" x="339.476553" y="75.603"/>
|
||||
<use xlink:href="#glyph1-15" x="345.720019" y="75.603"/>
|
||||
<use xlink:href="#glyph1-9" x="352.926115" y="75.603"/>
|
||||
<use xlink:href="#glyph1-5" x="359.169582" y="75.603"/>
|
||||
<use xlink:href="#glyph1-18" x="363.943997" y="75.603"/>
|
||||
<use xlink:href="#glyph1-14" x="370.668061" y="75.603"/>
|
||||
<use xlink:href="#glyph1-6" x="375.740877" y="75.603"/>
|
||||
<use xlink:href="#glyph1-11" x="379.044807" y="75.603"/>
|
||||
<use xlink:href="#glyph1-15" x="386.068707" y="75.603"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-23" x="231.724" y="117.459"/>
|
||||
<use xlink:href="#glyph1-6" x="241.569797" y="117.459"/>
|
||||
<use xlink:href="#glyph1-7" x="244.873727" y="117.459"/>
|
||||
<use xlink:href="#glyph1-7" x="252.079823" y="117.459"/>
|
||||
<use xlink:href="#glyph1-9" x="259.285919" y="117.459"/>
|
||||
<use xlink:href="#glyph1-15" x="265.529386" y="117.459"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-21" x="277.412343" y="117.459"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-24" x="291.078533" y="117.459"/>
|
||||
<use xlink:href="#glyph1-25" x="300.360525" y="117.459"/>
|
||||
<use xlink:href="#glyph1-26" x="309.68412" y="117.459"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-27" x="68.742" y="89.962"/>
|
||||
<use xlink:href="#glyph1-18" x="76.546333" y="89.962"/>
|
||||
<use xlink:href="#glyph1-16" x="83.270397" y="89.962"/>
|
||||
<use xlink:href="#glyph1-9" x="87.56278" y="89.962"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-12" x="37.407" y="103.909"/>
|
||||
<use xlink:href="#glyph1-14" x="42.791129" y="103.909"/>
|
||||
<use xlink:href="#glyph1-5" x="47.863945" y="103.909"/>
|
||||
<use xlink:href="#glyph1-18" x="52.638361" y="103.909"/>
|
||||
<use xlink:href="#glyph1-6" x="59.362424" y="103.909"/>
|
||||
<use xlink:href="#glyph1-8" x="62.666354" y="103.909"/>
|
||||
<use xlink:href="#glyph1-28" x="69.690254" y="103.909"/>
|
||||
<use xlink:href="#glyph1-14" x="76.89635" y="103.909"/>
|
||||
<use xlink:href="#glyph1-16" x="81.969166" y="103.909"/>
|
||||
<use xlink:href="#glyph1-11" x="86.261549" y="103.909"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-5" x="92.898102" y="103.909"/>
|
||||
<use xlink:href="#glyph1-29" x="97.672517" y="103.909"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-18" x="106.832566" y="103.909"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-5" x="113.154936" y="103.909"/>
|
||||
<use xlink:href="#glyph1-7" x="117.929351" y="103.909"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-20" x="51.871" y="117.857"/>
|
||||
<use xlink:href="#glyph1-17" x="60.911975" y="117.857"/>
|
||||
<use xlink:href="#glyph1-12" x="68.118072" y="117.857"/>
|
||||
<use xlink:href="#glyph1-14" x="73.5022" y="117.857"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-24" x="83.251878" y="117.857"/>
|
||||
<use xlink:href="#glyph1-30" x="92.533869" y="117.857"/>
|
||||
<use xlink:href="#glyph1-26" x="101.467248" y="117.857"/>
|
||||
<use xlink:href="#glyph1-12" x="105.286206" y="117.857"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-27" x="418.874" y="103.909"/>
|
||||
<use xlink:href="#glyph1-14" x="426.678333" y="103.909"/>
|
||||
<use xlink:href="#glyph1-5" x="431.751149" y="103.909"/>
|
||||
<use xlink:href="#glyph1-18" x="436.525564" y="103.909"/>
|
||||
<use xlink:href="#glyph1-6" x="443.249628" y="103.909"/>
|
||||
<use xlink:href="#glyph1-8" x="446.553558" y="103.909"/>
|
||||
<use xlink:href="#glyph1-28" x="453.577458" y="103.909"/>
|
||||
<use xlink:href="#glyph1-14" x="460.783554" y="103.909"/>
|
||||
<use xlink:href="#glyph1-16" x="465.85637" y="103.909"/>
|
||||
<use xlink:href="#glyph1-11" x="470.148753" y="103.909"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-5" x="476.785306" y="103.909"/>
|
||||
<use xlink:href="#glyph1-29" x="481.559721" y="103.909"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-18" x="490.705423" y="103.909"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-5" x="497.04214" y="103.909"/>
|
||||
<use xlink:href="#glyph1-7" x="501.816555" y="103.909"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-21" x="436.031" y="117.857"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-4" x="445.005" y="117.857"/>
|
||||
<use xlink:href="#glyph0-4" x="452.387555" y="117.857"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-24" x="464.452" y="117.857"/>
|
||||
<use xlink:href="#glyph1-30" x="473.733991" y="117.857"/>
|
||||
<use xlink:href="#glyph1-26" x="482.66737" y="117.857"/>
|
||||
<use xlink:href="#glyph1-12" x="486.486329" y="117.857"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 42 KiB |
29
vendor/cxx/book/src/reference.md
vendored
Normal file
29
vendor/cxx/book/src/reference.md
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{{#title The bridge module — Rust ♡ C++}}
|
||||
# The bridge module reference
|
||||
|
||||
The ***[Core concepts](concepts.md)*** in chapter 2 covered the high level model
|
||||
that CXX uses to represent a language boundary. This chapter builds on that one
|
||||
to document an exhaustive reference on the syntax and functionality of
|
||||
\#\[cxx::bridge\].
|
||||
|
||||
- ***[extern "Rust"](extern-rust.md)*** — exposing opaque Rust types, Rust
|
||||
functions, Rust methods to C++; functions with lifetimes.
|
||||
|
||||
- ***[extern "C++"](extern-c++.md)*** — binding opaque C++ types, C++
|
||||
functions, C++ member functions; sharing an opaque type definition across
|
||||
multiple bridge modules or different crates; using bindgen-generated data
|
||||
structures across a CXX bridge; Rust orphan-rule-compatible way to request
|
||||
that particular glue code be emitted in a specific bridge module.
|
||||
|
||||
- ***[Shared types](shared.md)*** — shared structs; shared enums; using
|
||||
Rust as source of truth vs C++ as source of truth.
|
||||
|
||||
- ***[Attributes](attributes.md)*** — working with namespaces; giving
|
||||
functions a different name in their non-native language.
|
||||
|
||||
- ***[Async functions](async.md)*** — integrating async C++ with async
|
||||
Rust.
|
||||
|
||||
- ***[Error handling](binding/result.md)*** — representing fallibility on
|
||||
the language boundary; accessing a Rust error message from C++; customizing
|
||||
the set of caught exceptions and their conversion to a Rust error message.
|
||||
246
vendor/cxx/book/src/shared.md
vendored
Normal file
246
vendor/cxx/book/src/shared.md
vendored
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
{{#title Shared types — Rust ♡ C++}}
|
||||
# Shared types
|
||||
|
||||
Shared types enable *both* languages to have visibility into the internals of a
|
||||
type. This is in contrast to opaque Rust types and opaque C++ types, for which
|
||||
only one side gets to manipulate the internals.
|
||||
|
||||
Unlike opaque types, the FFI bridge is allowed to pass and return shared types
|
||||
by value.
|
||||
|
||||
The order in which shared types are written is not important. C++ is order
|
||||
sensitive but CXX will topologically sort and forward-declare your types as
|
||||
necessary.
|
||||
|
||||
## Shared structs and enums
|
||||
|
||||
For enums, only C-like a.k.a. unit variants are currently supported.
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
struct PlayingCard {
|
||||
suit: Suit,
|
||||
value: u8, // A=1, J=11, Q=12, K=13
|
||||
}
|
||||
|
||||
enum Suit {
|
||||
Clubs,
|
||||
Diamonds,
|
||||
Hearts,
|
||||
Spades,
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
fn deck() -> Vec<PlayingCard>;
|
||||
fn sort(cards: &mut Vec<PlayingCard>);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## The generated data structures
|
||||
|
||||
Shared structs compile to an aggregate-initialization compatible C++ struct.
|
||||
|
||||
Shared enums compile to a C++ `enum class` with a sufficiently sized integral
|
||||
base type decided by CXX.
|
||||
|
||||
```cpp
|
||||
// generated header
|
||||
|
||||
struct PlayingCard final {
|
||||
Suit suit;
|
||||
uint8_t value;
|
||||
};
|
||||
|
||||
enum class Suit : uint8_t {
|
||||
Clubs = 0,
|
||||
Diamonds = 1,
|
||||
Hearts = 2,
|
||||
Spades = 3,
|
||||
};
|
||||
```
|
||||
|
||||
Because it is not UB in C++ for an `enum class` to hold a value different from
|
||||
all of the listed variants, we use a Rust representation for shared enums that
|
||||
is compatible with this. The API you'll get is something like:
|
||||
|
||||
```rust,noplayground
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(transparent)]
|
||||
pub struct Suit {
|
||||
pub repr: u8,
|
||||
}
|
||||
#[allow(non_upper_case_globals)]
|
||||
impl Suit {
|
||||
pub const Clubs: Self = Suit { repr: 0 };
|
||||
pub const Diamonds: Self = Suit { repr: 1 };
|
||||
pub const Hearts: Self = Suit { repr: 2 };
|
||||
pub const Spades: Self = Suit { repr: 3 };
|
||||
}
|
||||
```
|
||||
|
||||
Notice you're free to treat the enum as an integer in Rust code via the public
|
||||
`repr` field.
|
||||
|
||||
Pattern matching with `match` still works but will require you to write wildcard
|
||||
arms to handle the situation of an enum value that is not one of the listed
|
||||
variants.
|
||||
|
||||
```rust,noplayground
|
||||
fn main() {
|
||||
let suit: Suit = /*...*/;
|
||||
match suit {
|
||||
Suit::Clubs => ...,
|
||||
Suit::Diamonds => ...,
|
||||
Suit::Hearts => ...,
|
||||
Suit::Spades => ...,
|
||||
_ => ..., // fallback arm
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If a shared struct has generic lifetime parameters, the lifetimes are simply not
|
||||
represented on the C++ side. C++ code will need care when working with borrowed
|
||||
data (as usual in C++).
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
struct Borrowed<'a> {
|
||||
flags: &'a [&'a str],
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// generated header
|
||||
|
||||
struct Borrowed final {
|
||||
rust::Slice<const rust::Str> flags;
|
||||
};
|
||||
```
|
||||
|
||||
## Enum discriminants
|
||||
|
||||
You may provide explicit discriminants for some or all of the enum variants, in
|
||||
which case those numbers will be propagated into the generated C++ `enum class`.
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
enum SmallPrime {
|
||||
Two = 2,
|
||||
Three = 3,
|
||||
Five = 5,
|
||||
Seven = 7,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Variants without an explicit discriminant are assigned the previous discriminant
|
||||
plus 1. If the first variant has not been given an explicit discriminant, it is
|
||||
assigned discriminant 0.
|
||||
|
||||
By default CXX represents your enum using the smallest integer type capable of
|
||||
fitting all the discriminants (whether explicit or implicit). If you need a
|
||||
different representation for reasons, provide a `repr` attribute.
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
#[repr(i32)]
|
||||
enum Enum {
|
||||
Zero,
|
||||
One,
|
||||
Five = 5,
|
||||
Six,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// generated header
|
||||
|
||||
enum class Enum : int32_t {
|
||||
Zero = 0,
|
||||
One = 1,
|
||||
Five = 5,
|
||||
Six = 6,
|
||||
};
|
||||
```
|
||||
|
||||
## Extern enums
|
||||
|
||||
If you need to interoperate with an already existing enum for which an existing
|
||||
C++ definition is the source of truth, make sure that definition is provided by
|
||||
some header in the bridge and then declare your enum *additionally* as an extern
|
||||
C++ type.
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
enum Enum {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
extern "C++" {
|
||||
include!("path/to/the/header.h");
|
||||
type Enum;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
CXX will recognize this pattern and, instead of generating a C++ definition of
|
||||
the enum, will instead generate C++ static assertions asserting that the
|
||||
variants and discriminant values and integer representation written in Rust all
|
||||
correctly match the existing C++ enum definition.
|
||||
|
||||
Extern enums support all the same features as ordinary shared enums (explicit
|
||||
discriminants, repr). Again, CXX will static assert that all of those things you
|
||||
wrote are correct.
|
||||
|
||||
## Derives
|
||||
|
||||
The following standard traits are supported in `derive(...)` within the CXX
|
||||
bridge module.
|
||||
|
||||
- `Clone`
|
||||
- `Copy`
|
||||
- `Debug`
|
||||
- `Default`
|
||||
- `Eq`
|
||||
- `Hash`
|
||||
- `Ord`
|
||||
- `PartialEq`
|
||||
- `PartialOrd`
|
||||
|
||||
Note that shared enums automatically always come with impls of `Copy`, `Clone`,
|
||||
`Eq`, and `PartialEq`, so you're free to omit those derives on an enum.
|
||||
|
||||
```rust,noplayground
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
#[derive(Clone, Debug, Hash)]
|
||||
struct ExampleStruct {
|
||||
x: u32,
|
||||
s: String,
|
||||
}
|
||||
|
||||
#[derive(Hash, Ord, PartialOrd)]
|
||||
enum ExampleEnum {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The derives naturally apply to *both* the Rust data type *and* the corresponding
|
||||
C++ data type:
|
||||
|
||||
- `Hash` gives you a specialization of [`template <> struct std::hash<T>`][hash] in C++
|
||||
- `PartialEq` produces `operator==` and `operator!=`
|
||||
- `PartialOrd` produces `operator<`, `operator<=`, `operator>`, `operator>=`
|
||||
|
||||
[hash]: https://en.cppreference.com/w/cpp/utility/hash
|
||||
688
vendor/cxx/book/src/tutorial.md
vendored
Normal file
688
vendor/cxx/book/src/tutorial.md
vendored
Normal file
|
|
@ -0,0 +1,688 @@
|
|||
{{#title Tutorial — Rust ♡ C++}}
|
||||
# Tutorial: CXX blobstore client
|
||||
|
||||
This example walks through a Rust application that calls into a C++ client of a
|
||||
blobstore service. In fact we'll see calls going in both directions: Rust to C++
|
||||
as well as C++ to Rust. For your own use case it may be that you need just one
|
||||
of these directions.
|
||||
|
||||
All of the code involved in the example is shown on this page, but it's also
|
||||
provided in runnable form in the *demo* directory of
|
||||
<https://github.com/dtolnay/cxx>. To try it out directly, run `cargo run` from
|
||||
that directory.
|
||||
|
||||
This tutorial assumes you've read briefly about **shared structs**, **opaque
|
||||
types**, and **functions** in the [*Core concepts*](concepts.md) page.
|
||||
|
||||
## Creating the project
|
||||
|
||||
We'll use Cargo, which is the build system commonly used by open source Rust
|
||||
projects. (CXX works with other build systems too; refer to chapter 5.)
|
||||
|
||||
Create a blank Cargo project: `mkdir cxx-demo`; `cd cxx-demo`; `cargo init`.
|
||||
|
||||
Edit the Cargo.toml to add a dependency on the `cxx` crate:
|
||||
|
||||
```toml,hidelines
|
||||
## Cargo.toml
|
||||
# [package]
|
||||
# name = "cxx-demo"
|
||||
# version = "0.1.0"
|
||||
# edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cxx = "1.0"
|
||||
```
|
||||
|
||||
We'll revisit this Cargo.toml later when we get to compiling some C++ code.
|
||||
|
||||
## Defining the language boundary
|
||||
|
||||
CXX relies on a description of the function signatures that will be exposed from
|
||||
each language to the other. You provide this description using `extern` blocks
|
||||
in a Rust module annotated with the `#[cxx::bridge]` attribute macro.
|
||||
|
||||
We'll open with just the following at the top of src/main.rs and walk through
|
||||
each item in detail.
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
|
||||
}
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
The contents of this module will be everything that needs to be agreed upon by
|
||||
both sides of the FFI boundary.
|
||||
|
||||
## Calling a C++ function from Rust
|
||||
|
||||
Let's obtain an instance of the C++ blobstore client, a class `BlobstoreClient`
|
||||
defined in C++.
|
||||
|
||||
We'll treat `BlobstoreClient` as an *opaque type* in CXX's classification so
|
||||
that Rust does not need to assume anything about its implementation, not even
|
||||
its size or alignment. In general, a C++ type might have a move-constructor
|
||||
which is incompatible with Rust's move semantics, or may hold internal
|
||||
references which cannot be modeled by Rust's borrowing system. Though there are
|
||||
alternatives, the easiest way to not care about any such thing on an FFI
|
||||
boundary is to require no knowledge about a type by treating it as opaque.
|
||||
|
||||
Opaque types may only be manipulated behind an indirection such as a reference
|
||||
`&`, a Rust `Box`, or a `UniquePtr` (Rust binding of `std::unique_ptr`). We'll
|
||||
add a function through which C++ can return a `std::unique_ptr<BlobstoreClient>`
|
||||
to Rust.
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
unsafe extern "C++" {
|
||||
include!("cxx-demo/include/blobstore.h");
|
||||
|
||||
type BlobstoreClient;
|
||||
|
||||
fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let client = ffi::new_blobstore_client();
|
||||
}
|
||||
```
|
||||
|
||||
The nature of `unsafe` extern blocks is clarified in more detail in the
|
||||
[*extern "C++"*](extern-c++.md) chapter. In brief: the programmer is **not**
|
||||
promising that the signatures they have typed in are accurate; that would be
|
||||
unreasonable. CXX performs static assertions that the signatures exactly match
|
||||
what is declared in C++. Rather, the programmer is only on the hook for things
|
||||
that C++'s semantics are not precise enough to capture, i.e. things that would
|
||||
only be represented at most by comments in the C++ code. In this case, it's
|
||||
whether `new_blobstore_client` is safe or unsafe to call. If that function said
|
||||
something like "must be called at most once or we'll stomp yer memery", Rust
|
||||
would instead want to expose it as `unsafe fn new_blobstore_client`, this time
|
||||
inside a safe `extern "C++"` block because the programmer is no longer on the
|
||||
hook for any safety claim about the signature.
|
||||
|
||||
If you build this file right now with `cargo build`, it won't build because we
|
||||
haven't written a C++ implementation of `new_blobstore_client` nor instructed
|
||||
Cargo about how to link it into the resulting binary. You'll see an error from
|
||||
the linker like this:
|
||||
|
||||
```console
|
||||
error: linking with `cc` failed: exit code: 1
|
||||
|
|
||||
= /bin/ld: target/debug/deps/cxx-demo-7cb7fddf3d67d880.rcgu.o: in function `cxx_demo::ffi::new_blobstore_client':
|
||||
src/main.rs:1: undefined reference to `cxxbridge1$new_blobstore_client'
|
||||
collect2: error: ld returned 1 exit status
|
||||
```
|
||||
|
||||
## Adding in the C++ code
|
||||
|
||||
In CXX's integration with Cargo, all #include paths begin with a crate name by
|
||||
default (when not explicitly selected otherwise by a crate; see
|
||||
`CFG.include_prefix` in chapter 5). That's why we see
|
||||
`include!("cxx-demo/include/blobstore.h")` above — we'll be putting the
|
||||
C++ header at relative path `include/blobstore.h` within the Rust crate. If your
|
||||
crate is named something other than `cxx-demo` according to the `name` field in
|
||||
Cargo.toml, you will need to use that name everywhere in place of `cxx-demo`
|
||||
throughout this tutorial.
|
||||
|
||||
```cpp
|
||||
// include/blobstore.h
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
|
||||
class BlobstoreClient {
|
||||
public:
|
||||
BlobstoreClient();
|
||||
};
|
||||
|
||||
std::unique_ptr<BlobstoreClient> new_blobstore_client();
|
||||
```
|
||||
|
||||
```cpp
|
||||
// src/blobstore.cc
|
||||
|
||||
#include "cxx-demo/include/blobstore.h"
|
||||
|
||||
BlobstoreClient::BlobstoreClient() {}
|
||||
|
||||
std::unique_ptr<BlobstoreClient> new_blobstore_client() {
|
||||
return std::unique_ptr<BlobstoreClient>(new BlobstoreClient());
|
||||
}
|
||||
```
|
||||
|
||||
Using `std::make_unique` would work too, as long as you pass `-std=c++14` to the
|
||||
C++ compiler as described later on.
|
||||
|
||||
The placement in *include/* and *src/* is not significant; you can place C++
|
||||
code anywhere else in the crate as long as you use the right paths throughout
|
||||
the tutorial.
|
||||
|
||||
Be aware that *CXX does not look at any of these files.* You're free to put
|
||||
arbitrary C++ code in here, #include your own libraries, etc. All we do is emit
|
||||
static assertions against what you provide in the headers.
|
||||
|
||||
## Compiling the C++ code with Cargo
|
||||
|
||||
Cargo has a [build scripts] feature suitable for compiling non-Rust code.
|
||||
|
||||
We need to introduce a new build-time dependency on CXX's C++ code generator in
|
||||
Cargo.toml:
|
||||
|
||||
```toml,hidelines
|
||||
## Cargo.toml
|
||||
# [package]
|
||||
# name = "cxx-demo"
|
||||
# version = "0.1.0"
|
||||
# edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cxx = "1.0"
|
||||
|
||||
[build-dependencies]
|
||||
cxx-build = "1.0"
|
||||
```
|
||||
|
||||
Then add a build.rs build script adjacent to Cargo.toml to run the cxx-build
|
||||
code generator and C++ compiler. The relevant arguments are the path to the Rust
|
||||
source file containing the cxx::bridge language boundary definition, and the
|
||||
paths to any additional C++ source files to be compiled during the Rust crate's
|
||||
build.
|
||||
|
||||
```rust,noplayground
|
||||
// build.rs
|
||||
|
||||
fn main() {
|
||||
cxx_build::bridge("src/main.rs")
|
||||
.file("src/blobstore.cc")
|
||||
.compile("cxx-demo");
|
||||
}
|
||||
```
|
||||
|
||||
This build.rs would also be where you set up C++ compiler flags, for example if
|
||||
you'd like to have access to `std::make_unique` from C++14. See the page on
|
||||
***[Cargo-based builds](build/cargo.md)*** for more details about CXX's Cargo
|
||||
integration.
|
||||
|
||||
```rust,noplayground
|
||||
# // build.rs
|
||||
#
|
||||
# fn main() {
|
||||
cxx_build::bridge("src/main.rs")
|
||||
.file("src/blobstore.cc")
|
||||
.flag_if_supported("-std=c++14")
|
||||
.compile("cxx-demo");
|
||||
# }
|
||||
```
|
||||
|
||||
[build scripts]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
|
||||
|
||||
The project should now build and run successfully, though not do anything useful
|
||||
yet.
|
||||
|
||||
```console
|
||||
cxx-demo$ cargo run
|
||||
Compiling cxx-demo v0.1.0
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.34s
|
||||
Running `target/debug/cxx-demo`
|
||||
|
||||
cxx-demo$
|
||||
```
|
||||
|
||||
## Calling a Rust function from C++
|
||||
|
||||
Our C++ blobstore supports a `put` operation for a discontiguous buffer upload.
|
||||
For example we might be uploading snapshots of a circular buffer which would
|
||||
tend to consist of 2 pieces, or fragments of a file spread across memory for
|
||||
some other reason (like a rope data structure).
|
||||
|
||||
We'll express this by handing off an iterator over contiguous borrowed chunks.
|
||||
This loosely resembles the API of the widely used `bytes` crate's `Buf` trait.
|
||||
During a `put`, we'll make C++ call back into Rust to obtain contiguous chunks
|
||||
of the upload (all with no copying or allocation on the language boundary). In
|
||||
reality the C++ client might contain some sophisticated batching of chunks
|
||||
and/or parallel uploading that all of this ties into.
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
type MultiBuf;
|
||||
|
||||
fn next_chunk(buf: &mut MultiBuf) -> &[u8];
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("cxx-demo/include/blobstore.h");
|
||||
|
||||
type BlobstoreClient;
|
||||
|
||||
fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
|
||||
fn put(&self, parts: &mut MultiBuf) -> u64;
|
||||
}
|
||||
}
|
||||
#
|
||||
# fn main() {
|
||||
# let client = ffi::new_blobstore_client();
|
||||
# }
|
||||
```
|
||||
|
||||
Any signature having a `self` parameter (the Rust name for C++'s `this`) is
|
||||
considered a method / non-static member function. If there is only one `type` in
|
||||
the surrounding extern block, it'll be a method of that type. If there is more
|
||||
than one `type`, you can disambiguate which one a method belongs to by writing
|
||||
`self: &BlobstoreClient` in the argument list.
|
||||
|
||||
As usual, now we need to provide Rust definitions of everything declared by the
|
||||
`extern "Rust"` block and a C++ definition of the new signature declared by the
|
||||
`extern "C++"` block.
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
#
|
||||
# #[cxx::bridge]
|
||||
# mod ffi {
|
||||
# extern "Rust" {
|
||||
# type MultiBuf;
|
||||
#
|
||||
# fn next_chunk(buf: &mut MultiBuf) -> &[u8];
|
||||
# }
|
||||
#
|
||||
# unsafe extern "C++" {
|
||||
# include!("cxx-demo/include/blobstore.h");
|
||||
#
|
||||
# type BlobstoreClient;
|
||||
#
|
||||
# fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
|
||||
# fn put(&self, parts: &mut MultiBuf) -> u64;
|
||||
# }
|
||||
# }
|
||||
|
||||
// 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,
|
||||
}
|
||||
|
||||
pub fn next_chunk(buf: &mut MultiBuf) -> &[u8] {
|
||||
let next = buf.chunks.get(buf.pos);
|
||||
buf.pos += 1;
|
||||
next.map_or(&[], Vec::as_slice)
|
||||
}
|
||||
#
|
||||
# fn main() {
|
||||
# let client = ffi::new_blobstore_client();
|
||||
# }
|
||||
```
|
||||
|
||||
```cpp,hidelines
|
||||
// include/blobstore.h
|
||||
|
||||
# #pragma once
|
||||
# #include <memory>
|
||||
#
|
||||
struct MultiBuf;
|
||||
|
||||
class BlobstoreClient {
|
||||
public:
|
||||
BlobstoreClient();
|
||||
uint64_t put(MultiBuf &buf) const;
|
||||
};
|
||||
#
|
||||
#std::unique_ptr<BlobstoreClient> new_blobstore_client();
|
||||
```
|
||||
|
||||
In blobstore.cc we're able to call the Rust `next_chunk` function, exposed to
|
||||
C++ by a header `main.rs.h` generated by the CXX code generator. In CXX's Cargo
|
||||
integration this generated header has a path containing the crate name, the
|
||||
relative path of the Rust source file within the crate, and a `.rs.h` extension.
|
||||
|
||||
```cpp,hidelines
|
||||
// src/blobstore.cc
|
||||
|
||||
##include "cxx-demo/include/blobstore.h"
|
||||
##include "cxx-demo/src/main.rs.h"
|
||||
##include <functional>
|
||||
##include <string>
|
||||
#
|
||||
# BlobstoreClient::BlobstoreClient() {}
|
||||
#
|
||||
# std::unique_ptr<BlobstoreClient> new_blobstore_client() {
|
||||
# return std::make_unique<BlobstoreClient>();
|
||||
# }
|
||||
|
||||
// Upload a new blob and return a blobid that serves as a handle to the blob.
|
||||
uint64_t BlobstoreClient::put(MultiBuf &buf) const {
|
||||
// Traverse the caller's chunk iterator.
|
||||
std::string contents;
|
||||
while (true) {
|
||||
auto chunk = next_chunk(buf);
|
||||
if (chunk.size() == 0) {
|
||||
break;
|
||||
}
|
||||
contents.append(reinterpret_cast<const char *>(chunk.data()), chunk.size());
|
||||
}
|
||||
|
||||
// Pretend we did something useful to persist the data.
|
||||
auto blobid = std::hash<std::string>{}(contents);
|
||||
return blobid;
|
||||
}
|
||||
```
|
||||
|
||||
This is now ready to use. :)
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
#
|
||||
# #[cxx::bridge]
|
||||
# mod ffi {
|
||||
# extern "Rust" {
|
||||
# type MultiBuf;
|
||||
#
|
||||
# fn next_chunk(buf: &mut MultiBuf) -> &[u8];
|
||||
# }
|
||||
#
|
||||
# unsafe extern "C++" {
|
||||
# include!("cxx-demo/include/blobstore.h");
|
||||
#
|
||||
# type BlobstoreClient;
|
||||
#
|
||||
# fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
|
||||
# fn put(&self, parts: &mut MultiBuf) -> u64;
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# pub struct MultiBuf {
|
||||
# chunks: Vec<Vec<u8>>,
|
||||
# pos: usize,
|
||||
# }
|
||||
# pub fn next_chunk(buf: &mut MultiBuf) -> &[u8] {
|
||||
# let next = buf.chunks.get(buf.pos);
|
||||
# buf.pos += 1;
|
||||
# next.map_or(&[], Vec::as_slice)
|
||||
# }
|
||||
|
||||
fn main() {
|
||||
let client = ffi::new_blobstore_client();
|
||||
|
||||
// Upload a blob.
|
||||
let chunks = vec![b"fearless".to_vec(), b"concurrency".to_vec()];
|
||||
let mut buf = MultiBuf { chunks, pos: 0 };
|
||||
let blobid = client.put(&mut buf);
|
||||
println!("blobid = {}", blobid);
|
||||
}
|
||||
```
|
||||
|
||||
```console
|
||||
cxx-demo$ cargo run
|
||||
Compiling cxx-demo v0.1.0
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.41s
|
||||
Running `target/debug/cxx-demo`
|
||||
|
||||
blobid = 9851996977040795552
|
||||
```
|
||||
|
||||
## Interlude: What gets generated?
|
||||
|
||||
For the curious, it's easy to look behind the scenes at what CXX has done to
|
||||
make these function calls work. You shouldn't need to do this during normal
|
||||
usage of CXX, but for the purpose of this tutorial it can be educative.
|
||||
|
||||
CXX comprises *two* code generators: a Rust one (which is the cxx::bridge
|
||||
attribute procedural macro) and a C++ one.
|
||||
|
||||
### Rust generated code
|
||||
|
||||
It's easiest to view the output of the procedural macro by installing
|
||||
[cargo-expand]. Then run `cargo expand ::ffi` to macro-expand the `mod ffi`
|
||||
module.
|
||||
|
||||
[cargo-expand]: https://github.com/dtolnay/cargo-expand
|
||||
|
||||
```console
|
||||
cxx-demo$ cargo install cargo-expand
|
||||
cxx-demo$ cargo expand ::ffi
|
||||
```
|
||||
|
||||
You'll see some deeply unpleasant code involving `#[repr(C)]`, `#[link_name]`,
|
||||
and `#[export_name]`.
|
||||
|
||||
### C++ generated code
|
||||
|
||||
For debugging convenience, `cxx_build` links all generated C++ code into Cargo's
|
||||
target directory under *target/cxxbridge/*.
|
||||
|
||||
```console
|
||||
cxx-demo$ exa -T target/cxxbridge/
|
||||
target/cxxbridge
|
||||
├── cxx-demo
|
||||
│ └── src
|
||||
│ ├── main.rs.cc -> ../../../debug/build/cxx-demo-11c6f678ce5c3437/out/cxxbridge/sources/cxx-demo/src/main.rs.cc
|
||||
│ └── main.rs.h -> ../../../debug/build/cxx-demo-11c6f678ce5c3437/out/cxxbridge/include/cxx-demo/src/main.rs.h
|
||||
└── rust
|
||||
└── cxx.h -> ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cxx-1.0.0/include/cxx.h
|
||||
```
|
||||
|
||||
In those files you'll see declarations or templates of any CXX Rust types
|
||||
present in your language boundary (like `rust::Slice<T>` for `&[T]`) and `extern
|
||||
"C"` signatures corresponding to your extern functions.
|
||||
|
||||
If it fits your workflow better, the CXX C++ code generator is also available as
|
||||
a standalone executable which outputs generated code to stdout.
|
||||
|
||||
```console
|
||||
cxx-demo$ cargo install cxxbridge-cmd
|
||||
cxx-demo$ cxxbridge src/main.rs
|
||||
```
|
||||
|
||||
## Shared data structures
|
||||
|
||||
So far the calls in both directions above only used **opaque types**, not
|
||||
**shared structs**.
|
||||
|
||||
Shared structs are data structures whose complete definition is visible to both
|
||||
languages, making it possible to pass them by value across the language
|
||||
boundary. Shared structs translate to a C++ aggregate-initialization compatible
|
||||
struct exactly matching the layout of the Rust one.
|
||||
|
||||
As the last step of this demo, we'll use a shared struct `BlobMetadata` to pass
|
||||
metadata about blobs between our Rust application and C++ blobstore client.
|
||||
|
||||
```rust,noplayground
|
||||
// src/main.rs
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
struct BlobMetadata {
|
||||
size: usize,
|
||||
tags: Vec<String>,
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
// ...
|
||||
# type MultiBuf;
|
||||
#
|
||||
# fn next_chunk(buf: &mut MultiBuf) -> &[u8];
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
// ...
|
||||
# include!("cxx-demo/include/blobstore.h");
|
||||
#
|
||||
# type BlobstoreClient;
|
||||
#
|
||||
# fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
|
||||
# fn put(&self, parts: &mut MultiBuf) -> u64;
|
||||
fn tag(&self, blobid: u64, tag: &str);
|
||||
fn metadata(&self, blobid: u64) -> BlobMetadata;
|
||||
}
|
||||
}
|
||||
#
|
||||
# pub struct MultiBuf {
|
||||
# chunks: Vec<Vec<u8>>,
|
||||
# pos: usize,
|
||||
# }
|
||||
# pub fn next_chunk(buf: &mut MultiBuf) -> &[u8] {
|
||||
# let next = buf.chunks.get(buf.pos);
|
||||
# buf.pos += 1;
|
||||
# next.map_or(&[], Vec::as_slice)
|
||||
# }
|
||||
|
||||
fn main() {
|
||||
let client = ffi::new_blobstore_client();
|
||||
|
||||
// Upload a blob.
|
||||
let chunks = vec![b"fearless".to_vec(), b"concurrency".to_vec()];
|
||||
let mut buf = MultiBuf { chunks, pos: 0 };
|
||||
let blobid = client.put(&mut buf);
|
||||
println!("blobid = {}", blobid);
|
||||
|
||||
// Add a tag.
|
||||
client.tag(blobid, "rust");
|
||||
|
||||
// Read back the tags.
|
||||
let metadata = client.metadata(blobid);
|
||||
println!("tags = {:?}", metadata.tags);
|
||||
}
|
||||
```
|
||||
|
||||
```cpp,hidelines
|
||||
// include/blobstore.h
|
||||
|
||||
##pragma once
|
||||
##include "rust/cxx.h"
|
||||
# #include <memory>
|
||||
|
||||
struct MultiBuf;
|
||||
struct BlobMetadata;
|
||||
|
||||
class BlobstoreClient {
|
||||
public:
|
||||
BlobstoreClient();
|
||||
uint64_t put(MultiBuf &buf) const;
|
||||
void tag(uint64_t blobid, rust::Str tag) const;
|
||||
BlobMetadata metadata(uint64_t blobid) const;
|
||||
|
||||
private:
|
||||
class impl;
|
||||
std::shared_ptr<impl> impl;
|
||||
};
|
||||
#
|
||||
# std::unique_ptr<BlobstoreClient> new_blobstore_client();
|
||||
```
|
||||
|
||||
```cpp,hidelines
|
||||
// src/blobstore.cc
|
||||
|
||||
##include "cxx-demo/include/blobstore.h"
|
||||
##include "cxx-demo/src/main.rs.h"
|
||||
##include <algorithm>
|
||||
##include <functional>
|
||||
##include <set>
|
||||
##include <string>
|
||||
##include <unordered_map>
|
||||
|
||||
// Toy implementation of an in-memory blobstore.
|
||||
//
|
||||
// In reality the implementation of BlobstoreClient could be a large
|
||||
// complex C++ library.
|
||||
class BlobstoreClient::impl {
|
||||
friend BlobstoreClient;
|
||||
using Blob = struct {
|
||||
std::string data;
|
||||
std::set<std::string> tags;
|
||||
};
|
||||
std::unordered_map<uint64_t, Blob> blobs;
|
||||
};
|
||||
|
||||
BlobstoreClient::BlobstoreClient() : impl(new class BlobstoreClient::impl) {}
|
||||
#
|
||||
# // Upload a new blob and return a blobid that serves as a handle to the blob.
|
||||
# uint64_t BlobstoreClient::put(MultiBuf &buf) const {
|
||||
# // Traverse the caller's chunk iterator.
|
||||
# std::string contents;
|
||||
# while (true) {
|
||||
# auto chunk = next_chunk(buf);
|
||||
# if (chunk.size() == 0) {
|
||||
# break;
|
||||
# }
|
||||
# contents.append(reinterpret_cast<const char *>(chunk.data()), chunk.size());
|
||||
# }
|
||||
#
|
||||
# // Insert into map and provide caller the handle.
|
||||
# auto blobid = std::hash<std::string>{}(contents);
|
||||
# impl->blobs[blobid] = {std::move(contents), {}};
|
||||
# return blobid;
|
||||
# }
|
||||
|
||||
// Add tag to an existing blob.
|
||||
void BlobstoreClient::tag(uint64_t blobid, rust::Str tag) const {
|
||||
impl->blobs[blobid].tags.emplace(tag);
|
||||
}
|
||||
|
||||
// Retrieve metadata about a blob.
|
||||
BlobMetadata BlobstoreClient::metadata(uint64_t blobid) const {
|
||||
BlobMetadata metadata{};
|
||||
auto blob = impl->blobs.find(blobid);
|
||||
if (blob != impl->blobs.end()) {
|
||||
metadata.size = blob->second.data.size();
|
||||
std::for_each(blob->second.tags.cbegin(), blob->second.tags.cend(),
|
||||
[&](auto &t) { metadata.tags.emplace_back(t); });
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
#
|
||||
# std::unique_ptr<BlobstoreClient> new_blobstore_client() {
|
||||
# return std::make_unique<BlobstoreClient>();
|
||||
# }
|
||||
```
|
||||
|
||||
```console
|
||||
cxx-demo$ cargo run
|
||||
Running `target/debug/cxx-demo`
|
||||
|
||||
blobid = 9851996977040795552
|
||||
tags = ["rust"]
|
||||
```
|
||||
|
||||
*You've now seen all the code involved in the tutorial. It's available all
|
||||
together in runnable form in the* demo *directory of
|
||||
<https://github.com/dtolnay/cxx>. You can run it directly without stepping
|
||||
through the steps above by running `cargo run` from that directory.*
|
||||
|
||||
<br>
|
||||
|
||||
# Takeaways
|
||||
|
||||
The key contribution of CXX is it gives you Rust–C++ interop in which
|
||||
*all* of the Rust side of the code you write *really* looks like you are just
|
||||
writing normal Rust, and the C++ side *really* looks like you are just writing
|
||||
normal C++.
|
||||
|
||||
You've seen in this tutorial that none of the code involved feels like C or like
|
||||
the usual perilous "FFI glue" prone to leaks or memory safety flaws.
|
||||
|
||||
An expressive system of opaque types, shared types, and key standard library
|
||||
type bindings enables API design on the language boundary that captures the
|
||||
proper ownership and borrowing contracts of the interface.
|
||||
|
||||
CXX plays to the strengths of the Rust type system *and* C++ type system *and*
|
||||
the programmer's intuitions. An individual working on the C++ side without a
|
||||
Rust background, or the Rust side without a C++ background, will be able to
|
||||
apply all their usual intuitions and best practices about development in their
|
||||
language to maintain a correct FFI.
|
||||
|
||||
<br><br>
|
||||
7
vendor/cxx/book/theme/head.hbs
vendored
Normal file
7
vendor/cxx/book/theme/head.hbs
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-DG41MK6DDN"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-DG41MK6DDN', {'anonymize_ip': true});
|
||||
</script>
|
||||
55
vendor/cxx/build.rs
vendored
Normal file
55
vendor/cxx/build.rs
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
use std::env;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
cc::Build::new()
|
||||
.file("src/cxx.cc")
|
||||
.cpp(true)
|
||||
.cpp_link_stdlib(None) // linked via link-cplusplus crate
|
||||
.flag_if_supported(cxxbridge_flags::STD)
|
||||
.warnings_into_errors(cfg!(deny_warnings))
|
||||
.compile("cxxbridge1");
|
||||
|
||||
println!("cargo:rerun-if-changed=src/cxx.cc");
|
||||
println!("cargo:rerun-if-changed=include/cxx.h");
|
||||
println!("cargo:rustc-cfg=built_with_cargo");
|
||||
|
||||
if let Some(manifest_dir) = env::var_os("CARGO_MANIFEST_DIR") {
|
||||
let cxx_h = Path::new(&manifest_dir).join("include").join("cxx.h");
|
||||
println!("cargo:HEADER={}", cxx_h.to_string_lossy());
|
||||
}
|
||||
|
||||
if let Some(rustc) = rustc_version() {
|
||||
if rustc.minor < 48 {
|
||||
println!("cargo:warning=The cxx crate requires a rustc version 1.48.0 or newer.");
|
||||
println!(
|
||||
"cargo:warning=You appear to be building with: {}",
|
||||
rustc.version,
|
||||
);
|
||||
}
|
||||
|
||||
if rustc.minor < 52 {
|
||||
// #![deny(unsafe_op_in_unsafe_fn)].
|
||||
// https://github.com/rust-lang/rust/issues/71668
|
||||
println!("cargo:rustc-cfg=no_unsafe_op_in_unsafe_fn_lint");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RustVersion {
|
||||
version: String,
|
||||
minor: u32,
|
||||
}
|
||||
|
||||
fn rustc_version() -> Option<RustVersion> {
|
||||
let rustc = env::var_os("RUSTC")?;
|
||||
let output = Command::new(rustc).arg("--version").output().ok()?;
|
||||
let version = String::from_utf8(output.stdout).ok()?;
|
||||
let mut pieces = version.split('.');
|
||||
if pieces.next() != Some("rustc 1") {
|
||||
return None;
|
||||
}
|
||||
let minor = pieces.next()?.parse().ok()?;
|
||||
Some(RustVersion { version, minor })
|
||||
}
|
||||
1
vendor/cxx/compile_flags.txt
vendored
Normal file
1
vendor/cxx/compile_flags.txt
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
-std=c++11
|
||||
1111
vendor/cxx/include/cxx.h
vendored
Normal file
1111
vendor/cxx/include/cxx.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
69
vendor/cxx/src/c_char.rs
vendored
Normal file
69
vendor/cxx/src/c_char.rs
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#[allow(missing_docs)]
|
||||
pub type c_char = c_char_definition::c_char;
|
||||
|
||||
// Validate that our definition is consistent with libstd's definition, without
|
||||
// introducing a dependency on libstd in ordinary builds.
|
||||
#[cfg(all(test, feature = "std"))]
|
||||
const _: self::c_char = 0 as std::os::raw::c_char;
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod c_char_definition {
|
||||
// These are the targets on which c_char is unsigned.
|
||||
#[cfg(any(
|
||||
all(
|
||||
target_os = "linux",
|
||||
any(
|
||||
target_arch = "aarch64",
|
||||
target_arch = "arm",
|
||||
target_arch = "hexagon",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "s390x",
|
||||
target_arch = "riscv64",
|
||||
target_arch = "riscv32"
|
||||
)
|
||||
),
|
||||
all(
|
||||
target_os = "android",
|
||||
any(target_arch = "aarch64", target_arch = "arm")
|
||||
),
|
||||
all(target_os = "l4re", target_arch = "x86_64"),
|
||||
all(
|
||||
target_os = "freebsd",
|
||||
any(
|
||||
target_arch = "aarch64",
|
||||
target_arch = "arm",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "riscv64"
|
||||
)
|
||||
),
|
||||
all(
|
||||
target_os = "netbsd",
|
||||
any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
|
||||
),
|
||||
all(target_os = "openbsd", target_arch = "aarch64"),
|
||||
all(
|
||||
target_os = "vxworks",
|
||||
any(
|
||||
target_arch = "aarch64",
|
||||
target_arch = "arm",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "powerpc"
|
||||
)
|
||||
),
|
||||
all(target_os = "fuchsia", target_arch = "aarch64")
|
||||
))]
|
||||
pub use self::unsigned::c_char;
|
||||
|
||||
// On every other target, c_char is signed.
|
||||
pub use self::signed::*;
|
||||
|
||||
mod unsigned {
|
||||
pub type c_char = u8;
|
||||
}
|
||||
|
||||
mod signed {
|
||||
pub type c_char = i8;
|
||||
}
|
||||
}
|
||||
792
vendor/cxx/src/cxx.cc
vendored
Normal file
792
vendor/cxx/src/cxx.cc
vendored
Normal file
|
|
@ -0,0 +1,792 @@
|
|||
#include "../include/cxx.h"
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
extern "C" {
|
||||
void cxxbridge1$cxx_string$init(std::string *s, const std::uint8_t *ptr,
|
||||
std::size_t len) noexcept {
|
||||
new (s) std::string(reinterpret_cast<const char *>(ptr), len);
|
||||
}
|
||||
|
||||
void cxxbridge1$cxx_string$destroy(std::string *s) noexcept {
|
||||
using std::string;
|
||||
s->~string();
|
||||
}
|
||||
|
||||
const char *cxxbridge1$cxx_string$data(const std::string &s) noexcept {
|
||||
return s.data();
|
||||
}
|
||||
|
||||
std::size_t cxxbridge1$cxx_string$length(const std::string &s) noexcept {
|
||||
return s.length();
|
||||
}
|
||||
|
||||
void cxxbridge1$cxx_string$clear(std::string &s) noexcept { s.clear(); }
|
||||
|
||||
void cxxbridge1$cxx_string$reserve_total(std::string &s,
|
||||
size_t new_cap) noexcept {
|
||||
s.reserve(new_cap);
|
||||
}
|
||||
|
||||
void cxxbridge1$cxx_string$push(std::string &s, const std::uint8_t *ptr,
|
||||
std::size_t len) noexcept {
|
||||
s.append(reinterpret_cast<const char *>(ptr), len);
|
||||
}
|
||||
|
||||
// rust::String
|
||||
void cxxbridge1$string$new(rust::String *self) noexcept;
|
||||
void cxxbridge1$string$clone(rust::String *self,
|
||||
const rust::String &other) noexcept;
|
||||
bool cxxbridge1$string$from_utf8(rust::String *self, const char *ptr,
|
||||
std::size_t len) noexcept;
|
||||
void cxxbridge1$string$from_utf8_lossy(rust::String *self, const char *ptr,
|
||||
std::size_t len) noexcept;
|
||||
bool cxxbridge1$string$from_utf16(rust::String *self, const char16_t *ptr,
|
||||
std::size_t len) noexcept;
|
||||
void cxxbridge1$string$from_utf16_lossy(rust::String *self, const char16_t *ptr,
|
||||
std::size_t len) noexcept;
|
||||
void cxxbridge1$string$drop(rust::String *self) noexcept;
|
||||
const char *cxxbridge1$string$ptr(const rust::String *self) noexcept;
|
||||
std::size_t cxxbridge1$string$len(const rust::String *self) noexcept;
|
||||
std::size_t cxxbridge1$string$capacity(const rust::String *self) noexcept;
|
||||
void cxxbridge1$string$reserve_additional(rust::String *self,
|
||||
size_t additional) noexcept;
|
||||
void cxxbridge1$string$reserve_total(rust::String *self,
|
||||
size_t new_cap) noexcept;
|
||||
|
||||
// rust::Str
|
||||
void cxxbridge1$str$new(rust::Str *self) noexcept;
|
||||
void cxxbridge1$str$ref(rust::Str *self, const rust::String *string) noexcept;
|
||||
bool cxxbridge1$str$from(rust::Str *self, const char *ptr,
|
||||
std::size_t len) noexcept;
|
||||
const char *cxxbridge1$str$ptr(const rust::Str *self) noexcept;
|
||||
std::size_t cxxbridge1$str$len(const rust::Str *self) noexcept;
|
||||
|
||||
// rust::Slice
|
||||
void cxxbridge1$slice$new(void *self, const void *ptr,
|
||||
std::size_t len) noexcept;
|
||||
void *cxxbridge1$slice$ptr(const void *self) noexcept;
|
||||
std::size_t cxxbridge1$slice$len(const void *self) noexcept;
|
||||
} // extern "C"
|
||||
|
||||
namespace rust {
|
||||
inline namespace cxxbridge1 {
|
||||
|
||||
template <typename Exception>
|
||||
void panic [[noreturn]] (const char *msg) {
|
||||
#if defined(RUST_CXX_NO_EXCEPTIONS)
|
||||
std::cerr << "Error: " << msg << ". Aborting." << std::endl;
|
||||
std::terminate();
|
||||
#else
|
||||
throw Exception(msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
template void panic<std::out_of_range> [[noreturn]] (const char *msg);
|
||||
|
||||
template <typename T>
|
||||
static bool is_aligned(const void *ptr) noexcept {
|
||||
auto iptr = reinterpret_cast<std::uintptr_t>(ptr);
|
||||
return !(iptr % alignof(T));
|
||||
}
|
||||
|
||||
String::String() noexcept { cxxbridge1$string$new(this); }
|
||||
|
||||
String::String(const String &other) noexcept {
|
||||
cxxbridge1$string$clone(this, other);
|
||||
}
|
||||
|
||||
String::String(String &&other) noexcept : repr(other.repr) {
|
||||
cxxbridge1$string$new(&other);
|
||||
}
|
||||
|
||||
String::~String() noexcept { cxxbridge1$string$drop(this); }
|
||||
|
||||
static void initString(String *self, const char *s, std::size_t len) {
|
||||
if (!cxxbridge1$string$from_utf8(self, s, len)) {
|
||||
panic<std::invalid_argument>("data for rust::String is not utf-8");
|
||||
}
|
||||
}
|
||||
|
||||
static void initString(String *self, const char16_t *s, std::size_t len) {
|
||||
if (!cxxbridge1$string$from_utf16(self, s, len)) {
|
||||
panic<std::invalid_argument>("data for rust::String is not utf-16");
|
||||
}
|
||||
}
|
||||
|
||||
String::String(const std::string &s) { initString(this, s.data(), s.length()); }
|
||||
|
||||
String::String(const char *s) {
|
||||
assert(s != nullptr);
|
||||
initString(this, s, std::strlen(s));
|
||||
}
|
||||
|
||||
String::String(const char *s, std::size_t len) {
|
||||
assert(s != nullptr || len == 0);
|
||||
initString(this,
|
||||
s == nullptr && len == 0 ? reinterpret_cast<const char *>(1) : s,
|
||||
len);
|
||||
}
|
||||
|
||||
String::String(const char16_t *s) {
|
||||
assert(s != nullptr);
|
||||
assert(is_aligned<char16_t>(s));
|
||||
initString(this, s, std::char_traits<char16_t>::length(s));
|
||||
}
|
||||
|
||||
String::String(const char16_t *s, std::size_t len) {
|
||||
assert(s != nullptr || len == 0);
|
||||
assert(is_aligned<char16_t>(s));
|
||||
initString(this,
|
||||
s == nullptr && len == 0 ? reinterpret_cast<const char16_t *>(2)
|
||||
: s,
|
||||
len);
|
||||
}
|
||||
|
||||
struct String::lossy_t {};
|
||||
|
||||
String::String(lossy_t, const char *s, std::size_t len) noexcept {
|
||||
cxxbridge1$string$from_utf8_lossy(
|
||||
this, s == nullptr && len == 0 ? reinterpret_cast<const char *>(1) : s,
|
||||
len);
|
||||
}
|
||||
|
||||
String::String(lossy_t, const char16_t *s, std::size_t len) noexcept {
|
||||
cxxbridge1$string$from_utf16_lossy(
|
||||
this,
|
||||
s == nullptr && len == 0 ? reinterpret_cast<const char16_t *>(2) : s,
|
||||
len);
|
||||
}
|
||||
|
||||
String String::lossy(const std::string &s) noexcept {
|
||||
return String::lossy(s.data(), s.length());
|
||||
}
|
||||
|
||||
String String::lossy(const char *s) noexcept {
|
||||
assert(s != nullptr);
|
||||
return String::lossy(s, std::strlen(s));
|
||||
}
|
||||
|
||||
String String::lossy(const char *s, std::size_t len) noexcept {
|
||||
assert(s != nullptr || len == 0);
|
||||
return String(lossy_t{}, s, len);
|
||||
}
|
||||
|
||||
String String::lossy(const char16_t *s) noexcept {
|
||||
assert(s != nullptr);
|
||||
assert(is_aligned<char16_t>(s));
|
||||
return String(lossy_t{}, s, std::char_traits<char16_t>::length(s));
|
||||
}
|
||||
|
||||
String String::lossy(const char16_t *s, std::size_t len) noexcept {
|
||||
assert(s != nullptr || len == 0);
|
||||
assert(is_aligned<char16_t>(s));
|
||||
return String(lossy_t{}, s, len);
|
||||
}
|
||||
|
||||
String &String::operator=(const String &other) &noexcept {
|
||||
if (this != &other) {
|
||||
cxxbridge1$string$drop(this);
|
||||
cxxbridge1$string$clone(this, other);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator=(String &&other) &noexcept {
|
||||
cxxbridge1$string$drop(this);
|
||||
this->repr = other.repr;
|
||||
cxxbridge1$string$new(&other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
String::operator std::string() const {
|
||||
return std::string(this->data(), this->size());
|
||||
}
|
||||
|
||||
const char *String::data() const noexcept {
|
||||
return cxxbridge1$string$ptr(this);
|
||||
}
|
||||
|
||||
std::size_t String::size() const noexcept {
|
||||
return cxxbridge1$string$len(this);
|
||||
}
|
||||
|
||||
std::size_t String::length() const noexcept {
|
||||
return cxxbridge1$string$len(this);
|
||||
}
|
||||
|
||||
bool String::empty() const noexcept { return this->size() == 0; }
|
||||
|
||||
const char *String::c_str() noexcept {
|
||||
auto len = this->length();
|
||||
cxxbridge1$string$reserve_additional(this, 1);
|
||||
auto ptr = this->data();
|
||||
const_cast<char *>(ptr)[len] = '\0';
|
||||
return ptr;
|
||||
}
|
||||
|
||||
std::size_t String::capacity() const noexcept {
|
||||
return cxxbridge1$string$capacity(this);
|
||||
}
|
||||
|
||||
void String::reserve(std::size_t new_cap) noexcept {
|
||||
cxxbridge1$string$reserve_total(this, new_cap);
|
||||
}
|
||||
|
||||
String::iterator String::begin() noexcept {
|
||||
return const_cast<char *>(this->data());
|
||||
}
|
||||
|
||||
String::iterator String::end() noexcept {
|
||||
return const_cast<char *>(this->data()) + this->size();
|
||||
}
|
||||
|
||||
String::const_iterator String::begin() const noexcept { return this->cbegin(); }
|
||||
|
||||
String::const_iterator String::end() const noexcept { return this->cend(); }
|
||||
|
||||
String::const_iterator String::cbegin() const noexcept { return this->data(); }
|
||||
|
||||
String::const_iterator String::cend() const noexcept {
|
||||
return this->data() + this->size();
|
||||
}
|
||||
|
||||
bool String::operator==(const String &rhs) const noexcept {
|
||||
return rust::Str(*this) == rust::Str(rhs);
|
||||
}
|
||||
|
||||
bool String::operator!=(const String &rhs) const noexcept {
|
||||
return rust::Str(*this) != rust::Str(rhs);
|
||||
}
|
||||
|
||||
bool String::operator<(const String &rhs) const noexcept {
|
||||
return rust::Str(*this) < rust::Str(rhs);
|
||||
}
|
||||
|
||||
bool String::operator<=(const String &rhs) const noexcept {
|
||||
return rust::Str(*this) <= rust::Str(rhs);
|
||||
}
|
||||
|
||||
bool String::operator>(const String &rhs) const noexcept {
|
||||
return rust::Str(*this) > rust::Str(rhs);
|
||||
}
|
||||
|
||||
bool String::operator>=(const String &rhs) const noexcept {
|
||||
return rust::Str(*this) >= rust::Str(rhs);
|
||||
}
|
||||
|
||||
void String::swap(String &rhs) noexcept {
|
||||
using std::swap;
|
||||
swap(this->repr, rhs.repr);
|
||||
}
|
||||
|
||||
String::String(unsafe_bitcopy_t, const String &bits) noexcept
|
||||
: repr(bits.repr) {}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const String &s) {
|
||||
os.write(s.data(), s.size());
|
||||
return os;
|
||||
}
|
||||
|
||||
Str::Str() noexcept { cxxbridge1$str$new(this); }
|
||||
|
||||
Str::Str(const String &s) noexcept { cxxbridge1$str$ref(this, &s); }
|
||||
|
||||
static void initStr(Str *self, const char *ptr, std::size_t len) {
|
||||
if (!cxxbridge1$str$from(self, ptr, len)) {
|
||||
panic<std::invalid_argument>("data for rust::Str is not utf-8");
|
||||
}
|
||||
}
|
||||
|
||||
Str::Str(const std::string &s) { initStr(this, s.data(), s.length()); }
|
||||
|
||||
Str::Str(const char *s) {
|
||||
assert(s != nullptr);
|
||||
initStr(this, s, std::strlen(s));
|
||||
}
|
||||
|
||||
Str::Str(const char *s, std::size_t len) {
|
||||
assert(s != nullptr || len == 0);
|
||||
initStr(this,
|
||||
s == nullptr && len == 0 ? reinterpret_cast<const char *>(1) : s,
|
||||
len);
|
||||
}
|
||||
|
||||
Str::operator std::string() const {
|
||||
return std::string(this->data(), this->size());
|
||||
}
|
||||
|
||||
const char *Str::data() const noexcept { return cxxbridge1$str$ptr(this); }
|
||||
|
||||
std::size_t Str::size() const noexcept { return cxxbridge1$str$len(this); }
|
||||
|
||||
std::size_t Str::length() const noexcept { return this->size(); }
|
||||
|
||||
bool Str::empty() const noexcept { return this->size() == 0; }
|
||||
|
||||
Str::const_iterator Str::begin() const noexcept { return this->cbegin(); }
|
||||
|
||||
Str::const_iterator Str::end() const noexcept { return this->cend(); }
|
||||
|
||||
Str::const_iterator Str::cbegin() const noexcept { return this->data(); }
|
||||
|
||||
Str::const_iterator Str::cend() const noexcept {
|
||||
return this->data() + this->size();
|
||||
}
|
||||
|
||||
bool Str::operator==(const Str &rhs) const noexcept {
|
||||
return this->size() == rhs.size() &&
|
||||
std::equal(this->begin(), this->end(), rhs.begin());
|
||||
}
|
||||
|
||||
bool Str::operator!=(const Str &rhs) const noexcept { return !(*this == rhs); }
|
||||
|
||||
bool Str::operator<(const Str &rhs) const noexcept {
|
||||
return std::lexicographical_compare(this->begin(), this->end(), rhs.begin(),
|
||||
rhs.end());
|
||||
}
|
||||
|
||||
bool Str::operator<=(const Str &rhs) const noexcept {
|
||||
// std::mismatch(this->begin(), this->end(), rhs.begin(), rhs.end()), except
|
||||
// without Undefined Behavior on C++11 if rhs is shorter than *this.
|
||||
const_iterator liter = this->begin(), lend = this->end(), riter = rhs.begin(),
|
||||
rend = rhs.end();
|
||||
while (liter != lend && riter != rend && *liter == *riter) {
|
||||
++liter, ++riter;
|
||||
}
|
||||
if (liter == lend) {
|
||||
return true; // equal or *this is a prefix of rhs
|
||||
} else if (riter == rend) {
|
||||
return false; // rhs is a prefix of *this
|
||||
} else {
|
||||
return *liter <= *riter;
|
||||
}
|
||||
}
|
||||
|
||||
bool Str::operator>(const Str &rhs) const noexcept { return rhs < *this; }
|
||||
|
||||
bool Str::operator>=(const Str &rhs) const noexcept { return rhs <= *this; }
|
||||
|
||||
void Str::swap(Str &rhs) noexcept {
|
||||
using std::swap;
|
||||
swap(this->repr, rhs.repr);
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const Str &s) {
|
||||
os.write(s.data(), s.size());
|
||||
return os;
|
||||
}
|
||||
|
||||
void sliceInit(void *self, const void *ptr, std::size_t len) noexcept {
|
||||
cxxbridge1$slice$new(self, ptr, len);
|
||||
}
|
||||
|
||||
void *slicePtr(const void *self) noexcept { return cxxbridge1$slice$ptr(self); }
|
||||
|
||||
std::size_t sliceLen(const void *self) noexcept {
|
||||
return cxxbridge1$slice$len(self);
|
||||
}
|
||||
|
||||
// Rust specifies that usize is ABI compatible with C's uintptr_t.
|
||||
// https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize
|
||||
// However there is no direct Rust equivalent for size_t. C does not guarantee
|
||||
// that size_t and uintptr_t are compatible. In practice though, on all
|
||||
// platforms supported by Rust, they are identical for ABI purposes. See the
|
||||
// libc crate which unconditionally defines libc::size_t = usize. We expect the
|
||||
// same here and these assertions are just here to explicitly document that.
|
||||
// *Note that no assumption is made about C++ name mangling of signatures
|
||||
// containing these types, not here nor anywhere in CXX.*
|
||||
static_assert(sizeof(std::size_t) == sizeof(std::uintptr_t),
|
||||
"unsupported size_t size");
|
||||
static_assert(alignof(std::size_t) == alignof(std::uintptr_t),
|
||||
"unsupported size_t alignment");
|
||||
static_assert(sizeof(rust::isize) == sizeof(std::intptr_t),
|
||||
"unsupported ssize_t size");
|
||||
static_assert(alignof(rust::isize) == alignof(std::intptr_t),
|
||||
"unsupported ssize_t alignment");
|
||||
|
||||
static_assert(std::is_trivially_copy_constructible<Str>::value,
|
||||
"trivial Str(const Str &)");
|
||||
static_assert(std::is_trivially_copy_assignable<Str>::value,
|
||||
"trivial operator=(const Str &)");
|
||||
static_assert(std::is_trivially_destructible<Str>::value, "trivial ~Str()");
|
||||
|
||||
static_assert(
|
||||
std::is_trivially_copy_constructible<Slice<const std::uint8_t>>::value,
|
||||
"trivial Slice(const Slice &)");
|
||||
static_assert(
|
||||
std::is_trivially_move_constructible<Slice<const std::uint8_t>>::value,
|
||||
"trivial Slice(Slice &&)");
|
||||
static_assert(
|
||||
std::is_trivially_copy_assignable<Slice<const std::uint8_t>>::value,
|
||||
"trivial Slice::operator=(const Slice &) for const slices");
|
||||
static_assert(
|
||||
std::is_trivially_move_assignable<Slice<const std::uint8_t>>::value,
|
||||
"trivial Slice::operator=(Slice &&)");
|
||||
static_assert(std::is_trivially_destructible<Slice<const std::uint8_t>>::value,
|
||||
"trivial ~Slice()");
|
||||
|
||||
static_assert(std::is_trivially_copy_constructible<Slice<std::uint8_t>>::value,
|
||||
"trivial Slice(const Slice &)");
|
||||
static_assert(std::is_trivially_move_constructible<Slice<std::uint8_t>>::value,
|
||||
"trivial Slice(Slice &&)");
|
||||
static_assert(!std::is_copy_assignable<Slice<std::uint8_t>>::value,
|
||||
"delete Slice::operator=(const Slice &) for mut slices");
|
||||
static_assert(std::is_trivially_move_assignable<Slice<std::uint8_t>>::value,
|
||||
"trivial Slice::operator=(Slice &&)");
|
||||
static_assert(std::is_trivially_destructible<Slice<std::uint8_t>>::value,
|
||||
"trivial ~Slice()");
|
||||
|
||||
static_assert(std::is_same<Vec<std::uint8_t>::const_iterator,
|
||||
Vec<const std::uint8_t>::iterator>::value,
|
||||
"Vec<T>::const_iterator == Vec<const T>::iterator");
|
||||
static_assert(std::is_same<Vec<const std::uint8_t>::const_iterator,
|
||||
Vec<const std::uint8_t>::iterator>::value,
|
||||
"Vec<const T>::const_iterator == Vec<const T>::iterator");
|
||||
static_assert(!std::is_same<Vec<std::uint8_t>::const_iterator,
|
||||
Vec<std::uint8_t>::iterator>::value,
|
||||
"Vec<T>::const_iterator != Vec<T>::iterator");
|
||||
|
||||
static const char *errorCopy(const char *ptr, std::size_t len) {
|
||||
char *copy = new char[len];
|
||||
std::memcpy(copy, ptr, len);
|
||||
return copy;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
const char *cxxbridge1$error(const char *ptr, std::size_t len) noexcept {
|
||||
return errorCopy(ptr, len);
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
Error::Error(const Error &other)
|
||||
: std::exception(other),
|
||||
msg(other.msg ? errorCopy(other.msg, other.len) : nullptr),
|
||||
len(other.len) {}
|
||||
|
||||
Error::Error(Error &&other) noexcept
|
||||
: std::exception(std::move(other)), msg(other.msg), len(other.len) {
|
||||
other.msg = nullptr;
|
||||
other.len = 0;
|
||||
}
|
||||
|
||||
Error::~Error() noexcept { delete[] this->msg; }
|
||||
|
||||
Error &Error::operator=(const Error &other) & {
|
||||
if (this != &other) {
|
||||
std::exception::operator=(other);
|
||||
delete[] this->msg;
|
||||
this->msg = nullptr;
|
||||
if (other.msg) {
|
||||
this->msg = errorCopy(other.msg, other.len);
|
||||
this->len = other.len;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Error &Error::operator=(Error &&other) &noexcept {
|
||||
std::exception::operator=(std::move(other));
|
||||
this->msg = other.msg;
|
||||
this->len = other.len;
|
||||
other.msg = nullptr;
|
||||
other.len = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const char *Error::what() const noexcept { return this->msg; }
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
union MaybeUninit {
|
||||
T value;
|
||||
MaybeUninit() {}
|
||||
~MaybeUninit() {}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace repr {
|
||||
struct PtrLen final {
|
||||
void *ptr;
|
||||
std::size_t len;
|
||||
};
|
||||
} // namespace repr
|
||||
|
||||
extern "C" {
|
||||
repr::PtrLen cxxbridge1$exception(const char *, std::size_t len) noexcept;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
// On some platforms size_t is the same C++ type as one of the sized integer
|
||||
// types; on others it is a distinct type. Only in the latter case do we need to
|
||||
// define a specialized impl of rust::Vec<size_t>, because in the former case it
|
||||
// would collide with one of the other specializations.
|
||||
using usize_if_unique =
|
||||
typename std::conditional<std::is_same<size_t, uint64_t>::value ||
|
||||
std::is_same<size_t, uint32_t>::value,
|
||||
struct usize_ignore, size_t>::type;
|
||||
using isize_if_unique =
|
||||
typename std::conditional<std::is_same<rust::isize, int64_t>::value ||
|
||||
std::is_same<rust::isize, int32_t>::value,
|
||||
struct isize_ignore, rust::isize>::type;
|
||||
|
||||
class Fail final {
|
||||
repr::PtrLen &throw$;
|
||||
|
||||
public:
|
||||
Fail(repr::PtrLen &throw$) noexcept : throw$(throw$) {}
|
||||
void operator()(const char *) noexcept;
|
||||
void operator()(const std::string &) noexcept;
|
||||
};
|
||||
|
||||
void Fail::operator()(const char *catch$) noexcept {
|
||||
throw$ = cxxbridge1$exception(catch$, std::strlen(catch$));
|
||||
}
|
||||
|
||||
void Fail::operator()(const std::string &catch$) noexcept {
|
||||
throw$ = cxxbridge1$exception(catch$.data(), catch$.length());
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
} // namespace cxxbridge1
|
||||
} // namespace rust
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
void destroy(T *ptr) {
|
||||
ptr->~T();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
void cxxbridge1$unique_ptr$std$string$null(
|
||||
std::unique_ptr<std::string> *ptr) noexcept {
|
||||
new (ptr) std::unique_ptr<std::string>();
|
||||
}
|
||||
void cxxbridge1$unique_ptr$std$string$raw(std::unique_ptr<std::string> *ptr,
|
||||
std::string *raw) noexcept {
|
||||
new (ptr) std::unique_ptr<std::string>(raw);
|
||||
}
|
||||
const std::string *cxxbridge1$unique_ptr$std$string$get(
|
||||
const std::unique_ptr<std::string> &ptr) noexcept {
|
||||
return ptr.get();
|
||||
}
|
||||
std::string *cxxbridge1$unique_ptr$std$string$release(
|
||||
std::unique_ptr<std::string> &ptr) noexcept {
|
||||
return ptr.release();
|
||||
}
|
||||
void cxxbridge1$unique_ptr$std$string$drop(
|
||||
std::unique_ptr<std::string> *ptr) noexcept {
|
||||
ptr->~unique_ptr();
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
namespace {
|
||||
const std::size_t kMaxExpectedWordsInString = 8;
|
||||
static_assert(alignof(std::string) <= alignof(void *),
|
||||
"unexpectedly large std::string alignment");
|
||||
static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *),
|
||||
"unexpectedly large std::string size");
|
||||
} // namespace
|
||||
|
||||
#define STD_VECTOR_OPS(RUST_TYPE, CXX_TYPE) \
|
||||
std::size_t cxxbridge1$std$vector$##RUST_TYPE##$size( \
|
||||
const std::vector<CXX_TYPE> &s) noexcept { \
|
||||
return s.size(); \
|
||||
} \
|
||||
CXX_TYPE *cxxbridge1$std$vector$##RUST_TYPE##$get_unchecked( \
|
||||
std::vector<CXX_TYPE> *s, std::size_t pos) noexcept { \
|
||||
return &(*s)[pos]; \
|
||||
} \
|
||||
void cxxbridge1$unique_ptr$std$vector$##RUST_TYPE##$null( \
|
||||
std::unique_ptr<std::vector<CXX_TYPE>> *ptr) noexcept { \
|
||||
new (ptr) std::unique_ptr<std::vector<CXX_TYPE>>(); \
|
||||
} \
|
||||
void cxxbridge1$unique_ptr$std$vector$##RUST_TYPE##$raw( \
|
||||
std::unique_ptr<std::vector<CXX_TYPE>> *ptr, \
|
||||
std::vector<CXX_TYPE> *raw) noexcept { \
|
||||
new (ptr) std::unique_ptr<std::vector<CXX_TYPE>>(raw); \
|
||||
} \
|
||||
const std::vector<CXX_TYPE> \
|
||||
*cxxbridge1$unique_ptr$std$vector$##RUST_TYPE##$get( \
|
||||
const std::unique_ptr<std::vector<CXX_TYPE>> &ptr) noexcept { \
|
||||
return ptr.get(); \
|
||||
} \
|
||||
std::vector<CXX_TYPE> \
|
||||
*cxxbridge1$unique_ptr$std$vector$##RUST_TYPE##$release( \
|
||||
std::unique_ptr<std::vector<CXX_TYPE>> &ptr) noexcept { \
|
||||
return ptr.release(); \
|
||||
} \
|
||||
void cxxbridge1$unique_ptr$std$vector$##RUST_TYPE##$drop( \
|
||||
std::unique_ptr<std::vector<CXX_TYPE>> *ptr) noexcept { \
|
||||
ptr->~unique_ptr(); \
|
||||
}
|
||||
|
||||
#define STD_VECTOR_TRIVIAL_OPS(RUST_TYPE, CXX_TYPE) \
|
||||
void cxxbridge1$std$vector$##RUST_TYPE##$push_back( \
|
||||
std::vector<CXX_TYPE> *v, CXX_TYPE *value) noexcept { \
|
||||
v->push_back(std::move(*value)); \
|
||||
destroy(value); \
|
||||
} \
|
||||
void cxxbridge1$std$vector$##RUST_TYPE##$pop_back(std::vector<CXX_TYPE> *v, \
|
||||
CXX_TYPE *out) noexcept { \
|
||||
new (out) CXX_TYPE(std::move(v->back())); \
|
||||
v->pop_back(); \
|
||||
}
|
||||
|
||||
#define RUST_VEC_EXTERNS(RUST_TYPE, CXX_TYPE) \
|
||||
void cxxbridge1$rust_vec$##RUST_TYPE##$new( \
|
||||
rust::Vec<CXX_TYPE> *ptr) noexcept; \
|
||||
void cxxbridge1$rust_vec$##RUST_TYPE##$drop( \
|
||||
rust::Vec<CXX_TYPE> *ptr) noexcept; \
|
||||
std::size_t cxxbridge1$rust_vec$##RUST_TYPE##$len( \
|
||||
const rust::Vec<CXX_TYPE> *ptr) noexcept; \
|
||||
std::size_t cxxbridge1$rust_vec$##RUST_TYPE##$capacity( \
|
||||
const rust::Vec<CXX_TYPE> *ptr) noexcept; \
|
||||
const CXX_TYPE *cxxbridge1$rust_vec$##RUST_TYPE##$data( \
|
||||
const rust::Vec<CXX_TYPE> *ptr) noexcept; \
|
||||
void cxxbridge1$rust_vec$##RUST_TYPE##$reserve_total( \
|
||||
rust::Vec<CXX_TYPE> *ptr, std::size_t new_cap) noexcept; \
|
||||
void cxxbridge1$rust_vec$##RUST_TYPE##$set_len(rust::Vec<CXX_TYPE> *ptr, \
|
||||
std::size_t len) noexcept; \
|
||||
void cxxbridge1$rust_vec$##RUST_TYPE##$truncate(rust::Vec<CXX_TYPE> *ptr, \
|
||||
std::size_t len) noexcept;
|
||||
|
||||
#define RUST_VEC_OPS(RUST_TYPE, CXX_TYPE) \
|
||||
template <> \
|
||||
Vec<CXX_TYPE>::Vec() noexcept { \
|
||||
cxxbridge1$rust_vec$##RUST_TYPE##$new(this); \
|
||||
} \
|
||||
template <> \
|
||||
void Vec<CXX_TYPE>::drop() noexcept { \
|
||||
return cxxbridge1$rust_vec$##RUST_TYPE##$drop(this); \
|
||||
} \
|
||||
template <> \
|
||||
std::size_t Vec<CXX_TYPE>::size() const noexcept { \
|
||||
return cxxbridge1$rust_vec$##RUST_TYPE##$len(this); \
|
||||
} \
|
||||
template <> \
|
||||
std::size_t Vec<CXX_TYPE>::capacity() const noexcept { \
|
||||
return cxxbridge1$rust_vec$##RUST_TYPE##$capacity(this); \
|
||||
} \
|
||||
template <> \
|
||||
const CXX_TYPE *Vec<CXX_TYPE>::data() const noexcept { \
|
||||
return cxxbridge1$rust_vec$##RUST_TYPE##$data(this); \
|
||||
} \
|
||||
template <> \
|
||||
void Vec<CXX_TYPE>::reserve_total(std::size_t new_cap) noexcept { \
|
||||
cxxbridge1$rust_vec$##RUST_TYPE##$reserve_total(this, new_cap); \
|
||||
} \
|
||||
template <> \
|
||||
void Vec<CXX_TYPE>::set_len(std::size_t len) noexcept { \
|
||||
cxxbridge1$rust_vec$##RUST_TYPE##$set_len(this, len); \
|
||||
} \
|
||||
template <> \
|
||||
void Vec<CXX_TYPE>::truncate(std::size_t len) { \
|
||||
cxxbridge1$rust_vec$##RUST_TYPE##$truncate(this, len); \
|
||||
}
|
||||
|
||||
#define SHARED_PTR_OPS(RUST_TYPE, CXX_TYPE) \
|
||||
static_assert(sizeof(std::shared_ptr<CXX_TYPE>) == 2 * sizeof(void *), ""); \
|
||||
static_assert(alignof(std::shared_ptr<CXX_TYPE>) == alignof(void *), ""); \
|
||||
void cxxbridge1$std$shared_ptr$##RUST_TYPE##$null( \
|
||||
std::shared_ptr<CXX_TYPE> *ptr) noexcept { \
|
||||
new (ptr) std::shared_ptr<CXX_TYPE>(); \
|
||||
} \
|
||||
CXX_TYPE *cxxbridge1$std$shared_ptr$##RUST_TYPE##$uninit( \
|
||||
std::shared_ptr<CXX_TYPE> *ptr) noexcept { \
|
||||
CXX_TYPE *uninit = \
|
||||
reinterpret_cast<CXX_TYPE *>(new rust::MaybeUninit<CXX_TYPE>); \
|
||||
new (ptr) std::shared_ptr<CXX_TYPE>(uninit); \
|
||||
return uninit; \
|
||||
} \
|
||||
void cxxbridge1$std$shared_ptr$##RUST_TYPE##$clone( \
|
||||
const std::shared_ptr<CXX_TYPE> &self, \
|
||||
std::shared_ptr<CXX_TYPE> *ptr) noexcept { \
|
||||
new (ptr) std::shared_ptr<CXX_TYPE>(self); \
|
||||
} \
|
||||
const CXX_TYPE *cxxbridge1$std$shared_ptr$##RUST_TYPE##$get( \
|
||||
const std::shared_ptr<CXX_TYPE> &self) noexcept { \
|
||||
return self.get(); \
|
||||
} \
|
||||
void cxxbridge1$std$shared_ptr$##RUST_TYPE##$drop( \
|
||||
const std::shared_ptr<CXX_TYPE> *self) noexcept { \
|
||||
self->~shared_ptr(); \
|
||||
} \
|
||||
static_assert(sizeof(std::weak_ptr<CXX_TYPE>) == 2 * sizeof(void *), ""); \
|
||||
static_assert(alignof(std::weak_ptr<CXX_TYPE>) == alignof(void *), ""); \
|
||||
void cxxbridge1$std$weak_ptr$##RUST_TYPE##$null( \
|
||||
std::weak_ptr<CXX_TYPE> *ptr) noexcept { \
|
||||
new (ptr) std::weak_ptr<CXX_TYPE>(); \
|
||||
} \
|
||||
void cxxbridge1$std$weak_ptr$##RUST_TYPE##$clone( \
|
||||
const std::weak_ptr<CXX_TYPE> &self, \
|
||||
std::weak_ptr<CXX_TYPE> *ptr) noexcept { \
|
||||
new (ptr) std::weak_ptr<CXX_TYPE>(self); \
|
||||
} \
|
||||
void cxxbridge1$std$weak_ptr$##RUST_TYPE##$downgrade( \
|
||||
const std::shared_ptr<CXX_TYPE> &shared, \
|
||||
std::weak_ptr<CXX_TYPE> *weak) noexcept { \
|
||||
new (weak) std::weak_ptr<CXX_TYPE>(shared); \
|
||||
} \
|
||||
void cxxbridge1$std$weak_ptr$##RUST_TYPE##$upgrade( \
|
||||
const std::weak_ptr<CXX_TYPE> &weak, \
|
||||
std::shared_ptr<CXX_TYPE> *shared) noexcept { \
|
||||
new (shared) std::shared_ptr<CXX_TYPE>(weak.lock()); \
|
||||
} \
|
||||
void cxxbridge1$std$weak_ptr$##RUST_TYPE##$drop( \
|
||||
const std::weak_ptr<CXX_TYPE> *self) noexcept { \
|
||||
self->~weak_ptr(); \
|
||||
}
|
||||
|
||||
// Usize and isize are the same type as one of the below.
|
||||
#define FOR_EACH_NUMERIC(MACRO) \
|
||||
MACRO(u8, std::uint8_t) \
|
||||
MACRO(u16, std::uint16_t) \
|
||||
MACRO(u32, std::uint32_t) \
|
||||
MACRO(u64, std::uint64_t) \
|
||||
MACRO(i8, std::int8_t) \
|
||||
MACRO(i16, std::int16_t) \
|
||||
MACRO(i32, std::int32_t) \
|
||||
MACRO(i64, std::int64_t) \
|
||||
MACRO(f32, float) \
|
||||
MACRO(f64, double)
|
||||
|
||||
#define FOR_EACH_TRIVIAL_STD_VECTOR(MACRO) \
|
||||
FOR_EACH_NUMERIC(MACRO) \
|
||||
MACRO(usize, std::size_t) \
|
||||
MACRO(isize, rust::isize)
|
||||
|
||||
#define FOR_EACH_STD_VECTOR(MACRO) \
|
||||
FOR_EACH_TRIVIAL_STD_VECTOR(MACRO) \
|
||||
MACRO(string, std::string)
|
||||
|
||||
#define FOR_EACH_RUST_VEC(MACRO) \
|
||||
FOR_EACH_NUMERIC(MACRO) \
|
||||
MACRO(bool, bool) \
|
||||
MACRO(char, char) \
|
||||
MACRO(usize, rust::detail::usize_if_unique) \
|
||||
MACRO(isize, rust::detail::isize_if_unique) \
|
||||
MACRO(string, rust::String) \
|
||||
MACRO(str, rust::Str)
|
||||
|
||||
#define FOR_EACH_SHARED_PTR(MACRO) \
|
||||
FOR_EACH_NUMERIC(MACRO) \
|
||||
MACRO(bool, bool) \
|
||||
MACRO(usize, std::size_t) \
|
||||
MACRO(isize, rust::isize) \
|
||||
MACRO(string, std::string)
|
||||
|
||||
extern "C" {
|
||||
FOR_EACH_STD_VECTOR(STD_VECTOR_OPS)
|
||||
FOR_EACH_TRIVIAL_STD_VECTOR(STD_VECTOR_TRIVIAL_OPS)
|
||||
FOR_EACH_RUST_VEC(RUST_VEC_EXTERNS)
|
||||
FOR_EACH_SHARED_PTR(SHARED_PTR_OPS)
|
||||
} // extern "C"
|
||||
|
||||
namespace rust {
|
||||
inline namespace cxxbridge1 {
|
||||
FOR_EACH_RUST_VEC(RUST_VEC_OPS)
|
||||
} // namespace cxxbridge1
|
||||
} // namespace rust
|
||||
293
vendor/cxx/src/cxx_string.rs
vendored
Normal file
293
vendor/cxx/src/cxx_string.rs
vendored
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
use crate::actually_private::Private;
|
||||
use crate::lossy;
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::borrow::Cow;
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::string::String;
|
||||
use core::cmp::Ordering;
|
||||
use core::fmt::{self, Debug, Display};
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::marker::{PhantomData, PhantomPinned};
|
||||
use core::mem::MaybeUninit;
|
||||
use core::pin::Pin;
|
||||
use core::slice;
|
||||
use core::str::{self, Utf8Error};
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "cxxbridge1$cxx_string$init"]
|
||||
fn string_init(this: &mut MaybeUninit<CxxString>, ptr: *const u8, len: usize);
|
||||
#[link_name = "cxxbridge1$cxx_string$destroy"]
|
||||
fn string_destroy(this: &mut MaybeUninit<CxxString>);
|
||||
#[link_name = "cxxbridge1$cxx_string$data"]
|
||||
fn string_data(this: &CxxString) -> *const u8;
|
||||
#[link_name = "cxxbridge1$cxx_string$length"]
|
||||
fn string_length(this: &CxxString) -> usize;
|
||||
#[link_name = "cxxbridge1$cxx_string$clear"]
|
||||
fn string_clear(this: Pin<&mut CxxString>);
|
||||
#[link_name = "cxxbridge1$cxx_string$reserve_total"]
|
||||
fn string_reserve_total(this: Pin<&mut CxxString>, new_cap: usize);
|
||||
#[link_name = "cxxbridge1$cxx_string$push"]
|
||||
fn string_push(this: Pin<&mut CxxString>, ptr: *const u8, len: usize);
|
||||
}
|
||||
|
||||
/// Binding to C++ `std::string`.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// As an invariant of this API and the static analysis of the cxx::bridge
|
||||
/// macro, in Rust code we can never obtain a `CxxString` by value. C++'s string
|
||||
/// requires a move constructor and may hold internal pointers, which is not
|
||||
/// compatible with Rust's move behavior. Instead in Rust code we will only ever
|
||||
/// look at a CxxString through a reference or smart pointer, as in `&CxxString`
|
||||
/// or `UniquePtr<CxxString>`.
|
||||
#[repr(C)]
|
||||
pub struct CxxString {
|
||||
_private: [u8; 0],
|
||||
_pinned: PhantomData<PhantomPinned>,
|
||||
}
|
||||
|
||||
/// Construct a C++ std::string on the Rust stack.
|
||||
///
|
||||
/// # Syntax
|
||||
///
|
||||
/// In statement position:
|
||||
///
|
||||
/// ```
|
||||
/// # use cxx::let_cxx_string;
|
||||
/// # let expression = "";
|
||||
/// let_cxx_string!(var = expression);
|
||||
/// ```
|
||||
///
|
||||
/// The `expression` may have any type that implements `AsRef<[u8]>`. Commonly
|
||||
/// it will be a string literal, but for example `&[u8]` and `String` would work
|
||||
/// as well.
|
||||
///
|
||||
/// The macro expands to something resembling `let $var: Pin<&mut CxxString> =
|
||||
/// /*???*/;`. The resulting [`Pin`] can be deref'd to `&CxxString` as needed.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use cxx::{let_cxx_string, CxxString};
|
||||
///
|
||||
/// fn f(s: &CxxString) {/* ... */}
|
||||
///
|
||||
/// fn main() {
|
||||
/// let_cxx_string!(s = "example");
|
||||
/// f(&s);
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! let_cxx_string {
|
||||
($var:ident = $value:expr $(,)?) => {
|
||||
let mut cxx_stack_string = $crate::private::StackString::new();
|
||||
#[allow(unused_mut, unused_unsafe)]
|
||||
let mut $var = match $value {
|
||||
let_cxx_string => unsafe { cxx_stack_string.init(let_cxx_string) },
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
impl CxxString {
|
||||
/// `CxxString` is not constructible via `new`. Instead, use the
|
||||
/// [`let_cxx_string!`] macro.
|
||||
pub fn new<T: Private>() -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
/// Returns the length of the string in bytes.
|
||||
///
|
||||
/// Matches the behavior of C++ [std::string::size][size].
|
||||
///
|
||||
/// [size]: https://en.cppreference.com/w/cpp/string/basic_string/size
|
||||
pub fn len(&self) -> usize {
|
||||
unsafe { string_length(self) }
|
||||
}
|
||||
|
||||
/// Returns true if `self` has a length of zero bytes.
|
||||
///
|
||||
/// Matches the behavior of C++ [std::string::empty][empty].
|
||||
///
|
||||
/// [empty]: https://en.cppreference.com/w/cpp/string/basic_string/empty
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Returns a byte slice of this string's contents.
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
let data = self.as_ptr();
|
||||
let len = self.len();
|
||||
unsafe { slice::from_raw_parts(data, len) }
|
||||
}
|
||||
|
||||
/// Produces a pointer to the first character of the string.
|
||||
///
|
||||
/// Matches the behavior of C++ [std::string::data][data].
|
||||
///
|
||||
/// Note that the return type may look like `const char *` but is not a
|
||||
/// `const char *` in the typical C sense, as C++ strings may contain
|
||||
/// internal null bytes. As such, the returned pointer only makes sense as a
|
||||
/// string in combination with the length returned by [`len()`][len].
|
||||
///
|
||||
/// [data]: https://en.cppreference.com/w/cpp/string/basic_string/data
|
||||
/// [len]: #method.len
|
||||
pub fn as_ptr(&self) -> *const u8 {
|
||||
unsafe { string_data(self) }
|
||||
}
|
||||
|
||||
/// Validates that the C++ string contains UTF-8 data and produces a view of
|
||||
/// it as a Rust &str, otherwise an error.
|
||||
pub fn to_str(&self) -> Result<&str, Utf8Error> {
|
||||
str::from_utf8(self.as_bytes())
|
||||
}
|
||||
|
||||
/// If the contents of the C++ string are valid UTF-8, this function returns
|
||||
/// a view as a Cow::Borrowed &str. Otherwise replaces any invalid UTF-8
|
||||
/// sequences with the U+FFFD [replacement character] and returns a
|
||||
/// Cow::Owned String.
|
||||
///
|
||||
/// [replacement character]: https://doc.rust-lang.org/std/char/constant.REPLACEMENT_CHARACTER.html
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
|
||||
pub fn to_string_lossy(&self) -> Cow<str> {
|
||||
String::from_utf8_lossy(self.as_bytes())
|
||||
}
|
||||
|
||||
/// Removes all characters from the string.
|
||||
///
|
||||
/// Matches the behavior of C++ [std::string::clear][clear].
|
||||
///
|
||||
/// Note: **unlike** the guarantee of Rust's `std::string::String::clear`,
|
||||
/// the C++ standard does not require that capacity is unchanged by this
|
||||
/// operation. In practice existing implementations do not change the
|
||||
/// capacity but all pointers, references, and iterators into the string
|
||||
/// contents are nevertheless invalidated.
|
||||
///
|
||||
/// [clear]: https://en.cppreference.com/w/cpp/string/basic_string/clear
|
||||
pub fn clear(self: Pin<&mut Self>) {
|
||||
unsafe { string_clear(self) }
|
||||
}
|
||||
|
||||
/// Ensures that this string's capacity is at least `additional` bytes
|
||||
/// larger than its length.
|
||||
///
|
||||
/// The capacity may be increased by more than `additional` bytes if it
|
||||
/// chooses, to amortize the cost of frequent reallocations.
|
||||
///
|
||||
/// **The meaning of the argument is not the same as
|
||||
/// [std::string::reserve][reserve] in C++.** The C++ standard library and
|
||||
/// Rust standard library both have a `reserve` method on strings, but in
|
||||
/// C++ code the argument always refers to total capacity, whereas in Rust
|
||||
/// code it always refers to additional capacity. This API on `CxxString`
|
||||
/// follows the Rust convention, the same way that for the length accessor
|
||||
/// we use the Rust conventional `len()` naming and not C++ `size()` or
|
||||
/// `length()`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the new capacity overflows usize.
|
||||
///
|
||||
/// [reserve]: https://en.cppreference.com/w/cpp/string/basic_string/reserve
|
||||
pub fn reserve(self: Pin<&mut Self>, additional: usize) {
|
||||
let new_cap = self
|
||||
.len()
|
||||
.checked_add(additional)
|
||||
.expect("CxxString capacity overflow");
|
||||
unsafe { string_reserve_total(self, new_cap) }
|
||||
}
|
||||
|
||||
/// Appends a given string slice onto the end of this C++ string.
|
||||
pub fn push_str(self: Pin<&mut Self>, s: &str) {
|
||||
self.push_bytes(s.as_bytes());
|
||||
}
|
||||
|
||||
/// Appends arbitrary bytes onto the end of this C++ string.
|
||||
pub fn push_bytes(self: Pin<&mut Self>, bytes: &[u8]) {
|
||||
unsafe { string_push(self, bytes.as_ptr(), bytes.len()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for CxxString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
lossy::display(self.as_bytes(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for CxxString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
lossy::debug(self.as_bytes(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for CxxString {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_bytes() == other.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<CxxString> for str {
|
||||
fn eq(&self, other: &CxxString) -> bool {
|
||||
self.as_bytes() == other.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for CxxString {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
self.as_bytes() == other.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for CxxString {}
|
||||
|
||||
impl PartialOrd for CxxString {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
self.as_bytes().partial_cmp(other.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for CxxString {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.as_bytes().cmp(other.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for CxxString {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.as_bytes().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[repr(C)]
|
||||
pub struct StackString {
|
||||
// Static assertions in cxx.cc validate that this is large enough and
|
||||
// aligned enough.
|
||||
space: MaybeUninit<[usize; 8]>,
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
impl StackString {
|
||||
pub fn new() -> Self {
|
||||
StackString {
|
||||
space: MaybeUninit::uninit(),
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn init(&mut self, value: impl AsRef<[u8]>) -> Pin<&mut CxxString> {
|
||||
let value = value.as_ref();
|
||||
unsafe {
|
||||
let this = &mut *self.space.as_mut_ptr().cast::<MaybeUninit<CxxString>>();
|
||||
string_init(this, value.as_ptr(), value.len());
|
||||
Pin::new_unchecked(&mut *this.as_mut_ptr())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for StackString {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let this = &mut *self.space.as_mut_ptr().cast::<MaybeUninit<CxxString>>();
|
||||
string_destroy(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
492
vendor/cxx/src/cxx_vector.rs
vendored
Normal file
492
vendor/cxx/src/cxx_vector.rs
vendored
Normal file
|
|
@ -0,0 +1,492 @@
|
|||
//! Less used details of `CxxVector` are exposed in this module. `CxxVector`
|
||||
//! itself is exposed at the crate root.
|
||||
|
||||
use crate::extern_type::ExternType;
|
||||
use crate::kind::Trivial;
|
||||
use crate::string::CxxString;
|
||||
use core::ffi::c_void;
|
||||
use core::fmt::{self, Debug};
|
||||
use core::iter::FusedIterator;
|
||||
use core::marker::{PhantomData, PhantomPinned};
|
||||
use core::mem::{self, ManuallyDrop, MaybeUninit};
|
||||
use core::pin::Pin;
|
||||
use core::slice;
|
||||
|
||||
/// Binding to C++ `std::vector<T, std::allocator<T>>`.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// As an invariant of this API and the static analysis of the cxx::bridge
|
||||
/// macro, in Rust code we can never obtain a `CxxVector` by value. Instead in
|
||||
/// Rust code we will only ever look at a vector behind a reference or smart
|
||||
/// pointer, as in `&CxxVector<T>` or `UniquePtr<CxxVector<T>>`.
|
||||
#[repr(C, packed)]
|
||||
pub struct CxxVector<T> {
|
||||
// A thing, because repr(C) structs are not allowed to consist exclusively
|
||||
// of PhantomData fields.
|
||||
_void: [c_void; 0],
|
||||
// The conceptual vector elements to ensure that autotraits are propagated
|
||||
// correctly, e.g. CxxVector is UnwindSafe iff T is.
|
||||
_elements: PhantomData<[T]>,
|
||||
// Prevent unpin operation from Pin<&mut CxxVector<T>> to &mut CxxVector<T>.
|
||||
_pinned: PhantomData<PhantomPinned>,
|
||||
}
|
||||
|
||||
impl<T> CxxVector<T>
|
||||
where
|
||||
T: VectorElement,
|
||||
{
|
||||
/// Returns the number of elements in the vector.
|
||||
///
|
||||
/// Matches the behavior of C++ [std::vector\<T\>::size][size].
|
||||
///
|
||||
/// [size]: https://en.cppreference.com/w/cpp/container/vector/size
|
||||
pub fn len(&self) -> usize {
|
||||
T::__vector_size(self)
|
||||
}
|
||||
|
||||
/// Returns true if the vector contains no elements.
|
||||
///
|
||||
/// Matches the behavior of C++ [std::vector\<T\>::empty][empty].
|
||||
///
|
||||
/// [empty]: https://en.cppreference.com/w/cpp/container/vector/empty
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Returns a reference to an element at the given position, or `None` if
|
||||
/// out of bounds.
|
||||
pub fn get(&self, pos: usize) -> Option<&T> {
|
||||
if pos < self.len() {
|
||||
Some(unsafe { self.get_unchecked(pos) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a pinned mutable reference to an element at the given position,
|
||||
/// or `None` if out of bounds.
|
||||
pub fn index_mut(self: Pin<&mut Self>, pos: usize) -> Option<Pin<&mut T>> {
|
||||
if pos < self.len() {
|
||||
Some(unsafe { self.index_unchecked_mut(pos) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to an element without doing bounds checking.
|
||||
///
|
||||
/// This is generally not recommended, use with caution! Calling this method
|
||||
/// with an out-of-bounds index is undefined behavior even if the resulting
|
||||
/// reference is not used.
|
||||
///
|
||||
/// Matches the behavior of C++
|
||||
/// [std::vector\<T\>::operator\[\] const][operator_at].
|
||||
///
|
||||
/// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
|
||||
pub unsafe fn get_unchecked(&self, pos: usize) -> &T {
|
||||
let this = self as *const CxxVector<T> as *mut CxxVector<T>;
|
||||
unsafe {
|
||||
let ptr = T::__get_unchecked(this, pos) as *const T;
|
||||
&*ptr
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a pinned mutable reference to an element without doing bounds
|
||||
/// checking.
|
||||
///
|
||||
/// This is generally not recommended, use with caution! Calling this method
|
||||
/// with an out-of-bounds index is undefined behavior even if the resulting
|
||||
/// reference is not used.
|
||||
///
|
||||
/// Matches the behavior of C++
|
||||
/// [std::vector\<T\>::operator\[\]][operator_at].
|
||||
///
|
||||
/// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
|
||||
pub unsafe fn index_unchecked_mut(self: Pin<&mut Self>, pos: usize) -> Pin<&mut T> {
|
||||
unsafe {
|
||||
let ptr = T::__get_unchecked(self.get_unchecked_mut(), pos);
|
||||
Pin::new_unchecked(&mut *ptr)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a slice to the underlying contiguous array of elements.
|
||||
pub fn as_slice(&self) -> &[T]
|
||||
where
|
||||
T: ExternType<Kind = Trivial>,
|
||||
{
|
||||
let len = self.len();
|
||||
if len == 0 {
|
||||
// The slice::from_raw_parts in the other branch requires a nonnull
|
||||
// and properly aligned data ptr. C++ standard does not guarantee
|
||||
// that data() on a vector with size 0 would return a nonnull
|
||||
// pointer or sufficiently aligned pointer, so using it would be
|
||||
// undefined behavior. Create our own empty slice in Rust instead
|
||||
// which upholds the invariants.
|
||||
&[]
|
||||
} else {
|
||||
let this = self as *const CxxVector<T> as *mut CxxVector<T>;
|
||||
let ptr = unsafe { T::__get_unchecked(this, 0) };
|
||||
unsafe { slice::from_raw_parts(ptr, len) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a slice to the underlying contiguous array of elements by
|
||||
/// mutable reference.
|
||||
pub fn as_mut_slice(self: Pin<&mut Self>) -> &mut [T]
|
||||
where
|
||||
T: ExternType<Kind = Trivial>,
|
||||
{
|
||||
let len = self.len();
|
||||
if len == 0 {
|
||||
&mut []
|
||||
} else {
|
||||
let ptr = unsafe { T::__get_unchecked(self.get_unchecked_mut(), 0) };
|
||||
unsafe { slice::from_raw_parts_mut(ptr, len) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over elements of type `&T`.
|
||||
pub fn iter(&self) -> Iter<T> {
|
||||
Iter { v: self, index: 0 }
|
||||
}
|
||||
|
||||
/// Returns an iterator over elements of type `Pin<&mut T>`.
|
||||
pub fn iter_mut(self: Pin<&mut Self>) -> IterMut<T> {
|
||||
IterMut { v: self, index: 0 }
|
||||
}
|
||||
|
||||
/// Appends an element to the back of the vector.
|
||||
///
|
||||
/// Matches the behavior of C++ [std::vector\<T\>::push_back][push_back].
|
||||
///
|
||||
/// [push_back]: https://en.cppreference.com/w/cpp/container/vector/push_back
|
||||
pub fn push(self: Pin<&mut Self>, value: T)
|
||||
where
|
||||
T: ExternType<Kind = Trivial>,
|
||||
{
|
||||
let mut value = ManuallyDrop::new(value);
|
||||
unsafe {
|
||||
// C++ calls move constructor followed by destructor on `value`.
|
||||
T::__push_back(self, &mut value);
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the last element from a vector and returns it, or `None` if the
|
||||
/// vector is empty.
|
||||
pub fn pop(self: Pin<&mut Self>) -> Option<T>
|
||||
where
|
||||
T: ExternType<Kind = Trivial>,
|
||||
{
|
||||
if self.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let mut value = MaybeUninit::uninit();
|
||||
Some(unsafe {
|
||||
T::__pop_back(self, &mut value);
|
||||
value.assume_init()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator over elements of a `CxxVector` by shared reference.
|
||||
///
|
||||
/// The iterator element type is `&'a T`.
|
||||
pub struct Iter<'a, T> {
|
||||
v: &'a CxxVector<T>,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIterator for &'a CxxVector<T>
|
||||
where
|
||||
T: VectorElement,
|
||||
{
|
||||
type Item = &'a T;
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for Iter<'a, T>
|
||||
where
|
||||
T: VectorElement,
|
||||
{
|
||||
type Item = &'a T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let next = self.v.get(self.index)?;
|
||||
self.index += 1;
|
||||
Some(next)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.len();
|
||||
(len, Some(len))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> ExactSizeIterator for Iter<'a, T>
|
||||
where
|
||||
T: VectorElement,
|
||||
{
|
||||
fn len(&self) -> usize {
|
||||
self.v.len() - self.index
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> FusedIterator for Iter<'a, T> where T: VectorElement {}
|
||||
|
||||
/// Iterator over elements of a `CxxVector` by pinned mutable reference.
|
||||
///
|
||||
/// The iterator element type is `Pin<&'a mut T>`.
|
||||
pub struct IterMut<'a, T> {
|
||||
v: Pin<&'a mut CxxVector<T>>,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIterator for Pin<&'a mut CxxVector<T>>
|
||||
where
|
||||
T: VectorElement,
|
||||
{
|
||||
type Item = Pin<&'a mut T>;
|
||||
type IntoIter = IterMut<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for IterMut<'a, T>
|
||||
where
|
||||
T: VectorElement,
|
||||
{
|
||||
type Item = Pin<&'a mut T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let next = self.v.as_mut().index_mut(self.index)?;
|
||||
self.index += 1;
|
||||
// Extend lifetime to allow simultaneous holding of nonoverlapping
|
||||
// elements, analogous to slice::split_first_mut.
|
||||
unsafe {
|
||||
let ptr = Pin::into_inner_unchecked(next) as *mut T;
|
||||
Some(Pin::new_unchecked(&mut *ptr))
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.len();
|
||||
(len, Some(len))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> ExactSizeIterator for IterMut<'a, T>
|
||||
where
|
||||
T: VectorElement,
|
||||
{
|
||||
fn len(&self) -> usize {
|
||||
self.v.len() - self.index
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> FusedIterator for IterMut<'a, T> where T: VectorElement {}
|
||||
|
||||
impl<T> Debug for CxxVector<T>
|
||||
where
|
||||
T: VectorElement + Debug,
|
||||
{
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.debug_list().entries(self).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait bound for types which may be used as the `T` inside of a
|
||||
/// `CxxVector<T>` in generic code.
|
||||
///
|
||||
/// This trait has no publicly callable or implementable methods. Implementing
|
||||
/// it outside of the CXX codebase is not supported.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// A bound `T: VectorElement` may be necessary when manipulating [`CxxVector`]
|
||||
/// in generic code.
|
||||
///
|
||||
/// ```
|
||||
/// use cxx::vector::{CxxVector, VectorElement};
|
||||
/// use std::fmt::Display;
|
||||
///
|
||||
/// pub fn take_generic_vector<T>(vector: &CxxVector<T>)
|
||||
/// where
|
||||
/// T: VectorElement + Display,
|
||||
/// {
|
||||
/// println!("the vector elements are:");
|
||||
/// for element in vector {
|
||||
/// println!(" • {}", element);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Writing the same generic function without a `VectorElement` trait bound
|
||||
/// would not compile.
|
||||
pub unsafe trait VectorElement: Sized {
|
||||
#[doc(hidden)]
|
||||
fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
|
||||
#[doc(hidden)]
|
||||
fn __vector_size(v: &CxxVector<Self>) -> usize;
|
||||
#[doc(hidden)]
|
||||
unsafe fn __get_unchecked(v: *mut CxxVector<Self>, pos: usize) -> *mut Self;
|
||||
#[doc(hidden)]
|
||||
unsafe fn __push_back(v: Pin<&mut CxxVector<Self>>, value: &mut ManuallyDrop<Self>) {
|
||||
// Opaque C type vector elements do not get this method because they can
|
||||
// never exist by value on the Rust side of the bridge.
|
||||
let _ = v;
|
||||
let _ = value;
|
||||
unreachable!()
|
||||
}
|
||||
#[doc(hidden)]
|
||||
unsafe fn __pop_back(v: Pin<&mut CxxVector<Self>>, out: &mut MaybeUninit<Self>) {
|
||||
// Opaque C type vector elements do not get this method because they can
|
||||
// never exist by value on the Rust side of the bridge.
|
||||
let _ = v;
|
||||
let _ = out;
|
||||
unreachable!()
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn __unique_ptr_null() -> MaybeUninit<*mut c_void>;
|
||||
#[doc(hidden)]
|
||||
unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> MaybeUninit<*mut c_void>;
|
||||
#[doc(hidden)]
|
||||
unsafe fn __unique_ptr_get(repr: MaybeUninit<*mut c_void>) -> *const CxxVector<Self>;
|
||||
#[doc(hidden)]
|
||||
unsafe fn __unique_ptr_release(repr: MaybeUninit<*mut c_void>) -> *mut CxxVector<Self>;
|
||||
#[doc(hidden)]
|
||||
unsafe fn __unique_ptr_drop(repr: MaybeUninit<*mut c_void>);
|
||||
}
|
||||
|
||||
macro_rules! vector_element_by_value_methods {
|
||||
(opaque, $segment:expr, $ty:ty) => {};
|
||||
(trivial, $segment:expr, $ty:ty) => {
|
||||
unsafe fn __push_back(v: Pin<&mut CxxVector<$ty>>, value: &mut ManuallyDrop<$ty>) {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$std$vector$", $segment, "$push_back")]
|
||||
fn __push_back(_: Pin<&mut CxxVector<$ty>>, _: &mut ManuallyDrop<$ty>);
|
||||
}
|
||||
}
|
||||
unsafe { __push_back(v, value) }
|
||||
}
|
||||
unsafe fn __pop_back(v: Pin<&mut CxxVector<$ty>>, out: &mut MaybeUninit<$ty>) {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$std$vector$", $segment, "$pop_back")]
|
||||
fn __pop_back(_: Pin<&mut CxxVector<$ty>>, _: &mut MaybeUninit<$ty>);
|
||||
}
|
||||
}
|
||||
unsafe { __pop_back(v, out) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_vector_element {
|
||||
($kind:ident, $segment:expr, $name:expr, $ty:ty) => {
|
||||
const_assert_eq!(0, mem::size_of::<CxxVector<$ty>>());
|
||||
const_assert_eq!(1, mem::align_of::<CxxVector<$ty>>());
|
||||
|
||||
unsafe impl VectorElement for $ty {
|
||||
fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str($name)
|
||||
}
|
||||
fn __vector_size(v: &CxxVector<$ty>) -> usize {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$std$vector$", $segment, "$size")]
|
||||
fn __vector_size(_: &CxxVector<$ty>) -> usize;
|
||||
}
|
||||
}
|
||||
unsafe { __vector_size(v) }
|
||||
}
|
||||
unsafe fn __get_unchecked(v: *mut CxxVector<$ty>, pos: usize) -> *mut $ty {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$std$vector$", $segment, "$get_unchecked")]
|
||||
fn __get_unchecked(_: *mut CxxVector<$ty>, _: usize) -> *mut $ty;
|
||||
}
|
||||
}
|
||||
unsafe { __get_unchecked(v, pos) }
|
||||
}
|
||||
vector_element_by_value_methods!($kind, $segment, $ty);
|
||||
fn __unique_ptr_null() -> MaybeUninit<*mut c_void> {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$null")]
|
||||
fn __unique_ptr_null(this: *mut MaybeUninit<*mut c_void>);
|
||||
}
|
||||
}
|
||||
let mut repr = MaybeUninit::uninit();
|
||||
unsafe { __unique_ptr_null(&mut repr) }
|
||||
repr
|
||||
}
|
||||
unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> MaybeUninit<*mut c_void> {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$raw")]
|
||||
fn __unique_ptr_raw(this: *mut MaybeUninit<*mut c_void>, raw: *mut CxxVector<$ty>);
|
||||
}
|
||||
}
|
||||
let mut repr = MaybeUninit::uninit();
|
||||
unsafe { __unique_ptr_raw(&mut repr, raw) }
|
||||
repr
|
||||
}
|
||||
unsafe fn __unique_ptr_get(repr: MaybeUninit<*mut c_void>) -> *const CxxVector<Self> {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$get")]
|
||||
fn __unique_ptr_get(this: *const MaybeUninit<*mut c_void>) -> *const CxxVector<$ty>;
|
||||
}
|
||||
}
|
||||
unsafe { __unique_ptr_get(&repr) }
|
||||
}
|
||||
unsafe fn __unique_ptr_release(mut repr: MaybeUninit<*mut c_void>) -> *mut CxxVector<Self> {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$release")]
|
||||
fn __unique_ptr_release(this: *mut MaybeUninit<*mut c_void>) -> *mut CxxVector<$ty>;
|
||||
}
|
||||
}
|
||||
unsafe { __unique_ptr_release(&mut repr) }
|
||||
}
|
||||
unsafe fn __unique_ptr_drop(mut repr: MaybeUninit<*mut c_void>) {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$drop")]
|
||||
fn __unique_ptr_drop(this: *mut MaybeUninit<*mut c_void>);
|
||||
}
|
||||
}
|
||||
unsafe { __unique_ptr_drop(&mut repr) }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_vector_element_for_primitive {
|
||||
($ty:ident) => {
|
||||
impl_vector_element!(trivial, stringify!($ty), stringify!($ty), $ty);
|
||||
};
|
||||
}
|
||||
|
||||
impl_vector_element_for_primitive!(u8);
|
||||
impl_vector_element_for_primitive!(u16);
|
||||
impl_vector_element_for_primitive!(u32);
|
||||
impl_vector_element_for_primitive!(u64);
|
||||
impl_vector_element_for_primitive!(usize);
|
||||
impl_vector_element_for_primitive!(i8);
|
||||
impl_vector_element_for_primitive!(i16);
|
||||
impl_vector_element_for_primitive!(i32);
|
||||
impl_vector_element_for_primitive!(i64);
|
||||
impl_vector_element_for_primitive!(isize);
|
||||
impl_vector_element_for_primitive!(f32);
|
||||
impl_vector_element_for_primitive!(f64);
|
||||
|
||||
impl_vector_element!(opaque, "string", "CxxString", CxxString);
|
||||
28
vendor/cxx/src/exception.rs
vendored
Normal file
28
vendor/cxx/src/exception.rs
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#![cfg(feature = "alloc")]
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use core::fmt::{self, Display};
|
||||
|
||||
/// Exception thrown from an `extern "C++"` function.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
|
||||
#[derive(Debug)]
|
||||
pub struct Exception {
|
||||
pub(crate) what: Box<str>,
|
||||
}
|
||||
|
||||
impl Display for Exception {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(&self.what)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
|
||||
impl std::error::Error for Exception {}
|
||||
|
||||
impl Exception {
|
||||
#[allow(missing_docs)]
|
||||
pub fn what(&self) -> &str {
|
||||
&self.what
|
||||
}
|
||||
}
|
||||
225
vendor/cxx/src/extern_type.rs
vendored
Normal file
225
vendor/cxx/src/extern_type.rs
vendored
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
use self::kind::{Kind, Opaque, Trivial};
|
||||
use crate::CxxString;
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::string::String;
|
||||
|
||||
/// A type for which the layout is determined by its C++ definition.
|
||||
///
|
||||
/// This trait serves the following two related purposes.
|
||||
///
|
||||
/// <br>
|
||||
///
|
||||
/// ## Safely unifying occurrences of the same extern type
|
||||
///
|
||||
/// `ExternType` makes it possible for CXX to safely share a consistent Rust
|
||||
/// type across multiple #\[cxx::bridge\] invocations that refer to a common
|
||||
/// extern C++ type.
|
||||
///
|
||||
/// In the following snippet, two #\[cxx::bridge\] invocations in different
|
||||
/// files (possibly different crates) both contain function signatures involving
|
||||
/// the same C++ type `example::Demo`. If both were written just containing
|
||||
/// `type Demo;`, then both macro expansions would produce their own separate
|
||||
/// Rust type called `Demo` and thus the compiler wouldn't allow us to take the
|
||||
/// `Demo` returned by `file1::ffi::create_demo` and pass it as the `Demo`
|
||||
/// argument accepted by `file2::ffi::take_ref_demo`. Instead, one of the two
|
||||
/// `Demo`s has been defined as an extern type alias of the other, making them
|
||||
/// the same type in Rust. The CXX code generator will use an automatically
|
||||
/// generated `ExternType` impl emitted in file1 to statically verify that in
|
||||
/// file2 `crate::file1::ffi::Demo` really does refer to the C++ type
|
||||
/// `example::Demo` as expected in file2.
|
||||
///
|
||||
/// ```no_run
|
||||
/// // file1.rs
|
||||
/// # mod file1 {
|
||||
/// #[cxx::bridge(namespace = "example")]
|
||||
/// pub mod ffi {
|
||||
/// unsafe extern "C++" {
|
||||
/// type Demo;
|
||||
///
|
||||
/// fn create_demo() -> UniquePtr<Demo>;
|
||||
/// }
|
||||
/// }
|
||||
/// # }
|
||||
///
|
||||
/// // file2.rs
|
||||
/// #[cxx::bridge(namespace = "example")]
|
||||
/// pub mod ffi {
|
||||
/// unsafe extern "C++" {
|
||||
/// type Demo = crate::file1::ffi::Demo;
|
||||
///
|
||||
/// fn take_ref_demo(demo: &Demo);
|
||||
/// }
|
||||
/// }
|
||||
/// #
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// <br><br>
|
||||
///
|
||||
/// ## Integrating with bindgen-generated types
|
||||
///
|
||||
/// Handwritten `ExternType` impls make it possible to plug in a data structure
|
||||
/// emitted by bindgen as the definition of a C++ type emitted by CXX.
|
||||
///
|
||||
/// By writing the unsafe `ExternType` impl, the programmer asserts that the C++
|
||||
/// namespace and type name given in the type id refers to a C++ type that is
|
||||
/// equivalent to Rust type that is the `Self` type of the impl.
|
||||
///
|
||||
/// ```no_run
|
||||
/// # const _: &str = stringify! {
|
||||
/// mod folly_sys; // the bindgen-generated bindings
|
||||
/// # };
|
||||
/// # mod folly_sys {
|
||||
/// # #[repr(transparent)]
|
||||
/// # pub struct StringPiece([usize; 2]);
|
||||
/// # }
|
||||
///
|
||||
/// use cxx::{type_id, ExternType};
|
||||
///
|
||||
/// unsafe impl ExternType for folly_sys::StringPiece {
|
||||
/// type Id = type_id!("folly::StringPiece");
|
||||
/// type Kind = cxx::kind::Opaque;
|
||||
/// }
|
||||
///
|
||||
/// #[cxx::bridge(namespace = "folly")]
|
||||
/// pub mod ffi {
|
||||
/// unsafe extern "C++" {
|
||||
/// include!("rust_cxx_bindings.h");
|
||||
///
|
||||
/// type StringPiece = crate::folly_sys::StringPiece;
|
||||
///
|
||||
/// fn print_string_piece(s: &StringPiece);
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Now if we construct a StringPiece or obtain one through one
|
||||
/// // of the bindgen-generated signatures, we are able to pass it
|
||||
/// // along to ffi::print_string_piece.
|
||||
/// #
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
pub unsafe trait ExternType {
|
||||
/// A type-level representation of the type's C++ namespace and type name.
|
||||
///
|
||||
/// This will always be defined using `type_id!` in the following form:
|
||||
///
|
||||
/// ```
|
||||
/// # struct TypeName;
|
||||
/// # unsafe impl cxx::ExternType for TypeName {
|
||||
/// type Id = cxx::type_id!("name::space::of::TypeName");
|
||||
/// # type Kind = cxx::kind::Opaque;
|
||||
/// # }
|
||||
/// ```
|
||||
type Id;
|
||||
|
||||
/// Either [`cxx::kind::Opaque`] or [`cxx::kind::Trivial`].
|
||||
///
|
||||
/// [`cxx::kind::Opaque`]: kind::Opaque
|
||||
/// [`cxx::kind::Trivial`]: kind::Trivial
|
||||
///
|
||||
/// A C++ type is only okay to hold and pass around by value in Rust if its
|
||||
/// [move constructor is trivial] and it has no destructor. In CXX, these
|
||||
/// are called Trivial extern C++ types, while types with nontrivial move
|
||||
/// behavior or a destructor must be considered Opaque and handled by Rust
|
||||
/// only behind an indirection, such as a reference or UniquePtr.
|
||||
///
|
||||
/// [move constructor is trivial]: https://en.cppreference.com/w/cpp/types/is_move_constructible
|
||||
///
|
||||
/// If you believe your C++ type reflected by this ExternType impl is indeed
|
||||
/// fine to hold by value and move in Rust, you can specify:
|
||||
///
|
||||
/// ```
|
||||
/// # struct TypeName;
|
||||
/// # unsafe impl cxx::ExternType for TypeName {
|
||||
/// # type Id = cxx::type_id!("name::space::of::TypeName");
|
||||
/// type Kind = cxx::kind::Trivial;
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// which will enable you to pass it into C++ functions by value, return it
|
||||
/// by value, and include it in `struct`s that you have declared to
|
||||
/// `cxx::bridge`. Your claim about the triviality of the C++ type will be
|
||||
/// checked by a `static_assert` in the generated C++ side of the binding.
|
||||
type Kind: Kind;
|
||||
}
|
||||
|
||||
/// Marker types identifying Rust's knowledge about an extern C++ type.
|
||||
///
|
||||
/// These markers are used in the [`Kind`][ExternType::Kind] associated type in
|
||||
/// impls of the `ExternType` trait. Refer to the documentation of `Kind` for an
|
||||
/// overview of their purpose.
|
||||
pub mod kind {
|
||||
use super::private;
|
||||
|
||||
/// An opaque type which cannot be passed or held by value within Rust.
|
||||
///
|
||||
/// Rust's move semantics are such that every move is equivalent to a
|
||||
/// memcpy. This is incompatible in general with C++'s constructor-based
|
||||
/// move semantics, so a C++ type which has a destructor or nontrivial move
|
||||
/// constructor must never exist by value in Rust. In CXX, such types are
|
||||
/// called opaque C++ types.
|
||||
///
|
||||
/// When passed across an FFI boundary, an opaque C++ type must be behind an
|
||||
/// indirection such as a reference or UniquePtr.
|
||||
pub enum Opaque {}
|
||||
|
||||
/// A type with trivial move constructor and no destructor, which can
|
||||
/// therefore be owned and moved around in Rust code without requiring
|
||||
/// indirection.
|
||||
pub enum Trivial {}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub trait Kind: private::Sealed {}
|
||||
impl Kind for Opaque {}
|
||||
impl Kind for Trivial {}
|
||||
}
|
||||
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
impl Sealed for super::Opaque {}
|
||||
impl Sealed for super::Trivial {}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn verify_extern_type<T: ExternType<Id = Id>, Id>() {}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn verify_extern_kind<T: ExternType<Kind = Kind>, Kind: self::Kind>() {}
|
||||
|
||||
macro_rules! impl_extern_type {
|
||||
($([$kind:ident] $($(#[$($attr:tt)*])* $ty:path = $cxxpath:literal)*)*) => {
|
||||
$($(
|
||||
$(#[$($attr)*])*
|
||||
unsafe impl ExternType for $ty {
|
||||
#[allow(unused_attributes)] // incorrect lint; this doc(hidden) attr *is* respected by rustdoc
|
||||
#[doc(hidden)]
|
||||
type Id = crate::type_id!($cxxpath);
|
||||
type Kind = $kind;
|
||||
}
|
||||
)*)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_extern_type! {
|
||||
[Trivial]
|
||||
bool = "bool"
|
||||
u8 = "std::uint8_t"
|
||||
u16 = "std::uint16_t"
|
||||
u32 = "std::uint32_t"
|
||||
u64 = "std::uint64_t"
|
||||
usize = "size_t"
|
||||
i8 = "std::int8_t"
|
||||
i16 = "std::int16_t"
|
||||
i32 = "std::int32_t"
|
||||
i64 = "std::int64_t"
|
||||
isize = "rust::isize"
|
||||
f32 = "float"
|
||||
f64 = "double"
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
|
||||
String = "rust::String"
|
||||
|
||||
[Opaque]
|
||||
CxxString = "std::string"
|
||||
}
|
||||
16
vendor/cxx/src/fmt.rs
vendored
Normal file
16
vendor/cxx/src/fmt.rs
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
use core::fmt::{self, Display};
|
||||
|
||||
pub(crate) fn display(fmt: impl Fn(&mut fmt::Formatter) -> fmt::Result) -> impl Display {
|
||||
DisplayInvoke(fmt)
|
||||
}
|
||||
|
||||
struct DisplayInvoke<T>(T);
|
||||
|
||||
impl<T> Display for DisplayInvoke<T>
|
||||
where
|
||||
T: Fn(&mut fmt::Formatter) -> fmt::Result,
|
||||
{
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
(self.0)(formatter)
|
||||
}
|
||||
}
|
||||
9
vendor/cxx/src/function.rs
vendored
Normal file
9
vendor/cxx/src/function.rs
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use core::ffi::c_void;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct FatFunction {
|
||||
pub trampoline: *const c_void,
|
||||
pub ptr: *const c_void,
|
||||
}
|
||||
12
vendor/cxx/src/hash.rs
vendored
Normal file
12
vendor/cxx/src/hash.rs
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
use core::hash::{Hash, Hasher};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn hash<V: Hash>(value: &V) -> usize {
|
||||
#[cfg(feature = "std")]
|
||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||
#[cfg(not(feature = "std"))]
|
||||
let mut hasher = crate::sip::SipHasher13::new();
|
||||
|
||||
Hash::hash(value, &mut hasher);
|
||||
Hasher::finish(&hasher) as usize
|
||||
}
|
||||
538
vendor/cxx/src/lib.rs
vendored
Normal file
538
vendor/cxx/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,538 @@
|
|||
//! [![github]](https://github.com/dtolnay/cxx) [![crates-io]](https://crates.io/crates/cxx) [![docs-rs]](https://docs.rs/cxx)
|
||||
//!
|
||||
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
|
||||
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
|
||||
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! This library provides a **safe** mechanism for calling C++ code from Rust
|
||||
//! and Rust code from C++, not subject to the many ways that things can go
|
||||
//! wrong when using bindgen or cbindgen to generate unsafe C-style bindings.
|
||||
//!
|
||||
//! This doesn't change the fact that 100% of C++ code is unsafe. When auditing
|
||||
//! a project, you would be on the hook for auditing all the unsafe Rust code
|
||||
//! and *all* the C++ code. The core safety claim under this new model is that
|
||||
//! auditing just the C++ side would be sufficient to catch all problems, i.e.
|
||||
//! the Rust side can be 100% safe.
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! *Compiler support: requires rustc 1.48+ and c++11 or newer*<br>
|
||||
//! *[Release notes](https://github.com/dtolnay/cxx/releases)*
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! # Guide
|
||||
//!
|
||||
//! Please see **<https://cxx.rs>** for a tutorial, reference material, and
|
||||
//! example code.
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! # Overview
|
||||
//!
|
||||
//! The idea is that we define the signatures of both sides of our FFI boundary
|
||||
//! embedded together in one Rust module (the next section shows an example).
|
||||
//! From this, CXX receives a complete picture of the boundary to perform static
|
||||
//! analyses against the types and function signatures to uphold both Rust's and
|
||||
//! C++'s invariants and requirements.
|
||||
//!
|
||||
//! If everything checks out statically, then CXX uses a pair of code generators
|
||||
//! to emit the relevant `extern "C"` signatures on both sides together with any
|
||||
//! necessary static assertions for later in the build process to verify
|
||||
//! correctness. On the Rust side this code generator is simply an attribute
|
||||
//! procedural macro. On the C++ side it can be a small Cargo build script if
|
||||
//! your build is managed by Cargo, or for other build systems like Bazel or
|
||||
//! Buck we provide a command line tool which generates the header and source
|
||||
//! file and should be easy to integrate.
|
||||
//!
|
||||
//! The resulting FFI bridge operates at zero or negligible overhead, i.e. no
|
||||
//! copying, no serialization, no memory allocation, no runtime checks needed.
|
||||
//!
|
||||
//! The FFI signatures are able to use native types from whichever side they
|
||||
//! please, such as Rust's `String` or C++'s `std::string`, Rust's `Box` or
|
||||
//! C++'s `std::unique_ptr`, Rust's `Vec` or C++'s `std::vector`, etc in any
|
||||
//! combination. CXX guarantees an ABI-compatible signature that both sides
|
||||
//! understand, based on builtin bindings for key standard library types to
|
||||
//! expose an idiomatic API on those types to the other language. For example
|
||||
//! when manipulating a C++ string from Rust, its `len()` method becomes a call
|
||||
//! of the `size()` member function defined by C++; when manipulation a Rust
|
||||
//! string from C++, its `size()` member function calls Rust's `len()`.
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! In this example we are writing a Rust application that wishes to take
|
||||
//! advantage of an existing C++ client for a large-file blobstore service. The
|
||||
//! blobstore supports a `put` operation for a discontiguous buffer upload. For
|
||||
//! example we might be uploading snapshots of a circular buffer which would
|
||||
//! tend to consist of 2 chunks, or fragments of a file spread across memory for
|
||||
//! some other reason.
|
||||
//!
|
||||
//! A runnable version of this example is provided under the *demo* directory of
|
||||
//! <https://github.com/dtolnay/cxx>. To try it out, run `cargo run` from that
|
||||
//! directory.
|
||||
//!
|
||||
//! ```no_run
|
||||
//! #[cxx::bridge]
|
||||
//! mod ffi {
|
||||
//! // Any shared structs, whose fields will be visible to both languages.
|
||||
//! struct BlobMetadata {
|
||||
//! size: usize,
|
||||
//! tags: Vec<String>,
|
||||
//! }
|
||||
//!
|
||||
//! extern "Rust" {
|
||||
//! // Zero or more opaque types which both languages can pass around but
|
||||
//! // only Rust can see the fields.
|
||||
//! type MultiBuf;
|
||||
//!
|
||||
//! // Functions implemented in Rust.
|
||||
//! fn next_chunk(buf: &mut MultiBuf) -> &[u8];
|
||||
//! }
|
||||
//!
|
||||
//! unsafe extern "C++" {
|
||||
//! // One or more headers with the matching C++ declarations. Our code
|
||||
//! // generators don't read it but it gets #include'd and used in static
|
||||
//! // assertions to ensure our picture of the FFI boundary is accurate.
|
||||
//! include!("demo/include/blobstore.h");
|
||||
//!
|
||||
//! // Zero or more opaque types which both languages can pass around but
|
||||
//! // only C++ can see the fields.
|
||||
//! type BlobstoreClient;
|
||||
//!
|
||||
//! // Functions implemented in C++.
|
||||
//! fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
|
||||
//! fn put(&self, parts: &mut MultiBuf) -> u64;
|
||||
//! fn tag(&self, blobid: u64, tag: &str);
|
||||
//! fn metadata(&self, blobid: u64) -> BlobMetadata;
|
||||
//! }
|
||||
//! }
|
||||
//! #
|
||||
//! # pub struct MultiBuf;
|
||||
//! #
|
||||
//! # fn next_chunk(_buf: &mut MultiBuf) -> &[u8] {
|
||||
//! # unimplemented!()
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
//!
|
||||
//! Now we simply provide Rust definitions of all the things in the `extern
|
||||
//! "Rust"` block and C++ definitions of all the things in the `extern "C++"`
|
||||
//! block, and get to call back and forth safely.
|
||||
//!
|
||||
//! Here are links to the complete set of source files involved in the demo:
|
||||
//!
|
||||
//! - [demo/src/main.rs](https://github.com/dtolnay/cxx/blob/master/demo/src/main.rs)
|
||||
//! - [demo/build.rs](https://github.com/dtolnay/cxx/blob/master/demo/build.rs)
|
||||
//! - [demo/include/blobstore.h](https://github.com/dtolnay/cxx/blob/master/demo/include/blobstore.h)
|
||||
//! - [demo/src/blobstore.cc](https://github.com/dtolnay/cxx/blob/master/demo/src/blobstore.cc)
|
||||
//!
|
||||
//! To look at the code generated in both languages for the example by the CXX
|
||||
//! code generators:
|
||||
//!
|
||||
//! ```console
|
||||
//! # run Rust code generator and print to stdout
|
||||
//! # (requires https://github.com/dtolnay/cargo-expand)
|
||||
//! $ cargo expand --manifest-path demo/Cargo.toml
|
||||
//!
|
||||
//! # run C++ code generator and print to stdout
|
||||
//! $ cargo run --manifest-path gen/cmd/Cargo.toml -- demo/src/main.rs
|
||||
//! ```
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! # Details
|
||||
//!
|
||||
//! As seen in the example, the language of the FFI boundary involves 3 kinds of
|
||||
//! items:
|
||||
//!
|
||||
//! - **Shared structs** — their fields are made visible to both
|
||||
//! languages. The definition written within cxx::bridge is the single source
|
||||
//! of truth.
|
||||
//!
|
||||
//! - **Opaque types** — their fields are secret from the other language.
|
||||
//! These cannot be passed across the FFI by value but only behind an
|
||||
//! indirection, such as a reference `&`, a Rust `Box`, or a `UniquePtr`. Can
|
||||
//! be a type alias for an arbitrarily complicated generic language-specific
|
||||
//! type depending on your use case.
|
||||
//!
|
||||
//! - **Functions** — implemented in either language, callable from the
|
||||
//! other language.
|
||||
//!
|
||||
//! Within the `extern "Rust"` part of the CXX bridge we list the types and
|
||||
//! functions for which Rust is the source of truth. These all implicitly refer
|
||||
//! to the `super` module, the parent module of the CXX bridge. You can think of
|
||||
//! the two items listed in the example above as being like `use
|
||||
//! super::MultiBuf` and `use super::next_chunk` except re-exported to C++. The
|
||||
//! parent module will either contain the definitions directly for simple
|
||||
//! things, or contain the relevant `use` statements to bring them into scope
|
||||
//! from elsewhere.
|
||||
//!
|
||||
//! Within the `extern "C++"` part, we list types and functions for which C++ is
|
||||
//! the source of truth, as well as the header(s) that declare those APIs. In
|
||||
//! the future it's possible that this section could be generated bindgen-style
|
||||
//! from the headers but for now we need the signatures written out; static
|
||||
//! assertions will verify that they are accurate.
|
||||
//!
|
||||
//! Your function implementations themselves, whether in C++ or Rust, *do not*
|
||||
//! need to be defined as `extern "C"` ABI or no\_mangle. CXX will put in the
|
||||
//! right shims where necessary to make it all work.
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! # Comparison vs bindgen and cbindgen
|
||||
//!
|
||||
//! Notice that with CXX there is repetition of all the function signatures:
|
||||
//! they are typed out once where the implementation is defined (in C++ or Rust)
|
||||
//! and again inside the cxx::bridge module, though compile-time assertions
|
||||
//! guarantee these are kept in sync. This is different from [bindgen] and
|
||||
//! [cbindgen] where function signatures are typed by a human once and the tool
|
||||
//! consumes them in one language and emits them in the other language.
|
||||
//!
|
||||
//! [bindgen]: https://github.com/rust-lang/rust-bindgen
|
||||
//! [cbindgen]: https://github.com/eqrion/cbindgen/
|
||||
//!
|
||||
//! This is because CXX fills a somewhat different role. It is a lower level
|
||||
//! tool than bindgen or cbindgen in a sense; you can think of it as being a
|
||||
//! replacement for the concept of `extern "C"` signatures as we know them,
|
||||
//! rather than a replacement for a bindgen. It would be reasonable to build a
|
||||
//! higher level bindgen-like tool on top of CXX which consumes a C++ header
|
||||
//! and/or Rust module (and/or IDL like Thrift) as source of truth and generates
|
||||
//! the cxx::bridge, eliminating the repetition while leveraging the static
|
||||
//! analysis safety guarantees of CXX.
|
||||
//!
|
||||
//! But note in other ways CXX is higher level than the bindgens, with rich
|
||||
//! support for common standard library types. Frequently with bindgen when we
|
||||
//! are dealing with an idiomatic C++ API we would end up manually wrapping that
|
||||
//! API in C-style raw pointer functions, applying bindgen to get unsafe raw
|
||||
//! pointer Rust functions, and replicating the API again to expose those
|
||||
//! idiomatically in Rust. That's a much worse form of repetition because it is
|
||||
//! unsafe all the way through.
|
||||
//!
|
||||
//! By using a CXX bridge as the shared understanding between the languages,
|
||||
//! rather than `extern "C"` C-style signatures as the shared understanding,
|
||||
//! common FFI use cases become expressible using 100% safe code.
|
||||
//!
|
||||
//! It would also be reasonable to mix and match, using CXX bridge for the 95%
|
||||
//! of your FFI that is straightforward and doing the remaining few oddball
|
||||
//! signatures the old fashioned way with bindgen and cbindgen, if for some
|
||||
//! reason CXX's static restrictions get in the way. Please file an issue if you
|
||||
//! end up taking this approach so that we know what ways it would be worthwhile
|
||||
//! to make the tool more expressive.
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! # Cargo-based setup
|
||||
//!
|
||||
//! For builds that are orchestrated by Cargo, you will use a build script that
|
||||
//! runs CXX's C++ code generator and compiles the resulting C++ code along with
|
||||
//! any other C++ code for your crate.
|
||||
//!
|
||||
//! The canonical build script is as follows. The indicated line returns a
|
||||
//! [`cc::Build`] instance (from the usual widely used `cc` crate) on which you
|
||||
//! can set up any additional source files and compiler flags as normal.
|
||||
//!
|
||||
//! [`cc::Build`]: https://docs.rs/cc/1.0/cc/struct.Build.html
|
||||
//!
|
||||
//! ```toml
|
||||
//! # Cargo.toml
|
||||
//!
|
||||
//! [build-dependencies]
|
||||
//! cxx-build = "1.0"
|
||||
//! ```
|
||||
//!
|
||||
//! ```no_run
|
||||
//! // build.rs
|
||||
//!
|
||||
//! fn main() {
|
||||
//! cxx_build::bridge("src/main.rs") // returns a cc::Build
|
||||
//! .file("src/demo.cc")
|
||||
//! .flag_if_supported("-std=c++11")
|
||||
//! .compile("cxxbridge-demo");
|
||||
//!
|
||||
//! println!("cargo:rerun-if-changed=src/main.rs");
|
||||
//! println!("cargo:rerun-if-changed=src/demo.cc");
|
||||
//! println!("cargo:rerun-if-changed=include/demo.h");
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! <br><br>
|
||||
//!
|
||||
//! # Non-Cargo setup
|
||||
//!
|
||||
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an alternate
|
||||
//! way of invoking the C++ code generator as a standalone command line tool.
|
||||
//! The tool is packaged as the `cxxbridge-cmd` crate on crates.io or can be
|
||||
//! built from the *gen/cmd* directory of <https://github.com/dtolnay/cxx>.
|
||||
//!
|
||||
//! ```bash
|
||||
//! $ cargo install cxxbridge-cmd
|
||||
//!
|
||||
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
|
||||
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
|
||||
//! ```
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! # Safety
|
||||
//!
|
||||
//! Be aware that the design of this library is intentionally restrictive and
|
||||
//! opinionated! It isn't a goal to be powerful enough to handle arbitrary
|
||||
//! signatures in either language. Instead this project is about carving out a
|
||||
//! reasonably expressive set of functionality about which we can make useful
|
||||
//! safety guarantees today and maybe extend over time. You may find that it
|
||||
//! takes some practice to use CXX bridge effectively as it won't work in all
|
||||
//! the ways that you are used to.
|
||||
//!
|
||||
//! Some of the considerations that go into ensuring safety are:
|
||||
//!
|
||||
//! - By design, our paired code generators work together to control both sides
|
||||
//! of the FFI boundary. Ordinarily in Rust writing your own `extern "C"`
|
||||
//! blocks is unsafe because the Rust compiler has no way to know whether the
|
||||
//! signatures you've written actually match the signatures implemented in the
|
||||
//! other language. With CXX we achieve that visibility and know what's on the
|
||||
//! other side.
|
||||
//!
|
||||
//! - Our static analysis detects and prevents passing types by value that
|
||||
//! shouldn't be passed by value from C++ to Rust, for example because they
|
||||
//! may contain internal pointers that would be screwed up by Rust's move
|
||||
//! behavior.
|
||||
//!
|
||||
//! - To many people's surprise, it is possible to have a struct in Rust and a
|
||||
//! struct in C++ with exactly the same layout / fields / alignment /
|
||||
//! everything, and still not the same ABI when passed by value. This is a
|
||||
//! longstanding bindgen bug that leads to segfaults in absolutely
|
||||
//! correct-looking code ([rust-lang/rust-bindgen#778]). CXX knows about this
|
||||
//! and can insert the necessary zero-cost workaround transparently where
|
||||
//! needed, so go ahead and pass your structs by value without worries. This
|
||||
//! is made possible by owning both sides of the boundary rather than just
|
||||
//! one.
|
||||
//!
|
||||
//! - Template instantiations: for example in order to expose a UniquePtr\<T\>
|
||||
//! type in Rust backed by a real C++ unique\_ptr, we have a way of using a
|
||||
//! Rust trait to connect the behavior back to the template instantiations
|
||||
//! performed by the other language.
|
||||
//!
|
||||
//! [rust-lang/rust-bindgen#778]: https://github.com/rust-lang/rust-bindgen/issues/778
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! # Builtin types
|
||||
//!
|
||||
//! In addition to all the primitive types (i32 <=> int32_t), the
|
||||
//! following common types may be used in the fields of shared structs and the
|
||||
//! arguments and returns of functions.
|
||||
//!
|
||||
//! <table>
|
||||
//! <tr><th>name in Rust</th><th>name in C++</th><th>restrictions</th></tr>
|
||||
//! <tr><td>String</td><td>rust::String</td><td></td></tr>
|
||||
//! <tr><td>&str</td><td>rust::Str</td><td></td></tr>
|
||||
//! <tr><td>&[T]</td><td>rust::Slice<const T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
//! <tr><td>&mut [T]</td><td>rust::Slice<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
//! <tr><td><a href="struct.CxxString.html">CxxString</a></td><td>std::string</td><td><sup><i>cannot be passed by value</i></sup></td></tr>
|
||||
//! <tr><td>Box<T></td><td>rust::Box<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
//! <tr><td><a href="struct.UniquePtr.html">UniquePtr<T></a></td><td>std::unique_ptr<T></td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr>
|
||||
//! <tr><td><a href="struct.SharedPtr.html">SharedPtr<T></a></td><td>std::shared_ptr<T></td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr>
|
||||
//! <tr><td>[T; N]</td><td>std::array<T, N></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
//! <tr><td>Vec<T></td><td>rust::Vec<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
|
||||
//! <tr><td><a href="struct.CxxVector.html">CxxVector<T></a></td><td>std::vector<T></td><td><sup><i>cannot be passed by value, cannot hold opaque Rust type</i></sup></td></tr>
|
||||
//! <tr><td>*mut T, *const T</td><td>T*, const T*</td><td><sup><i>fn with a raw pointer argument must be declared unsafe to call</i></sup></td></tr>
|
||||
//! <tr><td>fn(T, U) -> V</td><td>rust::Fn<V(T, U)></td><td><sup><i>only passing from Rust to C++ is implemented so far</i></sup></td></tr>
|
||||
//! <tr><td>Result<T></td><td>throw/catch</td><td><sup><i>allowed as return type only</i></sup></td></tr>
|
||||
//! </table>
|
||||
//!
|
||||
//! The C++ API of the `rust` namespace is defined by the *include/cxx.h* file
|
||||
//! in <https://github.com/dtolnay/cxx>. You will need to include this header in
|
||||
//! your C++ code when working with those types.
|
||||
//!
|
||||
//! The following types are intended to be supported "soon" but are just not
|
||||
//! implemented yet. I don't expect any of these to be hard to make work but
|
||||
//! it's a matter of designing a nice API for each in its non-native language.
|
||||
//!
|
||||
//! <table>
|
||||
//! <tr><th>name in Rust</th><th>name in C++</th></tr>
|
||||
//! <tr><td>BTreeMap<K, V></td><td><sup><i>tbd</i></sup></td></tr>
|
||||
//! <tr><td>HashMap<K, V></td><td><sup><i>tbd</i></sup></td></tr>
|
||||
//! <tr><td>Arc<T></td><td><sup><i>tbd</i></sup></td></tr>
|
||||
//! <tr><td>Option<T></td><td><sup><i>tbd</i></sup></td></tr>
|
||||
//! <tr><td><sup><i>tbd</i></sup></td><td>std::map<K, V></td></tr>
|
||||
//! <tr><td><sup><i>tbd</i></sup></td><td>std::unordered_map<K, V></td></tr>
|
||||
//! </table>
|
||||
|
||||
#![no_std]
|
||||
#![doc(html_root_url = "https://docs.rs/cxx/1.0.85")]
|
||||
#![deny(improper_ctypes, improper_ctypes_definitions, missing_docs)]
|
||||
#![cfg_attr(not(no_unsafe_op_in_unsafe_fn_lint), deny(unsafe_op_in_unsafe_fn))]
|
||||
#![cfg_attr(no_unsafe_op_in_unsafe_fn_lint, allow(unused_unsafe))]
|
||||
#![cfg_attr(doc_cfg, feature(doc_cfg))]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(
|
||||
clippy::cognitive_complexity,
|
||||
clippy::declare_interior_mutable_const,
|
||||
clippy::doc_markdown,
|
||||
clippy::empty_enum,
|
||||
clippy::inherent_to_string,
|
||||
clippy::items_after_statements,
|
||||
clippy::large_enum_variant,
|
||||
clippy::len_without_is_empty,
|
||||
clippy::missing_errors_doc,
|
||||
clippy::missing_safety_doc,
|
||||
clippy::module_inception,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::must_use_candidate,
|
||||
clippy::needless_doctest_main,
|
||||
clippy::new_without_default,
|
||||
clippy::or_fun_call,
|
||||
clippy::ptr_arg,
|
||||
clippy::toplevel_ref_arg,
|
||||
clippy::transmute_undefined_repr, // clippy bug: https://github.com/rust-lang/rust-clippy/issues/8417
|
||||
clippy::useless_let_if_seq,
|
||||
clippy::wrong_self_convention
|
||||
)]
|
||||
|
||||
#[cfg(built_with_cargo)]
|
||||
extern crate link_cplusplus;
|
||||
|
||||
extern crate self as cxx;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub extern crate core;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[doc(hidden)]
|
||||
pub extern crate alloc;
|
||||
|
||||
#[cfg(not(feature = "alloc"))]
|
||||
extern crate core as alloc;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[doc(hidden)]
|
||||
pub extern crate std;
|
||||
|
||||
// Block inadvertent use of items from libstd, which does not otherwise produce
|
||||
// a compile-time error on edition 2018+.
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern crate core as std;
|
||||
|
||||
#[cfg(not(any(feature = "alloc", cxx_experimental_no_alloc)))]
|
||||
compile_error! {
|
||||
r#"cxx support for no_alloc is incomplete and semver exempt; you must build with at least one of feature="std", feature="alloc", or RUSTFLAGS='--cfg cxx_experimental_no_alloc'"#
|
||||
}
|
||||
|
||||
#[cfg(all(compile_error_if_alloc, feature = "alloc"))]
|
||||
compile_error! {
|
||||
r#"feature="alloc" is unexpectedly enabled"#
|
||||
}
|
||||
|
||||
#[cfg(all(compile_error_if_std, feature = "std"))]
|
||||
compile_error! {
|
||||
r#"feature="std" is unexpectedly enabled"#
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod c_char;
|
||||
mod cxx_vector;
|
||||
mod exception;
|
||||
mod extern_type;
|
||||
mod fmt;
|
||||
mod function;
|
||||
mod hash;
|
||||
mod lossy;
|
||||
pub mod memory;
|
||||
mod opaque;
|
||||
mod result;
|
||||
mod rust_slice;
|
||||
mod rust_str;
|
||||
mod rust_string;
|
||||
mod rust_type;
|
||||
mod rust_vec;
|
||||
mod shared_ptr;
|
||||
mod sip;
|
||||
#[path = "cxx_string.rs"]
|
||||
mod string;
|
||||
mod symbols;
|
||||
mod type_id;
|
||||
mod unique_ptr;
|
||||
mod unwind;
|
||||
pub mod vector;
|
||||
mod weak_ptr;
|
||||
|
||||
pub use crate::cxx_vector::CxxVector;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use crate::exception::Exception;
|
||||
pub use crate::extern_type::{kind, ExternType};
|
||||
pub use crate::shared_ptr::SharedPtr;
|
||||
pub use crate::string::CxxString;
|
||||
pub use crate::unique_ptr::UniquePtr;
|
||||
pub use crate::weak_ptr::WeakPtr;
|
||||
pub use cxxbridge_macro::bridge;
|
||||
|
||||
/// Synonym for `CxxString`.
|
||||
///
|
||||
/// To avoid confusion with Rust's standard library string you probably
|
||||
/// shouldn't import this type with `use`. Instead, write `cxx::String`, or
|
||||
/// import and use `CxxString`.
|
||||
pub type String = CxxString;
|
||||
|
||||
/// Synonym for `CxxVector`.
|
||||
///
|
||||
/// To avoid confusion with Rust's standard library vector you probably
|
||||
/// shouldn't import this type with `use`. Instead, write `cxx::Vector<T>`, or
|
||||
/// import and use `CxxVector`.
|
||||
pub type Vector<T> = CxxVector<T>;
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
pub mod private {
|
||||
pub use crate::c_char::c_char;
|
||||
pub use crate::cxx_vector::VectorElement;
|
||||
pub use crate::extern_type::{verify_extern_kind, verify_extern_type};
|
||||
pub use crate::function::FatFunction;
|
||||
pub use crate::hash::hash;
|
||||
pub use crate::opaque::Opaque;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use crate::result::{r#try, Result};
|
||||
pub use crate::rust_slice::RustSlice;
|
||||
pub use crate::rust_str::RustStr;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use crate::rust_string::RustString;
|
||||
pub use crate::rust_type::{ImplBox, ImplVec, RustType};
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use crate::rust_vec::RustVec;
|
||||
pub use crate::shared_ptr::SharedPtrTarget;
|
||||
pub use crate::string::StackString;
|
||||
pub use crate::unique_ptr::UniquePtrTarget;
|
||||
pub use crate::unwind::prevent_unwind;
|
||||
pub use crate::weak_ptr::WeakPtrTarget;
|
||||
pub use core::{concat, module_path};
|
||||
pub use cxxbridge_macro::type_id;
|
||||
}
|
||||
|
||||
mod actually_private {
|
||||
pub trait Private {}
|
||||
}
|
||||
|
||||
macro_rules! chars {
|
||||
($($ch:ident)*) => {
|
||||
$(
|
||||
#[doc(hidden)]
|
||||
pub enum $ch {}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
chars! {
|
||||
_0 _1 _2 _3 _4 _5 _6 _7 _8 _9
|
||||
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
||||
a b c d e f g h i j k l m n o p q r s t u v w x y z
|
||||
__ // underscore
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
struct void(core::ffi::c_void);
|
||||
67
vendor/cxx/src/lossy.rs
vendored
Normal file
67
vendor/cxx/src/lossy.rs
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
use core::char;
|
||||
use core::fmt::{self, Write as _};
|
||||
use core::str;
|
||||
|
||||
pub fn display(mut bytes: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
|
||||
loop {
|
||||
match str::from_utf8(bytes) {
|
||||
Ok(valid) => return f.write_str(valid),
|
||||
Err(utf8_error) => {
|
||||
let valid_up_to = utf8_error.valid_up_to();
|
||||
let valid = unsafe { str::from_utf8_unchecked(&bytes[..valid_up_to]) };
|
||||
f.write_str(valid)?;
|
||||
f.write_char(char::REPLACEMENT_CHARACTER)?;
|
||||
if let Some(error_len) = utf8_error.error_len() {
|
||||
bytes = &bytes[valid_up_to + error_len..];
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn debug(mut bytes: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_char('"')?;
|
||||
|
||||
while !bytes.is_empty() {
|
||||
let from_utf8_result = str::from_utf8(bytes);
|
||||
let valid = match from_utf8_result {
|
||||
Ok(valid) => valid,
|
||||
Err(utf8_error) => {
|
||||
let valid_up_to = utf8_error.valid_up_to();
|
||||
unsafe { str::from_utf8_unchecked(&bytes[..valid_up_to]) }
|
||||
}
|
||||
};
|
||||
|
||||
let mut written = 0;
|
||||
for (i, ch) in valid.char_indices() {
|
||||
let esc = ch.escape_debug();
|
||||
if esc.len() != 1 {
|
||||
f.write_str(&valid[written..i])?;
|
||||
for ch in esc {
|
||||
f.write_char(ch)?;
|
||||
}
|
||||
written = i + ch.len_utf8();
|
||||
}
|
||||
}
|
||||
f.write_str(&valid[written..])?;
|
||||
|
||||
match from_utf8_result {
|
||||
Ok(_valid) => break,
|
||||
Err(utf8_error) => {
|
||||
let end_of_broken = if let Some(error_len) = utf8_error.error_len() {
|
||||
valid.len() + error_len
|
||||
} else {
|
||||
bytes.len()
|
||||
};
|
||||
for b in &bytes[valid.len()..end_of_broken] {
|
||||
write!(f, "\\x{:02x}", b)?;
|
||||
}
|
||||
bytes = &bytes[end_of_broken..];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f.write_char('"')
|
||||
}
|
||||
7
vendor/cxx/src/macros/assert.rs
vendored
Normal file
7
vendor/cxx/src/macros/assert.rs
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! const_assert_eq {
|
||||
($left:expr, $right:expr $(,)?) => {
|
||||
const _: [(); $left] = [(); $right];
|
||||
};
|
||||
}
|
||||
8
vendor/cxx/src/macros/concat.rs
vendored
Normal file
8
vendor/cxx/src/macros/concat.rs
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! attr {
|
||||
(#[$name:ident = $value:expr] $($rest:tt)*) => {
|
||||
#[$name = $value]
|
||||
$($rest)*
|
||||
};
|
||||
}
|
||||
4
vendor/cxx/src/macros/mod.rs
vendored
Normal file
4
vendor/cxx/src/macros/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#[macro_use]
|
||||
mod assert;
|
||||
#[macro_use]
|
||||
mod concat;
|
||||
9
vendor/cxx/src/memory.rs
vendored
Normal file
9
vendor/cxx/src/memory.rs
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
//! Less used details of `UniquePtr` and `SharedPtr`.
|
||||
//!
|
||||
//! The pointer types themselves are exposed at the crate root.
|
||||
|
||||
pub use crate::shared_ptr::SharedPtrTarget;
|
||||
pub use crate::unique_ptr::UniquePtrTarget;
|
||||
pub use crate::weak_ptr::WeakPtrTarget;
|
||||
#[doc(no_inline)]
|
||||
pub use cxx::{SharedPtr, UniquePtr};
|
||||
20
vendor/cxx/src/opaque.rs
vendored
Normal file
20
vendor/cxx/src/opaque.rs
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use crate::void;
|
||||
use core::marker::{PhantomData, PhantomPinned};
|
||||
use core::mem;
|
||||
|
||||
// . size = 0
|
||||
// . align = 1
|
||||
// . ffi-safe
|
||||
// . !Send
|
||||
// . !Sync
|
||||
// . !Unpin
|
||||
#[repr(C, packed)]
|
||||
pub struct Opaque {
|
||||
_private: [*const void; 0],
|
||||
_pinned: PhantomData<PhantomPinned>,
|
||||
}
|
||||
|
||||
const_assert_eq!(0, mem::size_of::<Opaque>());
|
||||
const_assert_eq!(1, mem::align_of::<Opaque>());
|
||||
70
vendor/cxx/src/result.rs
vendored
Normal file
70
vendor/cxx/src/result.rs
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#![cfg(feature = "alloc")]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use crate::exception::Exception;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::{String, ToString};
|
||||
use core::fmt::Display;
|
||||
use core::ptr::{self, NonNull};
|
||||
use core::result::Result as StdResult;
|
||||
use core::slice;
|
||||
use core::str;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PtrLen {
|
||||
pub ptr: NonNull<u8>,
|
||||
pub len: usize,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union Result {
|
||||
err: PtrLen,
|
||||
ok: *const u8, // null
|
||||
}
|
||||
|
||||
pub unsafe fn r#try<T, E>(ret: *mut T, result: StdResult<T, E>) -> Result
|
||||
where
|
||||
E: Display,
|
||||
{
|
||||
match result {
|
||||
Ok(ok) => {
|
||||
unsafe { ptr::write(ret, ok) }
|
||||
Result { ok: ptr::null() }
|
||||
}
|
||||
Err(err) => unsafe { to_c_error(err.to_string()) },
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn to_c_error(msg: String) -> Result {
|
||||
let mut msg = msg;
|
||||
unsafe { msg.as_mut_vec() }.push(b'\0');
|
||||
let ptr = msg.as_ptr();
|
||||
let len = msg.len();
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "cxxbridge1$error"]
|
||||
fn error(ptr: *const u8, len: usize) -> NonNull<u8>;
|
||||
}
|
||||
|
||||
let copy = unsafe { error(ptr, len) };
|
||||
let err = PtrLen { ptr: copy, len };
|
||||
Result { err }
|
||||
}
|
||||
|
||||
impl Result {
|
||||
pub unsafe fn exception(self) -> StdResult<(), Exception> {
|
||||
unsafe {
|
||||
if self.ok.is_null() {
|
||||
Ok(())
|
||||
} else {
|
||||
let err = self.err;
|
||||
let slice = slice::from_raw_parts_mut(err.ptr.as_ptr(), err.len);
|
||||
let s = str::from_utf8_unchecked_mut(slice);
|
||||
Err(Exception {
|
||||
what: Box::from_raw(s),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
vendor/cxx/src/rust_slice.rs
vendored
Normal file
66
vendor/cxx/src/rust_slice.rs
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use core::mem::{self, MaybeUninit};
|
||||
use core::ptr::{self, NonNull};
|
||||
use core::slice;
|
||||
|
||||
// ABI compatible with C++ rust::Slice<T> (not necessarily &[T]).
|
||||
#[repr(C)]
|
||||
pub struct RustSlice {
|
||||
repr: [MaybeUninit<usize>; mem::size_of::<NonNull<[()]>>() / mem::size_of::<usize>()],
|
||||
}
|
||||
|
||||
impl RustSlice {
|
||||
pub fn from_ref<T>(slice: &[T]) -> Self {
|
||||
let ptr = NonNull::from(slice).cast::<T>();
|
||||
let len = slice.len();
|
||||
Self::from_raw_parts(ptr, len)
|
||||
}
|
||||
|
||||
pub fn from_mut<T>(slice: &mut [T]) -> Self {
|
||||
let ptr = NonNull::from(&mut *slice).cast::<T>();
|
||||
let len = slice.len();
|
||||
Self::from_raw_parts(ptr, len)
|
||||
}
|
||||
|
||||
pub unsafe fn as_slice<'a, T>(self) -> &'a [T] {
|
||||
let ptr = self.as_non_null_ptr().as_ptr();
|
||||
let len = self.len();
|
||||
unsafe { slice::from_raw_parts(ptr, len) }
|
||||
}
|
||||
|
||||
pub unsafe fn as_mut_slice<'a, T>(self) -> &'a mut [T] {
|
||||
let ptr = self.as_non_null_ptr().as_ptr();
|
||||
let len = self.len();
|
||||
unsafe { slice::from_raw_parts_mut(ptr, len) }
|
||||
}
|
||||
|
||||
pub(crate) fn from_raw_parts<T>(ptr: NonNull<T>, len: usize) -> Self {
|
||||
// TODO: use NonNull::from_raw_parts(ptr.cast(), len) when stable.
|
||||
// https://doc.rust-lang.org/nightly/std/ptr/struct.NonNull.html#method.from_raw_parts
|
||||
// https://github.com/rust-lang/rust/issues/81513
|
||||
let ptr = ptr::slice_from_raw_parts_mut(ptr.as_ptr().cast(), len);
|
||||
unsafe { mem::transmute::<NonNull<[()]>, RustSlice>(NonNull::new_unchecked(ptr)) }
|
||||
}
|
||||
|
||||
pub(crate) fn as_non_null_ptr<T>(&self) -> NonNull<T> {
|
||||
let rust_slice = RustSlice { repr: self.repr };
|
||||
let repr = unsafe { mem::transmute::<RustSlice, NonNull<[()]>>(rust_slice) };
|
||||
repr.cast()
|
||||
}
|
||||
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
let rust_slice = RustSlice { repr: self.repr };
|
||||
let repr = unsafe { mem::transmute::<RustSlice, NonNull<[()]>>(rust_slice) };
|
||||
// TODO: use repr.len() when stable.
|
||||
// https://doc.rust-lang.org/nightly/std/ptr/struct.NonNull.html#method.len
|
||||
// https://github.com/rust-lang/rust/issues/71146
|
||||
unsafe { repr.as_ref() }.len()
|
||||
}
|
||||
}
|
||||
|
||||
const_assert_eq!(mem::size_of::<NonNull<[()]>>(), mem::size_of::<RustSlice>());
|
||||
const_assert_eq!(
|
||||
mem::align_of::<NonNull<[()]>>(),
|
||||
mem::align_of::<RustSlice>(),
|
||||
);
|
||||
28
vendor/cxx/src/rust_str.rs
vendored
Normal file
28
vendor/cxx/src/rust_str.rs
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use core::mem::{self, MaybeUninit};
|
||||
use core::ptr::NonNull;
|
||||
use core::str;
|
||||
|
||||
// ABI compatible with C++ rust::Str (not necessarily &str).
|
||||
#[repr(C)]
|
||||
pub struct RustStr {
|
||||
repr: [MaybeUninit<usize>; mem::size_of::<NonNull<str>>() / mem::size_of::<usize>()],
|
||||
}
|
||||
|
||||
impl RustStr {
|
||||
pub fn from(repr: &str) -> Self {
|
||||
let repr = NonNull::from(repr);
|
||||
unsafe { mem::transmute::<NonNull<str>, RustStr>(repr) }
|
||||
}
|
||||
|
||||
pub unsafe fn as_str<'a>(self) -> &'a str {
|
||||
unsafe {
|
||||
let repr = mem::transmute::<RustStr, NonNull<str>>(self);
|
||||
&*repr.as_ptr()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const_assert_eq!(mem::size_of::<NonNull<str>>(), mem::size_of::<RustStr>());
|
||||
const_assert_eq!(mem::align_of::<NonNull<str>>(), mem::align_of::<RustStr>());
|
||||
48
vendor/cxx/src/rust_string.rs
vendored
Normal file
48
vendor/cxx/src/rust_string.rs
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#![cfg(feature = "alloc")]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use alloc::string::String;
|
||||
use core::mem::{self, MaybeUninit};
|
||||
use core::ptr;
|
||||
|
||||
// ABI compatible with C++ rust::String (not necessarily alloc::string::String).
|
||||
#[repr(C)]
|
||||
pub struct RustString {
|
||||
repr: [MaybeUninit<usize>; mem::size_of::<String>() / mem::size_of::<usize>()],
|
||||
}
|
||||
|
||||
impl RustString {
|
||||
pub fn from(s: String) -> Self {
|
||||
unsafe { mem::transmute::<String, RustString>(s) }
|
||||
}
|
||||
|
||||
pub fn from_ref(s: &String) -> &Self {
|
||||
unsafe { &*(s as *const String as *const RustString) }
|
||||
}
|
||||
|
||||
pub fn from_mut(s: &mut String) -> &mut Self {
|
||||
unsafe { &mut *(s as *mut String as *mut RustString) }
|
||||
}
|
||||
|
||||
pub fn into_string(self) -> String {
|
||||
unsafe { mem::transmute::<RustString, String>(self) }
|
||||
}
|
||||
|
||||
pub fn as_string(&self) -> &String {
|
||||
unsafe { &*(self as *const RustString as *const String) }
|
||||
}
|
||||
|
||||
pub fn as_mut_string(&mut self) -> &mut String {
|
||||
unsafe { &mut *(self as *mut RustString as *mut String) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RustString {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ptr::drop_in_place(self.as_mut_string()) }
|
||||
}
|
||||
}
|
||||
|
||||
const_assert_eq!(mem::size_of::<[usize; 3]>(), mem::size_of::<RustString>());
|
||||
const_assert_eq!(mem::size_of::<String>(), mem::size_of::<RustString>());
|
||||
const_assert_eq!(mem::align_of::<String>(), mem::align_of::<RustString>());
|
||||
5
vendor/cxx/src/rust_type.rs
vendored
Normal file
5
vendor/cxx/src/rust_type.rs
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
pub unsafe trait RustType {}
|
||||
pub unsafe trait ImplBox {}
|
||||
pub unsafe trait ImplVec {}
|
||||
115
vendor/cxx/src/rust_vec.rs
vendored
Normal file
115
vendor/cxx/src/rust_vec.rs
vendored
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
#![cfg(feature = "alloc")]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use crate::rust_string::RustString;
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use core::ffi::c_void;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::{self, ManuallyDrop, MaybeUninit};
|
||||
use core::ptr;
|
||||
|
||||
// ABI compatible with C++ rust::Vec<T> (not necessarily alloc::vec::Vec<T>).
|
||||
#[repr(C)]
|
||||
pub struct RustVec<T> {
|
||||
repr: [MaybeUninit<usize>; mem::size_of::<Vec<c_void>>() / mem::size_of::<usize>()],
|
||||
marker: PhantomData<Vec<T>>,
|
||||
}
|
||||
|
||||
impl<T> RustVec<T> {
|
||||
pub fn new() -> Self {
|
||||
Self::from(Vec::new())
|
||||
}
|
||||
|
||||
pub fn from(v: Vec<T>) -> Self {
|
||||
unsafe { mem::transmute::<Vec<T>, RustVec<T>>(v) }
|
||||
}
|
||||
|
||||
pub fn from_ref(v: &Vec<T>) -> &Self {
|
||||
unsafe { &*(v as *const Vec<T> as *const RustVec<T>) }
|
||||
}
|
||||
|
||||
pub fn from_mut(v: &mut Vec<T>) -> &mut Self {
|
||||
unsafe { &mut *(v as *mut Vec<T> as *mut RustVec<T>) }
|
||||
}
|
||||
|
||||
pub fn into_vec(self) -> Vec<T> {
|
||||
unsafe { mem::transmute::<RustVec<T>, Vec<T>>(self) }
|
||||
}
|
||||
|
||||
pub fn as_vec(&self) -> &Vec<T> {
|
||||
unsafe { &*(self as *const RustVec<T> as *const Vec<T>) }
|
||||
}
|
||||
|
||||
pub fn as_mut_vec(&mut self) -> &mut Vec<T> {
|
||||
unsafe { &mut *(self as *mut RustVec<T> as *mut Vec<T>) }
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.as_vec().len()
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.as_vec().capacity()
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
self.as_vec().as_ptr()
|
||||
}
|
||||
|
||||
pub fn reserve_total(&mut self, new_cap: usize) {
|
||||
let vec = self.as_mut_vec();
|
||||
if new_cap > vec.capacity() {
|
||||
let additional = new_cap - vec.len();
|
||||
vec.reserve(additional);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn set_len(&mut self, len: usize) {
|
||||
unsafe { self.as_mut_vec().set_len(len) }
|
||||
}
|
||||
|
||||
pub fn truncate(&mut self, len: usize) {
|
||||
self.as_mut_vec().truncate(len);
|
||||
}
|
||||
}
|
||||
|
||||
impl RustVec<RustString> {
|
||||
pub fn from_vec_string(v: Vec<String>) -> Self {
|
||||
let mut v = ManuallyDrop::new(v);
|
||||
let ptr = v.as_mut_ptr().cast::<RustString>();
|
||||
let len = v.len();
|
||||
let cap = v.capacity();
|
||||
Self::from(unsafe { Vec::from_raw_parts(ptr, len, cap) })
|
||||
}
|
||||
|
||||
pub fn from_ref_vec_string(v: &Vec<String>) -> &Self {
|
||||
Self::from_ref(unsafe { &*(v as *const Vec<String> as *const Vec<RustString>) })
|
||||
}
|
||||
|
||||
pub fn from_mut_vec_string(v: &mut Vec<String>) -> &mut Self {
|
||||
Self::from_mut(unsafe { &mut *(v as *mut Vec<String> as *mut Vec<RustString>) })
|
||||
}
|
||||
|
||||
pub fn into_vec_string(self) -> Vec<String> {
|
||||
let mut v = ManuallyDrop::new(self.into_vec());
|
||||
let ptr = v.as_mut_ptr().cast::<String>();
|
||||
let len = v.len();
|
||||
let cap = v.capacity();
|
||||
unsafe { Vec::from_raw_parts(ptr, len, cap) }
|
||||
}
|
||||
|
||||
pub fn as_vec_string(&self) -> &Vec<String> {
|
||||
unsafe { &*(self as *const RustVec<RustString> as *const Vec<String>) }
|
||||
}
|
||||
|
||||
pub fn as_mut_vec_string(&mut self) -> &mut Vec<String> {
|
||||
unsafe { &mut *(self as *mut RustVec<RustString> as *mut Vec<String>) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for RustVec<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ptr::drop_in_place(self.as_mut_vec()) }
|
||||
}
|
||||
}
|
||||
283
vendor/cxx/src/shared_ptr.rs
vendored
Normal file
283
vendor/cxx/src/shared_ptr.rs
vendored
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
use crate::fmt::display;
|
||||
use crate::kind::Trivial;
|
||||
use crate::string::CxxString;
|
||||
use crate::weak_ptr::{WeakPtr, WeakPtrTarget};
|
||||
use crate::ExternType;
|
||||
use core::ffi::c_void;
|
||||
use core::fmt::{self, Debug, Display};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::ops::Deref;
|
||||
|
||||
/// Binding to C++ `std::shared_ptr<T>`.
|
||||
#[repr(C)]
|
||||
pub struct SharedPtr<T>
|
||||
where
|
||||
T: SharedPtrTarget,
|
||||
{
|
||||
repr: [MaybeUninit<*mut c_void>; 2],
|
||||
ty: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> SharedPtr<T>
|
||||
where
|
||||
T: SharedPtrTarget,
|
||||
{
|
||||
/// Makes a new SharedPtr wrapping a null pointer.
|
||||
///
|
||||
/// Matches the behavior of default-constructing a std::shared\_ptr.
|
||||
pub fn null() -> Self {
|
||||
let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
|
||||
let new = shared_ptr.as_mut_ptr().cast();
|
||||
unsafe {
|
||||
T::__null(new);
|
||||
shared_ptr.assume_init()
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocates memory on the heap and makes a SharedPtr owner for it.
|
||||
pub fn new(value: T) -> Self
|
||||
where
|
||||
T: ExternType<Kind = Trivial>,
|
||||
{
|
||||
let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
|
||||
let new = shared_ptr.as_mut_ptr().cast();
|
||||
unsafe {
|
||||
T::__new(value, new);
|
||||
shared_ptr.assume_init()
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether the SharedPtr does not own an object.
|
||||
///
|
||||
/// This is the opposite of [std::shared_ptr\<T\>::operator bool](https://en.cppreference.com/w/cpp/memory/shared_ptr/operator_bool).
|
||||
pub fn is_null(&self) -> bool {
|
||||
let this = self as *const Self as *const c_void;
|
||||
let ptr = unsafe { T::__get(this) };
|
||||
ptr.is_null()
|
||||
}
|
||||
|
||||
/// Returns a reference to the object owned by this SharedPtr if any,
|
||||
/// otherwise None.
|
||||
pub fn as_ref(&self) -> Option<&T> {
|
||||
let this = self as *const Self as *const c_void;
|
||||
unsafe { T::__get(this).as_ref() }
|
||||
}
|
||||
|
||||
/// Constructs new WeakPtr as a non-owning reference to the object managed
|
||||
/// by `self`. If `self` manages no object, the WeakPtr manages no object
|
||||
/// too.
|
||||
///
|
||||
/// Matches the behavior of [std::weak_ptr\<T\>::weak_ptr(const std::shared_ptr\<T\> \&)](https://en.cppreference.com/w/cpp/memory/weak_ptr/weak_ptr).
|
||||
pub fn downgrade(self: &SharedPtr<T>) -> WeakPtr<T>
|
||||
where
|
||||
T: WeakPtrTarget,
|
||||
{
|
||||
let this = self as *const Self as *const c_void;
|
||||
let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit();
|
||||
let new = weak_ptr.as_mut_ptr().cast();
|
||||
unsafe {
|
||||
T::__downgrade(this, new);
|
||||
weak_ptr.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T> Send for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
|
||||
unsafe impl<T> Sync for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
|
||||
|
||||
impl<T> Clone for SharedPtr<T>
|
||||
where
|
||||
T: SharedPtrTarget,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
|
||||
let new = shared_ptr.as_mut_ptr().cast();
|
||||
let this = self as *const Self as *mut c_void;
|
||||
unsafe {
|
||||
T::__clone(this, new);
|
||||
shared_ptr.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SharedPtr is not a self-referential type and is safe to move out of a Pin,
|
||||
// regardless whether the pointer's target is Unpin.
|
||||
impl<T> Unpin for SharedPtr<T> where T: SharedPtrTarget {}
|
||||
|
||||
impl<T> Drop for SharedPtr<T>
|
||||
where
|
||||
T: SharedPtrTarget,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
let this = self as *mut Self as *mut c_void;
|
||||
unsafe { T::__drop(this) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for SharedPtr<T>
|
||||
where
|
||||
T: SharedPtrTarget,
|
||||
{
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self.as_ref() {
|
||||
Some(target) => target,
|
||||
None => panic!(
|
||||
"called deref on a null SharedPtr<{}>",
|
||||
display(T::__typename),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Debug for SharedPtr<T>
|
||||
where
|
||||
T: Debug + SharedPtrTarget,
|
||||
{
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.as_ref() {
|
||||
None => formatter.write_str("nullptr"),
|
||||
Some(value) => Debug::fmt(value, formatter),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Display for SharedPtr<T>
|
||||
where
|
||||
T: Display + SharedPtrTarget,
|
||||
{
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.as_ref() {
|
||||
None => formatter.write_str("nullptr"),
|
||||
Some(value) => Display::fmt(value, formatter),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait bound for types which may be used as the `T` inside of a
|
||||
/// `SharedPtr<T>` in generic code.
|
||||
///
|
||||
/// This trait has no publicly callable or implementable methods. Implementing
|
||||
/// it outside of the CXX codebase is not supported.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// A bound `T: SharedPtrTarget` may be necessary when manipulating
|
||||
/// [`SharedPtr`] in generic code.
|
||||
///
|
||||
/// ```
|
||||
/// use cxx::memory::{SharedPtr, SharedPtrTarget};
|
||||
/// use std::fmt::Display;
|
||||
///
|
||||
/// pub fn take_generic_ptr<T>(ptr: SharedPtr<T>)
|
||||
/// where
|
||||
/// T: SharedPtrTarget + Display,
|
||||
/// {
|
||||
/// println!("the shared_ptr points to: {}", *ptr);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Writing the same generic function without a `SharedPtrTarget` trait bound
|
||||
/// would not compile.
|
||||
pub unsafe trait SharedPtrTarget {
|
||||
#[doc(hidden)]
|
||||
fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
|
||||
#[doc(hidden)]
|
||||
unsafe fn __null(new: *mut c_void);
|
||||
#[doc(hidden)]
|
||||
unsafe fn __new(value: Self, new: *mut c_void)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
// Opoaque C types do not get this method because they can never exist
|
||||
// by value on the Rust side of the bridge.
|
||||
let _ = value;
|
||||
let _ = new;
|
||||
unreachable!()
|
||||
}
|
||||
#[doc(hidden)]
|
||||
unsafe fn __clone(this: *const c_void, new: *mut c_void);
|
||||
#[doc(hidden)]
|
||||
unsafe fn __get(this: *const c_void) -> *const Self;
|
||||
#[doc(hidden)]
|
||||
unsafe fn __drop(this: *mut c_void);
|
||||
}
|
||||
|
||||
macro_rules! impl_shared_ptr_target {
|
||||
($segment:expr, $name:expr, $ty:ty) => {
|
||||
unsafe impl SharedPtrTarget for $ty {
|
||||
fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str($name)
|
||||
}
|
||||
unsafe fn __null(new: *mut c_void) {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$null")]
|
||||
fn __null(new: *mut c_void);
|
||||
}
|
||||
}
|
||||
unsafe { __null(new) }
|
||||
}
|
||||
unsafe fn __new(value: Self, new: *mut c_void) {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$uninit")]
|
||||
fn __uninit(new: *mut c_void) -> *mut c_void;
|
||||
}
|
||||
}
|
||||
unsafe { __uninit(new).cast::<$ty>().write(value) }
|
||||
}
|
||||
unsafe fn __clone(this: *const c_void, new: *mut c_void) {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$clone")]
|
||||
fn __clone(this: *const c_void, new: *mut c_void);
|
||||
}
|
||||
}
|
||||
unsafe { __clone(this, new) }
|
||||
}
|
||||
unsafe fn __get(this: *const c_void) -> *const Self {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$get")]
|
||||
fn __get(this: *const c_void) -> *const c_void;
|
||||
}
|
||||
}
|
||||
unsafe { __get(this) }.cast()
|
||||
}
|
||||
unsafe fn __drop(this: *mut c_void) {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$drop")]
|
||||
fn __drop(this: *mut c_void);
|
||||
}
|
||||
}
|
||||
unsafe { __drop(this) }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_shared_ptr_target_for_primitive {
|
||||
($ty:ident) => {
|
||||
impl_shared_ptr_target!(stringify!($ty), stringify!($ty), $ty);
|
||||
};
|
||||
}
|
||||
|
||||
impl_shared_ptr_target_for_primitive!(bool);
|
||||
impl_shared_ptr_target_for_primitive!(u8);
|
||||
impl_shared_ptr_target_for_primitive!(u16);
|
||||
impl_shared_ptr_target_for_primitive!(u32);
|
||||
impl_shared_ptr_target_for_primitive!(u64);
|
||||
impl_shared_ptr_target_for_primitive!(usize);
|
||||
impl_shared_ptr_target_for_primitive!(i8);
|
||||
impl_shared_ptr_target_for_primitive!(i16);
|
||||
impl_shared_ptr_target_for_primitive!(i32);
|
||||
impl_shared_ptr_target_for_primitive!(i64);
|
||||
impl_shared_ptr_target_for_primitive!(isize);
|
||||
impl_shared_ptr_target_for_primitive!(f32);
|
||||
impl_shared_ptr_target_for_primitive!(f64);
|
||||
|
||||
impl_shared_ptr_target!("string", "CxxString", CxxString);
|
||||
228
vendor/cxx/src/sip.rs
vendored
Normal file
228
vendor/cxx/src/sip.rs
vendored
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
// Vendored from libstd:
|
||||
// https://github.com/rust-lang/rust/blob/1.57.0/library/core/src/hash/sip.rs
|
||||
//
|
||||
// TODO: maybe depend on a hasher from crates.io if this becomes annoying to
|
||||
// maintain, or change this to a simpler one.
|
||||
|
||||
#![cfg(not(feature = "std"))]
|
||||
|
||||
use core::cmp;
|
||||
use core::hash::Hasher;
|
||||
use core::mem;
|
||||
use core::ptr;
|
||||
|
||||
/// An implementation of SipHash 1-3.
|
||||
///
|
||||
/// This is currently the default hashing function used by standard library
|
||||
/// (e.g., `collections::HashMap` uses it by default).
|
||||
///
|
||||
/// See: <https://131002.net/siphash>
|
||||
pub struct SipHasher13 {
|
||||
k0: u64,
|
||||
k1: u64,
|
||||
length: usize, // how many bytes we've processed
|
||||
state: State, // hash State
|
||||
tail: u64, // unprocessed bytes le
|
||||
ntail: usize, // how many bytes in tail are valid
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
struct State {
|
||||
// v0, v2 and v1, v3 show up in pairs in the algorithm,
|
||||
// and simd implementations of SipHash will use vectors
|
||||
// of v02 and v13. By placing them in this order in the struct,
|
||||
// the compiler can pick up on just a few simd optimizations by itself.
|
||||
v0: u64,
|
||||
v2: u64,
|
||||
v1: u64,
|
||||
v3: u64,
|
||||
}
|
||||
|
||||
macro_rules! compress {
|
||||
($state:expr) => {
|
||||
compress!($state.v0, $state.v1, $state.v2, $state.v3)
|
||||
};
|
||||
($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {
|
||||
$v0 = $v0.wrapping_add($v1);
|
||||
$v1 = $v1.rotate_left(13);
|
||||
$v1 ^= $v0;
|
||||
$v0 = $v0.rotate_left(32);
|
||||
$v2 = $v2.wrapping_add($v3);
|
||||
$v3 = $v3.rotate_left(16);
|
||||
$v3 ^= $v2;
|
||||
$v0 = $v0.wrapping_add($v3);
|
||||
$v3 = $v3.rotate_left(21);
|
||||
$v3 ^= $v0;
|
||||
$v2 = $v2.wrapping_add($v1);
|
||||
$v1 = $v1.rotate_left(17);
|
||||
$v1 ^= $v2;
|
||||
$v2 = $v2.rotate_left(32);
|
||||
};
|
||||
}
|
||||
|
||||
/// Loads an integer of the desired type from a byte stream, in LE order. Uses
|
||||
/// `copy_nonoverlapping` to let the compiler generate the most efficient way
|
||||
/// to load it from a possibly unaligned address.
|
||||
///
|
||||
/// Unsafe because: unchecked indexing at i..i+size_of(int_ty)
|
||||
macro_rules! load_int_le {
|
||||
($buf:expr, $i:expr, $int_ty:ident) => {{
|
||||
debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len());
|
||||
let mut data = 0 as $int_ty;
|
||||
ptr::copy_nonoverlapping(
|
||||
$buf.as_ptr().add($i),
|
||||
&mut data as *mut _ as *mut u8,
|
||||
mem::size_of::<$int_ty>(),
|
||||
);
|
||||
data.to_le()
|
||||
}};
|
||||
}
|
||||
|
||||
/// Loads a u64 using up to 7 bytes of a byte slice. It looks clumsy but the
|
||||
/// `copy_nonoverlapping` calls that occur (via `load_int_le!`) all have fixed
|
||||
/// sizes and avoid calling `memcpy`, which is good for speed.
|
||||
///
|
||||
/// Unsafe because: unchecked indexing at start..start+len
|
||||
unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
|
||||
debug_assert!(len < 8);
|
||||
let mut i = 0; // current byte index (from LSB) in the output u64
|
||||
let mut out = 0;
|
||||
if i + 3 < len {
|
||||
// SAFETY: `i` cannot be greater than `len`, and the caller must guarantee
|
||||
// that the index start..start+len is in bounds.
|
||||
out = unsafe { load_int_le!(buf, start + i, u32) } as u64;
|
||||
i += 4;
|
||||
}
|
||||
if i + 1 < len {
|
||||
// SAFETY: same as above.
|
||||
out |= (unsafe { load_int_le!(buf, start + i, u16) } as u64) << (i * 8);
|
||||
i += 2
|
||||
}
|
||||
if i < len {
|
||||
// SAFETY: same as above.
|
||||
out |= (unsafe { *buf.get_unchecked(start + i) } as u64) << (i * 8);
|
||||
i += 1;
|
||||
}
|
||||
debug_assert_eq!(i, len);
|
||||
out
|
||||
}
|
||||
|
||||
impl SipHasher13 {
|
||||
/// Creates a new `SipHasher13` with the two initial keys set to 0.
|
||||
pub fn new() -> Self {
|
||||
Self::new_with_keys(0, 0)
|
||||
}
|
||||
|
||||
/// Creates a `SipHasher13` that is keyed off the provided keys.
|
||||
fn new_with_keys(key0: u64, key1: u64) -> Self {
|
||||
let mut state = SipHasher13 {
|
||||
k0: key0,
|
||||
k1: key1,
|
||||
length: 0,
|
||||
state: State {
|
||||
v0: 0,
|
||||
v1: 0,
|
||||
v2: 0,
|
||||
v3: 0,
|
||||
},
|
||||
tail: 0,
|
||||
ntail: 0,
|
||||
};
|
||||
state.reset();
|
||||
state
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.length = 0;
|
||||
self.state.v0 = self.k0 ^ 0x736f6d6570736575;
|
||||
self.state.v1 = self.k1 ^ 0x646f72616e646f6d;
|
||||
self.state.v2 = self.k0 ^ 0x6c7967656e657261;
|
||||
self.state.v3 = self.k1 ^ 0x7465646279746573;
|
||||
self.ntail = 0;
|
||||
}
|
||||
}
|
||||
|
||||
impl Hasher for SipHasher13 {
|
||||
// Note: no integer hashing methods (`write_u*`, `write_i*`) are defined
|
||||
// for this type. We could add them, copy the `short_write` implementation
|
||||
// in librustc_data_structures/sip128.rs, and add `write_u*`/`write_i*`
|
||||
// methods to `SipHasher`, `SipHasher13`, and `DefaultHasher`. This would
|
||||
// greatly speed up integer hashing by those hashers, at the cost of
|
||||
// slightly slowing down compile speeds on some benchmarks. See #69152 for
|
||||
// details.
|
||||
fn write(&mut self, msg: &[u8]) {
|
||||
let length = msg.len();
|
||||
self.length += length;
|
||||
|
||||
let mut needed = 0;
|
||||
|
||||
if self.ntail != 0 {
|
||||
needed = 8 - self.ntail;
|
||||
// SAFETY: `cmp::min(length, needed)` is guaranteed to not be over `length`
|
||||
self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail);
|
||||
if length < needed {
|
||||
self.ntail += length;
|
||||
return;
|
||||
} else {
|
||||
self.state.v3 ^= self.tail;
|
||||
Sip13Rounds::c_rounds(&mut self.state);
|
||||
self.state.v0 ^= self.tail;
|
||||
self.ntail = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Buffered tail is now flushed, process new input.
|
||||
let len = length - needed;
|
||||
let left = len & 0x7; // len % 8
|
||||
|
||||
let mut i = needed;
|
||||
while i < len - left {
|
||||
// SAFETY: because `len - left` is the biggest multiple of 8 under
|
||||
// `len`, and because `i` starts at `needed` where `len` is `length - needed`,
|
||||
// `i + 8` is guaranteed to be less than or equal to `length`.
|
||||
let mi = unsafe { load_int_le!(msg, i, u64) };
|
||||
|
||||
self.state.v3 ^= mi;
|
||||
Sip13Rounds::c_rounds(&mut self.state);
|
||||
self.state.v0 ^= mi;
|
||||
|
||||
i += 8;
|
||||
}
|
||||
|
||||
// SAFETY: `i` is now `needed + len.div_euclid(8) * 8`,
|
||||
// so `i + left` = `needed + len` = `length`, which is by
|
||||
// definition equal to `msg.len()`.
|
||||
self.tail = unsafe { u8to64_le(msg, i, left) };
|
||||
self.ntail = left;
|
||||
}
|
||||
|
||||
fn finish(&self) -> u64 {
|
||||
let mut state = self.state;
|
||||
|
||||
let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;
|
||||
|
||||
state.v3 ^= b;
|
||||
Sip13Rounds::c_rounds(&mut state);
|
||||
state.v0 ^= b;
|
||||
|
||||
state.v2 ^= 0xff;
|
||||
Sip13Rounds::d_rounds(&mut state);
|
||||
|
||||
state.v0 ^ state.v1 ^ state.v2 ^ state.v3
|
||||
}
|
||||
}
|
||||
|
||||
struct Sip13Rounds;
|
||||
|
||||
impl Sip13Rounds {
|
||||
fn c_rounds(state: &mut State) {
|
||||
compress!(state);
|
||||
}
|
||||
|
||||
fn d_rounds(state: &mut State) {
|
||||
compress!(state);
|
||||
compress!(state);
|
||||
compress!(state);
|
||||
}
|
||||
}
|
||||
18
vendor/cxx/src/symbols/exception.rs
vendored
Normal file
18
vendor/cxx/src/symbols/exception.rs
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#![cfg(feature = "alloc")]
|
||||
|
||||
use crate::result::PtrLen;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use core::ptr::NonNull;
|
||||
use core::slice;
|
||||
|
||||
#[export_name = "cxxbridge1$exception"]
|
||||
unsafe extern "C" fn exception(ptr: *const u8, len: usize) -> PtrLen {
|
||||
let slice = unsafe { slice::from_raw_parts(ptr, len) };
|
||||
let string = String::from_utf8_lossy(slice);
|
||||
let len = string.len();
|
||||
let raw_str = Box::into_raw(string.into_owned().into_boxed_str());
|
||||
let raw_u8 = raw_str.cast::<u8>();
|
||||
let nonnull = unsafe { NonNull::new_unchecked(raw_u8) };
|
||||
PtrLen { ptr: nonnull, len }
|
||||
}
|
||||
5
vendor/cxx/src/symbols/mod.rs
vendored
Normal file
5
vendor/cxx/src/symbols/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
mod exception;
|
||||
mod rust_slice;
|
||||
mod rust_str;
|
||||
mod rust_string;
|
||||
mod rust_vec;
|
||||
20
vendor/cxx/src/symbols/rust_slice.rs
vendored
Normal file
20
vendor/cxx/src/symbols/rust_slice.rs
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
use crate::rust_slice::RustSlice;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::ptr::{self, NonNull};
|
||||
|
||||
#[export_name = "cxxbridge1$slice$new"]
|
||||
unsafe extern "C" fn slice_new(this: &mut MaybeUninit<RustSlice>, ptr: NonNull<()>, len: usize) {
|
||||
let this = this.as_mut_ptr();
|
||||
let rust_slice = RustSlice::from_raw_parts(ptr, len);
|
||||
unsafe { ptr::write(this, rust_slice) }
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$slice$ptr"]
|
||||
unsafe extern "C" fn slice_ptr(this: &RustSlice) -> NonNull<()> {
|
||||
this.as_non_null_ptr()
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$slice$len"]
|
||||
unsafe extern "C" fn slice_len(this: &RustSlice) -> usize {
|
||||
this.len()
|
||||
}
|
||||
43
vendor/cxx/src/symbols/rust_str.rs
vendored
Normal file
43
vendor/cxx/src/symbols/rust_str.rs
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#[cfg(feature = "alloc")]
|
||||
use alloc::string::String;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::ptr;
|
||||
use core::slice;
|
||||
use core::str;
|
||||
|
||||
#[export_name = "cxxbridge1$str$new"]
|
||||
unsafe extern "C" fn str_new(this: &mut MaybeUninit<&str>) {
|
||||
let this = this.as_mut_ptr();
|
||||
unsafe { ptr::write(this, "") }
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[export_name = "cxxbridge1$str$ref"]
|
||||
unsafe extern "C" fn str_ref<'a>(this: &mut MaybeUninit<&'a str>, string: &'a String) {
|
||||
let this = this.as_mut_ptr();
|
||||
let s = string.as_str();
|
||||
unsafe { ptr::write(this, s) }
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$str$from"]
|
||||
unsafe extern "C" fn str_from(this: &mut MaybeUninit<&str>, ptr: *const u8, len: usize) -> bool {
|
||||
let slice = unsafe { slice::from_raw_parts(ptr, len) };
|
||||
match str::from_utf8(slice) {
|
||||
Ok(s) => {
|
||||
let this = this.as_mut_ptr();
|
||||
unsafe { ptr::write(this, s) }
|
||||
true
|
||||
}
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$str$ptr"]
|
||||
unsafe extern "C" fn str_ptr(this: &&str) -> *const u8 {
|
||||
this.as_ptr()
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$str$len"]
|
||||
unsafe extern "C" fn str_len(this: &&str) -> usize {
|
||||
this.len()
|
||||
}
|
||||
114
vendor/cxx/src/symbols/rust_string.rs
vendored
Normal file
114
vendor/cxx/src/symbols/rust_string.rs
vendored
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#![cfg(feature = "alloc")]
|
||||
|
||||
use alloc::borrow::ToOwned;
|
||||
use alloc::string::String;
|
||||
use core::mem::{ManuallyDrop, MaybeUninit};
|
||||
use core::ptr;
|
||||
use core::slice;
|
||||
use core::str;
|
||||
|
||||
#[export_name = "cxxbridge1$string$new"]
|
||||
unsafe extern "C" fn string_new(this: &mut MaybeUninit<String>) {
|
||||
let this = this.as_mut_ptr();
|
||||
let new = String::new();
|
||||
unsafe { ptr::write(this, new) }
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$string$clone"]
|
||||
unsafe extern "C" fn string_clone(this: &mut MaybeUninit<String>, other: &String) {
|
||||
let this = this.as_mut_ptr();
|
||||
let clone = other.clone();
|
||||
unsafe { ptr::write(this, clone) }
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$string$from_utf8"]
|
||||
unsafe extern "C" fn string_from_utf8(
|
||||
this: &mut MaybeUninit<String>,
|
||||
ptr: *const u8,
|
||||
len: usize,
|
||||
) -> bool {
|
||||
let slice = unsafe { slice::from_raw_parts(ptr, len) };
|
||||
match str::from_utf8(slice) {
|
||||
Ok(s) => {
|
||||
let this = this.as_mut_ptr();
|
||||
let owned = s.to_owned();
|
||||
unsafe { ptr::write(this, owned) }
|
||||
true
|
||||
}
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$string$from_utf8_lossy"]
|
||||
unsafe extern "C" fn string_from_utf8_lossy(
|
||||
this: &mut MaybeUninit<String>,
|
||||
ptr: *const u8,
|
||||
len: usize,
|
||||
) {
|
||||
let slice = unsafe { slice::from_raw_parts(ptr, len) };
|
||||
let owned = String::from_utf8_lossy(slice).into_owned();
|
||||
let this = this.as_mut_ptr();
|
||||
unsafe { ptr::write(this, owned) }
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$string$from_utf16"]
|
||||
unsafe extern "C" fn string_from_utf16(
|
||||
this: &mut MaybeUninit<String>,
|
||||
ptr: *const u16,
|
||||
len: usize,
|
||||
) -> bool {
|
||||
let slice = unsafe { slice::from_raw_parts(ptr, len) };
|
||||
match String::from_utf16(slice) {
|
||||
Ok(s) => {
|
||||
let this = this.as_mut_ptr();
|
||||
unsafe { ptr::write(this, s) }
|
||||
true
|
||||
}
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$string$from_utf16_lossy"]
|
||||
unsafe extern "C" fn string_from_utf16_lossy(
|
||||
this: &mut MaybeUninit<String>,
|
||||
ptr: *const u16,
|
||||
len: usize,
|
||||
) {
|
||||
let slice = unsafe { slice::from_raw_parts(ptr, len) };
|
||||
let owned = String::from_utf16_lossy(slice);
|
||||
let this = this.as_mut_ptr();
|
||||
unsafe { ptr::write(this, owned) }
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$string$drop"]
|
||||
unsafe extern "C" fn string_drop(this: &mut ManuallyDrop<String>) {
|
||||
unsafe { ManuallyDrop::drop(this) }
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$string$ptr"]
|
||||
unsafe extern "C" fn string_ptr(this: &String) -> *const u8 {
|
||||
this.as_ptr()
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$string$len"]
|
||||
unsafe extern "C" fn string_len(this: &String) -> usize {
|
||||
this.len()
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$string$capacity"]
|
||||
unsafe extern "C" fn string_capacity(this: &String) -> usize {
|
||||
this.capacity()
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$string$reserve_additional"]
|
||||
unsafe extern "C" fn string_reserve_additional(this: &mut String, additional: usize) {
|
||||
this.reserve(additional);
|
||||
}
|
||||
|
||||
#[export_name = "cxxbridge1$string$reserve_total"]
|
||||
unsafe extern "C" fn string_reserve_total(this: &mut String, new_cap: usize) {
|
||||
if new_cap > this.capacity() {
|
||||
let additional = new_cap - this.len();
|
||||
this.reserve(additional);
|
||||
}
|
||||
}
|
||||
91
vendor/cxx/src/symbols/rust_vec.rs
vendored
Normal file
91
vendor/cxx/src/symbols/rust_vec.rs
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#![cfg(feature = "alloc")]
|
||||
|
||||
use crate::c_char::c_char;
|
||||
use crate::rust_string::RustString;
|
||||
use crate::rust_vec::RustVec;
|
||||
use alloc::vec::Vec;
|
||||
use core::mem;
|
||||
use core::ptr;
|
||||
|
||||
macro_rules! rust_vec_shims {
|
||||
($segment:expr, $ty:ty) => {
|
||||
const_assert_eq!(mem::size_of::<[usize; 3]>(), mem::size_of::<RustVec<$ty>>());
|
||||
const_assert_eq!(mem::size_of::<Vec<$ty>>(), mem::size_of::<RustVec<$ty>>());
|
||||
const_assert_eq!(mem::align_of::<Vec<$ty>>(), mem::align_of::<RustVec<$ty>>());
|
||||
|
||||
const _: () = {
|
||||
attr! {
|
||||
#[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$new")]
|
||||
unsafe extern "C" fn __new(this: *mut RustVec<$ty>) {
|
||||
unsafe { ptr::write(this, RustVec::new()) }
|
||||
}
|
||||
}
|
||||
attr! {
|
||||
#[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$drop")]
|
||||
unsafe extern "C" fn __drop(this: *mut RustVec<$ty>) {
|
||||
unsafe { ptr::drop_in_place(this) }
|
||||
}
|
||||
}
|
||||
attr! {
|
||||
#[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$len")]
|
||||
unsafe extern "C" fn __len(this: *const RustVec<$ty>) -> usize {
|
||||
unsafe { &*this }.len()
|
||||
}
|
||||
}
|
||||
attr! {
|
||||
#[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$capacity")]
|
||||
unsafe extern "C" fn __capacity(this: *const RustVec<$ty>) -> usize {
|
||||
unsafe { &*this }.capacity()
|
||||
}
|
||||
}
|
||||
attr! {
|
||||
#[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$data")]
|
||||
unsafe extern "C" fn __data(this: *const RustVec<$ty>) -> *const $ty {
|
||||
unsafe { &*this }.as_ptr()
|
||||
}
|
||||
}
|
||||
attr! {
|
||||
#[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$reserve_total")]
|
||||
unsafe extern "C" fn __reserve_total(this: *mut RustVec<$ty>, new_cap: usize) {
|
||||
unsafe { &mut *this }.reserve_total(new_cap);
|
||||
}
|
||||
}
|
||||
attr! {
|
||||
#[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$set_len")]
|
||||
unsafe extern "C" fn __set_len(this: *mut RustVec<$ty>, len: usize) {
|
||||
unsafe { (*this).set_len(len) }
|
||||
}
|
||||
}
|
||||
attr! {
|
||||
#[export_name = concat!("cxxbridge1$rust_vec$", $segment, "$truncate")]
|
||||
unsafe extern "C" fn __truncate(this: *mut RustVec<$ty>, len: usize) {
|
||||
unsafe { (*this).truncate(len) }
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! rust_vec_shims_for_primitive {
|
||||
($ty:ident) => {
|
||||
rust_vec_shims!(stringify!($ty), $ty);
|
||||
};
|
||||
}
|
||||
|
||||
rust_vec_shims_for_primitive!(bool);
|
||||
rust_vec_shims_for_primitive!(u8);
|
||||
rust_vec_shims_for_primitive!(u16);
|
||||
rust_vec_shims_for_primitive!(u32);
|
||||
rust_vec_shims_for_primitive!(u64);
|
||||
rust_vec_shims_for_primitive!(usize);
|
||||
rust_vec_shims_for_primitive!(i8);
|
||||
rust_vec_shims_for_primitive!(i16);
|
||||
rust_vec_shims_for_primitive!(i32);
|
||||
rust_vec_shims_for_primitive!(i64);
|
||||
rust_vec_shims_for_primitive!(isize);
|
||||
rust_vec_shims_for_primitive!(f32);
|
||||
rust_vec_shims_for_primitive!(f64);
|
||||
|
||||
rust_vec_shims!("char", c_char);
|
||||
rust_vec_shims!("string", RustString);
|
||||
rust_vec_shims!("str", &str);
|
||||
9
vendor/cxx/src/type_id.rs
vendored
Normal file
9
vendor/cxx/src/type_id.rs
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/// For use in impls of the `ExternType` trait. See [`ExternType`].
|
||||
///
|
||||
/// [`ExternType`]: trait.ExternType.html
|
||||
#[macro_export]
|
||||
macro_rules! type_id {
|
||||
($($path:tt)*) => {
|
||||
$crate::private::type_id! { $crate $($path)* }
|
||||
};
|
||||
}
|
||||
296
vendor/cxx/src/unique_ptr.rs
vendored
Normal file
296
vendor/cxx/src/unique_ptr.rs
vendored
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
use crate::cxx_vector::{CxxVector, VectorElement};
|
||||
use crate::fmt::display;
|
||||
use crate::kind::Trivial;
|
||||
use crate::string::CxxString;
|
||||
use crate::ExternType;
|
||||
use core::ffi::c_void;
|
||||
use core::fmt::{self, Debug, Display};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::{self, MaybeUninit};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::pin::Pin;
|
||||
|
||||
/// Binding to C++ `std::unique_ptr<T, std::default_delete<T>>`.
|
||||
#[repr(C)]
|
||||
pub struct UniquePtr<T>
|
||||
where
|
||||
T: UniquePtrTarget,
|
||||
{
|
||||
repr: MaybeUninit<*mut c_void>,
|
||||
ty: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> UniquePtr<T>
|
||||
where
|
||||
T: UniquePtrTarget,
|
||||
{
|
||||
/// Makes a new UniquePtr wrapping a null pointer.
|
||||
///
|
||||
/// Matches the behavior of default-constructing a std::unique\_ptr.
|
||||
pub fn null() -> Self {
|
||||
UniquePtr {
|
||||
repr: T::__null(),
|
||||
ty: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocates memory on the heap and makes a UniquePtr pointing to it.
|
||||
pub fn new(value: T) -> Self
|
||||
where
|
||||
T: ExternType<Kind = Trivial>,
|
||||
{
|
||||
UniquePtr {
|
||||
repr: T::__new(value),
|
||||
ty: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether the UniquePtr does not own an object.
|
||||
///
|
||||
/// This is the opposite of [std::unique_ptr\<T\>::operator bool](https://en.cppreference.com/w/cpp/memory/unique_ptr/operator_bool).
|
||||
pub fn is_null(&self) -> bool {
|
||||
let ptr = unsafe { T::__get(self.repr) };
|
||||
ptr.is_null()
|
||||
}
|
||||
|
||||
/// Returns a reference to the object owned by this UniquePtr if any,
|
||||
/// otherwise None.
|
||||
pub fn as_ref(&self) -> Option<&T> {
|
||||
unsafe { T::__get(self.repr).as_ref() }
|
||||
}
|
||||
|
||||
/// Returns a mutable pinned reference to the object owned by this UniquePtr
|
||||
/// if any, otherwise None.
|
||||
pub fn as_mut(&mut self) -> Option<Pin<&mut T>> {
|
||||
unsafe {
|
||||
let mut_reference = (T::__get(self.repr) as *mut T).as_mut()?;
|
||||
Some(Pin::new_unchecked(mut_reference))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable pinned reference to the object owned by this
|
||||
/// UniquePtr.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the UniquePtr holds a null pointer.
|
||||
pub fn pin_mut(&mut self) -> Pin<&mut T> {
|
||||
match self.as_mut() {
|
||||
Some(target) => target,
|
||||
None => panic!(
|
||||
"called pin_mut on a null UniquePtr<{}>",
|
||||
display(T::__typename),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes the UniquePtr, releasing its ownership of the heap-allocated T.
|
||||
///
|
||||
/// Matches the behavior of [std::unique_ptr\<T\>::release](https://en.cppreference.com/w/cpp/memory/unique_ptr/release).
|
||||
pub fn into_raw(self) -> *mut T {
|
||||
let ptr = unsafe { T::__release(self.repr) };
|
||||
mem::forget(self);
|
||||
ptr
|
||||
}
|
||||
|
||||
/// Constructs a UniquePtr retaking ownership of a pointer previously
|
||||
/// obtained from `into_raw`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because improper use may lead to memory
|
||||
/// problems. For example a double-free may occur if the function is called
|
||||
/// twice on the same raw pointer.
|
||||
pub unsafe fn from_raw(raw: *mut T) -> Self {
|
||||
UniquePtr {
|
||||
repr: unsafe { T::__raw(raw) },
|
||||
ty: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T> Send for UniquePtr<T> where T: Send + UniquePtrTarget {}
|
||||
unsafe impl<T> Sync for UniquePtr<T> where T: Sync + UniquePtrTarget {}
|
||||
|
||||
// UniquePtr is not a self-referential type and is safe to move out of a Pin,
|
||||
// regardless whether the pointer's target is Unpin.
|
||||
impl<T> Unpin for UniquePtr<T> where T: UniquePtrTarget {}
|
||||
|
||||
impl<T> Drop for UniquePtr<T>
|
||||
where
|
||||
T: UniquePtrTarget,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
unsafe { T::__drop(self.repr) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for UniquePtr<T>
|
||||
where
|
||||
T: UniquePtrTarget,
|
||||
{
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self.as_ref() {
|
||||
Some(target) => target,
|
||||
None => panic!(
|
||||
"called deref on a null UniquePtr<{}>",
|
||||
display(T::__typename),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for UniquePtr<T>
|
||||
where
|
||||
T: UniquePtrTarget + Unpin,
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
match self.as_mut() {
|
||||
Some(target) => Pin::into_inner(target),
|
||||
None => panic!(
|
||||
"called deref_mut on a null UniquePtr<{}>",
|
||||
display(T::__typename),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Debug for UniquePtr<T>
|
||||
where
|
||||
T: Debug + UniquePtrTarget,
|
||||
{
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.as_ref() {
|
||||
None => formatter.write_str("nullptr"),
|
||||
Some(value) => Debug::fmt(value, formatter),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Display for UniquePtr<T>
|
||||
where
|
||||
T: Display + UniquePtrTarget,
|
||||
{
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.as_ref() {
|
||||
None => formatter.write_str("nullptr"),
|
||||
Some(value) => Display::fmt(value, formatter),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait bound for types which may be used as the `T` inside of a
|
||||
/// `UniquePtr<T>` in generic code.
|
||||
///
|
||||
/// This trait has no publicly callable or implementable methods. Implementing
|
||||
/// it outside of the CXX codebase is not supported.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// A bound `T: UniquePtrTarget` may be necessary when manipulating
|
||||
/// [`UniquePtr`] in generic code.
|
||||
///
|
||||
/// ```
|
||||
/// use cxx::memory::{UniquePtr, UniquePtrTarget};
|
||||
/// use std::fmt::Display;
|
||||
///
|
||||
/// pub fn take_generic_ptr<T>(ptr: UniquePtr<T>)
|
||||
/// where
|
||||
/// T: UniquePtrTarget + Display,
|
||||
/// {
|
||||
/// println!("the unique_ptr points to: {}", *ptr);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Writing the same generic function without a `UniquePtrTarget` trait bound
|
||||
/// would not compile.
|
||||
pub unsafe trait UniquePtrTarget {
|
||||
#[doc(hidden)]
|
||||
fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
|
||||
#[doc(hidden)]
|
||||
fn __null() -> MaybeUninit<*mut c_void>;
|
||||
#[doc(hidden)]
|
||||
fn __new(value: Self) -> MaybeUninit<*mut c_void>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
// Opaque C types do not get this method because they can never exist by
|
||||
// value on the Rust side of the bridge.
|
||||
let _ = value;
|
||||
unreachable!()
|
||||
}
|
||||
#[doc(hidden)]
|
||||
unsafe fn __raw(raw: *mut Self) -> MaybeUninit<*mut c_void>;
|
||||
#[doc(hidden)]
|
||||
unsafe fn __get(repr: MaybeUninit<*mut c_void>) -> *const Self;
|
||||
#[doc(hidden)]
|
||||
unsafe fn __release(repr: MaybeUninit<*mut c_void>) -> *mut Self;
|
||||
#[doc(hidden)]
|
||||
unsafe fn __drop(repr: MaybeUninit<*mut c_void>);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "cxxbridge1$unique_ptr$std$string$null"]
|
||||
fn unique_ptr_std_string_null(this: *mut MaybeUninit<*mut c_void>);
|
||||
#[link_name = "cxxbridge1$unique_ptr$std$string$raw"]
|
||||
fn unique_ptr_std_string_raw(this: *mut MaybeUninit<*mut c_void>, raw: *mut CxxString);
|
||||
#[link_name = "cxxbridge1$unique_ptr$std$string$get"]
|
||||
fn unique_ptr_std_string_get(this: *const MaybeUninit<*mut c_void>) -> *const CxxString;
|
||||
#[link_name = "cxxbridge1$unique_ptr$std$string$release"]
|
||||
fn unique_ptr_std_string_release(this: *mut MaybeUninit<*mut c_void>) -> *mut CxxString;
|
||||
#[link_name = "cxxbridge1$unique_ptr$std$string$drop"]
|
||||
fn unique_ptr_std_string_drop(this: *mut MaybeUninit<*mut c_void>);
|
||||
}
|
||||
|
||||
unsafe impl UniquePtrTarget for CxxString {
|
||||
fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("CxxString")
|
||||
}
|
||||
fn __null() -> MaybeUninit<*mut c_void> {
|
||||
let mut repr = MaybeUninit::uninit();
|
||||
unsafe {
|
||||
unique_ptr_std_string_null(&mut repr);
|
||||
}
|
||||
repr
|
||||
}
|
||||
unsafe fn __raw(raw: *mut Self) -> MaybeUninit<*mut c_void> {
|
||||
let mut repr = MaybeUninit::uninit();
|
||||
unsafe { unique_ptr_std_string_raw(&mut repr, raw) }
|
||||
repr
|
||||
}
|
||||
unsafe fn __get(repr: MaybeUninit<*mut c_void>) -> *const Self {
|
||||
unsafe { unique_ptr_std_string_get(&repr) }
|
||||
}
|
||||
unsafe fn __release(mut repr: MaybeUninit<*mut c_void>) -> *mut Self {
|
||||
unsafe { unique_ptr_std_string_release(&mut repr) }
|
||||
}
|
||||
unsafe fn __drop(mut repr: MaybeUninit<*mut c_void>) {
|
||||
unsafe { unique_ptr_std_string_drop(&mut repr) }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T> UniquePtrTarget for CxxVector<T>
|
||||
where
|
||||
T: VectorElement,
|
||||
{
|
||||
fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "CxxVector<{}>", display(T::__typename))
|
||||
}
|
||||
fn __null() -> MaybeUninit<*mut c_void> {
|
||||
T::__unique_ptr_null()
|
||||
}
|
||||
unsafe fn __raw(raw: *mut Self) -> MaybeUninit<*mut c_void> {
|
||||
unsafe { T::__unique_ptr_raw(raw) }
|
||||
}
|
||||
unsafe fn __get(repr: MaybeUninit<*mut c_void>) -> *const Self {
|
||||
unsafe { T::__unique_ptr_get(repr) }
|
||||
}
|
||||
unsafe fn __release(repr: MaybeUninit<*mut c_void>) -> *mut Self {
|
||||
unsafe { T::__unique_ptr_release(repr) }
|
||||
}
|
||||
unsafe fn __drop(repr: MaybeUninit<*mut c_void>) {
|
||||
unsafe { T::__unique_ptr_drop(repr) }
|
||||
}
|
||||
}
|
||||
39
vendor/cxx/src/unwind.rs
vendored
Normal file
39
vendor/cxx/src/unwind.rs
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use core::mem;
|
||||
|
||||
pub fn prevent_unwind<F, R>(label: &'static str, foreign_call: F) -> R
|
||||
where
|
||||
F: FnOnce() -> R,
|
||||
{
|
||||
// Goal is to make it impossible to propagate a panic across the C interface
|
||||
// of an extern "Rust" function, which would be Undefined Behavior. We
|
||||
// transform such panicks into a deterministic abort instead. When cxx is
|
||||
// built in an application using panic=abort, this guard object is compiled
|
||||
// out because its destructor is statically unreachable. When built with
|
||||
// panic=unwind, an unwind from the foreign call will attempt to drop the
|
||||
// guard object leading to a double panic, which is defined by Rust to
|
||||
// abort. In no_std programs, on most platforms the current mechanism for
|
||||
// this is for core::intrinsics::abort to invoke an invalid instruction. On
|
||||
// Unix, the process will probably terminate with a signal like SIGABRT,
|
||||
// SIGILL, SIGTRAP, SIGSEGV or SIGBUS. The precise behaviour is not
|
||||
// guaranteed and not stable, but is safe.
|
||||
let guard = Guard { label };
|
||||
|
||||
let ret = foreign_call();
|
||||
|
||||
// If we made it here, no uncaught panic occurred during the foreign call.
|
||||
mem::forget(guard);
|
||||
ret
|
||||
}
|
||||
|
||||
struct Guard {
|
||||
label: &'static str,
|
||||
}
|
||||
|
||||
impl Drop for Guard {
|
||||
#[cold]
|
||||
fn drop(&mut self) {
|
||||
panic!("panic in ffi function {}, aborting.", self.label);
|
||||
}
|
||||
}
|
||||
9
vendor/cxx/src/vector.rs
vendored
Normal file
9
vendor/cxx/src/vector.rs
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
//! Less used details of `CxxVector`.
|
||||
//!
|
||||
//! `CxxVector` itself is exposed at the crate root.
|
||||
|
||||
pub use crate::cxx_vector::{Iter, IterMut, VectorElement};
|
||||
#[doc(inline)]
|
||||
pub use crate::Vector;
|
||||
#[doc(no_inline)]
|
||||
pub use cxx::CxxVector;
|
||||
189
vendor/cxx/src/weak_ptr.rs
vendored
Normal file
189
vendor/cxx/src/weak_ptr.rs
vendored
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
use crate::shared_ptr::{SharedPtr, SharedPtrTarget};
|
||||
use crate::string::CxxString;
|
||||
use core::ffi::c_void;
|
||||
use core::fmt::{self, Debug};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
/// Binding to C++ `std::weak_ptr<T>`.
|
||||
///
|
||||
/// The typical way to construct a WeakPtr from Rust is by [downgrading] from a
|
||||
/// SharedPtr.
|
||||
///
|
||||
/// [downgrading]: crate::SharedPtr::downgrade
|
||||
#[repr(C)]
|
||||
pub struct WeakPtr<T>
|
||||
where
|
||||
T: WeakPtrTarget,
|
||||
{
|
||||
repr: [MaybeUninit<*mut c_void>; 2],
|
||||
ty: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> WeakPtr<T>
|
||||
where
|
||||
T: WeakPtrTarget,
|
||||
{
|
||||
/// Makes a new WeakPtr wrapping a null pointer.
|
||||
///
|
||||
/// Matches the behavior of default-constructing a std::weak\_ptr.
|
||||
pub fn null() -> Self {
|
||||
let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit();
|
||||
let new = weak_ptr.as_mut_ptr().cast();
|
||||
unsafe {
|
||||
T::__null(new);
|
||||
weak_ptr.assume_init()
|
||||
}
|
||||
}
|
||||
|
||||
/// Upgrades a non-owning reference into an owning reference if possible,
|
||||
/// otherwise to a null reference.
|
||||
///
|
||||
/// Matches the behavior of [std::weak_ptr\<T\>::lock](https://en.cppreference.com/w/cpp/memory/weak_ptr/lock).
|
||||
pub fn upgrade(&self) -> SharedPtr<T>
|
||||
where
|
||||
T: SharedPtrTarget,
|
||||
{
|
||||
let this = self as *const Self as *const c_void;
|
||||
let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
|
||||
let new = shared_ptr.as_mut_ptr().cast();
|
||||
unsafe {
|
||||
T::__upgrade(this, new);
|
||||
shared_ptr.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T> Send for WeakPtr<T> where T: Send + Sync + WeakPtrTarget {}
|
||||
unsafe impl<T> Sync for WeakPtr<T> where T: Send + Sync + WeakPtrTarget {}
|
||||
|
||||
impl<T> Clone for WeakPtr<T>
|
||||
where
|
||||
T: WeakPtrTarget,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit();
|
||||
let new = weak_ptr.as_mut_ptr().cast();
|
||||
let this = self as *const Self as *mut c_void;
|
||||
unsafe {
|
||||
T::__clone(this, new);
|
||||
weak_ptr.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for WeakPtr<T>
|
||||
where
|
||||
T: WeakPtrTarget,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
let this = self as *mut Self as *mut c_void;
|
||||
unsafe { T::__drop(this) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Debug for WeakPtr<T>
|
||||
where
|
||||
T: Debug + WeakPtrTarget + SharedPtrTarget,
|
||||
{
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
Debug::fmt(&self.upgrade(), formatter)
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait bound for types which may be used as the `T` inside of a `WeakPtr<T>`
|
||||
/// in generic code.
|
||||
///
|
||||
/// This trait has no publicly callable or implementable methods. Implementing
|
||||
/// it outside of the CXX codebase is not supported.
|
||||
pub unsafe trait WeakPtrTarget {
|
||||
#[doc(hidden)]
|
||||
fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
|
||||
#[doc(hidden)]
|
||||
unsafe fn __null(new: *mut c_void);
|
||||
#[doc(hidden)]
|
||||
unsafe fn __clone(this: *const c_void, new: *mut c_void);
|
||||
#[doc(hidden)]
|
||||
unsafe fn __downgrade(shared: *const c_void, new: *mut c_void);
|
||||
#[doc(hidden)]
|
||||
unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void);
|
||||
#[doc(hidden)]
|
||||
unsafe fn __drop(this: *mut c_void);
|
||||
}
|
||||
|
||||
macro_rules! impl_weak_ptr_target {
|
||||
($segment:expr, $name:expr, $ty:ty) => {
|
||||
unsafe impl WeakPtrTarget for $ty {
|
||||
fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str($name)
|
||||
}
|
||||
unsafe fn __null(new: *mut c_void) {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$null")]
|
||||
fn __null(new: *mut c_void);
|
||||
}
|
||||
}
|
||||
unsafe { __null(new) }
|
||||
}
|
||||
unsafe fn __clone(this: *const c_void, new: *mut c_void) {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$clone")]
|
||||
fn __clone(this: *const c_void, new: *mut c_void);
|
||||
}
|
||||
}
|
||||
unsafe { __clone(this, new) }
|
||||
}
|
||||
unsafe fn __downgrade(shared: *const c_void, weak: *mut c_void) {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$downgrade")]
|
||||
fn __downgrade(shared: *const c_void, weak: *mut c_void);
|
||||
}
|
||||
}
|
||||
unsafe { __downgrade(shared, weak) }
|
||||
}
|
||||
unsafe fn __upgrade(weak: *const c_void, shared: *mut c_void) {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$upgrade")]
|
||||
fn __upgrade(weak: *const c_void, shared: *mut c_void);
|
||||
}
|
||||
}
|
||||
unsafe { __upgrade(weak, shared) }
|
||||
}
|
||||
unsafe fn __drop(this: *mut c_void) {
|
||||
extern "C" {
|
||||
attr! {
|
||||
#[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$drop")]
|
||||
fn __drop(this: *mut c_void);
|
||||
}
|
||||
}
|
||||
unsafe { __drop(this) }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_weak_ptr_target_for_primitive {
|
||||
($ty:ident) => {
|
||||
impl_weak_ptr_target!(stringify!($ty), stringify!($ty), $ty);
|
||||
};
|
||||
}
|
||||
|
||||
impl_weak_ptr_target_for_primitive!(bool);
|
||||
impl_weak_ptr_target_for_primitive!(u8);
|
||||
impl_weak_ptr_target_for_primitive!(u16);
|
||||
impl_weak_ptr_target_for_primitive!(u32);
|
||||
impl_weak_ptr_target_for_primitive!(u64);
|
||||
impl_weak_ptr_target_for_primitive!(usize);
|
||||
impl_weak_ptr_target_for_primitive!(i8);
|
||||
impl_weak_ptr_target_for_primitive!(i16);
|
||||
impl_weak_ptr_target_for_primitive!(i32);
|
||||
impl_weak_ptr_target_for_primitive!(i64);
|
||||
impl_weak_ptr_target_for_primitive!(isize);
|
||||
impl_weak_ptr_target_for_primitive!(f32);
|
||||
impl_weak_ptr_target_for_primitive!(f64);
|
||||
|
||||
impl_weak_ptr_target!("string", "CxxString", CxxString);
|
||||
57
vendor/cxx/tests/BUCK
vendored
Normal file
57
vendor/cxx/tests/BUCK
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
load("//tools/buck:rust_cxx_bridge.bzl", "rust_cxx_bridge")
|
||||
|
||||
rust_test(
|
||||
name = "test",
|
||||
srcs = ["test.rs"],
|
||||
edition = "2018",
|
||||
deps = [
|
||||
":ffi",
|
||||
"//:cxx",
|
||||
],
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "ffi",
|
||||
srcs = [
|
||||
"ffi/cast.rs",
|
||||
"ffi/lib.rs",
|
||||
"ffi/module.rs",
|
||||
],
|
||||
crate = "cxx_test_suite",
|
||||
edition = "2018",
|
||||
deps = [
|
||||
":impl",
|
||||
"//:cxx",
|
||||
],
|
||||
)
|
||||
|
||||
cxx_library(
|
||||
name = "impl",
|
||||
srcs = [
|
||||
"ffi/tests.cc",
|
||||
":bridge/source",
|
||||
":module/source",
|
||||
],
|
||||
exported_deps = ["//:core"],
|
||||
exported_headers = {
|
||||
"ffi/lib.rs.h": ":bridge/header",
|
||||
"ffi/module.rs.h": ":module/header",
|
||||
"ffi/tests.h": "ffi/tests.h",
|
||||
},
|
||||
)
|
||||
|
||||
rust_cxx_bridge(
|
||||
name = "bridge",
|
||||
src = "ffi/lib.rs",
|
||||
deps = [
|
||||
":impl",
|
||||
],
|
||||
)
|
||||
|
||||
rust_cxx_bridge(
|
||||
name = "module",
|
||||
src = "ffi/module.rs",
|
||||
deps = [
|
||||
":impl",
|
||||
],
|
||||
)
|
||||
55
vendor/cxx/tests/BUILD
vendored
Normal file
55
vendor/cxx/tests/BUILD
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
load("@rules_cc//cc:defs.bzl", "cc_library")
|
||||
load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
|
||||
load("//tools/bazel:rust_cxx_bridge.bzl", "rust_cxx_bridge")
|
||||
|
||||
rust_test(
|
||||
name = "test",
|
||||
size = "small",
|
||||
srcs = ["test.rs"],
|
||||
edition = "2018",
|
||||
deps = [
|
||||
":cxx_test_suite",
|
||||
"//:cxx",
|
||||
],
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "cxx_test_suite",
|
||||
srcs = [
|
||||
"ffi/cast.rs",
|
||||
"ffi/lib.rs",
|
||||
"ffi/module.rs",
|
||||
],
|
||||
edition = "2018",
|
||||
deps = [
|
||||
":impl",
|
||||
"//:cxx",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "impl",
|
||||
srcs = [
|
||||
"ffi/tests.cc",
|
||||
":bridge/source",
|
||||
":module/source",
|
||||
],
|
||||
hdrs = ["ffi/tests.h"],
|
||||
deps = [
|
||||
":bridge/include",
|
||||
":module/include",
|
||||
"//:core",
|
||||
],
|
||||
)
|
||||
|
||||
rust_cxx_bridge(
|
||||
name = "bridge",
|
||||
src = "ffi/lib.rs",
|
||||
deps = [":impl"],
|
||||
)
|
||||
|
||||
rust_cxx_bridge(
|
||||
name = "module",
|
||||
src = "ffi/module.rs",
|
||||
deps = [":impl"],
|
||||
)
|
||||
9
vendor/cxx/tests/compiletest.rs
vendored
Normal file
9
vendor/cxx/tests/compiletest.rs
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#[allow(unused_attributes)]
|
||||
#[rustversion::attr(not(nightly), ignore)]
|
||||
#[cfg_attr(skip_ui_tests, ignore)]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
#[test]
|
||||
fn ui() {
|
||||
let t = trybuild::TestCases::new();
|
||||
t.compile_fail("tests/ui/*.rs");
|
||||
}
|
||||
34
vendor/cxx/tests/cxx_gen.rs
vendored
Normal file
34
vendor/cxx/tests/cxx_gen.rs
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#![allow(clippy::field_reassign_with_default)]
|
||||
|
||||
use cxx_gen::{generate_header_and_cc, Opt};
|
||||
use std::str;
|
||||
|
||||
const BRIDGE0: &str = r#"
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
unsafe extern "C++" {
|
||||
pub fn do_cpp_thing(foo: &str);
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn test_extern_c_function() {
|
||||
let opt = Opt::default();
|
||||
let source = BRIDGE0.parse().unwrap();
|
||||
let generated = generate_header_and_cc(source, &opt).unwrap();
|
||||
let output = str::from_utf8(&generated.implementation).unwrap();
|
||||
// To avoid continual breakage we won't test every byte.
|
||||
// Let's look for the major features.
|
||||
assert!(output.contains("void cxxbridge1$do_cpp_thing(::rust::Str foo)"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_impl_annotation() {
|
||||
let mut opt = Opt::default();
|
||||
opt.cxx_impl_annotations = Some("ANNOTATION".to_owned());
|
||||
let source = BRIDGE0.parse().unwrap();
|
||||
let generated = generate_header_and_cc(source, &opt).unwrap();
|
||||
let output = str::from_utf8(&generated.implementation).unwrap();
|
||||
assert!(output.contains("ANNOTATION void cxxbridge1$do_cpp_thing(::rust::Str foo)"));
|
||||
}
|
||||
15
vendor/cxx/tests/cxx_string.rs
vendored
Normal file
15
vendor/cxx/tests/cxx_string.rs
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
use cxx::{let_cxx_string, CxxString};
|
||||
|
||||
#[test]
|
||||
fn test_async_cxx_string() {
|
||||
async fn f() {
|
||||
let_cxx_string!(s = "...");
|
||||
|
||||
async fn g(_: &CxxString) {}
|
||||
g(&s).await;
|
||||
}
|
||||
|
||||
// https://github.com/dtolnay/cxx/issues/693
|
||||
fn assert_send(_: impl Send) {}
|
||||
assert_send(f());
|
||||
}
|
||||
380
vendor/cxx/tests/test.rs
vendored
Normal file
380
vendor/cxx/tests/test.rs
vendored
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
#![allow(
|
||||
clippy::assertions_on_constants,
|
||||
clippy::assertions_on_result_states,
|
||||
clippy::cast_possible_truncation,
|
||||
clippy::cast_possible_wrap,
|
||||
clippy::float_cmp,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::unit_cmp,
|
||||
clippy::unseparated_literal_suffix
|
||||
)]
|
||||
|
||||
use cxx::SharedPtr;
|
||||
use cxx_test_suite::module::ffi2;
|
||||
use cxx_test_suite::{cast, ffi, R};
|
||||
use std::cell::Cell;
|
||||
use std::ffi::CStr;
|
||||
|
||||
thread_local! {
|
||||
static CORRECT: Cell<bool> = Cell::new(false);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn cxx_test_suite_set_correct() {
|
||||
CORRECT.with(|correct| correct.set(true));
|
||||
}
|
||||
|
||||
macro_rules! check {
|
||||
($run:expr) => {{
|
||||
CORRECT.with(|correct| correct.set(false));
|
||||
$run;
|
||||
assert!(CORRECT.with(Cell::get), "{}", stringify!($run));
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_c_return() {
|
||||
let shared = ffi::Shared { z: 2020 };
|
||||
let ns_shared = ffi::AShared { z: 2020 };
|
||||
let nested_ns_shared = ffi::ABShared { z: 2020 };
|
||||
|
||||
assert_eq!(2020, ffi::c_return_primitive());
|
||||
assert_eq!(2020, ffi::c_return_shared().z);
|
||||
assert_eq!(2020, ffi::c_return_box().0);
|
||||
ffi::c_return_unique_ptr();
|
||||
ffi2::c_return_ns_unique_ptr();
|
||||
assert_eq!(2020, *ffi::c_return_ref(&shared));
|
||||
assert_eq!(2020, *ffi::c_return_ns_ref(&ns_shared));
|
||||
assert_eq!(2020, *ffi::c_return_nested_ns_ref(&nested_ns_shared));
|
||||
assert_eq!("2020", ffi::c_return_str(&shared));
|
||||
assert_eq!(
|
||||
b"2020\0",
|
||||
cast::c_char_to_unsigned(ffi::c_return_slice_char(&shared)),
|
||||
);
|
||||
assert_eq!("2020", ffi::c_return_rust_string());
|
||||
assert_eq!("Hello \u{fffd}World", ffi::c_return_rust_string_lossy());
|
||||
assert_eq!("2020", ffi::c_return_unique_ptr_string().to_str().unwrap());
|
||||
assert_eq!(4, ffi::c_return_unique_ptr_vector_u8().len());
|
||||
assert_eq!(
|
||||
200_u8,
|
||||
ffi::c_return_unique_ptr_vector_u8().into_iter().sum(),
|
||||
);
|
||||
assert_eq!(
|
||||
200.5_f64,
|
||||
ffi::c_return_unique_ptr_vector_f64().into_iter().sum(),
|
||||
);
|
||||
assert_eq!(2, ffi::c_return_unique_ptr_vector_shared().len());
|
||||
assert_eq!(
|
||||
2021_usize,
|
||||
ffi::c_return_unique_ptr_vector_shared()
|
||||
.into_iter()
|
||||
.map(|o| o.z)
|
||||
.sum(),
|
||||
);
|
||||
assert_eq!(b"\x02\0\x02\0"[..], ffi::c_return_rust_vec_u8());
|
||||
assert_eq!([true, true, false][..], ffi::c_return_rust_vec_bool());
|
||||
assert_eq!(2020, ffi::c_return_identity(2020));
|
||||
assert_eq!(2021, ffi::c_return_sum(2020, 1));
|
||||
match ffi::c_return_enum(0) {
|
||||
enm @ ffi::Enum::AVal => assert_eq!(0, enm.repr),
|
||||
_ => assert!(false),
|
||||
}
|
||||
match ffi::c_return_enum(1) {
|
||||
enm @ ffi::Enum::BVal => assert_eq!(2020, enm.repr),
|
||||
_ => assert!(false),
|
||||
}
|
||||
match ffi::c_return_enum(2021) {
|
||||
enm @ ffi::Enum::LastVal => assert_eq!(2021, enm.repr),
|
||||
_ => assert!(false),
|
||||
}
|
||||
match ffi::c_return_ns_enum(0) {
|
||||
enm @ ffi::AEnum::AAVal => assert_eq!(0, enm.repr),
|
||||
_ => assert!(false),
|
||||
}
|
||||
match ffi::c_return_nested_ns_enum(0) {
|
||||
enm @ ffi::ABEnum::ABAVal => assert_eq!(0, enm.repr),
|
||||
_ => assert!(false),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_c_try_return() {
|
||||
assert_eq!((), ffi::c_try_return_void().unwrap());
|
||||
assert_eq!(2020, ffi::c_try_return_primitive().unwrap());
|
||||
assert_eq!(
|
||||
"logic error",
|
||||
ffi::c_fail_return_primitive().unwrap_err().what(),
|
||||
);
|
||||
assert_eq!(2020, ffi::c_try_return_box().unwrap().0);
|
||||
assert_eq!("2020", *ffi::c_try_return_ref(&"2020".to_owned()).unwrap());
|
||||
assert_eq!("2020", ffi::c_try_return_str("2020").unwrap());
|
||||
assert_eq!(b"2020", ffi::c_try_return_sliceu8(b"2020").unwrap());
|
||||
assert_eq!("2020", ffi::c_try_return_rust_string().unwrap());
|
||||
assert_eq!("2020", &*ffi::c_try_return_unique_ptr_string().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_c_take() {
|
||||
let unique_ptr = ffi::c_return_unique_ptr();
|
||||
let unique_ptr_ns = ffi2::c_return_ns_unique_ptr();
|
||||
|
||||
check!(ffi::c_take_primitive(2020));
|
||||
check!(ffi::c_take_shared(ffi::Shared { z: 2020 }));
|
||||
check!(ffi::c_take_ns_shared(ffi::AShared { z: 2020 }));
|
||||
check!(ffi::ns_c_take_ns_shared(ffi::AShared { z: 2020 }));
|
||||
check!(ffi::c_take_nested_ns_shared(ffi::ABShared { z: 2020 }));
|
||||
check!(ffi::c_take_box(Box::new(R(2020))));
|
||||
check!(ffi::c_take_ref_c(&unique_ptr));
|
||||
check!(ffi2::c_take_ref_ns_c(&unique_ptr_ns));
|
||||
check!(cxx_test_suite::module::ffi::c_take_unique_ptr(unique_ptr));
|
||||
check!(ffi::c_take_str("2020"));
|
||||
check!(ffi::c_take_slice_char(cast::unsigned_to_c_char(b"2020")));
|
||||
check!(ffi::c_take_slice_shared(&[
|
||||
ffi::Shared { z: 2020 },
|
||||
ffi::Shared { z: 2021 },
|
||||
]));
|
||||
let shared_sort_slice = &mut [
|
||||
ffi::Shared { z: 2 },
|
||||
ffi::Shared { z: 0 },
|
||||
ffi::Shared { z: 7 },
|
||||
ffi::Shared { z: 4 },
|
||||
];
|
||||
check!(ffi::c_take_slice_shared_sort(shared_sort_slice));
|
||||
assert_eq!(shared_sort_slice[0].z, 0);
|
||||
assert_eq!(shared_sort_slice[1].z, 2);
|
||||
assert_eq!(shared_sort_slice[2].z, 4);
|
||||
assert_eq!(shared_sort_slice[3].z, 7);
|
||||
let r_sort_slice = &mut [R(2020), R(2050), R(2021)];
|
||||
check!(ffi::c_take_slice_r(r_sort_slice));
|
||||
check!(ffi::c_take_slice_r_sort(r_sort_slice));
|
||||
assert_eq!(r_sort_slice[0].0, 2020);
|
||||
assert_eq!(r_sort_slice[1].0, 2021);
|
||||
assert_eq!(r_sort_slice[2].0, 2050);
|
||||
check!(ffi::c_take_rust_string("2020".to_owned()));
|
||||
check!(ffi::c_take_unique_ptr_string(
|
||||
ffi::c_return_unique_ptr_string()
|
||||
));
|
||||
let mut vector = ffi::c_return_unique_ptr_vector_u8();
|
||||
assert_eq!(vector.pin_mut().pop(), Some(9));
|
||||
check!(ffi::c_take_unique_ptr_vector_u8(vector));
|
||||
let mut vector = ffi::c_return_unique_ptr_vector_f64();
|
||||
vector.pin_mut().push(9.0);
|
||||
check!(ffi::c_take_unique_ptr_vector_f64(vector));
|
||||
let mut vector = ffi::c_return_unique_ptr_vector_shared();
|
||||
vector.pin_mut().push(ffi::Shared { z: 9 });
|
||||
check!(ffi::c_take_unique_ptr_vector_shared(vector));
|
||||
check!(ffi::c_take_ref_vector(&ffi::c_return_unique_ptr_vector_u8()));
|
||||
let test_vec = [86_u8, 75_u8, 30_u8, 9_u8].to_vec();
|
||||
check!(ffi::c_take_rust_vec(test_vec.clone()));
|
||||
check!(ffi::c_take_rust_vec_index(test_vec.clone()));
|
||||
let shared_test_vec = vec![ffi::Shared { z: 1010 }, ffi::Shared { z: 1011 }];
|
||||
check!(ffi::c_take_rust_vec_shared(shared_test_vec.clone()));
|
||||
check!(ffi::c_take_rust_vec_shared_index(shared_test_vec.clone()));
|
||||
check!(ffi::c_take_rust_vec_shared_push(shared_test_vec.clone()));
|
||||
check!(ffi::c_take_rust_vec_shared_truncate(
|
||||
shared_test_vec.clone()
|
||||
));
|
||||
check!(ffi::c_take_rust_vec_shared_clear(shared_test_vec.clone()));
|
||||
check!(ffi::c_take_rust_vec_shared_forward_iterator(
|
||||
shared_test_vec,
|
||||
));
|
||||
let shared_sort_vec = vec![
|
||||
ffi::Shared { z: 2 },
|
||||
ffi::Shared { z: 0 },
|
||||
ffi::Shared { z: 7 },
|
||||
ffi::Shared { z: 4 },
|
||||
];
|
||||
check!(ffi::c_take_rust_vec_shared_sort(shared_sort_vec));
|
||||
check!(ffi::c_take_ref_rust_vec(&test_vec));
|
||||
check!(ffi::c_take_ref_rust_vec_index(&test_vec));
|
||||
check!(ffi::c_take_ref_rust_vec_copy(&test_vec));
|
||||
check!(ffi::c_take_ref_shared_string(&ffi::SharedString {
|
||||
msg: "2020".to_owned()
|
||||
}));
|
||||
let ns_shared_test_vec = vec![ffi::AShared { z: 1010 }, ffi::AShared { z: 1011 }];
|
||||
check!(ffi::c_take_rust_vec_ns_shared(ns_shared_test_vec));
|
||||
let nested_ns_shared_test_vec = vec![ffi::ABShared { z: 1010 }, ffi::ABShared { z: 1011 }];
|
||||
check!(ffi::c_take_rust_vec_nested_ns_shared(
|
||||
nested_ns_shared_test_vec
|
||||
));
|
||||
|
||||
check!(ffi::c_take_enum(ffi::Enum::AVal));
|
||||
check!(ffi::c_take_ns_enum(ffi::AEnum::AAVal));
|
||||
check!(ffi::c_take_nested_ns_enum(ffi::ABEnum::ABAVal));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_c_callback() {
|
||||
fn callback(s: String) -> usize {
|
||||
if s == "2020" {
|
||||
cxx_test_suite_set_correct();
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[allow(clippy::ptr_arg)]
|
||||
fn callback_ref(s: &String) {
|
||||
if s == "2020" {
|
||||
cxx_test_suite_set_correct();
|
||||
}
|
||||
}
|
||||
|
||||
fn callback_mut(s: &mut String) {
|
||||
if s == "2020" {
|
||||
cxx_test_suite_set_correct();
|
||||
}
|
||||
}
|
||||
|
||||
check!(ffi::c_take_callback(callback));
|
||||
check!(ffi::c_take_callback_ref(callback_ref));
|
||||
check!(ffi::c_take_callback_ref_lifetime(callback_ref));
|
||||
check!(ffi::c_take_callback_mut(callback_mut));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_c_call_r() {
|
||||
fn cxx_run_test() {
|
||||
extern "C" {
|
||||
fn cxx_run_test() -> *const i8;
|
||||
}
|
||||
let failure = unsafe { cxx_run_test() };
|
||||
if !failure.is_null() {
|
||||
let msg = unsafe { CStr::from_ptr(failure as *mut std::os::raw::c_char) };
|
||||
eprintln!("{}", msg.to_string_lossy());
|
||||
}
|
||||
}
|
||||
check!(cxx_run_test());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_c_method_calls() {
|
||||
let mut unique_ptr = ffi::c_return_unique_ptr();
|
||||
|
||||
let old_value = unique_ptr.get();
|
||||
assert_eq!(2020, old_value);
|
||||
assert_eq!(2021, unique_ptr.pin_mut().set(2021));
|
||||
assert_eq!(2021, unique_ptr.get());
|
||||
assert_eq!(2021, unique_ptr.get2());
|
||||
assert_eq!(2021, *unique_ptr.getRef());
|
||||
assert_eq!(2021, *unique_ptr.pin_mut().getMut());
|
||||
assert_eq!(2022, unique_ptr.pin_mut().set_succeed(2022).unwrap());
|
||||
assert!(unique_ptr.pin_mut().get_fail().is_err());
|
||||
assert_eq!(2021, ffi::Shared { z: 0 }.c_method_on_shared());
|
||||
assert_eq!(2022, *ffi::Shared { z: 2022 }.c_method_ref_on_shared());
|
||||
assert_eq!(2023, *ffi::Shared { z: 2023 }.c_method_mut_on_shared());
|
||||
|
||||
let val = 42;
|
||||
let mut array = ffi::Array {
|
||||
a: [0, 0, 0, 0],
|
||||
b: ffi::Buffer::default(),
|
||||
};
|
||||
array.c_set_array(val);
|
||||
assert_eq!(array.a.len() as i32 * val, array.r_get_array_sum());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shared_ptr_weak_ptr() {
|
||||
let shared_ptr = ffi::c_return_shared_ptr();
|
||||
let weak_ptr = SharedPtr::downgrade(&shared_ptr);
|
||||
assert_eq!(1, ffi::c_get_use_count(&weak_ptr));
|
||||
|
||||
assert!(!weak_ptr.upgrade().is_null());
|
||||
assert_eq!(1, ffi::c_get_use_count(&weak_ptr));
|
||||
|
||||
drop(shared_ptr);
|
||||
assert_eq!(0, ffi::c_get_use_count(&weak_ptr));
|
||||
assert!(weak_ptr.upgrade().is_null());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_c_ns_method_calls() {
|
||||
let unique_ptr = ffi2::ns_c_return_unique_ptr_ns();
|
||||
|
||||
let old_value = unique_ptr.get();
|
||||
assert_eq!(1000, old_value);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enum_representations() {
|
||||
assert_eq!(0, ffi::Enum::AVal.repr);
|
||||
assert_eq!(2020, ffi::Enum::BVal.repr);
|
||||
assert_eq!(2021, ffi::Enum::LastVal.repr);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_debug() {
|
||||
assert_eq!("Shared { z: 1 }", format!("{:?}", ffi::Shared { z: 1 }));
|
||||
assert_eq!("BVal", format!("{:?}", ffi::Enum::BVal));
|
||||
assert_eq!("Enum(9)", format!("{:?}", ffi::Enum { repr: 9 }));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn cxx_test_suite_get_box() -> *mut R {
|
||||
Box::into_raw(Box::new(R(2020usize)))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn cxx_test_suite_r_is_correct(r: *const R) -> bool {
|
||||
(*r).0 == 2020
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rust_name_attribute() {
|
||||
assert_eq!("2020", ffi::i32_overloaded_function(2020));
|
||||
assert_eq!("2020", ffi::str_overloaded_function("2020"));
|
||||
let unique_ptr = ffi::c_return_unique_ptr();
|
||||
assert_eq!("2020", unique_ptr.i32_overloaded_method(2020));
|
||||
assert_eq!("2020", unique_ptr.str_overloaded_method("2020"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extern_trivial() {
|
||||
let mut d = ffi2::c_return_trivial();
|
||||
check!(ffi2::c_take_trivial_ref(&d));
|
||||
check!(d.c_take_trivial_ref_method());
|
||||
check!(d.c_take_trivial_mut_ref_method());
|
||||
check!(ffi2::c_take_trivial(d));
|
||||
let mut d = ffi2::c_return_trivial_ptr();
|
||||
check!(d.c_take_trivial_ref_method());
|
||||
check!(d.c_take_trivial_mut_ref_method());
|
||||
check!(ffi2::c_take_trivial_ptr(d));
|
||||
cxx::UniquePtr::new(ffi2::D { d: 42 });
|
||||
let d = ffi2::ns_c_return_trivial();
|
||||
check!(ffi2::ns_c_take_trivial(d));
|
||||
|
||||
let g = ffi2::c_return_trivial_ns();
|
||||
check!(ffi2::c_take_trivial_ns_ref(&g));
|
||||
check!(ffi2::c_take_trivial_ns(g));
|
||||
let g = ffi2::c_return_trivial_ns_ptr();
|
||||
check!(ffi2::c_take_trivial_ns_ptr(g));
|
||||
cxx::UniquePtr::new(ffi2::G { g: 42 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extern_opaque() {
|
||||
let mut e = ffi2::c_return_opaque_ptr();
|
||||
check!(ffi2::c_take_opaque_ref(e.as_ref().unwrap()));
|
||||
check!(e.c_take_opaque_ref_method());
|
||||
check!(e.pin_mut().c_take_opaque_mut_ref_method());
|
||||
check!(ffi2::c_take_opaque_ptr(e));
|
||||
|
||||
let f = ffi2::c_return_ns_opaque_ptr();
|
||||
check!(ffi2::c_take_opaque_ns_ref(f.as_ref().unwrap()));
|
||||
check!(ffi2::c_take_opaque_ns_ptr(f));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_ptr() {
|
||||
let c = ffi::c_return_mut_ptr(2023);
|
||||
let mut c_unique = unsafe { cxx::UniquePtr::from_raw(c) };
|
||||
assert_eq!(2023, c_unique.pin_mut().set_succeed(2023).unwrap());
|
||||
// c will be dropped as it's now in a UniquePtr
|
||||
|
||||
let c2 = ffi::c_return_mut_ptr(2024);
|
||||
assert_eq!(2024, unsafe { ffi::c_take_const_ptr(c2) });
|
||||
assert_eq!(2024, unsafe { ffi::c_take_mut_ptr(c2) }); // deletes c2
|
||||
|
||||
let c3 = ffi::c_return_const_ptr(2025);
|
||||
assert_eq!(2025, unsafe { ffi::c_take_const_ptr(c3) });
|
||||
assert_eq!(2025, unsafe { ffi::c_take_mut_ptr(c3 as *mut ffi::C) }); // deletes c3
|
||||
}
|
||||
10
vendor/cxx/tests/ui/array_len_expr.rs
vendored
Normal file
10
vendor/cxx/tests/ui/array_len_expr.rs
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
struct Shared {
|
||||
arraystr: [String; "13"],
|
||||
arraysub: [String; 15 - 1],
|
||||
arrayzero: [String; 0],
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
17
vendor/cxx/tests/ui/array_len_expr.stderr
vendored
Normal file
17
vendor/cxx/tests/ui/array_len_expr.stderr
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
error: array length must be an integer literal
|
||||
--> tests/ui/array_len_expr.rs:4:28
|
||||
|
|
||||
4 | arraystr: [String; "13"],
|
||||
| ^^^^
|
||||
|
||||
error: unsupported expression, array length must be an integer literal
|
||||
--> tests/ui/array_len_expr.rs:5:28
|
||||
|
|
||||
5 | arraysub: [String; 15 - 1],
|
||||
| ^^^^^^
|
||||
|
||||
error: array with zero size is not supported
|
||||
--> tests/ui/array_len_expr.rs:6:20
|
||||
|
|
||||
6 | arrayzero: [String; 0],
|
||||
| ^^^^^^^^^^^
|
||||
8
vendor/cxx/tests/ui/array_len_suffix.rs
vendored
Normal file
8
vendor/cxx/tests/ui/array_len_suffix.rs
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
unsafe extern "C++" {
|
||||
fn array() -> [String; 12u16];
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
10
vendor/cxx/tests/ui/array_len_suffix.stderr
vendored
Normal file
10
vendor/cxx/tests/ui/array_len_suffix.stderr
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
error[E0308]: mismatched types
|
||||
--> tests/ui/array_len_suffix.rs:4:32
|
||||
|
|
||||
4 | fn array() -> [String; 12u16];
|
||||
| ^^^^^ expected `usize`, found `u16`
|
||||
|
|
||||
help: change the type of the numeric literal from `u16` to `usize`
|
||||
|
|
||||
4 | fn array() -> [String; 12usize];
|
||||
| ~~~~~
|
||||
14
vendor/cxx/tests/ui/async_fn.rs
vendored
Normal file
14
vendor/cxx/tests/ui/async_fn.rs
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
async fn f();
|
||||
}
|
||||
|
||||
extern "C++" {
|
||||
async fn g();
|
||||
}
|
||||
}
|
||||
|
||||
async fn f() {}
|
||||
|
||||
fn main() {}
|
||||
11
vendor/cxx/tests/ui/async_fn.stderr
vendored
Normal file
11
vendor/cxx/tests/ui/async_fn.stderr
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
error: async function is not directly supported yet, but see https://cxx.rs/async.html for a working approach, and https://github.com/pcwalton/cxx-async for some helpers; eventually what you wrote will work but it isn't integrated into the cxx::bridge macro yet
|
||||
--> tests/ui/async_fn.rs:4:9
|
||||
|
|
||||
4 | async fn f();
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: async function is not directly supported yet, but see https://cxx.rs/async.html for a working approach, and https://github.com/pcwalton/cxx-async for some helpers; eventually what you wrote will work but it isn't integrated into the cxx::bridge macro yet
|
||||
--> tests/ui/async_fn.rs:8:9
|
||||
|
|
||||
8 | async fn g();
|
||||
| ^^^^^^^^^^^^^
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue